Projet

Général

Profil

Paste
Télécharger (15,9 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / themes / bootstrap / includes / alter.inc @ 01f36513

1
<?php
2

    
3
/**
4
 * @file
5
 * alter.inc
6
 *
7
 * Contains various implementations of hook_*_alter().
8
 */
9

    
10
/**
11
 * Include #pre_render callbacks for elements.
12
 */
13
bootstrap_include('bootstrap', 'includes/pre-render.inc');
14

    
15
/**
16
 * Include #process callbacks for elements.
17
 */
18
bootstrap_include('bootstrap', 'includes/process.inc');
19

    
20
/**
21
 * Implements hook_css_alter().
22
 */
23
function bootstrap_css_alter(&$css) {
24
  $theme_path = drupal_get_path('theme', 'bootstrap');
25

    
26
  // Exclude specified CSS files from theme.
27
  $excludes = bootstrap_get_theme_info(NULL, 'exclude][css');
28

    
29
  // Add CDN assets, if any.
30
  $provider = bootstrap_setting('cdn_provider');
31
  if ($cdn_assets = bootstrap_get_cdn_assets('css', $provider)) {
32
    $cdn_weight = -2.99;
33
    foreach ($cdn_assets as $cdn_asset) {
34
      $cdn_weight += .01;
35
      $css[$cdn_asset] = array(
36
        'data' => $cdn_asset,
37
        'type' => 'external',
38
        'every_page' => TRUE,
39
        'media' => 'all',
40
        'preprocess' => FALSE,
41
        'group' => CSS_THEME,
42
        'browsers' => array('IE' => TRUE, '!IE' => TRUE),
43
        'weight' => $cdn_weight,
44
      );
45
    }
46

    
47
    // Add a specific version and theme CSS overrides file.
48
    $version = bootstrap_setting('cdn_' . $provider . '_version');
49
    if (!$version) {
50
      $version = BOOTSTRAP_VERSION;
51
    }
52
    $theme = bootstrap_setting('cdn_' . $provider . '_theme');
53
    if (!$theme) {
54
      $theme = 'bootstrap';
55
    }
56
    $theme = $theme === 'bootstrap' || $theme === 'bootstrap_theme' ? '' : "-$theme";
57
    $overrides = "$theme_path/css/$version/overrides$theme.min.css";
58
    if (file_exists($overrides)) {
59
      $css[$overrides] = array(
60
        'data' => $overrides,
61
        'type' => 'file',
62
        'every_page' => TRUE,
63
        'media' => 'all',
64
        'preprocess' => TRUE,
65
        'group' => CSS_THEME,
66
        'browsers' => array('IE' => TRUE, '!IE' => TRUE),
67
        'weight' => -1,
68
      );
69
    }
70
  }
71
  if (!empty($excludes)) {
72
    $excludes = array_merge($excludes, str_replace('.css', '-rtl.css', $excludes));
73
    $css = array_diff_key($css, drupal_map_assoc($excludes));
74
  }
75
}
76

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

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

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

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

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

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

    
142
      // Cache the element information.
143
      cache_set($cid, $cached);
144
    }
145

    
146
    // Merge in each theme's cached element info.
147
    $info = _bootstrap_element_info_array_merge($info, $cached[$theme]);
148
  }
149
}
150

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

    
199
  // Return the altered element info array.
200
  return $info;
201
}
202

    
203
/**
204
 * Implements hook_field_widget_form_alter().
205
 */
206
function bootstrap_field_widget_form_alter(&$element, &$form_state, $context) {
207
  $widget_type = isset($context['instance']['widget']['type']) ? $context['instance']['widget']['type'] : NULL;
208
  if ($widget_type === 'image_image') {
209
    foreach (element_children($element) as $child) {
210
      $element[$child]['#process'][] = '_bootstrap_image_field_widget_process';
211
    }
212
  }
213
}
214

    
215
/**
216
 * Implements above #process callback.
217
 */
218
function _bootstrap_image_field_widget_process($element, &$form_state, $form) {
219
  // Core explicitly sets #theme_wrappers to an empty array for the upload
220
  // element (perhaps for styling reasons?). Thus, bootstrap_form_element() is
221
  // invoked, preventing any necessary logic from executing. To achieve the
222
  // same goal and keep backwards compatibility, reset the theme wrapper back
223
  // and indicating that the wrapper shouldn't be printed.
224
  $element['upload']['#theme_wrappers'][] = 'form_element__image_widget';
225
  $element['upload']['#form_element_wrapper'] = FALSE;
226

    
227
  // Unfortunately, core also doesn't set #access on the appropriate elements
228
  // until way too late (ironically, because of #ajax). Instead of calling
229
  // file_managed_file_pre_render(), just mimic the same #access logic, but
230
  // using #default_value instead of #value since the ajax request populates
231
  // #value.
232
  $value = empty($element['#default_value']['fid']);
233
  if (!$value) {
234
    $element['upload']['#access'] = FALSE;
235
    $element['upload_button']['#access'] = FALSE;
236
  }
237
  // If we don't already have a file, there is nothing to remove.
238
  else {
239
    $element['remove_button']['#access'] = FALSE;
240
  }
241

    
242
  // Make the upload file element an input group with a button.
243
  $element['upload']['#input_group_button'] = $value;
244

    
245
  return $element;
246
}
247

    
248
/**
249
 * Implements hook_form_alter().
250
 */
