common.inc 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297
  1. <?php
  2. /**
  3. * @file
  4. * List of common helper functions for use in Bootstrap based themes.
  5. */
  6. define('BOOTSTRAP_VERSION_MAJOR', 3);
  7. define('BOOTSTRAP_VERSION_MINOR', 3);
  8. define('BOOTSTRAP_VERSION_PATCH', 5);
  9. define('BOOTSTRAP_VERSION', BOOTSTRAP_VERSION_MAJOR . '.' . BOOTSTRAP_VERSION_MINOR . '.' . BOOTSTRAP_VERSION_PATCH);
  10. /**
  11. * @defgroup subtheme_helper_functions Helper Functions
  12. * @ingroup subtheme
  13. *
  14. * List of common helper functions for use in Drupal Bootstrap based themes.
  15. *
  16. * @{
  17. */
  18. /**
  19. * Converts an element description into a tooltip based on certain criteria.
  20. *
  21. * @param array $element
  22. * An element render array, passed by reference.
  23. * @param array $target
  24. * The target element render array the tooltip is to be attached to, passed
  25. * by reference. If not set, it will default to the $element passed.
  26. * @param bool $input_only
  27. * Toggle determining whether or not to only convert input elements.
  28. * @param int $length
  29. * The length of characters to determine if description is "simple".
  30. */
  31. function bootstrap_element_smart_description(&$element, &$target = NULL, $input_only = TRUE, $length = NULL) {
  32. // Determine if tooltips are enabled.
  33. static $enabled;
  34. if (!isset($enabled)) {
  35. $enabled = bootstrap_setting('tooltip_enabled') && bootstrap_setting('forms_smart_descriptions');
  36. }
  37. // Immediately return if "simple" tooltip descriptions are not enabled.
  38. if (!$enabled) {
  39. return;
  40. }
  41. // Allow a different element to attach the tooltip.
  42. if (!isset($target)) {
  43. $target = &$element;
  44. }
  45. // Retrieve the length limit for smart descriptions.
  46. if (!isset($length)) {
  47. $length = (int) bootstrap_setting('forms_smart_descriptions_limit');
  48. // Disable length checking by setting it to FALSE if empty.
  49. if (empty($length)) {
  50. $length = FALSE;
  51. }
  52. }
  53. // Retrieve the allowed tags for smart descriptions. This is primarily used
  54. // for display purposes only (i.e. non-UI/UX related elements that wouldn't
  55. // require a user to "click", like a link).
  56. $allowed_tags = array_filter(array_unique(array_map('trim', explode(',', bootstrap_setting('forms_smart_descriptions_allowed_tags') . ''))));
  57. // Disable length checking by setting it to FALSE if empty.
  58. if (empty($allowed_tags)) {
  59. $allowed_tags = FALSE;
  60. }
  61. $html = FALSE;
  62. $type = !empty($element['#type']) ? $element['#type'] : FALSE;
  63. if (!$input_only || !empty($target['#input']) || !empty($element['#smart_description']) || !empty($target['#smart_description'])) {
  64. if (!empty($element['#description']) && empty($target['#attributes']['title']) && empty($target['#attributes']['data-toggle'])) {
  65. if (_bootstrap_is_simple_string($element['#description'], $length, $allowed_tags, $html)) {
  66. // Default property (on the element itself).
  67. $property = 'attributes';
  68. // Add the tooltip to the #label_attributes property for 'checkbox'
  69. // and 'radio' elements.
  70. if ($type === 'checkbox' || $type === 'radio') {
  71. $property = 'label_attributes';
  72. }
  73. // Add the tooltip to the #wrapper_attributes property for 'checkboxes'
  74. // and 'radios' elements.
  75. elseif ($type === 'checkboxes' || $type === 'radios') {
  76. $property = 'wrapper_attributes';
  77. }
  78. // Add the tooltip to the #input_group_attributes property for elements
  79. // that have valid input groups set.
  80. elseif ((!empty($element['#field_prefix']) || !empty($element['#field_suffix'])) && (!empty($element['#input_group']) || !empty($element['#input_group_button']))) {
  81. $property = 'input_group_attributes';
  82. }
  83. // Retrieve the proper attributes array.
  84. $attributes = &_bootstrap_get_attributes($target, $property);
  85. // Set the tooltip attributes.
  86. $attributes['title'] = $allowed_tags !== FALSE ? filter_xss($element['#description'], $allowed_tags) : $element['#description'];
  87. $attributes['data-toggle'] = 'tooltip';
  88. if ($html || $allowed_tags === FALSE) {
  89. $attributes['data-html'] = 'true';
  90. }
  91. // Remove the element description so it isn't (re-)rendered later.
  92. unset($element['#description']);
  93. }
  94. }
  95. }
  96. }
  97. /**
  98. * Retrieves CDN assets for the active provider, if any.
  99. *
  100. * @param string|array $type
  101. * The type of asset to retrieve: "css" or "js", defaults to an array
  102. * array containing both if not set.
  103. * @param string $provider
  104. * The name of a specific CDN provider to use, defaults to the active provider
  105. * set in the theme settings.
  106. * @param string $theme
  107. * The name of a specific theme the settings should be retrieved from,
  108. * defaults to the active theme.
  109. *
  110. * @return array
  111. * If $type is a string or an array with only one (1) item in it, the assets
  112. * are returned as an indexed array of files. Otherwise, an associative array
  113. * is returned keyed by the type.
  114. */
  115. function bootstrap_get_cdn_assets($type = NULL, $provider = NULL, $theme = NULL) {
  116. $original_type = $type;
  117. $assets = array();
  118. $types = array();
  119. // If no type is set, return all CSS and JS.
  120. if (!isset($type)) {
  121. $types = array('css', 'js');
  122. }
  123. elseif (isset($type)) {
  124. if (!is_array($type)) {
  125. $type = array($type);
  126. }
  127. $types = $type;
  128. }
  129. // Ensure default arrays exist for the requested types.
  130. foreach ($types as $type) {
  131. $assets[$type] = array();
  132. }
  133. // Retrieve the CDN provider from the theme.
  134. if (!isset($provider)) {
  135. $provider = bootstrap_setting('cdn_provider', $theme);
  136. }
  137. // Load the CDN provider data.
  138. bootstrap_include('bootstrap', 'includes/cdn.inc');
  139. if (!empty($provider) && ($data = bootstrap_cdn_provider($provider))) {
  140. // Alter the assets based on provider.
  141. $function = 'bootstrap_bootstrap_cdn_provider_' . $provider . '_assets_alter';
  142. if (function_exists($function)) {
  143. $function($data, $theme);
  144. }
  145. // @todo Use drupal_alter() once CDN is in bootstrap_core companion module.
  146. // drupal_alter('bootstrap_cdn_provider_' . $provider . '_assets', $data, $theme);
  147. // Iterate over each type.
  148. foreach ($types as $type) {
  149. if (variable_get("preprocess_$type", FALSE) && !empty($data['min'][$type])) {
  150. $assets[$type] = $data['min'][$type];
  151. }
  152. elseif (!empty($data[$type])) {
  153. $assets[$type] = $data[$type];
  154. }
  155. }
  156. }
  157. return is_string($original_type) ? $assets[$original_type] : $assets;
  158. }
  159. /**
  160. * Return information from the .info file of a theme (and possible base themes).
  161. *
  162. * @param string $theme_key
  163. * The machine name of the theme.
  164. * @param string $key
  165. * The key name of the item to return from the .info file. This value can
  166. * include "][" to automatically attempt to traverse any arrays.
  167. * @param bool $base_themes
  168. * Recursively search base themes, defaults to TRUE.
  169. *
  170. * @return string|array|false
  171. * A string or array depending on the type of value and if a base theme also
  172. * contains the same $key, FALSE if no $key is found.
  173. */
  174. function bootstrap_get_theme_info($theme_key = NULL, $key = NULL, $base_themes = TRUE) {
  175. // If no $theme_key is given, use the current theme if we can determine it.
  176. if (!isset($theme_key)) {
  177. $theme_key = !empty($GLOBALS['theme_key']) ? $GLOBALS['theme_key'] : FALSE;
  178. }
  179. if ($theme_key) {
  180. $themes = list_themes();
  181. if (!empty($themes[$theme_key])) {
  182. $theme = $themes[$theme_key];
  183. // If a key name was specified, return just that array.
  184. if ($key) {
  185. $value = FALSE;
  186. // Recursively add base theme values.
  187. if ($base_themes && isset($theme->base_themes)) {
  188. foreach (array_keys($theme->base_themes) as $base_theme) {
  189. $value = bootstrap_get_theme_info($base_theme, $key);
  190. }
  191. }
  192. if (!empty($themes[$theme_key])) {
  193. $info = $themes[$theme_key]->info;
  194. // Allow array traversal.
  195. $keys = explode('][', $key);
  196. foreach ($keys as $parent) {
  197. if (isset($info[$parent])) {
  198. $info = $info[$parent];
  199. }
  200. else {
  201. $info = FALSE;
  202. }
  203. }
  204. if (is_array($value)) {
  205. if (!empty($info)) {
  206. if (!is_array($info)) {
  207. $info = array($info);
  208. }
  209. $value = drupal_array_merge_deep($value, $info);
  210. }
  211. }
  212. else {
  213. if (!empty($info)) {
  214. if (empty($value)) {
  215. $value = $info;
  216. }
  217. else {
  218. if (!is_array($value)) {
  219. $value = array($value);
  220. }
  221. if (!is_array($info)) {
  222. $info = array($info);
  223. }
  224. $value = drupal_array_merge_deep($value, $info);
  225. }
  226. }
  227. }
  228. }
  229. return $value;
  230. }
  231. // If no info $key was specified, just return the entire info array.
  232. return $theme->info;
  233. }
  234. }
  235. return FALSE;
  236. }
  237. /**
  238. * Includes a theme file.
  239. *
  240. * @param string $theme
  241. * Name of the theme to use for base path.
  242. * @param string $path
  243. * Path relative to $theme.
  244. */
  245. function bootstrap_include($theme, $path) {
  246. static $themes = array();
  247. if (!isset($themes[$theme])) {
  248. $themes[$theme] = drupal_get_path('theme', $theme);
  249. }
  250. if ($themes[$theme] && ($file = DRUPAL_ROOT . '/' . $themes[$theme] . '/' . $path) && file_exists($file)) {
  251. include_once $file;
  252. }
  253. }
  254. /**
  255. * Retrieves a setting for the current theme or for a given theme.
  256. *
  257. * This is a wrapper for theme_get_setting(), ensuring to use deprecated
  258. * setting values instead.
  259. *
  260. * @param string $name
  261. * The name of the setting to be retrieved.
  262. * @param string $theme
  263. * The name of a given theme; defaults to the currently active theme.
  264. * @param string $prefix
  265. * The prefix used on the $name of the setting, this will be appended with
  266. * "_" automatically if set.
  267. *
  268. * @return mixed
  269. * The value of the requested setting, NULL if the setting does not exist.
  270. *
  271. * @see theme_get_setting()
  272. *
  273. * @todo Refactor in 7.x-4.x and get rid of the deprecated settings.
  274. */
  275. function bootstrap_setting($name, $theme = NULL, $prefix = 'bootstrap') {
  276. $prefix = !empty($prefix) ? $prefix . '_' : '';
  277. $setting = theme_get_setting($prefix . $name, $theme);
  278. switch ($prefix . $name) {
  279. case 'bootstrap_cdn_provider':
  280. $deprecated = theme_get_setting('bootstrap_cdn', $theme);
  281. if (isset($deprecated)) {
  282. $setting = empty($deprecated) ? '' : 'jsdelivr';
  283. }
  284. break;
  285. case 'bootstrap_cdn_jsdelivr_version':
  286. $deprecated = theme_get_setting('bootstrap_cdn', $theme);
  287. if (isset($deprecated)) {
  288. $setting = empty($deprecated) ? BOOTSTRAP_VERSION : $deprecated;
  289. }
  290. break;
  291. case 'bootstrap_cdn_jsdelivr_theme':
  292. $deprecated = theme_get_setting('bootstrap_bootswatch', $theme);
  293. if (isset($deprecated)) {
  294. $setting = empty($deprecated) ? 'bootstrap' : $deprecated;
  295. }
  296. break;
  297. case 'bootstrap_forms_smart_descriptions':
  298. $deprecated = theme_get_setting('bootstrap_tooltip_descriptions', $theme);
  299. if (isset($deprecated)) {
  300. $setting = (int) !empty($deprecated);
  301. }
  302. break;
  303. case 'bootstrap_forms_smart_descriptions_limit':
  304. $deprecated = theme_get_setting('bootstrap_tooltip_descriptions_length', $theme);
  305. if (isset($deprecated)) {
  306. $setting = (int) !empty($deprecated);
  307. }
  308. break;
  309. }
  310. return $setting;
  311. }
  312. /**
  313. * Retrieves an element's "attributes" array.
  314. *
  315. * @param array $element
  316. * The individual renderable array element. It is possible to also pass the
  317. * $variables parameter in [pre]process functions and it will logically
  318. * determine the correct path to that particular theme hook's attribute array.
  319. * Passed by reference.
  320. * @param string $property
  321. * Determines which attributes array to retrieve. By default, this is the
  322. * normal attributes, but can be "wrapper_attributes" or
  323. * "input_group_attributes".
  324. *
  325. * @return array
  326. * The attributes array. Passed by reference.
  327. */
  328. function &_bootstrap_get_attributes(&$element, $property = 'attributes') {
  329. // Attempt to retrieve a renderable element attributes first.
  330. if (
  331. isset($element['#type']) ||
  332. isset($element['#theme']) ||
  333. isset($element['#pre_render']) ||
  334. isset($element['#markup']) ||
  335. isset($element['#theme_wrappers']) ||
  336. isset($element["#$property"])
  337. ) {
  338. if (!isset($element["#$property"])) {
  339. $element["#$property"] = array();
  340. }
  341. return $element["#$property"];
  342. }
  343. // Treat $element as if it were a [pre]process function $variables parameter
  344. // and look for a renderable "element".
  345. elseif (isset($element['element'])) {
  346. if (!isset($element['element']["#$property"])) {
  347. $element['element']["#$property"] = array();
  348. }
  349. return $element['element']["#$property"];
  350. }
  351. // If all else fails, create (if needed) a default "attributes" array. This
  352. // will, at the very least, either work or cause an error that can be tracked.
  353. if (!isset($element[$property])) {
  354. $element[$property] = array();
  355. }
  356. return $element[$property];
  357. }
  358. /**
  359. * Retrieves an element's "class" array.
  360. *
  361. * @param array $element
  362. * The individual renderable array element. It is possible to also pass the
  363. * $variables parameter in [pre]process functions and it will logically
  364. * determine the correct path to that particular theme hook's classes array.
  365. * Passed by reference.
  366. * @param string $property
  367. * Determines which attributes array to retrieve. By default, this is the
  368. * normal attributes, but can be "wrapper_attributes" or
  369. * "input_group_attributes".
  370. *
  371. * @return array
  372. * The classes array. Passed by reference.
  373. */
  374. function &_bootstrap_get_classes(&$element, $property = 'attributes') {
  375. $attributes = &_bootstrap_get_attributes($element, $property);
  376. if (!isset($attributes['class'])) {
  377. $attributes['class'] = array();
  378. }
  379. // Contrib modules have a very bad habit of frequently adding classes as
  380. // strings, convert them to a proper array.
  381. // @see https://www.drupal.org/node/2269653
  382. elseif (!is_array($attributes['class'])) {
  383. $attributes['class'] = explode(' ', $attributes['class']);
  384. }
  385. // Ensure classes are not duplicated.
  386. $attributes['class'] = array_unique($attributes['class']);
  387. return $attributes['class'];
  388. }
  389. /**
  390. * Adds a class to an element's render array.
  391. *
  392. * @param string|array $class
  393. * An individual class or an array of classes to add.
  394. * @param array $element
  395. * The individual renderable array element. It is possible to also pass the
  396. * $variables parameter in [pre]process functions and it will logically
  397. * determine the correct path to that particular theme hook's classes array.
  398. * Passed by reference.
  399. * @param string $property
  400. * Determines which attributes array to retrieve. By default, this is the
  401. * normal attributes, but can be "wrapper_attributes" or
  402. * "input_group_attributes".
  403. */
  404. function _bootstrap_add_class($class, &$element, $property = 'attributes') {
  405. // Retrieve the element's classes.
  406. $classes = &_bootstrap_get_classes($element, $property);
  407. // Convert the class to an array.
  408. if (!is_array($class)) {
  409. $class = array($class);
  410. }
  411. // Iterate over all classes to add.
  412. foreach ($class as $_class) {
  413. // Ensure the class to add does not yet already exist.
  414. if (!in_array($_class, $classes)) {
  415. $classes[] = $_class;
  416. }
  417. }
  418. }
  419. /**
  420. * Removes a class from an element's render array.
  421. *
  422. * @param string|array $class
  423. * An individual class or an array of classes to remove.
  424. * @param array $element
  425. * The individual renderable array element. It is possible to also pass the
  426. * $variables parameter in [pre]process functions and it will logically
  427. * determine the correct path to that particular theme hook's classes array.
  428. * Passed by reference.
  429. * @param string $property
  430. * Determines which attributes array to retrieve. By default, this is the
  431. * normal attributes, but can be "wrapper_attributes" or
  432. * "input_group_attributes".
  433. */
  434. function _bootstrap_remove_class($class, &$element, $property = 'attributes') {
  435. // Retrieve the element's classes.
  436. $classes = &_bootstrap_get_classes($element, $property);
  437. // Convert the class to an array.
  438. if (!is_array($class)) {
  439. $class = array($class);
  440. }
  441. // Iterate over all classes to add.
  442. foreach ($class as $_class) {
  443. $key = array_search($_class, $classes);
  444. if ($key !== FALSE) {
  445. unset($classes[$key]);
  446. }
  447. }
  448. }
  449. /**
  450. * Returns a list of base themes for active or provided theme.
  451. *
  452. * @param string $theme_key
  453. * The machine name of the theme to check, if not set the active theme name
  454. * will be used.
  455. * @param bool $include_theme_key
  456. * Whether to append the returned list with $theme_key.
  457. *
  458. * @return array
  459. * An indexed array of base themes.
  460. */
  461. function _bootstrap_get_base_themes($theme_key = NULL, $include_theme_key = FALSE) {
  462. static $themes;
  463. if (!isset($theme_key)) {
  464. $theme_key = $GLOBALS['theme_key'];
  465. }
  466. if (!isset($themes[$theme_key])) {
  467. $themes[$theme_key] = array_unique(array_filter((array) bootstrap_get_theme_info($theme_key, 'base theme')));
  468. }
  469. if ($include_theme_key) {
  470. $themes[$theme_key][] = $theme_key;
  471. }
  472. return $themes[$theme_key];
  473. }
  474. /**
  475. * Wrapper for the core file_scan_directory() function.
  476. *
  477. * Finds all files that match a given mask in a given directory and then caches
  478. * the results. A general site cache clear will force new scans to be initiated
  479. * for already cached directories.
  480. *
  481. * @param string $dir
  482. * The base directory or URI to scan, without trailing slash.
  483. * @param string $mask
  484. * The preg_match() regular expression of the files to find.
  485. * @param array $options
  486. * Additional options to pass to file_scan_directory().
  487. *
  488. * @return array
  489. * An associative array (keyed on the chosen key) of objects with 'uri',
  490. * 'filename', and 'name' members corresponding to the matching files.
  491. *
  492. * @see file_scan_directory()
  493. */
  494. function _bootstrap_file_scan_directory($dir, $mask, array $options = array()) {
  495. // Retrieve cached data.
  496. $cid = 'theme_registry:bootstrap:files';
  497. $files = array();
  498. if ($cache = cache_get($cid)) {
  499. $files = $cache->data;
  500. }
  501. // Generate a unique hash for all parameters passed as a change in any of
  502. // them would return different results.
  503. $hash = drupal_hash_base64(serialize(func_get_args()));
  504. if (!isset($files[$hash])) {
  505. $files[$hash] = file_scan_directory($dir, $mask, $options);
  506. cache_set($cid, $files);
  507. }
  508. return $files[$hash];
  509. }
  510. /**
  511. * Returns a list of available Bootstrap Glyphicons.
  512. *
  513. * @param string $version
  514. * The specific version of glyphicons to return. If not set, the latest
  515. * BOOTSTRAP_VERSION will be used.
  516. *
  517. * @return array
  518. * An associative array of icons keyed by their classes.
  519. */
  520. function _bootstrap_glyphicons($version = NULL) {
  521. static $versions;
  522. if (!isset($versions)) {
  523. $versions = array();
  524. $versions['3.0.0'] = array(
  525. // Class => Name.
  526. 'glyphicon-adjust' => 'adjust',
  527. 'glyphicon-align-center' => 'align-center',
  528. 'glyphicon-align-justify' => 'align-justify',
  529. 'glyphicon-align-left' => 'align-left',
  530. 'glyphicon-align-right' => 'align-right',
  531. 'glyphicon-arrow-down' => 'arrow-down',
  532. 'glyphicon-arrow-left' => 'arrow-left',
  533. 'glyphicon-arrow-right' => 'arrow-right',
  534. 'glyphicon-arrow-up' => 'arrow-up',
  535. 'glyphicon-asterisk' => 'asterisk',
  536. 'glyphicon-backward' => 'backward',
  537. 'glyphicon-ban-circle' => 'ban-circle',
  538. 'glyphicon-barcode' => 'barcode',
  539. 'glyphicon-bell' => 'bell',
  540. 'glyphicon-bold' => 'bold',
  541. 'glyphicon-book' => 'book',
  542. 'glyphicon-bookmark' => 'bookmark',
  543. 'glyphicon-briefcase' => 'briefcase',
  544. 'glyphicon-bullhorn' => 'bullhorn',
  545. 'glyphicon-calendar' => 'calendar',
  546. 'glyphicon-camera' => 'camera',
  547. 'glyphicon-certificate' => 'certificate',
  548. 'glyphicon-check' => 'check',
  549. 'glyphicon-chevron-down' => 'chevron-down',
  550. 'glyphicon-chevron-left' => 'chevron-left',
  551. 'glyphicon-chevron-right' => 'chevron-right',
  552. 'glyphicon-chevron-up' => 'chevron-up',
  553. 'glyphicon-circle-arrow-down' => 'circle-arrow-down',
  554. 'glyphicon-circle-arrow-left' => 'circle-arrow-left',
  555. 'glyphicon-circle-arrow-right' => 'circle-arrow-right',
  556. 'glyphicon-circle-arrow-up' => 'circle-arrow-up',
  557. 'glyphicon-cloud' => 'cloud',
  558. 'glyphicon-cloud-download' => 'cloud-download',
  559. 'glyphicon-cloud-upload' => 'cloud-upload',
  560. 'glyphicon-cog' => 'cog',
  561. 'glyphicon-collapse-down' => 'collapse-down',
  562. 'glyphicon-collapse-up' => 'collapse-up',
  563. 'glyphicon-comment' => 'comment',
  564. 'glyphicon-compressed' => 'compressed',
  565. 'glyphicon-copyright-mark' => 'copyright-mark',
  566. 'glyphicon-credit-card' => 'credit-card',
  567. 'glyphicon-cutlery' => 'cutlery',
  568. 'glyphicon-dashboard' => 'dashboard',
  569. 'glyphicon-download' => 'download',
  570. 'glyphicon-download-alt' => 'download-alt',
  571. 'glyphicon-earphone' => 'earphone',
  572. 'glyphicon-edit' => 'edit',
  573. 'glyphicon-eject' => 'eject',
  574. 'glyphicon-envelope' => 'envelope',
  575. 'glyphicon-euro' => 'euro',
  576. 'glyphicon-exclamation-sign' => 'exclamation-sign',
  577. 'glyphicon-expand' => 'expand',
  578. 'glyphicon-export' => 'export',
  579. 'glyphicon-eye-close' => 'eye-close',
  580. 'glyphicon-eye-open' => 'eye-open',
  581. 'glyphicon-facetime-video' => 'facetime-video',
  582. 'glyphicon-fast-backward' => 'fast-backward',
  583. 'glyphicon-fast-forward' => 'fast-forward',
  584. 'glyphicon-file' => 'file',
  585. 'glyphicon-film' => 'film',
  586. 'glyphicon-filter' => 'filter',
  587. 'glyphicon-fire' => 'fire',
  588. 'glyphicon-flag' => 'flag',
  589. 'glyphicon-flash' => 'flash',
  590. 'glyphicon-floppy-disk' => 'floppy-disk',
  591. 'glyphicon-floppy-open' => 'floppy-open',
  592. 'glyphicon-floppy-remove' => 'floppy-remove',
  593. 'glyphicon-floppy-save' => 'floppy-save',
  594. 'glyphicon-floppy-saved' => 'floppy-saved',
  595. 'glyphicon-folder-close' => 'folder-close',
  596. 'glyphicon-folder-open' => 'folder-open',
  597. 'glyphicon-font' => 'font',
  598. 'glyphicon-forward' => 'forward',
  599. 'glyphicon-fullscreen' => 'fullscreen',
  600. 'glyphicon-gbp' => 'gbp',
  601. 'glyphicon-gift' => 'gift',
  602. 'glyphicon-glass' => 'glass',
  603. 'glyphicon-globe' => 'globe',
  604. 'glyphicon-hand-down' => 'hand-down',
  605. 'glyphicon-hand-left' => 'hand-left',
  606. 'glyphicon-hand-right' => 'hand-right',
  607. 'glyphicon-hand-up' => 'hand-up',
  608. 'glyphicon-hd-video' => 'hd-video',
  609. 'glyphicon-hdd' => 'hdd',
  610. 'glyphicon-header' => 'header',
  611. 'glyphicon-headphones' => 'headphones',
  612. 'glyphicon-heart' => 'heart',
  613. 'glyphicon-heart-empty' => 'heart-empty',
  614. 'glyphicon-home' => 'home',
  615. 'glyphicon-import' => 'import',
  616. 'glyphicon-inbox' => 'inbox',
  617. 'glyphicon-indent-left' => 'indent-left',
  618. 'glyphicon-indent-right' => 'indent-right',
  619. 'glyphicon-info-sign' => 'info-sign',
  620. 'glyphicon-italic' => 'italic',
  621. 'glyphicon-leaf' => 'leaf',
  622. 'glyphicon-link' => 'link',
  623. 'glyphicon-list' => 'list',
  624. 'glyphicon-list-alt' => 'list-alt',
  625. 'glyphicon-lock' => 'lock',
  626. 'glyphicon-log-in' => 'log-in',
  627. 'glyphicon-log-out' => 'log-out',
  628. 'glyphicon-magnet' => 'magnet',
  629. 'glyphicon-map-marker' => 'map-marker',
  630. 'glyphicon-minus' => 'minus',
  631. 'glyphicon-minus-sign' => 'minus-sign',
  632. 'glyphicon-move' => 'move',
  633. 'glyphicon-music' => 'music',
  634. 'glyphicon-new-window' => 'new-window',
  635. 'glyphicon-off' => 'off',
  636. 'glyphicon-ok' => 'ok',
  637. 'glyphicon-ok-circle' => 'ok-circle',
  638. 'glyphicon-ok-sign' => 'ok-sign',
  639. 'glyphicon-open' => 'open',
  640. 'glyphicon-paperclip' => 'paperclip',
  641. 'glyphicon-pause' => 'pause',
  642. 'glyphicon-pencil' => 'pencil',
  643. 'glyphicon-phone' => 'phone',
  644. 'glyphicon-phone-alt' => 'phone-alt',
  645. 'glyphicon-picture' => 'picture',
  646. 'glyphicon-plane' => 'plane',
  647. 'glyphicon-play' => 'play',
  648. 'glyphicon-play-circle' => 'play-circle',
  649. 'glyphicon-plus' => 'plus',
  650. 'glyphicon-plus-sign' => 'plus-sign',
  651. 'glyphicon-print' => 'print',
  652. 'glyphicon-pushpin' => 'pushpin',
  653. 'glyphicon-qrcode' => 'qrcode',
  654. 'glyphicon-question-sign' => 'question-sign',
  655. 'glyphicon-random' => 'random',
  656. 'glyphicon-record' => 'record',
  657. 'glyphicon-refresh' => 'refresh',
  658. 'glyphicon-registration-mark' => 'registration-mark',
  659. 'glyphicon-remove' => 'remove',
  660. 'glyphicon-remove-circle' => 'remove-circle',
  661. 'glyphicon-remove-sign' => 'remove-sign',
  662. 'glyphicon-repeat' => 'repeat',
  663. 'glyphicon-resize-full' => 'resize-full',
  664. 'glyphicon-resize-horizontal' => 'resize-horizontal',
  665. 'glyphicon-resize-small' => 'resize-small',
  666. 'glyphicon-resize-vertical' => 'resize-vertical',
  667. 'glyphicon-retweet' => 'retweet',
  668. 'glyphicon-road' => 'road',
  669. 'glyphicon-save' => 'save',
  670. 'glyphicon-saved' => 'saved',
  671. 'glyphicon-screenshot' => 'screenshot',
  672. 'glyphicon-sd-video' => 'sd-video',
  673. 'glyphicon-search' => 'search',
  674. 'glyphicon-send' => 'send',
  675. 'glyphicon-share' => 'share',
  676. 'glyphicon-share-alt' => 'share-alt',
  677. 'glyphicon-shopping-cart' => 'shopping-cart',
  678. 'glyphicon-signal' => 'signal',
  679. 'glyphicon-sort' => 'sort',
  680. 'glyphicon-sort-by-alphabet' => 'sort-by-alphabet',
  681. 'glyphicon-sort-by-alphabet-alt' => 'sort-by-alphabet-alt',
  682. 'glyphicon-sort-by-attributes' => 'sort-by-attributes',
  683. 'glyphicon-sort-by-attributes-alt' => 'sort-by-attributes-alt',
  684. 'glyphicon-sort-by-order' => 'sort-by-order',
  685. 'glyphicon-sort-by-order-alt' => 'sort-by-order-alt',
  686. 'glyphicon-sound-5-1' => 'sound-5-1',
  687. 'glyphicon-sound-6-1' => 'sound-6-1',
  688. 'glyphicon-sound-7-1' => 'sound-7-1',
  689. 'glyphicon-sound-dolby' => 'sound-dolby',
  690. 'glyphicon-sound-stereo' => 'sound-stereo',
  691. 'glyphicon-star' => 'star',
  692. 'glyphicon-star-empty' => 'star-empty',
  693. 'glyphicon-stats' => 'stats',
  694. 'glyphicon-step-backward' => 'step-backward',
  695. 'glyphicon-step-forward' => 'step-forward',
  696. 'glyphicon-stop' => 'stop',
  697. 'glyphicon-subtitles' => 'subtitles',
  698. 'glyphicon-tag' => 'tag',
  699. 'glyphicon-tags' => 'tags',
  700. 'glyphicon-tasks' => 'tasks',
  701. 'glyphicon-text-height' => 'text-height',
  702. 'glyphicon-text-width' => 'text-width',
  703. 'glyphicon-th' => 'th',
  704. 'glyphicon-th-large' => 'th-large',
  705. 'glyphicon-th-list' => 'th-list',
  706. 'glyphicon-thumbs-down' => 'thumbs-down',
  707. 'glyphicon-thumbs-up' => 'thumbs-up',
  708. 'glyphicon-time' => 'time',
  709. 'glyphicon-tint' => 'tint',
  710. 'glyphicon-tower' => 'tower',
  711. 'glyphicon-transfer' => 'transfer',
  712. 'glyphicon-trash' => 'trash',
  713. 'glyphicon-tree-conifer' => 'tree-conifer',
  714. 'glyphicon-tree-deciduous' => 'tree-deciduous',
  715. 'glyphicon-unchecked' => 'unchecked',
  716. 'glyphicon-upload' => 'upload',
  717. 'glyphicon-usd' => 'usd',
  718. 'glyphicon-user' => 'user',
  719. 'glyphicon-volume-down' => 'volume-down',
  720. 'glyphicon-volume-off' => 'volume-off',
  721. 'glyphicon-volume-up' => 'volume-up',
  722. 'glyphicon-warning-sign' => 'warning-sign',
  723. 'glyphicon-wrench' => 'wrench',
  724. 'glyphicon-zoom-in' => 'zoom-in',
  725. 'glyphicon-zoom-out' => 'zoom-out',
  726. );
  727. $versions['3.0.1'] = $versions['3.0.0'];
  728. $versions['3.0.2'] = $versions['3.0.1'];
  729. $versions['3.0.3'] = $versions['3.0.2'];
  730. $versions['3.1.0'] = $versions['3.0.3'];
  731. $versions['3.1.1'] = $versions['3.1.0'];
  732. $versions['3.2.0'] = $versions['3.1.1'];
  733. $versions['3.3.0'] = array_merge($versions['3.2.0'], array(
  734. 'glyphicon-eur' => 'eur',
  735. ));
  736. $versions['3.3.1'] = $versions['3.3.0'];
  737. $versions['3.3.2'] = array_merge($versions['3.3.1'], array(
  738. 'glyphicon-alert' => 'alert',
  739. 'glyphicon-apple' => 'apple',
  740. 'glyphicon-baby-formula' => 'baby-formula',
  741. 'glyphicon-bed' => 'bed',
  742. 'glyphicon-bishop' => 'bishop',
  743. 'glyphicon-bitcoin' => 'bitcoin',
  744. 'glyphicon-blackboard' => 'blackboard',
  745. 'glyphicon-cd' => 'cd',
  746. 'glyphicon-console' => 'console',
  747. 'glyphicon-copy' => 'copy',
  748. 'glyphicon-duplicate' => 'duplicate',
  749. 'glyphicon-education' => 'education',
  750. 'glyphicon-equalizer' => 'equalizer',
  751. 'glyphicon-erase' => 'erase',
  752. 'glyphicon-grain' => 'grain',
  753. 'glyphicon-hourglass' => 'hourglass',
  754. 'glyphicon-ice-lolly' => 'ice-lolly',
  755. 'glyphicon-ice-lolly-tasted' => 'ice-lolly-tasted',
  756. 'glyphicon-king' => 'king',
  757. 'glyphicon-knight' => 'knight',
  758. 'glyphicon-lamp' => 'lamp',
  759. 'glyphicon-level-up' => 'level-up',
  760. 'glyphicon-menu-down' => 'menu-down',
  761. 'glyphicon-menu-hamburger' => 'menu-hamburger',
  762. 'glyphicon-menu-left' => 'menu-left',
  763. 'glyphicon-menu-right' => 'menu-right',
  764. 'glyphicon-menu-up' => 'menu-up',
  765. 'glyphicon-modal-window' => 'modal-window',
  766. 'glyphicon-object-align-bottom' => 'object-align-bottom',
  767. 'glyphicon-object-align-horizontal' => 'object-align-horizontal',
  768. 'glyphicon-object-align-left' => 'object-align-left',
  769. 'glyphicon-object-align-right' => 'object-align-right',
  770. 'glyphicon-object-align-top' => 'object-align-top',
  771. 'glyphicon-object-align-vertical' => 'object-align-vertical',
  772. 'glyphicon-oil' => 'oil',
  773. 'glyphicon-open-file' => 'open-file',
  774. 'glyphicon-option-horizontal' => 'option-horizontal',
  775. 'glyphicon-option-vertical' => 'option-vertical',
  776. 'glyphicon-paste' => 'paste',
  777. 'glyphicon-pawn' => 'pawn',
  778. 'glyphicon-piggy-bank' => 'piggy-bank',
  779. 'glyphicon-queen' => 'queen',
  780. 'glyphicon-ruble' => 'ruble',
  781. 'glyphicon-save-file' => 'save-file',
  782. 'glyphicon-scale' => 'scale',
  783. 'glyphicon-scissors' => 'scissors',
  784. 'glyphicon-subscript' => 'subscript',
  785. 'glyphicon-sunglasses' => 'sunglasses',
  786. 'glyphicon-superscript' => 'superscript',
  787. 'glyphicon-tent' => 'tent',
  788. 'glyphicon-text-background' => 'text-background',
  789. 'glyphicon-text-color' => 'text-color',
  790. 'glyphicon-text-size' => 'text-size',
  791. 'glyphicon-triangle-bottom' => 'triangle-bottom',
  792. 'glyphicon-triangle-left' => 'triangle-left',
  793. 'glyphicon-triangle-right' => 'triangle-right',
  794. 'glyphicon-triangle-top' => 'triangle-top',
  795. 'glyphicon-yen' => 'yen',
  796. ));
  797. $versions['3.3.4'] = array_merge($versions['3.3.2'], array(
  798. 'glyphicon-btc' => 'btc',
  799. 'glyphicon-jpy' => 'jpy',
  800. 'glyphicon-rub' => 'rub',
  801. 'glyphicon-xbt' => 'xbt',
  802. ));
  803. $versions['3.3.5'] = $versions['3.3.4'];
  804. }
  805. // Return a specific versions icon set.
  806. if (isset($version) && isset($versions[$version])) {
  807. return $versions[$version];
  808. }
  809. // Return the latest version.
  810. return $versions[BOOTSTRAP_VERSION];
  811. }
  812. /**
  813. * Returns a specific Bootstrap Glyphicon.
  814. *
  815. * @param string $name
  816. * The icon name, minus the "glyphicon-" prefix.
  817. * @param string $default
  818. * (Optional) The default value to return.
  819. *
  820. * @return string
  821. * The HTML markup containing the icon defined by $name, $default value if
  822. * icon does not exist or returns empty output for whatever reason.
  823. */
  824. function _bootstrap_icon($name, $default = NULL) {
  825. $output = NULL;
  826. // Ensure the icon specified is a valid Bootstrap Glyphicon.
  827. // @todo Supply a specific version to _bootstrap_glyphicons() when Icon API
  828. // supports versioning.
  829. if (_bootstrap_glyphicons_supported() && in_array($name, _bootstrap_glyphicons())) {
  830. // Attempt to use the Icon API module, if enabled and it generates output.
  831. if (module_exists('icon')) {
  832. $output = theme('icon', array('bundle' => 'bootstrap', 'icon' => 'glyphicon-' . $name));
  833. }
  834. if (empty($output)) {
  835. // Mimic the Icon API markup.
  836. $attributes = array(
  837. 'class' => array('icon', 'glyphicon', 'glyphicon-' . $name),
  838. 'aria-hidden' => 'true',
  839. );
  840. $output = '<span' . drupal_attributes($attributes) . '></span>';
  841. }
  842. }
  843. return empty($output) && isset($default) ? $default : $output;
  844. }
  845. /**
  846. * Determine whether or not Bootstrap Glyphicons can be used.
  847. */
  848. function _bootstrap_glyphicons_supported() {
  849. // Use the advanced drupal_static() pattern, since this has the potential to
  850. // be called very often by _bootstrap_icon().
  851. static $drupal_static_fast;
  852. if (!isset($drupal_static_fast)) {
  853. $drupal_static_fast['supported'] = &drupal_static(__FUNCTION__);
  854. // Get the active theme.
  855. $drupal_static_fast['theme'] = variable_get('theme_default', $GLOBALS['theme']);
  856. }
  857. // Get static data.
  858. $supported = &$drupal_static_fast['supported'];
  859. $theme = &$drupal_static_fast['theme'];
  860. // Retrieve supported themes.
  861. if (!isset($supported)) {
  862. $supported = array();
  863. // Retrieve cached data.
  864. $cid = 'theme_registry:bootstrap:icon_support';
  865. if (($cache = cache_get($cid)) && !empty($cache->data)) {
  866. $supported = $cache->data;
  867. }
  868. if (!isset($supported[$theme])) {
  869. // Bootstrap based themes are enabled by default to use CDN. Check if
  870. // that is the case here so no file discovery is necessary. If the active
  871. // theme does not have this setting, it falls back to the base theme that
  872. // does.
  873. $supported[$theme] = !!bootstrap_get_cdn_assets('css', NULL, $theme);
  874. // CDN not used, iterate over all of the active (base) themes to determine
  875. // if they contain glyphicon font files.
  876. if (!$supported[$theme]) {
  877. foreach (_bootstrap_get_base_themes($theme, TRUE) as $_theme) {
  878. // Scan the theme for files.
  879. $fonts = _bootstrap_file_scan_directory(drupal_get_path('theme', $_theme), '/glyphicons-halflings-regular\.(eot|svg|ttf|woff)$/');
  880. // Fonts found, stop the search.
  881. if (!empty($fonts)) {
  882. $supported[$theme] = TRUE;
  883. break;
  884. }
  885. }
  886. }
  887. // Cache all supported themes now that this theme is added to the array.
  888. cache_set($cid, $supported);
  889. }
  890. }
  891. return $supported[$theme];
  892. }
  893. /**
  894. * Determine whether a specific element is a button.
  895. *
  896. * @param array $element
  897. * A renderable element.
  898. *
  899. * @return bool
  900. * TRUE or FALSE.
  901. */
  902. function _bootstrap_is_button($element) {
  903. return
  904. !empty($element['#type']) &&
  905. !empty($element['#value']) && (
  906. $element['#type'] === 'button' ||
  907. $element['#type'] === 'submit' ||
  908. $element['#type'] === 'image_button'
  909. );
  910. }
  911. /**
  912. * Adds a specific Bootstrap class to color a button based on its text value.
  913. *
  914. * @param array $element
  915. * The form element, passed by reference.
  916. */
  917. function _bootstrap_colorize_button(&$element) {
  918. if (_bootstrap_is_button($element)) {
  919. // Do not add the class if one is already present in the array.
  920. $button_classes = array(
  921. 'btn-default',
  922. 'btn-primary',
  923. 'btn-success',
  924. 'btn-info',
  925. 'btn-warning',
  926. 'btn-danger',
  927. 'btn-link',
  928. );
  929. $class_intersection = array_intersect($button_classes, $element['#attributes']['class']);
  930. if (empty($class_intersection)) {
  931. // Get the matched class.
  932. $class = bootstrap_setting('button_colorize') ? _bootstrap_colorize_text($element['#value']) : FALSE;
  933. // If no particular class matched, use the default style.
  934. if (!$class) {
  935. $class = 'default';
  936. }
  937. $element['#attributes']['class'][] = 'btn-' . $class;
  938. }
  939. }
  940. }
  941. /**
  942. * Matches a Bootstrap class based on a string value.
  943. *
  944. * @param string $string
  945. * The string to match classes against.
  946. * @param string $default
  947. * The default class to return if no match is found.
  948. *
  949. * @return string
  950. * The Bootstrap class matched against the value of $haystack or $default if
  951. * no match could be made.
  952. */
  953. function _bootstrap_colorize_text($string, $default = '') {
  954. static $texts;
  955. if (!isset($texts)) {
  956. $texts = array(
  957. // Text that match these specific strings are checked first.
  958. 'matches' => array(
  959. // Primary class.
  960. t('Download feature') => 'primary',
  961. // Success class.
  962. t('Add effect') => 'success',
  963. t('Add and configure') => 'success',
  964. // Info class.
  965. t('Save and add') => 'info',
  966. t('Add another item') => 'info',
  967. t('Update style') => 'info',
  968. ),
  969. // Text that contain these words anywhere in the string are checked last.
  970. 'contains' => array(
  971. // Primary class.
  972. t('Confirm') => 'primary',
  973. t('Filter') => 'primary',
  974. t('Submit') => 'primary',
  975. t('Search') => 'primary',
  976. // Success class.
  977. t('Add') => 'success',
  978. t('Create') => 'success',
  979. t('Save') => 'success',
  980. t('Write') => 'success',
  981. // Warning class.
  982. t('Export') => 'warning',
  983. t('Import') => 'warning',
  984. t('Restore') => 'warning',
  985. t('Rebuild') => 'warning',
  986. // Info class.
  987. t('Apply') => 'info',
  988. t('Update') => 'info',
  989. // Danger class.
  990. t('Delete') => 'danger',
  991. t('Remove') => 'danger',
  992. ),
  993. );
  994. // Allow sub-themes to alter this array of patterns.
  995. drupal_alter('bootstrap_colorize_text', $texts);
  996. }
  997. // Iterate over the array.
  998. foreach ($texts as $pattern => $strings) {
  999. foreach ($strings as $value => $class) {
  1000. switch ($pattern) {
  1001. case 'matches':
  1002. if ($string === $value) {
  1003. return $class;
  1004. }
  1005. break;
  1006. case 'contains':
  1007. if (strpos(drupal_strtolower($string), drupal_strtolower($value)) !== FALSE) {
  1008. return $class;
  1009. }
  1010. break;
  1011. }
  1012. }
  1013. }
  1014. // Return the default if nothing was matched.
  1015. return $default;
  1016. }
  1017. /**
  1018. * Adds an icon to button element based on its text value.
  1019. *
  1020. * @param array $element
  1021. * The form element, passed by reference.
  1022. */
  1023. function _bootstrap_iconize_button(&$element) {
  1024. if (bootstrap_setting('button_iconize') && _bootstrap_is_button($element) && ($icon = _bootstrap_iconize_text($element['#value']))) {
  1025. $element['#icon'] = $icon;
  1026. }
  1027. }
  1028. /**
  1029. * Matches a Bootstrap Glyphicon based on a string value.
  1030. *
  1031. * @param string $string
  1032. * The string to match classes against.
  1033. * @param string $default
  1034. * The default icon to return if no match is found.
  1035. *
  1036. * @return string
  1037. * The Bootstrap icon matched against the value of $haystack or $default if
  1038. * no match could be made.
  1039. */
  1040. function _bootstrap_iconize_text($string, $default = '') {
  1041. static $texts;
  1042. if (!isset($texts)) {
  1043. $texts = array(
  1044. // Text that match these specific strings are checked first.
  1045. 'matches' => array(),
  1046. // Text that contain these words anywhere in the string are checked last.
  1047. 'contains' => array(
  1048. t('Manage') => 'cog',
  1049. t('Configure') => 'cog',
  1050. t('Download') => 'download',
  1051. t('Export') => 'export',
  1052. t('Filter') => 'filter',
  1053. t('Import') => 'import',
  1054. t('Save') => 'ok',
  1055. t('Update') => 'ok',
  1056. t('Edit') => 'pencil',
  1057. t('Add') => 'plus',
  1058. t('Write') => 'plus',
  1059. t('Cancel') => 'remove',
  1060. t('Delete') => 'trash',
  1061. t('Remove') => 'trash',
  1062. t('Upload') => 'upload',
  1063. ),
  1064. );
  1065. // Allow sub-themes to alter this array of patterns.
  1066. drupal_alter('bootstrap_iconize_text', $texts);
  1067. }
  1068. // Iterate over the array.
  1069. foreach ($texts as $pattern => $strings) {
  1070. foreach ($strings as $value => $icon) {
  1071. switch ($pattern) {
  1072. case 'matches':
  1073. if ($string === $value) {
  1074. return _bootstrap_icon($icon, $default);
  1075. }
  1076. break;
  1077. case 'contains':
  1078. if (strpos(drupal_strtolower($string), drupal_strtolower($value)) !== FALSE) {
  1079. return _bootstrap_icon($icon, $default);
  1080. }
  1081. break;
  1082. }
  1083. }
  1084. }
  1085. // Return a default icon if nothing was matched.
  1086. return _bootstrap_icon($default);
  1087. }
  1088. /**
  1089. * Invokes a specific suggestion's preprocess functions.
  1090. *
  1091. * @param array $variables
  1092. * The theme implementation variables array.
  1093. */
  1094. function _bootstrap_preprocess_theme_suggestion(&$variables) {
  1095. $registry = theme_get_registry();
  1096. if (!empty($variables['theme_hook_suggestion']) && !empty($registry[$variables['theme_hook_suggestion']]['preprocess functions'])) {
  1097. // Save the suggestion as the hook to pass to the function.
  1098. $hook = $variables['theme_hook_suggestion'];
  1099. // Iterate over the preprocess functions.
  1100. foreach ($registry[$hook]['preprocess functions'] as $function) {
  1101. if (function_exists($function)) {
  1102. // Invoke theme hook suggestion preprocess function.
  1103. $function($variables, $hook);
  1104. // Unset the theme_hook_suggestion so the suggestion's preprocess
  1105. // functions can provide theme_hook_suggestions if needed.
  1106. if (!empty($variables['theme_hook_suggestions'])) {
  1107. unset($variables['theme_hook_suggestion']);
  1108. }
  1109. }
  1110. }
  1111. }
  1112. }
  1113. /**
  1114. * Invokes a specific suggestion's process functions.
  1115. *
  1116. * @param array $variables
  1117. * The theme implementation variables array.
  1118. */
  1119. function _bootstrap_process_theme_suggestion(&$variables) {
  1120. $registry = theme_get_registry();
  1121. if (!empty($variables['theme_hook_suggestion']) && !empty($registry[$variables['theme_hook_suggestion']]['process functions'])) {
  1122. // Save the suggestion as the hook to pass to the function.
  1123. $hook = $variables['theme_hook_suggestion'];
  1124. // Iterate over the process functions.
  1125. foreach ($registry[$hook]['process functions'] as $function) {
  1126. if (function_exists($function)) {
  1127. // Invoke theme hook suggestion process function.
  1128. $function($variables, $hook);
  1129. // Unset the theme_hook_suggestion so the suggestion's preprocess
  1130. // functions can provide theme_hook_suggestions if needed.
  1131. if (!empty($variables['theme_hook_suggestions'])) {
  1132. unset($variables['theme_hook_suggestion']);
  1133. }
  1134. }
  1135. }
  1136. }
  1137. }
  1138. /**
  1139. * Determines if a string of text is considered "simple".
  1140. *
  1141. * @param string $string
  1142. * The string of text to check "simple" criteria on.
  1143. * @param int|FALSE $length
  1144. * The length of characters used to determine whether or not $string is
  1145. * considered "simple". Set explicitly to FALSE to disable this criteria.
  1146. * @param array|FALSE $allowed_tags
  1147. * An array of allowed tag elements. Set explicitly to FALSE to disable this
  1148. * criteria.
  1149. * @param bool $html
  1150. * A variable, passed by reference, that indicates whether or not the
  1151. * string contains HTML.
  1152. *
  1153. * @return bool
  1154. * Returns TRUE if the $string is considered "simple", FALSE otherwise.
  1155. */
  1156. function _bootstrap_is_simple_string($string, $length = 250, $allowed_tags = NULL, &$html = FALSE) {
  1157. // Use the advanced drupal_static() pattern, since this is called very often.
  1158. static $drupal_static_fast;
  1159. if (!isset($drupal_static_fast)) {
  1160. $drupal_static_fast['strings'] = &drupal_static(__FUNCTION__);
  1161. }
  1162. $strings = &$drupal_static_fast['strings'];
  1163. if (!isset($strings[$string])) {
  1164. $plain_string = strip_tags($string);
  1165. $simple = TRUE;
  1166. if ($allowed_tags !== FALSE) {
  1167. $filtered_string = filter_xss($string, $allowed_tags);
  1168. $html = $filtered_string !== $plain_string;
  1169. $simple = $simple && $string === $filtered_string;
  1170. }
  1171. if ($length !== FALSE) {
  1172. $simple = $simple && strlen($plain_string) <= intval($length);
  1173. }
  1174. $strings[$string] = $simple;
  1175. }
  1176. return $strings[$string];
  1177. }
  1178. /**
  1179. * Determines if the Path Breadcrumbs module theme function should be used.
  1180. *
  1181. * @param string $theme
  1182. * The machine name of a specific theme to determine status if the Path
  1183. * Breadcrumbs module has been configured to only use its internal function
  1184. * on a specific list of themes.
  1185. *
  1186. * @return bool
  1187. * TRUE or FALSE
  1188. */
  1189. function _bootstrap_use_path_breadcrumbs($theme = NULL) {
  1190. static $path_breadcrumbs;
  1191. if (!isset($path_breadcrumbs)) {
  1192. $path_breadcrumbs = FALSE;
  1193. // Use active theme as the theme key if not explicitly set.
  1194. if (!isset($theme)) {
  1195. $theme = $GLOBALS['theme_key'];
  1196. }
  1197. // Determine whether or not the internal Path Breadcrumbs theme function
  1198. // should be used or not.
  1199. if (function_exists('path_breadcrumbs_breadcrumb') && module_exists('path_breadcrumbs')) {
  1200. $internal_render = variable_get('path_breadcrumbs_internal_render', 1);
  1201. $themes = variable_get('path_breadcrumbs_internal_render_themes', array());
  1202. $path_breadcrumbs = ($internal_render && (empty($themes) || in_array($theme, $themes)));
  1203. }
  1204. }
  1205. return $path_breadcrumbs;
  1206. }
  1207. /**
  1208. * @} End of "defgroup subtheme_helper_functions".
  1209. */