Projet

Général

Profil

Paste
Télécharger (14,3 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / themes / bootstrap / includes / alter.inc @ 749b8a23

1
<?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
    $css = array_diff_key($css, drupal_map_assoc($excludes));
72
  }
73
}
74

    
75
/**
76
 * Implements hook_element_info_alter().
77
 */
78
function bootstrap_element_info_alter(&$info) {
79
  global $theme_key;
80

    
81
  $cid = "theme_registry:bootstrap:element_info";
82
  $cached = array();
83
  if (($cache = cache_get($cid)) && !empty($cache->data)) {
84
    $cached = $cache->data;
85
  }
86

    
87
  $themes = _bootstrap_get_base_themes($theme_key, TRUE);
88
  foreach ($themes as $theme) {
89
    if (!isset($cached[$theme])) {
90
      $cached[$theme] = array();
91
      foreach (array_keys($info) as $type) {
92
        $element = array();
93

    
94
        // Ensure elements that have a base type with the #input set match.
95
        if (isset($info[$type]['#base_type']) && isset($info[$type][$info[$type]['#base_type']]['#input'])) {
96
          $element['#input'] = $info[$info[$type]['#base_type']]['#input'];
97
        }
98

    
99
        // Replace fieldset theme implementations with bootstrap_panel.
100
        if (!empty($info[$type]['#theme']) && $info[$type]['#theme'] === 'fieldset') {
101
          $element['#bootstrap_replace']['#theme'] = 'bootstrap_panel';
102
        }
103
        if (!empty($info[$type]['#theme_wrappers']) && array_search('fieldset', $info[$type]['#theme_wrappers']) !== FALSE) {
104
          $element['#bootstrap_replace']['#theme_wrappers']['fieldset'] = 'bootstrap_panel';
105
        }
106

    
107
        // Setup a default "icon" variable. This allows #icon to be passed
108
        // to every template and theme function.
109
        // @see https://drupal.org/node/2219965
110
        $element['#icon'] = NULL;
111
        $element['#icon_position'] = 'before';
112

    
113
        $properties = array(
114
          '#process' => array(
115
            'form_process',
116
            'form_process_' . $type,
117
          ),
118
          '#pre_render' => array(
119
            'pre_render',
120
            'pre_render_' . $type,
121
          ),
122
        );
123
        foreach ($properties as $property => $callbacks) {
124
          foreach ($callbacks as $callback) {
125
            $function = $theme . '_' . $callback;
126
            if (function_exists($function)) {
127
              // Replace direct core function correlation.
128
              if (!empty($info[$type][$property]) && array_search($callback, $info[$type][$property]) !== FALSE) {
129
                $element['#bootstrap_replace'][$property][$callback] = $function;
130
              }
131
              // Check for a "form_" prefix instead (for #pre_render).
132
              elseif (!empty($info[$type][$property]) && array_search('form_' . $callback, $info[$type][$property]) !== FALSE) {
133
                $element['#bootstrap_replace'][$property]['form_' . $callback] = $function;
134
              }
135
              // Otherwise, append the function.
136
              else {
137
                $element[$property][] = $function;
138
              }
139
            }
140
          }
141
        }
142
        $cached[$theme][$type] = $element;
143
      }
144

    
145
      // Cache the element information.
146
      cache_set($cid, $cached);
147
    }
148

    
149
    // Merge in each theme's cached element info.
150
    $info = _bootstrap_element_info_array_merge($info, $cached[$theme]);
151
  }
152
}
153

    
154
/**
155
 * Merges the cached element information into the runtime array.
156
 *
157
 * @param array $info
158
 *   The element info array to merge data into.
159
 * @param array $cached
160
 *   The cached element info data array to merge from.
161
 *
162
 * @return array
163
 *   The altered element info array.
164
 */
165
function _bootstrap_element_info_array_merge($info, $cached) {
166
  foreach ($cached as $type => $element) {
167
    $replacement_data = isset($element['#bootstrap_replace']) ? $element['#bootstrap_replace'] : array();
168
    unset($element['#bootstrap_replace']);
169
    foreach ($element as $property => $data) {
170
      if (is_array($data)) {
171
        if (!isset($info[$type][$property])) {
172
          $info[$type][$property] = array();
173
        }
174
        // Append the values if not already in the array.
175
        foreach ($data as $key => $value) {
176
          if (!in_array($value, $info[$type][$property])) {
177
            $info[$type][$property][] = $value;
178
          }
179
        }
180
      }
181
      // Create the property, if not already set.
182
      elseif (!isset($info[$type][$property])) {
183
        $info[$type][$property] = $data;
184
      }
185
    }
186
    // Replace data, if necessary.
187
    foreach ($replacement_data as $property => $data) {
188
      if (is_array($data)) {
189
        foreach ($data as $needle => $replacement) {
190
          if (!empty($info[$type][$property]) && ($key = array_search($needle, $info[$type][$property])) !== FALSE) {
191
            $info[$type][$property][$key] = $replacement;
192
          }
193
        }
194
      }
195
      // Replace the property with the new data.
196
      else {
197
        $info[$type][$property] = $data;
198
      }
199
    }
200
  }
201

    
202
  // Return the altered element info array.
203
  return $info;
204
}
205

    
206
/**
207
 * Implements hook_form_alter().
208
 */