251
function bootstrap_form_alter(array &$form, array &$form_state = array(), $form_id = NULL) {
252
  if ($form_id) {
253
    switch ($form_id) {
254
      case 'system_theme_settings':
255
        // Create vertical tabs for global settings (provided by core or other
256
        // contrib modules).
257
        if (!isset($form['global'])) {
258
          $form['global'] = array(
259
            '#type' => 'vertical_tabs',
260
            '#weight' => -9,
261
          );
262
          if (!empty($form_state['build_info']['args'][0])) {
263
            $form['global']['#prefix'] = '<h2><small>' . t('Override Global Settings') . '</small></h2>';
264
          }
265
        }
266

    
267
        // Iterate over all child elements and check to see if they should be
268
        // moved in the global vertical tabs.
269
        $global_children = element_children($form);
270
        foreach ($global_children as $child) {
271
          if (isset($form[$child]['#type']) && $form[$child]['#type'] === 'fieldset' && !isset($form[$child]['#group'])) {
272
            $form[$child]['#group'] = 'global';
273
          }
274
        }
275
        break;
276

    
277
      case 'search_form':
278
        // Add a clearfix class so the results don't overflow onto the form.
279
        $form['#attributes']['class'][] = 'clearfix';
280

    
281
        // Remove container-inline from the container classes.
282
        $form['basic']['#attributes']['class'] = array();
283

    
284
        // Hide the default button from display.
285
        $form['basic']['submit']['#attributes']['class'][] = 'element-invisible';
286

    
287
        // Implement a theme wrapper to add a submit button containing a search
288
        // icon directly after the input element.
289
        $form['basic']['keys']['#theme_wrappers'] = array('bootstrap_search_form_wrapper');
290
        $form['basic']['keys']['#title'] = '';
291
        $form['basic']['keys']['#attributes']['placeholder'] = t('Search');
292
        break;
293

    
294
      case 'search_block_form':
295
        $form['#attributes']['class'][] = 'form-search';
296

    
297
        $form['search_block_form']['#title'] = '';
298
        $form['search_block_form']['#attributes']['placeholder'] = t('Search');
299

    
300
        // Hide the default button from display and implement a theme wrapper
301
        // to add a submit button containing a search icon directly after the
302
        // input element.
303
        $form['actions']['submit']['#attributes']['class'][] = 'element-invisible';
304
        $form['search_block_form']['#theme_wrappers'] = array('bootstrap_search_form_wrapper');
305

    
306
        // Apply a clearfix so the results don't overflow onto the form.
307
        $form['#attributes']['class'][] = 'content-search';
308
        break;
309

    
310
      case 'image_style_form':
311
        $form['effects']['new']['new']['#input_group_button'] = TRUE;
312
        break;
313

    
314
      case 'path_admin_filter_form':
315
        $form['basic']['filter']['#input_group_button'] = TRUE;
316
        break;
317
    }
318

    
319
  }
320
}
321

    
322
/**
323
 * Implements hook_js_alter().
324
 */
