1 |
caf16a48
|
Assos Assos
|
<?php
|
2 |
|
|
/**
|
3 |
|
|
* @file
|
4 |
|
|
* alter.inc
|
5 |
|
|
*
|
6 |
|
|
* Contains various implementations of hook_*_alter().
|
7 |
|
|
*/
|
8 |
|
|
|
9 |
|
|
/**
|
10 |
|
|
* Include #pre_render callbacks for elements.
|
11 |
|
|
*/
|
12 |
|
|
bootstrap_include('bootstrap', 'includes/pre-render.inc');
|
13 |
|
|
|
14 |
|
|
/**
|
15 |
|
|
* Include #process callbacks for elements.
|
16 |
|
|
*/
|
17 |
|
|
bootstrap_include('bootstrap', 'includes/process.inc');
|
18 |
|
|
|
19 |
|
|
/**
|
20 |
|
|
* Implements hook_css_alter().
|
21 |
|
|
*/
|
22 |
|
|
function bootstrap_css_alter(&$css) {
|
23 |
|
|
$theme_path = drupal_get_path('theme', 'bootstrap');
|
24 |
|
|
|
25 |
|
|
// Exclude specified CSS files from theme.
|
26 |
|
|
$excludes = bootstrap_get_theme_info(NULL, 'exclude][css');
|
27 |
|
|
|
28 |
|
|
// Add CDN assets, if any.
|
29 |
|
|
$provider = bootstrap_setting('cdn_provider');
|
30 |
|
|
if ($cdn_assets = bootstrap_get_cdn_assets('css', $provider)) {
|
31 |
|
|
$cdn_weight = -2.99;
|
32 |
|
|
foreach ($cdn_assets as $cdn_asset) {
|
33 |
|
|
$cdn_weight += .01;
|
34 |
|
|
$css[$cdn_asset] = array(
|
35 |
|
|
'data' => $cdn_asset,
|
36 |
|
|
'type' => 'external',
|
37 |
|
|
'every_page' => TRUE,
|
38 |
|
|
'media' => 'all',
|
39 |
|
|
'preprocess' => FALSE,
|
40 |
|
|
'group' => CSS_THEME,
|
41 |
|
|
'browsers' => array('IE' => TRUE, '!IE' => TRUE),
|
42 |
|
|
'weight' => $cdn_weight,
|
43 |
|
|
);
|
44 |
|
|
}
|
45 |
|
|
|
46 |
|
|
// Add a specific version and theme CSS overrides file.
|
47 |
|
|
$version = bootstrap_setting('cdn_' . $provider . '_version');
|
48 |
|
|
if (!$version) {
|
49 |
|
|
$version = BOOTSTRAP_VERSION;
|
50 |
|
|
}
|
51 |
|
|
$theme = bootstrap_setting('cdn_' . $provider . '_theme');
|
52 |
|
|
if (!$theme) {
|
53 |
|
|
$theme = 'bootstrap';
|
54 |
|
|
}
|
55 |
|
|
$theme = $theme === 'bootstrap' || $theme === 'bootstrap_theme' ? '' : "-$theme";
|
56 |
|
|
$overrides = "$theme_path/css/$version/overrides$theme.min.css";
|
57 |
|
|
if (file_exists($overrides)) {
|
58 |
|
|
$css[$overrides] = array(
|
59 |
|
|
'data' => $overrides,
|
60 |
|
|
'type' => 'file',
|
61 |
|
|
'every_page' => TRUE,
|
62 |
|
|
'media' => 'all',
|
63 |
|
|
'preprocess' => TRUE,
|
64 |
|
|
'group' => CSS_THEME,
|
65 |
|
|
'browsers' => array('IE' => TRUE, '!IE' => TRUE),
|
66 |
|
|
'weight' => -1,
|
67 |
|
|
);
|
68 |
|
|
}
|
69 |
|
|
}
|
70 |
|
|
if (!empty($excludes)) {
|
71 |
4eeb3b46
|
Assos Assos
|
$excludes = array_merge($excludes, str_replace('.css', '-rtl.css', $excludes));
|
72 |
caf16a48
|
Assos Assos
|
$css = array_diff_key($css, drupal_map_assoc($excludes));
|
73 |
|
|
}
|
74 |
|
|
}
|
75 |
|
|
|
76 |
|
|
/**
|
77 |
|
|
* Implements hook_element_info_alter().
|
78 |
|
|
*/
|
79 |
|
|
function bootstrap_element_info_alter(&$info) {
|
80 |
|
|
global $theme_key;
|
81 |
|
|
|
82 |
|
|
$cid = "theme_registry:bootstrap:element_info";
|
83 |
|
|
$cached = array();
|
84 |
|
|
if (($cache = cache_get($cid)) && !empty($cache->data)) {
|
85 |
|
|
$cached = $cache->data;
|
86 |
|
|
}
|
87 |
|
|
|
88 |
|
|
$themes = _bootstrap_get_base_themes($theme_key, TRUE);
|
89 |
|
|
foreach ($themes as $theme) {
|
90 |
|
|
if (!isset($cached[$theme])) {
|
91 |
|
|
$cached[$theme] = array();
|
92 |
|
|
foreach (array_keys($info) as $type) {
|
93 |
|
|
$element = array();
|
94 |
|
|
|
95 |
|
|
// Replace fieldset theme implementations with bootstrap_panel.
|
96 |
|
|
if (!empty($info[$type]['#theme']) && $info[$type]['#theme'] === 'fieldset') {
|
97 |
|
|
$element['#bootstrap_replace']['#theme'] = 'bootstrap_panel';
|
98 |
|
|
}
|
99 |
|
|
if (!empty($info[$type]['#theme_wrappers']) && array_search('fieldset', $info[$type]['#theme_wrappers']) !== FALSE) {
|
100 |
|
|
$element['#bootstrap_replace']['#theme_wrappers']['fieldset'] = 'bootstrap_panel';
|
101 |
|
|
}
|
102 |
|
|
|
103 |
|
|
// Setup a default "icon" variable. This allows #icon to be passed
|
104 |
|
|
// to every template and theme function.
|
105 |
|
|
// @see https://drupal.org/node/2219965
|
106 |
|
|
$element['#icon'] = NULL;
|
107 |
|
|
$element['#icon_position'] = 'before';
|
108 |
|
|
|
109 |
|
|
$properties = array(
|
110 |
|
|
'#process' => array(
|
111 |
|
|
'form_process',
|
112 |
|
|
'form_process_' . $type,
|
113 |
|
|
),
|
114 |
|
|
'#pre_render' => array(
|
115 |
|
|
'pre_render',
|
116 |
|
|
'pre_render_' . $type,
|
117 |
|
|
),
|
118 |
|
|
);
|
119 |
|
|
foreach ($properties as $property => $callbacks) {
|
120 |
|
|
foreach ($callbacks as $callback) {
|
121 |
|
|
$function = $theme . '_' . $callback;
|
122 |
|
|
if (function_exists($function)) {
|
123 |
|
|
// Replace direct core function correlation.
|
124 |
|
|
if (!empty($info[$type][$property]) && array_search($callback, $info[$type][$property]) !== FALSE) {
|
125 |
|
|
$element['#bootstrap_replace'][$property][$callback] = $function;
|
126 |
|
|
}
|
127 |
|
|
// Check for a "form_" prefix instead (for #pre_render).
|
128 |
749b8a23
|
Assos Assos
|
elseif (!empty($info[$type][$property]) && array_search('form_' . $callback, $info[$type][$property]) !== FALSE) {
|
129 |
caf16a48
|
Assos Assos
|
$element['#bootstrap_replace'][$property]['form_' . $callback] = $function;
|
130 |
|
|
}
|
131 |
|
|
// Otherwise, append the function.
|
132 |
|
|
else {
|
133 |
|
|
$element[$property][] = $function;
|
134 |
|
|
}
|
135 |
|
|
}
|
136 |
|
|
}
|
137 |
|
|
}
|
138 |
|
|
$cached[$theme][$type] = $element;
|
139 |
|
|
}
|
140 |
|
|
|
141 |
|
|
// Cache the element information.
|
142 |
|
|
cache_set($cid, $cached);
|
143 |
|
|
}
|
144 |
|
|
|
145 |
|
|
// Merge in each theme's cached element info.
|
146 |
|
|
$info = _bootstrap_element_info_array_merge($info, $cached[$theme]);
|
147 |
|
|
}
|
148 |
|
|
}
|
149 |
|
|
|
150 |
|
|
/**
|
151 |
|
|
* Merges the cached element information into the runtime array.
|
152 |
|
|
*
|
153 |
|
|
* @param array $info
|
154 |
|
|
* The element info array to merge data into.
|
155 |
|
|
* @param array $cached
|
156 |
|
|
* The cached element info data array to merge from.
|
157 |
|
|
*
|
158 |
|
|
* @return array
|
159 |
|
|
* The altered element info array.
|
160 |
|
|
*/
|
161 |
|
|
function _bootstrap_element_info_array_merge($info, $cached) {
|
162 |
|
|
foreach ($cached as $type => $element) {
|
163 |
|
|
$replacement_data = isset($element['#bootstrap_replace']) ? $element['#bootstrap_replace'] : array();
|
164 |
|
|
unset($element['#bootstrap_replace']);
|
165 |
|
|
foreach ($element as $property => $data) {
|
166 |
|
|
if (is_array($data)) {
|
167 |
|
|
if (!isset($info[$type][$property])) {
|
168 |
|
|
$info[$type][$property] = array();
|
169 |
|
|
}
|
170 |
|
|
// Append the values if not already in the array.
|
171 |
|
|
foreach ($data as $key => $value) {
|
172 |
|
|
if (!in_array($value, $info[$type][$property])) {
|
173 |
|
|
$info[$type][$property][] = $value;
|
174 |
|
|
}
|
175 |
|
|
}
|
176 |
|
|
}
|
177 |
|
|
// Create the property, if not already set.
|
178 |
749b8a23
|
Assos Assos
|
elseif (!isset($info[$type][$property])) {
|
179 |
caf16a48
|
Assos Assos
|
$info[$type][$property] = $data;
|
180 |
|
|
}
|
181 |
|
|
}
|
182 |
|
|
// Replace data, if necessary.
|
183 |
|
|
foreach ($replacement_data as $property => $data) {
|
184 |
|
|
if (is_array($data)) {
|
185 |
|
|
foreach ($data as $needle => $replacement) {
|
186 |
|
|
if (!empty($info[$type][$property]) && ($key = array_search($needle, $info[$type][$property])) !== FALSE) {
|
187 |
|
|
$info[$type][$property][$key] = $replacement;
|
188 |
|
|
}
|
189 |
|
|
}
|
190 |
|
|
}
|
191 |
|
|
// Replace the property with the new data.
|
192 |
|
|
else {
|
193 |
|
|
$info[$type][$property] = $data;
|
194 |
|
|
}
|
195 |
|
|
}
|
196 |
|
|
}
|
197 |
|
|
|
198 |
|
|
// Return the altered element info array.
|
199 |
|
|
return $info;
|
200 |
|
|
}
|
201 |
|
|
|
202 |
|
|
/**
|
203 |
|
|
* Implements hook_form_alter().
|
204 |
|
|
*/
|
205 |
|
|
function bootstrap_form_alter(array &$form, array &$form_state = array(), $form_id = NULL) {
|
206 |
|
|
if ($form_id) {
|
207 |
|
|
switch ($form_id) {
|
208 |
|
|
case 'system_theme_settings':
|
209 |
|
|
// Create vertical tabs for global settings (provided by core or other
|
210 |
|
|
// contrib modules).
|
211 |
|
|
if (!isset($form['global'])) {
|
212 |
|
|
$form['global'] = array(
|
213 |
|
|
'#type' => 'vertical_tabs',
|
214 |
|
|
'#weight' => -9,
|
215 |
|
|
);
|
216 |
|
|
if (!empty($form_state['build_info']['args'][0])) {
|
217 |
|
|
$form['global']['#prefix'] = '<h2><small>' . t('Override Global Settings') . '</small></h2>';
|
218 |
|
|
}
|
219 |
|
|
}
|
220 |
|
|
|
221 |
|
|
// Iterate over all child elements and check to see if they should be
|
222 |
|
|
// moved in the global vertical tabs.
|
223 |
|
|
$global_children = element_children($form);
|
224 |
|
|
foreach ($global_children as $child) {
|
225 |
|
|
if (isset($form[$child]['#type']) && $form[$child]['#type'] === 'fieldset' && !isset($form[$child]['#group'])) {
|
226 |
|
|
$form[$child]['#group'] = 'global';
|
227 |
|
|
}
|
228 |
|
|
}
|
229 |
|
|
break;
|
230 |
|
|
|
231 |
|
|
case 'search_form':
|
232 |
|
|
// Add a clearfix class so the results don't overflow onto the form.
|
233 |
|
|
$form['#attributes']['class'][] = 'clearfix';
|
234 |
|
|
|
235 |
|
|
// Remove container-inline from the container classes.
|
236 |
|
|
$form['basic']['#attributes']['class'] = array();
|
237 |
|
|
|
238 |
|
|
// Hide the default button from display.
|
239 |
|
|
$form['basic']['submit']['#attributes']['class'][] = 'element-invisible';
|
240 |
|
|
|
241 |
|
|
// Implement a theme wrapper to add a submit button containing a search
|
242 |
|
|
// icon directly after the input element.
|
243 |
|
|
$form['basic']['keys']['#theme_wrappers'] = array('bootstrap_search_form_wrapper');
|
244 |
|
|
$form['basic']['keys']['#title'] = '';
|
245 |
|
|
$form['basic']['keys']['#attributes']['placeholder'] = t('Search');
|
246 |
|
|
break;
|
247 |
|
|
|
248 |
|
|
case 'search_block_form':
|
249 |
|
|
$form['#attributes']['class'][] = 'form-search';
|
250 |
|
|
|
251 |
|
|
$form['search_block_form']['#title'] = '';
|
252 |
|
|
$form['search_block_form']['#attributes']['placeholder'] = t('Search');
|
253 |
|
|
|
254 |
|
|
// Hide the default button from display and implement a theme wrapper
|
255 |
|
|
// to add a submit button containing a search icon directly after the
|
256 |
|
|
// input element.
|
257 |
|
|
$form['actions']['submit']['#attributes']['class'][] = 'element-invisible';
|
258 |
|
|
$form['search_block_form']['#theme_wrappers'] = array('bootstrap_search_form_wrapper');
|
259 |
|
|
|
260 |
|
|
// Apply a clearfix so the results don't overflow onto the form.
|
261 |
|
|
$form['#attributes']['class'][] = 'content-search';
|
262 |
|
|
break;
|
263 |
|
|
|
264 |
|
|
case 'image_style_form':
|
265 |
|
|
$form['effects']['new']['new']['#input_group_button'] = TRUE;
|
266 |
|
|
break;
|
267 |
|
|
|
268 |
|
|
case 'path_admin_filter_form':
|
269 |
|
|
$form['basic']['filter']['#input_group_button'] = TRUE;
|
270 |
|
|
break;
|
271 |
|
|
}
|
272 |
|
|
|
273 |
|
|
}
|
274 |
|
|
}
|
275 |
|
|
|
276 |
|
|
/**
|
277 |
|
|
* Implements hook_js_alter().
|
278 |
|
|
*/
|
279 |
|
|
function bootstrap_js_alter(&$js) {
|
280 |
|
|
// Exclude specified JavaScript files from theme.
|
281 |
|
|
$excludes = bootstrap_get_theme_info(NULL, 'exclude][js');
|
282 |
|
|
|
283 |
|
|
$theme_path = drupal_get_path('theme', 'bootstrap');
|
284 |
|
|
|
285 |
|
|
// Add or replace JavaScript files when matching paths are detected.
|
286 |
|
|
// Replacement files must begin with '_', like '_node.js'.
|
287 |
|
|
$files = _bootstrap_file_scan_directory($theme_path . '/js', '/\.js$/');
|
288 |
|
|
foreach ($files as $file) {
|
289 |
|
|
$path = str_replace($theme_path . '/js/', '', $file->uri);
|
290 |
|
|
// Detect if this is a replacement file.
|
291 |
|
|
$replace = FALSE;
|
292 |
|
|
if (preg_match('/^[_]/', $file->filename)) {
|
293 |
|
|
$replace = TRUE;
|
294 |
|
|
$path = dirname($path) . '/' . preg_replace('/^[_]/', '', $file->filename);
|
295 |
|
|
}
|
296 |
|
|
$matches = array();
|
297 |
|
|
if (preg_match('/^modules\/([^\/]*)/', $path, $matches)) {
|
298 |
|
|
if (!module_exists($matches[1])) {
|
299 |
|
|
continue;
|
300 |
|
|
}
|
301 |
|
|
else {
|
302 |
|
|
$path = str_replace('modules/' . $matches[1], drupal_get_path('module', $matches[1]), $path);
|
303 |
|
|
}
|
304 |
|
|
}
|
305 |
|
|
// Path should always exist to either add or replace JavaScript file.
|
306 |
|
|
if (!empty($js[$path])) {
|
307 |
|
|
// Replace file.
|
308 |
|
|
if ($replace) {
|
309 |
|
|
$js[$file->uri] = $js[$path];
|
310 |
|
|
$js[$file->uri]['data'] = $file->uri;
|
311 |
|
|
unset($js[$path]);
|
312 |
|
|
}
|
313 |
|
|
// Add file.
|
314 |
|
|
else {
|
315 |
|
|
$js[$file->uri] = drupal_js_defaults($file->uri);
|
316 |
|
|
$js[$file->uri]['group'] = JS_THEME;
|
317 |
|
|
}
|
318 |
|
|
}
|
319 |
|
|
}
|
320 |
|
|
|
321 |
|
|
// Ensure jQuery Once is always loaded.
|
322 |
|
|
// @see https://drupal.org/node/2149561
|
323 |
|
|
if (empty($js['misc/jquery.once.js'])) {
|
324 |
|
|
$jquery_once = drupal_get_library('system', 'jquery.once');
|
325 |
|
|
$js['misc/jquery.once.js'] = $jquery_once['js']['misc/jquery.once.js'];
|
326 |
|
|
$js['misc/jquery.once.js'] += drupal_js_defaults('misc/jquery.once.js');
|
327 |
|
|
}
|
328 |
|
|
|
329 |
|
|
// Always add bootstrap.js last.
|
330 |
|
|
$bootstrap = $theme_path . '/js/bootstrap.js';
|
331 |
|
|
$js[$bootstrap] = drupal_js_defaults($bootstrap);
|
332 |
|
|
$js[$bootstrap]['group'] = JS_THEME;
|
333 |
|
|
$js[$bootstrap]['scope'] = 'footer';
|
334 |
|
|
|
335 |
|
|
if (!empty($excludes)) {
|
336 |
|
|
$js = array_diff_key($js, drupal_map_assoc($excludes));
|
337 |
|
|
}
|
338 |
|
|
|
339 |
|
|
// Add Bootstrap settings.
|
340 |
|
|
$js['settings']['data'][]['bootstrap'] = array(
|
341 |
|
|
'anchorsFix' => bootstrap_setting('anchors_fix'),
|
342 |
|
|
'anchorsSmoothScrolling' => bootstrap_setting('anchors_smooth_scrolling'),
|
343 |
|
|
'formHasError' => (int) bootstrap_setting('forms_has_error_value_toggle'),
|
344 |
|
|
'popoverEnabled' => bootstrap_setting('popover_enabled'),
|
345 |
|
|
'popoverOptions' => array(
|
346 |
|
|
'animation' => (int) bootstrap_setting('popover_animation'),
|
347 |
|
|
'html' => (int) bootstrap_setting('popover_html'),
|
348 |
|
|
'placement' => bootstrap_setting('popover_placement'),
|
349 |
|
|
'selector' => bootstrap_setting('popover_selector'),
|
350 |
|
|
'trigger' => implode(' ', array_filter(array_values((array) bootstrap_setting('popover_trigger')))),
|
351 |
|
|
'triggerAutoclose' => (int) bootstrap_setting('popover_trigger_autoclose'),
|
352 |
|
|
'title' => bootstrap_setting('popover_title'),
|
353 |
|
|
'content' => bootstrap_setting('popover_content'),
|
354 |
|
|
'delay' => (int) bootstrap_setting('popover_delay'),
|
355 |
|
|
'container' => bootstrap_setting('popover_container'),
|
356 |
|
|
),
|
357 |
|
|
'tooltipEnabled' => bootstrap_setting('tooltip_enabled'),
|
358 |
|
|
'tooltipOptions' => array(
|
359 |
|
|
'animation' => (int) bootstrap_setting('tooltip_animation'),
|
360 |
|
|
'html' => (int) bootstrap_setting('tooltip_html'),
|
361 |
|
|
'placement' => bootstrap_setting('tooltip_placement'),
|
362 |
|
|
'selector' => bootstrap_setting('tooltip_selector'),
|
363 |
|
|
'trigger' => implode(' ', array_filter(array_values((array) bootstrap_setting('tooltip_trigger')))),
|
364 |
|
|
'delay' => (int) bootstrap_setting('tooltip_delay'),
|
365 |
|
|
'container' => bootstrap_setting('tooltip_container'),
|
366 |
|
|
),
|
367 |
|
|
);
|
368 |
|
|
|
369 |
|
|
// Add CDN assets, if any.
|
370 |
|
|
if ($cdn_assets = bootstrap_get_cdn_assets('js')) {
|
371 |
|
|
$cdn_weight = -99.99;
|
372 |
|
|
foreach ($cdn_assets as $cdn_asset) {
|
373 |
|
|
$cdn_weight += .01;
|
374 |
|
|
$js[$cdn_asset] = drupal_js_defaults($cdn_asset);
|
375 |
|
|
$js[$cdn_asset]['type'] = 'external';
|
376 |
|
|
$js[$cdn_asset]['every_page'] = TRUE;
|
377 |
|
|
$js[$cdn_asset]['weight'] = $cdn_weight;
|
378 |
|
|
}
|
379 |
|
|
}
|
380 |
|
|
}
|
381 |
|
|
|
382 |
|
|
/**
|
383 |
|
|
* Implements hook_icon_bundle_list_alter().
|
384 |
|
|
*/
|
385 |
|
|
function bootstrap_icon_bundle_list_alter(&$build, $bundle) {
|
386 |
|
|
if (bootstrap_setting('tooltip_enabled')) {
|
387 |
|
|
foreach ($build as &$icon) {
|
388 |
|
|
$icon['#attributes']['data-toggle'] = 'tooltip';
|
389 |
|
|
$icon['#attributes']['data-placement'] = 'bottom';
|
390 |
|
|
}
|
391 |
|
|
}
|
392 |
|
|
}
|
393 |
|
|
|
394 |
|
|
/**
|
395 |
|
|
* Implements hook_menu_local_tasks_alter().
|
396 |
|
|
*/
|
397 |
|
|
function bootstrap_menu_local_tasks_alter(&$data, &$router_item, $root_path) {
|
398 |
|
|
if (!empty($data['actions']['output'])) {
|
399 |
|
|
$items = array();
|
400 |
|
|
foreach ($data['actions']['output'] as $item) {
|
401 |
|
|
$items[] = array(
|
402 |
|
|
'data' => $item,
|
403 |
|
|
);
|
404 |
|
|
}
|
405 |
|
|
$data['actions']['output'] = array(
|
406 |
|
|
'#theme' => 'item_list__action_links',
|
407 |
|
|
'#items' => $items,
|
408 |
|
|
'#attributes' => array(
|
409 |
|
|
'class' => array('action-links'),
|
410 |
|
|
),
|
411 |
|
|
);
|
412 |
|
|
}
|
413 |
|
|
}
|
414 |
|
|
|
415 |
|
|
/**
|
416 |
|
|
* Implements hook_js_callback_filter_xss_alter().
|
417 |
|
|
*/
|
418 |
|
|
function bootstrap_js_callback_filter_xss_alter(array &$allowed_tags = array()) {
|
419 |
|
|
$allowed_tags[] = 'button';
|
420 |
|
|
} |