209
function bootstrap_form_alter(array &$form, array &$form_state = array(), $form_id = NULL) {
210
  if ($form_id) {
211
    switch ($form_id) {
212
      case 'system_theme_settings':
213
        // Create vertical tabs for global settings (provided by core or other
214
        // contrib modules).
215
        if (!isset($form['global'])) {
216
          $form['global'] = array(
217
            '#type' => 'vertical_tabs',
218
            '#weight' => -9,
219
          );
220
          if (!empty($form_state['build_info']['args'][0])) {
221
            $form['global']['#prefix'] = '<h2><small>' . t('Override Global Settings') . '</small></h2>';
222
          }
223
        }
224

    
225
        // Iterate over all child elements and check to see if they should be
226
        // moved in the global vertical tabs.
227
        $global_children = element_children($form);
228
        foreach ($global_children as $child) {
229
          if (isset($form[$child]['#type']) && $form[$child]['#type'] === 'fieldset' && !isset($form[$child]['#group'])) {
230
            $form[$child]['#group'] = 'global';
231
          }
232
        }
233
        break;
234

    
235
      case 'search_form':
236
        // Add a clearfix class so the results don't overflow onto the form.
237
        $form['#attributes']['class'][] = 'clearfix';
238

    
239
        // Remove container-inline from the container classes.
240
        $form['basic']['#attributes']['class'] = array();
241

    
242
        // Hide the default button from display.
243
        $form['basic']['submit']['#attributes']['class'][] = 'element-invisible';
244

    
245
        // Implement a theme wrapper to add a submit button containing a search
246
        // icon directly after the input element.
247
        $form['basic']['keys']['#theme_wrappers'] = array('bootstrap_search_form_wrapper');
248
        $form['basic']['keys']['#title'] = '';
249
        $form['basic']['keys']['#attributes']['placeholder'] = t('Search');
250
        break;
251

    
252
      case 'search_block_form':
253
        $form['#attributes']['class'][] = 'form-search';
254

    
255
        $form['search_block_form']['#title'] = '';
256
        $form['search_block_form']['#attributes']['placeholder'] = t('Search');
257

    
258
        // Hide the default button from display and implement a theme wrapper
259
        // to add a submit button containing a search icon directly after the
260
        // input element.
261
        $form['actions']['submit']['#attributes']['class'][] = 'element-invisible';
262
        $form['search_block_form']['#theme_wrappers'] = array('bootstrap_search_form_wrapper');
263

    
264
        // Apply a clearfix so the results don't overflow onto the form.
265
        $form['#attributes']['class'][] = 'content-search';
266
        break;
267

    
268
      case 'image_style_form':
269
        $form['effects']['new']['new']['#input_group_button'] = TRUE;
270
        break;
271

    
272
      case 'path_admin_filter_form':
273
        $form['basic']['filter']['#input_group_button'] = TRUE;
274
        break;
275
    }
276

    
277
  }
278
}
279

    
280
/**
281
 * Implements hook_js_alter().
282
 */