325
function bootstrap_js_alter(&$js) {
326
  // Exclude specified JavaScript files from theme.
327
  $excludes = bootstrap_get_theme_info(NULL, 'exclude][js');
328

    
329
  $theme_path = drupal_get_path('theme', 'bootstrap');
330

    
331
  // Add or replace JavaScript files when matching paths are detected.
332
  // Replacement files must begin with '_', like '_node.js'.
333
  $files = _bootstrap_file_scan_directory($theme_path . '/js', '/\.js$/');
334
  foreach ($files as $file) {
335
    $path = str_replace($theme_path . '/js/', '', $file->uri);
336
    // Detect if this is a replacement file.
337
    $replace = FALSE;
338
    if (preg_match('/^[_]/', $file->filename)) {
339
      $replace = TRUE;
340
      $path = dirname($path) . '/' . preg_replace('/^[_]/', '', $file->filename);
341
    }
342
    $matches = array();
343
    if (preg_match('/^modules\/([^\/]*)/', $path, $matches)) {
344
      if (!module_exists($matches[1])) {
345
        continue;
346
      }
347
      else {
348
        $path = str_replace('modules/' . $matches[1], drupal_get_path('module', $matches[1]), $path);
349
      }
350
    }
351
    // Path should always exist to either add or replace JavaScript file.
352
    if (!empty($js[$path])) {
353
      // Replace file.
354
      if ($replace) {
355
        $js[$file->uri] = $js[$path];
356
        $js[$file->uri]['data'] = $file->uri;
357
        unset($js[$path]);
358
      }
359
      // Add file.
360
      else {
361
        $js[$file->uri] = drupal_js_defaults($file->uri);
362
        $js[$file->uri]['group'] = JS_THEME;
363
      }
364
    }
365
  }
366

    
367
  // Ensure jQuery Once is always loaded.
368
  // @see https://www.drupal.org/node/2149561
369
  if (empty($js['misc/jquery.once.js'])) {
370
    $jquery_once = drupal_get_library('system', 'jquery.once');
371
    $js['misc/jquery.once.js'] = $jquery_once['js']['misc/jquery.once.js'];
372
    $js['misc/jquery.once.js'] += drupal_js_defaults('misc/jquery.once.js');
373
  }
374

    
375
  // Always add bootstrap.js last.
376
  $bootstrap = $theme_path . '/js/bootstrap.js';
377
  $js[$bootstrap] = drupal_js_defaults($bootstrap);
378
  $js[$bootstrap]['group'] = JS_THEME;
379
  $js[$bootstrap]['scope'] = 'footer';
380

    
381
  if (!empty($excludes)) {
382
    $js = array_diff_key($js, drupal_map_assoc($excludes));
383
  }
384

    
385
  // Add Bootstrap settings.
386
  $js['settings']['data'][]['bootstrap'] = array(
387
    'anchorsFix' => bootstrap_setting('anchors_fix'),
388
    'anchorsSmoothScrolling' => bootstrap_setting('anchors_smooth_scrolling'),
389
    'formHasError' => (int) bootstrap_setting('forms_has_error_value_toggle'),
390
    'popoverEnabled' => bootstrap_setting('popover_enabled'),
391
    'popoverOptions' => array(
392
      'animation' => (int) bootstrap_setting('popover_animation'),
393
      'html' => (int) bootstrap_setting('popover_html'),
394
      'placement' => bootstrap_setting('popover_placement'),
395
      'selector' => bootstrap_setting('popover_selector'),
396
      'trigger' => implode(' ', array_filter(array_values((array) bootstrap_setting('popover_trigger')))),
397
      'triggerAutoclose' => (int) bootstrap_setting('popover_trigger_autoclose'),
398
      'title' => bootstrap_setting('popover_title'),
399
      'content' => bootstrap_setting('popover_content'),
400
      'delay' => (int) bootstrap_setting('popover_delay'),
401
      'container' => bootstrap_setting('popover_container'),
402
    ),
403
    'tooltipEnabled' => bootstrap_setting('tooltip_enabled'),
404
    'tooltipOptions' => array(
405
      'animation' => (int) bootstrap_setting('tooltip_animation'),
406
      'html' => (int) bootstrap_setting('tooltip_html'),
407
      'placement' => bootstrap_setting('tooltip_placement'),
408
      'selector' => bootstrap_setting('tooltip_selector'),
409
      'trigger' => implode(' ', array_filter(array_values((array) bootstrap_setting('tooltip_trigger')))),
410
      'delay' => (int) bootstrap_setting('tooltip_delay'),
411
      'container' => bootstrap_setting('tooltip_container'),
412
    ),
413
  );
414

    
415
  // Add CDN assets, if any.
416
  if ($cdn_assets = bootstrap_get_cdn_assets('js')) {
417
    $cdn_weight = -99.99;
418
    foreach ($cdn_assets as $cdn_asset) {
419
      $cdn_weight += .01;
420
      $js[$cdn_asset] = drupal_js_defaults($cdn_asset);
421
      $js[$cdn_asset]['type'] = 'external';
422
      $js[$cdn_asset]['every_page'] = TRUE;
423
      $js[$cdn_asset]['weight'] = $cdn_weight;
424
    }
425
  }
426
}
427

    
428
/**
429
 * Implements hook_icon_bundle_list_alter().
430
 */
431
function bootstrap_icon_bundle_list_alter(&$build, $bundle) {
432
  if (bootstrap_setting('tooltip_enabled')) {
433
    foreach ($build as &$icon) {
434
      $icon['#attributes']['data-toggle'] = 'tooltip';
435
      $icon['#attributes']['data-placement'] = 'bottom';
436
    }
437
  }
438
}
439

    
440
/**
441
 * Implements hook_menu_local_tasks_alter().
442
 */
443
function bootstrap_menu_local_tasks_alter(&$data, &$router_item, $root_path) {
444
  if (!empty($data['actions']['output'])) {
445
    $items = array();
446
    foreach ($data['actions']['output'] as $item) {
447
      $items[] = array(
448
        'data' => $item,
449
      );
450
    }
451
    $data['actions']['output'] = array(
452
      '#theme' => 'item_list__action_links',
453
      '#items' => $items,
454
      '#attributes' => array(
455
        'class' => array('action-links'),
456
      ),
457
    );
458
  }
459
}
460

    
461
/**
462
 * Implements hook_js_callback_filter_xss_alter().
463
 */
464
function bootstrap_js_callback_filter_xss_alter(array &$allowed_tags = array()) {
465
  $allowed_tags[] = 'button';
466
}