283
function bootstrap_js_alter(&$js) {
284
  // Exclude specified JavaScript files from theme.
285
  $excludes = bootstrap_get_theme_info(NULL, 'exclude][js');
286

    
287
  $theme_path = drupal_get_path('theme', 'bootstrap');
288

    
289
  // Add or replace JavaScript files when matching paths are detected.
290
  // Replacement files must begin with '_', like '_node.js'.
291
  $files = _bootstrap_file_scan_directory($theme_path . '/js', '/\.js$/');
292
  foreach ($files as $file) {
293
    $path = str_replace($theme_path . '/js/', '', $file->uri);
294
    // Detect if this is a replacement file.
295
    $replace = FALSE;
296
    if (preg_match('/^[_]/', $file->filename)) {
297
      $replace = TRUE;
298
      $path = dirname($path) . '/' . preg_replace('/^[_]/', '', $file->filename);
299
    }
300
    $matches = array();
301
    if (preg_match('/^modules\/([^\/]*)/', $path, $matches)) {
302
      if (!module_exists($matches[1])) {
303
        continue;
304
      }
305
      else {
306
        $path = str_replace('modules/' . $matches[1], drupal_get_path('module', $matches[1]), $path);
307
      }
308
    }
309
    // Path should always exist to either add or replace JavaScript file.
310
    if (!empty($js[$path])) {
311
      // Replace file.
312
      if ($replace) {
313
        $js[$file->uri] = $js[$path];
314
        $js[$file->uri]['data'] = $file->uri;
315
        unset($js[$path]);
316
      }
317
      // Add file.
318
      else {
319
        $js[$file->uri] = drupal_js_defaults($file->uri);
320
        $js[$file->uri]['group'] = JS_THEME;
321
      }
322
    }
323
  }
324

    
325
  // Ensure jQuery Once is always loaded.
326
  // @see https://drupal.org/node/2149561
327
  if (empty($js['misc/jquery.once.js'])) {
328
    $jquery_once = drupal_get_library('system', 'jquery.once');
329
    $js['misc/jquery.once.js'] = $jquery_once['js']['misc/jquery.once.js'];
330
    $js['misc/jquery.once.js'] += drupal_js_defaults('misc/jquery.once.js');
331
  }
332

    
333
  // Always add bootstrap.js last.
334
  $bootstrap = $theme_path . '/js/bootstrap.js';
335
  $js[$bootstrap] = drupal_js_defaults($bootstrap);
336
  $js[$bootstrap]['group'] = JS_THEME;
337
  $js[$bootstrap]['scope'] = 'footer';
338

    
339
  if (!empty($excludes)) {
340
    $js = array_diff_key($js, drupal_map_assoc($excludes));
341
  }
342

    
343
  // Add Bootstrap settings.
344
  $js['settings']['data'][]['bootstrap'] = array(
345
    'anchorsFix' => bootstrap_setting('anchors_fix'),
346
    'anchorsSmoothScrolling' => bootstrap_setting('anchors_smooth_scrolling'),
347
    'formHasError' => (int) bootstrap_setting('forms_has_error_value_toggle'),
348
    'popoverEnabled' => bootstrap_setting('popover_enabled'),
349
    'popoverOptions' => array(
350
      'animation' => (int) bootstrap_setting('popover_animation'),
351
      'html' => (int) bootstrap_setting('popover_html'),
352
      'placement' => bootstrap_setting('popover_placement'),
353
      'selector' => bootstrap_setting('popover_selector'),
354
      'trigger' => implode(' ', array_filter(array_values((array) bootstrap_setting('popover_trigger')))),
355
      'triggerAutoclose' => (int) bootstrap_setting('popover_trigger_autoclose'),
356
      'title' => bootstrap_setting('popover_title'),
357
      'content' => bootstrap_setting('popover_content'),
358
      'delay' => (int) bootstrap_setting('popover_delay'),
359
      'container' => bootstrap_setting('popover_container'),
360
    ),
361
    'tooltipEnabled' => bootstrap_setting('tooltip_enabled'),
362
    'tooltipOptions' => array(
363
      'animation' => (int) bootstrap_setting('tooltip_animation'),
364
      'html' => (int) bootstrap_setting('tooltip_html'),
365
      'placement' => bootstrap_setting('tooltip_placement'),
366
      'selector' => bootstrap_setting('tooltip_selector'),
367
      'trigger' => implode(' ', array_filter(array_values((array) bootstrap_setting('tooltip_trigger')))),
368
      'delay' => (int) bootstrap_setting('tooltip_delay'),
369
      'container' => bootstrap_setting('tooltip_container'),
370
    ),
371
  );
372

    
373
  // Add CDN assets, if any.
374
  if ($cdn_assets = bootstrap_get_cdn_assets('js')) {
375
    $cdn_weight = -99.99;
376
    foreach ($cdn_assets as $cdn_asset) {
377
      $cdn_weight += .01;
378
      $js[$cdn_asset] = drupal_js_defaults($cdn_asset);
379
      $js[$cdn_asset]['type'] = 'external';
380
      $js[$cdn_asset]['every_page'] = TRUE;
381
      $js[$cdn_asset]['weight'] = $cdn_weight;
382
    }
383
  }
384
}
385

    
386
/**
387
 * Implements hook_icon_bundle_list_alter().
388
 */
389
function bootstrap_icon_bundle_list_alter(&$build, $bundle) {
390
  if (bootstrap_setting('tooltip_enabled')) {
391
    foreach ($build as &$icon) {
392
      $icon['#attributes']['data-toggle'] = 'tooltip';
393
      $icon['#attributes']['data-placement'] = 'bottom';
394
    }
395
  }
396
}
397

    
398
/**
399
 * Implements hook_menu_local_tasks_alter().
400
 */
401
function bootstrap_menu_local_tasks_alter(&$data, &$router_item, $root_path) {
402
  if (!empty($data['actions']['output'])) {
403
    $items = array();
404
    foreach ($data['actions']['output'] as $item) {
405
      $items[] = array(
406
        'data' => $item,
407
      );
408
    }
409
    $data['actions']['output'] = array(
410
      '#theme' => 'item_list__action_links',
411
      '#items' => $items,
412
      '#attributes' => array(
413
        'class' => array('action-links'),
414
      ),
415
    );
416
  }
417
}
418

    
419
/**
420
 * Implements hook_js_callback_filter_xss_alter().
421
 */
422
function bootstrap_js_callback_filter_xss_alter(array &$allowed_tags = array()) {
423
  $allowed_tags[] = 'button';
424
}