Mercurial > hg > isophonics-drupal-site
comparison core/includes/theme.inc @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 7a779792577d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 /** | |
4 * @file | |
5 * The theme system, which controls the output of Drupal. | |
6 * | |
7 * The theme system allows for nearly all output of the Drupal system to be | |
8 * customized by user themes. | |
9 */ | |
10 | |
11 use Drupal\Component\Serialization\Json; | |
12 use Drupal\Component\Utility\Crypt; | |
13 use Drupal\Component\Utility\Html; | |
14 use Drupal\Component\Render\MarkupInterface; | |
15 use Drupal\Component\Utility\Unicode; | |
16 use Drupal\Core\Cache\CacheableDependencyInterface; | |
17 use Drupal\Core\Config\Config; | |
18 use Drupal\Core\Config\StorageException; | |
19 use Drupal\Core\Render\AttachmentsInterface; | |
20 use Drupal\Core\Render\BubbleableMetadata; | |
21 use Drupal\Core\Render\RenderableInterface; | |
22 use Drupal\Core\Template\Attribute; | |
23 use Drupal\Core\Theme\ThemeSettings; | |
24 use Drupal\Component\Utility\NestedArray; | |
25 use Drupal\Core\Render\Element; | |
26 use Drupal\Core\Render\Markup; | |
27 | |
28 /** | |
29 * @defgroup content_flags Content markers | |
30 * @{ | |
31 * Markers used by mark.html.twig and node_mark() to designate content. | |
32 * | |
33 * @see mark.html.twig | |
34 * @see node_mark() | |
35 */ | |
36 | |
37 /** | |
38 * Mark content as read. | |
39 */ | |
40 const MARK_READ = 0; | |
41 | |
42 /** | |
43 * Mark content as being new. | |
44 */ | |
45 const MARK_NEW = 1; | |
46 | |
47 /** | |
48 * Mark content as being updated. | |
49 */ | |
50 const MARK_UPDATED = 2; | |
51 | |
52 /** | |
53 * A responsive table class; hide table cell on narrow devices. | |
54 * | |
55 * Indicates that a column has medium priority and thus can be hidden on narrow | |
56 * width devices and shown on medium+ width devices (i.e. tablets and desktops). | |
57 */ | |
58 const RESPONSIVE_PRIORITY_MEDIUM = 'priority-medium'; | |
59 | |
60 /** | |
61 * A responsive table class; only show table cell on wide devices. | |
62 * | |
63 * Indicates that a column has low priority and thus can be hidden on narrow | |
64 * and medium viewports and shown on wide devices (i.e. desktops). | |
65 */ | |
66 const RESPONSIVE_PRIORITY_LOW = 'priority-low'; | |
67 | |
68 /** | |
69 * @} End of "defgroup content_flags". | |
70 */ | |
71 | |
72 /** | |
73 * Gets the theme registry. | |
74 * | |
75 * @param bool $complete | |
76 * Optional boolean to indicate whether to return the complete theme registry | |
77 * array or an instance of the Drupal\Core\Utility\ThemeRegistry class. | |
78 * If TRUE, the complete theme registry array will be returned. This is useful | |
79 * if you want to foreach over the whole registry, use array_* functions or | |
80 * inspect it in a debugger. If FALSE, an instance of the | |
81 * Drupal\Core\Utility\ThemeRegistry class will be returned, this provides an | |
82 * ArrayObject which allows it to be accessed with array syntax and isset(), | |
83 * and should be more lightweight than the full registry. Defaults to TRUE. | |
84 * | |
85 * @return | |
86 * The complete theme registry array, or an instance of the | |
87 * Drupal\Core\Utility\ThemeRegistry class. | |
88 */ | |
89 function theme_get_registry($complete = TRUE) { | |
90 $theme_registry = \Drupal::service('theme.registry'); | |
91 if ($complete) { | |
92 return $theme_registry->get(); | |
93 } | |
94 else { | |
95 return $theme_registry->getRuntime(); | |
96 } | |
97 } | |
98 | |
99 /** | |
100 * Returns an array of default theme features. | |
101 * | |
102 * @see \Drupal\Core\Extension\ThemeHandler::$defaultFeatures | |
103 */ | |
104 function _system_default_theme_features() { | |
105 return [ | |
106 'favicon', | |
107 'logo', | |
108 'node_user_picture', | |
109 'comment_user_picture', | |
110 'comment_user_verification', | |
111 ]; | |
112 } | |
113 | |
114 /** | |
115 * Forces the system to rebuild the theme registry. | |
116 * | |
117 * This function should be called when modules are added to the system, or when | |
118 * a dynamic system needs to add more theme hooks. | |
119 */ | |
120 function drupal_theme_rebuild() { | |
121 \Drupal::service('theme.registry')->reset(); | |
122 } | |
123 | |
124 /** | |
125 * Allows themes and/or theme engines to discover overridden theme functions. | |
126 * | |
127 * @param array $cache | |
128 * The existing cache of theme hooks to test against. | |
129 * @param array $prefixes | |
130 * An array of prefixes to test, in reverse order of importance. | |
131 * | |
132 * @return array | |
133 * The functions found, suitable for returning from hook_theme; | |
134 */ | |
135 function drupal_find_theme_functions($cache, $prefixes) { | |
136 $implementations = []; | |
137 $grouped_functions = \Drupal::service('theme.registry')->getPrefixGroupedUserFunctions($prefixes); | |
138 | |
139 foreach ($cache as $hook => $info) { | |
140 foreach ($prefixes as $prefix) { | |
141 // Find theme functions that implement possible "suggestion" variants of | |
142 // registered theme hooks and add those as new registered theme hooks. | |
143 // The 'pattern' key defines a common prefix that all suggestions must | |
144 // start with. The default is the name of the hook followed by '__'. An | |
145 // 'base hook' key is added to each entry made for a found suggestion, | |
146 // so that common functionality can be implemented for all suggestions of | |
147 // the same base hook. To keep things simple, deep hierarchy of | |
148 // suggestions is not supported: each suggestion's 'base hook' key | |
149 // refers to a base hook, not to another suggestion, and all suggestions | |
150 // are found using the base hook's pattern, not a pattern from an | |
151 // intermediary suggestion. | |
152 $pattern = isset($info['pattern']) ? $info['pattern'] : ($hook . '__'); | |
153 // Grep only the functions which are within the prefix group. | |
154 list($first_prefix,) = explode('_', $prefix, 2); | |
155 if (!isset($info['base hook']) && !empty($pattern) && isset($grouped_functions[$first_prefix])) { | |
156 $matches = preg_grep('/^' . $prefix . '_' . $pattern . '/', $grouped_functions[$first_prefix]); | |
157 if ($matches) { | |
158 foreach ($matches as $match) { | |
159 $new_hook = substr($match, strlen($prefix) + 1); | |
160 $arg_name = isset($info['variables']) ? 'variables' : 'render element'; | |
161 $implementations[$new_hook] = [ | |
162 'function' => $match, | |
163 $arg_name => $info[$arg_name], | |
164 'base hook' => $hook, | |
165 ]; | |
166 } | |
167 } | |
168 } | |
169 // Find theme functions that implement registered theme hooks and include | |
170 // that in what is returned so that the registry knows that the theme has | |
171 // this implementation. | |
172 if (function_exists($prefix . '_' . $hook)) { | |
173 $implementations[$hook] = [ | |
174 'function' => $prefix . '_' . $hook, | |
175 ]; | |
176 } | |
177 } | |
178 } | |
179 | |
180 return $implementations; | |
181 } | |
182 | |
183 /** | |
184 * Allows themes and/or theme engines to easily discover overridden templates. | |
185 * | |
186 * @param $cache | |
187 * The existing cache of theme hooks to test against. | |
188 * @param $extension | |
189 * The extension that these templates will have. | |
190 * @param $path | |
191 * The path to search. | |
192 */ | |
193 function drupal_find_theme_templates($cache, $extension, $path) { | |
194 $implementations = []; | |
195 | |
196 // Collect paths to all sub-themes grouped by base themes. These will be | |
197 // used for filtering. This allows base themes to have sub-themes in its | |
198 // folder hierarchy without affecting the base themes template discovery. | |
199 $theme_paths = []; | |
200 foreach (\Drupal::service('theme_handler')->listInfo() as $theme_info) { | |
201 if (!empty($theme_info->base_theme)) { | |
202 $theme_paths[$theme_info->base_theme][$theme_info->getName()] = $theme_info->getPath(); | |
203 } | |
204 } | |
205 foreach ($theme_paths as $basetheme => $subthemes) { | |
206 foreach ($subthemes as $subtheme => $subtheme_path) { | |
207 if (isset($theme_paths[$subtheme])) { | |
208 $theme_paths[$basetheme] = array_merge($theme_paths[$basetheme], $theme_paths[$subtheme]); | |
209 } | |
210 } | |
211 } | |
212 $theme = \Drupal::theme()->getActiveTheme()->getName(); | |
213 $subtheme_paths = isset($theme_paths[$theme]) ? $theme_paths[$theme] : []; | |
214 | |
215 // Escape the periods in the extension. | |
216 $regex = '/' . str_replace('.', '\.', $extension) . '$/'; | |
217 // Get a listing of all template files in the path to search. | |
218 $files = file_scan_directory($path, $regex, ['key' => 'filename']); | |
219 | |
220 // Find templates that implement registered theme hooks and include that in | |
221 // what is returned so that the registry knows that the theme has this | |
222 // implementation. | |
223 foreach ($files as $template => $file) { | |
224 // Ignore sub-theme templates for the current theme. | |
225 if (strpos($file->uri, str_replace($subtheme_paths, '', $file->uri)) !== 0) { | |
226 continue; | |
227 } | |
228 // Remove the extension from the filename. | |
229 $template = str_replace($extension, '', $template); | |
230 // Transform - in filenames to _ to match function naming scheme | |
231 // for the purposes of searching. | |
232 $hook = strtr($template, '-', '_'); | |
233 if (isset($cache[$hook])) { | |
234 $implementations[$hook] = [ | |
235 'template' => $template, | |
236 'path' => dirname($file->uri), | |
237 ]; | |
238 } | |
239 | |
240 // Match templates based on the 'template' filename. | |
241 foreach ($cache as $hook => $info) { | |
242 if (isset($info['template'])) { | |
243 if ($template === $info['template']) { | |
244 $implementations[$hook] = [ | |
245 'template' => $template, | |
246 'path' => dirname($file->uri), | |
247 ]; | |
248 } | |
249 } | |
250 } | |
251 } | |
252 | |
253 // Find templates that implement possible "suggestion" variants of registered | |
254 // theme hooks and add those as new registered theme hooks. See | |
255 // drupal_find_theme_functions() for more information about suggestions and | |
256 // the use of 'pattern' and 'base hook'. | |
257 $patterns = array_keys($files); | |
258 foreach ($cache as $hook => $info) { | |
259 $pattern = isset($info['pattern']) ? $info['pattern'] : ($hook . '__'); | |
260 if (!isset($info['base hook']) && !empty($pattern)) { | |
261 // Transform _ in pattern to - to match file naming scheme | |
262 // for the purposes of searching. | |
263 $pattern = strtr($pattern, '_', '-'); | |
264 | |
265 $matches = preg_grep('/^' . $pattern . '/', $patterns); | |
266 if ($matches) { | |
267 foreach ($matches as $match) { | |
268 $file = $match; | |
269 // Remove the extension from the filename. | |
270 $file = str_replace($extension, '', $file); | |
271 // Put the underscores back in for the hook name and register this | |
272 // pattern. | |
273 $arg_name = isset($info['variables']) ? 'variables' : 'render element'; | |
274 $implementations[strtr($file, '-', '_')] = [ | |
275 'template' => $file, | |
276 'path' => dirname($files[$match]->uri), | |
277 $arg_name => $info[$arg_name], | |
278 'base hook' => $hook, | |
279 ]; | |
280 } | |
281 } | |
282 } | |
283 } | |
284 return $implementations; | |
285 } | |
286 | |
287 /** | |
288 * Retrieves a setting for the current theme or for a given theme. | |
289 * | |
290 * The final setting is obtained from the last value found in the following | |
291 * sources: | |
292 * - the saved values from the global theme settings form | |
293 * - the saved values from the theme's settings form | |
294 * To only retrieve the default global theme setting, an empty string should be | |
295 * given for $theme. | |
296 * | |
297 * @param $setting_name | |
298 * The name of the setting to be retrieved. | |
299 * @param $theme | |
300 * The name of a given theme; defaults to the current theme. | |
301 * | |
302 * @return | |
303 * The value of the requested setting, NULL if the setting does not exist. | |
304 */ | |
305 function theme_get_setting($setting_name, $theme = NULL) { | |
306 /** @var \Drupal\Core\Theme\ThemeSettings[] $cache */ | |
307 $cache = &drupal_static(__FUNCTION__, []); | |
308 | |
309 // If no key is given, use the current theme if we can determine it. | |
310 if (!isset($theme)) { | |
311 $theme = \Drupal::theme()->getActiveTheme()->getName(); | |
312 } | |
313 | |
314 if (empty($cache[$theme])) { | |
315 // Create a theme settings object. | |
316 $cache[$theme] = new ThemeSettings($theme); | |
317 // Get the global settings from configuration. | |
318 $cache[$theme]->setData(\Drupal::config('system.theme.global')->get()); | |
319 | |
320 // Get the values for the theme-specific settings from the .info.yml files | |
321 // of the theme and all its base themes. | |
322 $themes = \Drupal::service('theme_handler')->listInfo(); | |
323 if (isset($themes[$theme])) { | |
324 $theme_object = $themes[$theme]; | |
325 | |
326 // Retrieve configured theme-specific settings, if any. | |
327 try { | |
328 if ($theme_settings = \Drupal::config($theme . '.settings')->get()) { | |
329 $cache[$theme]->merge($theme_settings); | |
330 } | |
331 } | |
332 catch (StorageException $e) { | |
333 } | |
334 | |
335 // If the theme does not support a particular feature, override the global | |
336 // setting and set the value to NULL. | |
337 if (!empty($theme_object->info['features'])) { | |
338 foreach (_system_default_theme_features() as $feature) { | |
339 if (!in_array($feature, $theme_object->info['features'])) { | |
340 $cache[$theme]->set('features.' . $feature, NULL); | |
341 } | |
342 } | |
343 } | |
344 | |
345 // Generate the path to the logo image. | |
346 if ($cache[$theme]->get('logo.use_default')) { | |
347 $cache[$theme]->set('logo.url', file_url_transform_relative(file_create_url($theme_object->getPath() . '/logo.svg'))); | |
348 } | |
349 elseif ($logo_path = $cache[$theme]->get('logo.path')) { | |
350 $cache[$theme]->set('logo.url', file_url_transform_relative(file_create_url($logo_path))); | |
351 } | |
352 | |
353 // Generate the path to the favicon. | |
354 if ($cache[$theme]->get('features.favicon')) { | |
355 $favicon_path = $cache[$theme]->get('favicon.path'); | |
356 if ($cache[$theme]->get('favicon.use_default')) { | |
357 if (file_exists($favicon = $theme_object->getPath() . '/favicon.ico')) { | |
358 $cache[$theme]->set('favicon.url', file_url_transform_relative(file_create_url($favicon))); | |
359 } | |
360 else { | |
361 $cache[$theme]->set('favicon.url', file_url_transform_relative(file_create_url('core/misc/favicon.ico'))); | |
362 } | |
363 } | |
364 elseif ($favicon_path) { | |
365 $cache[$theme]->set('favicon.url', file_url_transform_relative(file_create_url($favicon_path))); | |
366 } | |
367 else { | |
368 $cache[$theme]->set('features.favicon', FALSE); | |
369 } | |
370 } | |
371 } | |
372 } | |
373 | |
374 return $cache[$theme]->get($setting_name); | |
375 } | |
376 | |
377 /** | |
378 * Escapes and renders variables for theme functions. | |
379 * | |
380 * This method is used in theme functions to ensure that the result is safe for | |
381 * output inside HTML fragments. This mimics the behavior of the auto-escape | |
382 * functionality in Twig. | |
383 * | |
384 * Note: This function should be kept in sync with | |
385 * \Drupal\Core\Template\TwigExtension::escapeFilter(). | |
386 * | |
387 * @param mixed $arg | |
388 * The string, object, or render array to escape if needed. | |
389 * | |
390 * @return string | |
391 * The rendered string, safe for use in HTML. The string is not safe when used | |
392 * as any part of an HTML attribute name or value. | |
393 * | |
394 * @throws \Exception | |
395 * Thrown when an object is passed in which cannot be printed. | |
396 * | |
397 * @see \Drupal\Core\Template\TwigExtension::escapeFilter() | |
398 * | |
399 * @todo Discuss deprecating this in https://www.drupal.org/node/2575081. | |
400 * @todo Refactor this to keep it in sync with Twig filtering in | |
401 * https://www.drupal.org/node/2575065 | |
402 */ | |
403 function theme_render_and_autoescape($arg) { | |
404 // If it's a renderable, then it'll be up to the generated render array it | |
405 // returns to contain the necessary cacheability & attachment metadata. If | |
406 // it doesn't implement CacheableDependencyInterface or AttachmentsInterface | |
407 // then there is nothing to do here. | |
408 if (!($arg instanceof RenderableInterface) && ($arg instanceof CacheableDependencyInterface || $arg instanceof AttachmentsInterface)) { | |
409 $arg_bubbleable = []; | |
410 BubbleableMetadata::createFromObject($arg) | |
411 ->applyTo($arg_bubbleable); | |
412 \Drupal::service('renderer')->render($arg_bubbleable); | |
413 } | |
414 | |
415 if ($arg instanceof MarkupInterface) { | |
416 return (string) $arg; | |
417 } | |
418 $return = NULL; | |
419 | |
420 if (is_scalar($arg)) { | |
421 $return = (string) $arg; | |
422 } | |
423 elseif (is_object($arg)) { | |
424 if ($arg instanceof RenderableInterface) { | |
425 $arg = $arg->toRenderable(); | |
426 } | |
427 elseif (method_exists($arg, '__toString')) { | |
428 $return = (string) $arg; | |
429 } | |
430 // You can't throw exceptions in the magic PHP __toString methods, see | |
431 // http://php.net/manual/language.oop5.magic.php#object.tostring so | |
432 // we also support a toString method. | |
433 elseif (method_exists($arg, 'toString')) { | |
434 $return = $arg->toString(); | |
435 } | |
436 else { | |
437 throw new \Exception('Object of type ' . get_class($arg) . ' cannot be printed.'); | |
438 } | |
439 } | |
440 | |
441 // We have a string or an object converted to a string: Escape it! | |
442 if (isset($return)) { | |
443 return $return instanceof MarkupInterface ? $return : Html::escape($return); | |
444 } | |
445 | |
446 // This is a normal render array, which is safe by definition, with special | |
447 // simple cases already handled. | |
448 | |
449 // Early return if this element was pre-rendered (no need to re-render). | |
450 if (isset($arg['#printed']) && $arg['#printed'] == TRUE && isset($arg['#markup']) && strlen($arg['#markup']) > 0) { | |
451 return (string) $arg['#markup']; | |
452 } | |
453 $arg['#printed'] = FALSE; | |
454 return (string) \Drupal::service('renderer')->render($arg); | |
455 } | |
456 | |
457 /** | |
458 * Converts theme settings to configuration. | |
459 * | |
460 * @see system_theme_settings_submit() | |
461 * | |
462 * @param array $theme_settings | |
463 * An array of theme settings from system setting form or a Drupal 7 variable. | |
464 * @param Config $config | |
465 * The configuration object to update. | |
466 * | |
467 * @return | |
468 * The Config object with updated data. | |
469 */ | |
470 function theme_settings_convert_to_config(array $theme_settings, Config $config) { | |
471 foreach ($theme_settings as $key => $value) { | |
472 if ($key == 'default_logo') { | |
473 $config->set('logo.use_default', $value); | |
474 } | |
475 elseif ($key == 'logo_path') { | |
476 $config->set('logo.path', $value); | |
477 } | |
478 elseif ($key == 'default_favicon') { | |
479 $config->set('favicon.use_default', $value); | |
480 } | |
481 elseif ($key == 'favicon_path') { | |
482 $config->set('favicon.path', $value); | |
483 } | |
484 elseif ($key == 'favicon_mimetype') { | |
485 $config->set('favicon.mimetype', $value); | |
486 } | |
487 elseif (substr($key, 0, 7) == 'toggle_') { | |
488 $config->set('features.' . Unicode::substr($key, 7), $value); | |
489 } | |
490 elseif (!in_array($key, ['theme', 'logo_upload'])) { | |
491 $config->set($key, $value); | |
492 } | |
493 } | |
494 return $config; | |
495 } | |
496 | |
497 /** | |
498 * Prepares variables for time templates. | |
499 * | |
500 * Default template: time.html.twig. | |
501 * | |
502 * @param array $variables | |
503 * An associative array possibly containing: | |
504 * - attributes['timestamp']: | |
505 * - timestamp: | |
506 * - text: | |
507 */ | |
508 function template_preprocess_time(&$variables) { | |
509 // Format the 'datetime' attribute based on the timestamp. | |
510 // @see http://www.w3.org/TR/html5-author/the-time-element.html#attr-time-datetime | |
511 if (!isset($variables['attributes']['datetime']) && isset($variables['timestamp'])) { | |
512 $variables['attributes']['datetime'] = format_date($variables['timestamp'], 'html_datetime', '', 'UTC'); | |
513 } | |
514 | |
515 // If no text was provided, try to auto-generate it. | |
516 if (!isset($variables['text'])) { | |
517 // Format and use a human-readable version of the timestamp, if any. | |
518 if (isset($variables['timestamp'])) { | |
519 $variables['text'] = format_date($variables['timestamp']); | |
520 } | |
521 // Otherwise, use the literal datetime attribute. | |
522 elseif (isset($variables['attributes']['datetime'])) { | |
523 $variables['text'] = $variables['attributes']['datetime']; | |
524 } | |
525 } | |
526 } | |
527 | |
528 /** | |
529 * Prepares variables for datetime form element templates. | |
530 * | |
531 * The datetime form element serves as a wrapper around the date element type, | |
532 * which creates a date and a time component for a date. | |
533 * | |
534 * Default template: datetime-form.html.twig. | |
535 * | |
536 * @param array $variables | |
537 * An associative array containing: | |
538 * - element: An associative array containing the properties of the element. | |
539 * Properties used: #title, #value, #options, #description, #required, | |
540 * #attributes. | |
541 * | |
542 * @see form_process_datetime() | |
543 */ | |
544 function template_preprocess_datetime_form(&$variables) { | |
545 $element = $variables['element']; | |
546 | |
547 $variables['attributes'] = []; | |
548 if (isset($element['#id'])) { | |
549 $variables['attributes']['id'] = $element['#id']; | |
550 } | |
551 if (!empty($element['#attributes']['class'])) { | |
552 $variables['attributes']['class'] = (array) $element['#attributes']['class']; | |
553 } | |
554 | |
555 $variables['content'] = $element; | |
556 } | |
557 | |
558 /** | |
559 * Prepares variables for datetime form wrapper templates. | |
560 * | |
561 * Default template: datetime-wrapper.html.twig. | |
562 * | |
563 * @param array $variables | |
564 * An associative array containing: | |
565 * - element: An associative array containing the properties of the element. | |
566 * Properties used: #title, #children, #required, #attributes. | |
567 */ | |
568 function template_preprocess_datetime_wrapper(&$variables) { | |
569 $element = $variables['element']; | |
570 | |
571 if (!empty($element['#title'])) { | |
572 $variables['title'] = $element['#title']; | |
573 } | |
574 | |
575 // Suppress error messages. | |
576 $variables['errors'] = NULL; | |
577 | |
578 $variables['description'] = NULL; | |
579 if (!empty($element['#description'])) { | |
580 $description_attributes = []; | |
581 if (!empty($element['#id'])) { | |
582 $description_attributes['id'] = $element['#id'] . '--description'; | |
583 } | |
584 $variables['description'] = $element['#description']; | |
585 $variables['description_attributes'] = new Attribute($description_attributes); | |
586 } | |
587 | |
588 $variables['required'] = FALSE; | |
589 // For required datetime fields 'form-required' & 'js-form-required' classes | |
590 // are appended to the label attributes. | |
591 if (!empty($element['#required'])) { | |
592 $variables['required'] = TRUE; | |
593 } | |
594 $variables['content'] = $element['#children']; | |
595 } | |
596 | |
597 /** | |
598 * Prepares variables for links templates. | |
599 * | |
600 * Default template: links.html.twig. | |
601 * | |
602 * Unfortunately links templates duplicate the "active" class handling of l() | |
603 * and LinkGenerator::generate() because it needs to be able to set the "active" | |
604 * class not on the links themselves (<a> tags), but on the list items (<li> | |
605 * tags) that contain the links. This is necessary for CSS to be able to style | |
606 * list items differently when the link is active, since CSS does not yet allow | |
607 * one to style list items only if it contains a certain element with a certain | |
608 * class. I.e. we cannot yet convert this jQuery selector to a CSS selector: | |
609 * jQuery('li:has("a.is-active")') | |
610 * | |
611 * @param array $variables | |
612 * An associative array containing: | |
613 * - links: An array of links to be themed. Each link should be itself an | |
614 * array, with the following elements: | |
615 * - title: The link text. | |
616 * - url: (optional) The \Drupal\Core\Url object to link to. If omitted, no | |
617 * anchor tag is printed out. | |
618 * - attributes: (optional) Attributes for the anchor, or for the <span> | |
619 * tag used in its place if no 'href' is supplied. If element 'class' is | |
620 * included, it must be an array of one or more class names. | |
621 * If the 'href' element is supplied, the entire link array is passed to | |
622 * l() as its $options parameter. | |
623 * - attributes: A keyed array of attributes for the <ul> containing the list | |
624 * of links. | |
625 * - set_active_class: (optional) Whether each link should compare the | |
626 * route_name + route_parameters or href (path), language and query options | |
627 * to the current URL, to determine whether the link is "active". If so, an | |
628 * "active" class will be applied to the list item containing the link, as | |
629 * well as the link itself. It is important to use this sparingly since it | |
630 * is usually unnecessary and requires extra processing. | |
631 * For anonymous users, the "active" class will be calculated on the server, | |
632 * because most sites serve each anonymous user the same cached page anyway. | |
633 * For authenticated users, the "active" class will be calculated on the | |
634 * client (through JavaScript), only data- attributes are added to list | |
635 * items and contained links, to prevent breaking the render cache. The | |
636 * JavaScript is added in system_page_attachments(). | |
637 * - heading: (optional) A heading to precede the links. May be an | |
638 * associative array or a string. If it's an array, it can have the | |
639 * following elements: | |
640 * - text: The heading text. | |
641 * - level: The heading level (e.g. 'h2', 'h3'). | |
642 * - attributes: (optional) An array of the CSS attributes for the heading. | |
643 * When using a string it will be used as the text of the heading and the | |
644 * level will default to 'h2'. Headings should be used on navigation menus | |
645 * and any list of links that consistently appears on multiple pages. To | |
646 * make the heading invisible use the 'visually-hidden' CSS class. Do not | |
647 * use 'display:none', which removes it from screen readers and assistive | |
648 * technology. Headings allow screen reader and keyboard only users to | |
649 * navigate to or skip the links. See | |
650 * http://juicystudio.com/article/screen-readers-display-none.php and | |
651 * http://www.w3.org/TR/WCAG-TECHS/H42.html for more information. | |
652 * | |
653 * @see \Drupal\Core\Utility\LinkGenerator | |
654 * @see \Drupal\Core\Utility\LinkGenerator::generate() | |
655 * @see system_page_attachments() | |
656 */ | |
657 function template_preprocess_links(&$variables) { | |
658 $links = $variables['links']; | |
659 $heading = &$variables['heading']; | |
660 | |
661 if (!empty($links)) { | |
662 // Prepend the heading to the list, if any. | |
663 if (!empty($heading)) { | |
664 // Convert a string heading into an array, using a <h2> tag by default. | |
665 if (is_string($heading)) { | |
666 $heading = ['text' => $heading]; | |
667 } | |
668 // Merge in default array properties into $heading. | |
669 $heading += [ | |
670 'level' => 'h2', | |
671 'attributes' => [], | |
672 ]; | |
673 // Convert the attributes array into an Attribute object. | |
674 $heading['attributes'] = new Attribute($heading['attributes']); | |
675 } | |
676 | |
677 $variables['links'] = []; | |
678 foreach ($links as $key => $link) { | |
679 $item = []; | |
680 $link += [ | |
681 'ajax' => NULL, | |
682 'url' => NULL, | |
683 ]; | |
684 | |
685 $li_attributes = []; | |
686 $keys = ['title', 'url']; | |
687 $link_element = [ | |
688 '#type' => 'link', | |
689 '#title' => $link['title'], | |
690 '#options' => array_diff_key($link, array_combine($keys, $keys)), | |
691 '#url' => $link['url'], | |
692 '#ajax' => $link['ajax'], | |
693 ]; | |
694 | |
695 // Handle links and ensure that the active class is added on the LIs, but | |
696 // only if the 'set_active_class' option is not empty. | |
697 if (isset($link['url'])) { | |
698 if (!empty($variables['set_active_class'])) { | |
699 | |
700 // Also enable set_active_class for the contained link. | |
701 $link_element['#options']['set_active_class'] = TRUE; | |
702 | |
703 if (!empty($link['language'])) { | |
704 $li_attributes['hreflang'] = $link['language']->getId(); | |
705 } | |
706 | |
707 // Add a "data-drupal-link-query" attribute to let the | |
708 // drupal.active-link library know the query in a standardized manner. | |
709 if (!empty($link['query'])) { | |
710 $query = $link['query']; | |
711 ksort($query); | |
712 $li_attributes['data-drupal-link-query'] = Json::encode($query); | |
713 } | |
714 | |
715 /** @var \Drupal\Core\Url $url */ | |
716 $url = $link['url']; | |
717 if ($url->isRouted()) { | |
718 // Add a "data-drupal-link-system-path" attribute to let the | |
719 // drupal.active-link library know the path in a standardized manner. | |
720 $system_path = $url->getInternalPath(); | |
721 // @todo System path is deprecated - use the route name and parameters. | |
722 // Special case for the front page. | |
723 $li_attributes['data-drupal-link-system-path'] = $system_path == '' ? '<front>' : $system_path; | |
724 } | |
725 } | |
726 | |
727 $item['link'] = $link_element; | |
728 } | |
729 | |
730 // Handle title-only text items. | |
731 $item['text'] = $link['title']; | |
732 if (isset($link['attributes'])) { | |
733 $item['text_attributes'] = new Attribute($link['attributes']); | |
734 } | |
735 | |
736 // Handle list item attributes. | |
737 $item['attributes'] = new Attribute($li_attributes); | |
738 | |
739 // Add the item to the list of links. | |
740 $variables['links'][$key] = $item; | |
741 } | |
742 } | |
743 } | |
744 | |
745 /** | |
746 * Prepares variables for image templates. | |
747 * | |
748 * Default template: image.html.twig. | |
749 * | |
750 * @param array $variables | |
751 * An associative array containing: | |
752 * - uri: Either the path of the image file (relative to base_path()) or a | |
753 * full URL. | |
754 * - width: The width of the image (if known). | |
755 * - height: The height of the image (if known). | |
756 * - alt: The alternative text for text-based browsers. HTML 4 and XHTML 1.0 | |
757 * always require an alt attribute. The HTML 5 draft allows the alt | |
758 * attribute to be omitted in some cases. Therefore, this variable defaults | |
759 * to an empty string, but can be set to NULL for the attribute to be | |
760 * omitted. Usually, neither omission nor an empty string satisfies | |
761 * accessibility requirements, so it is strongly encouraged for code | |
762 * building variables for image.html.twig templates to pass a meaningful | |
763 * value for this variable. | |
764 * - http://www.w3.org/TR/REC-html40/struct/objects.html#h-13.8 | |
765 * - http://www.w3.org/TR/xhtml1/dtds.html | |
766 * - http://dev.w3.org/html5/spec/Overview.html#alt | |
767 * - title: The title text is displayed when the image is hovered in some | |
768 * popular browsers. | |
769 * - attributes: Associative array of attributes to be placed in the img tag. | |
770 * - srcset: Array of multiple URIs and sizes/multipliers. | |
771 * - sizes: The sizes attribute for viewport-based selection of images. | |
772 * - http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-content.html#introduction-3:viewport-based-selection-2 | |
773 */ | |
774 function template_preprocess_image(&$variables) { | |
775 if (!empty($variables['uri'])) { | |
776 $variables['attributes']['src'] = file_url_transform_relative(file_create_url($variables['uri'])); | |
777 } | |
778 // Generate a srcset attribute conforming to the spec at | |
779 // http://www.w3.org/html/wg/drafts/html/master/embedded-content.html#attr-img-srcset | |
780 if (!empty($variables['srcset'])) { | |
781 $srcset = []; | |
782 foreach ($variables['srcset'] as $src) { | |
783 // URI is mandatory. | |
784 $source = file_url_transform_relative(file_create_url($src['uri'])); | |
785 if (isset($src['width']) && !empty($src['width'])) { | |
786 $source .= ' ' . $src['width']; | |
787 } | |
788 elseif (isset($src['multiplier']) && !empty($src['multiplier'])) { | |
789 $source .= ' ' . $src['multiplier']; | |
790 } | |
791 $srcset[] = $source; | |
792 } | |
793 $variables['attributes']['srcset'] = implode(', ', $srcset); | |
794 } | |
795 | |
796 foreach (['width', 'height', 'alt', 'title', 'sizes'] as $key) { | |
797 if (isset($variables[$key])) { | |
798 // If the property has already been defined in the attributes, | |
799 // do not override, including NULL. | |
800 if (array_key_exists($key, $variables['attributes'])) { | |
801 continue; | |
802 } | |
803 $variables['attributes'][$key] = $variables[$key]; | |
804 } | |
805 } | |
806 } | |
807 | |
808 /** | |
809 * Prepares variables for table templates. | |
810 * | |
811 * Default template: table.html.twig. | |
812 * | |
813 * @param array $variables | |
814 * An associative array containing: | |
815 * - header: An array containing the table headers. Each element of the array | |
816 * can be either a localized string or an associative array with the | |
817 * following keys: | |
818 * - data: The localized title of the table column, as a string or render | |
819 * array. | |
820 * - field: The database field represented in the table column (required | |
821 * if user is to be able to sort on this column). | |
822 * - sort: A default sort order for this column ("asc" or "desc"). Only | |
823 * one column should be given a default sort order because table sorting | |
824 * only applies to one column at a time. | |
825 * - class: An array of values for the 'class' attribute. In particular, | |
826 * the least important columns that can be hidden on narrow and medium | |
827 * width screens should have a 'priority-low' class, referenced with the | |
828 * RESPONSIVE_PRIORITY_LOW constant. Columns that should be shown on | |
829 * medium+ wide screens should be marked up with a class of | |
830 * 'priority-medium', referenced by with the RESPONSIVE_PRIORITY_MEDIUM | |
831 * constant. Themes may hide columns with one of these two classes on | |
832 * narrow viewports to save horizontal space. | |
833 * - Any HTML attributes, such as "colspan", to apply to the column header | |
834 * cell. | |
835 * - rows: An array of table rows. Every row is an array of cells, or an | |
836 * associative array with the following keys: | |
837 * - data: An array of cells. | |
838 * - Any HTML attributes, such as "class", to apply to the table row. | |
839 * - no_striping: A Boolean indicating that the row should receive no | |
840 * 'even / odd' styling. Defaults to FALSE. | |
841 * Each cell can be either a string or an associative array with the | |
842 * following keys: | |
843 * - data: The string or render array to display in the table cell. | |
844 * - header: Indicates this cell is a header. | |
845 * - Any HTML attributes, such as "colspan", to apply to the table cell. | |
846 * Here's an example for $rows: | |
847 * @code | |
848 * $rows = array( | |
849 * // Simple row | |
850 * array( | |
851 * 'Cell 1', 'Cell 2', 'Cell 3' | |
852 * ), | |
853 * // Row with attributes on the row and some of its cells. | |
854 * array( | |
855 * 'data' => array('Cell 1', array('data' => 'Cell 2', 'colspan' => 2)), 'class' => array('funky') | |
856 * ), | |
857 * ); | |
858 * @endcode | |
859 * - footer: An array of table rows which will be printed within a <tfoot> | |
860 * tag, in the same format as the rows element (see above). | |
861 * - attributes: An array of HTML attributes to apply to the table tag. | |
862 * - caption: A localized string to use for the <caption> tag. | |
863 * - colgroups: An array of column groups. Each element of the array can be | |
864 * either: | |
865 * - An array of columns, each of which is an associative array of HTML | |
866 * attributes applied to the <col> element. | |
867 * - An array of attributes applied to the <colgroup> element, which must | |
868 * include a "data" attribute. To add attributes to <col> elements, | |
869 * set the "data" attribute with an array of columns, each of which is an | |
870 * associative array of HTML attributes. | |
871 * Here's an example for $colgroup: | |
872 * @code | |
873 * $colgroup = array( | |
874 * // <colgroup> with one <col> element. | |
875 * array( | |
876 * array( | |
877 * 'class' => array('funky'), // Attribute for the <col> element. | |
878 * ), | |
879 * ), | |
880 * // <colgroup> with attributes and inner <col> elements. | |
881 * array( | |
882 * 'data' => array( | |
883 * array( | |
884 * 'class' => array('funky'), // Attribute for the <col> element. | |
885 * ), | |
886 * ), | |
887 * 'class' => array('jazzy'), // Attribute for the <colgroup> element. | |
888 * ), | |
889 * ); | |
890 * @endcode | |
891 * These optional tags are used to group and set properties on columns | |
892 * within a table. For example, one may easily group three columns and | |
893 * apply same background style to all. | |
894 * - sticky: Use a "sticky" table header. | |
895 * - empty: The message to display in an extra row if table does not have any | |
896 * rows. | |
897 */ | |
898 function template_preprocess_table(&$variables) { | |
899 // Format the table columns: | |
900 if (!empty($variables['colgroups'])) { | |
901 foreach ($variables['colgroups'] as &$colgroup) { | |
902 // Check if we're dealing with a simple or complex column | |
903 if (isset($colgroup['data'])) { | |
904 $cols = $colgroup['data']; | |
905 unset($colgroup['data']); | |
906 $colgroup_attributes = $colgroup; | |
907 } | |
908 else { | |
909 $cols = $colgroup; | |
910 $colgroup_attributes = []; | |
911 } | |
912 $colgroup = []; | |
913 $colgroup['attributes'] = new Attribute($colgroup_attributes); | |
914 $colgroup['cols'] = []; | |
915 | |
916 // Build columns. | |
917 if (is_array($cols) && !empty($cols)) { | |
918 foreach ($cols as $col_key => $col) { | |
919 $colgroup['cols'][$col_key]['attributes'] = new Attribute($col); | |
920 } | |
921 } | |
922 } | |
923 } | |
924 | |
925 // Build an associative array of responsive classes keyed by column. | |
926 $responsive_classes = []; | |
927 | |
928 // Format the table header: | |
929 $ts = []; | |
930 $header_columns = 0; | |
931 if (!empty($variables['header'])) { | |
932 $ts = tablesort_init($variables['header']); | |
933 | |
934 // Use a separate index with responsive classes as headers | |
935 // may be associative. | |
936 $responsive_index = -1; | |
937 foreach ($variables['header'] as $col_key => $cell) { | |
938 // Increase the responsive index. | |
939 $responsive_index++; | |
940 | |
941 if (!is_array($cell)) { | |
942 $header_columns++; | |
943 $cell_content = $cell; | |
944 $cell_attributes = new Attribute(); | |
945 $is_header = TRUE; | |
946 } | |
947 else { | |
948 if (isset($cell['colspan'])) { | |
949 $header_columns += $cell['colspan']; | |
950 } | |
951 else { | |
952 $header_columns++; | |
953 } | |
954 $cell_content = ''; | |
955 if (isset($cell['data'])) { | |
956 $cell_content = $cell['data']; | |
957 unset($cell['data']); | |
958 } | |
959 // Flag the cell as a header or not and remove the flag. | |
960 $is_header = isset($cell['header']) ? $cell['header'] : TRUE; | |
961 unset($cell['header']); | |
962 | |
963 // Track responsive classes for each column as needed. Only the header | |
964 // cells for a column are marked up with the responsive classes by a | |
965 // module developer or themer. The responsive classes on the header cells | |
966 // must be transferred to the content cells. | |
967 if (!empty($cell['class']) && is_array($cell['class'])) { | |
968 if (in_array(RESPONSIVE_PRIORITY_MEDIUM, $cell['class'])) { | |
969 $responsive_classes[$responsive_index] = RESPONSIVE_PRIORITY_MEDIUM; | |
970 } | |
971 elseif (in_array(RESPONSIVE_PRIORITY_LOW, $cell['class'])) { | |
972 $responsive_classes[$responsive_index] = RESPONSIVE_PRIORITY_LOW; | |
973 } | |
974 } | |
975 | |
976 tablesort_header($cell_content, $cell, $variables['header'], $ts); | |
977 | |
978 // tablesort_header() removes the 'sort' and 'field' keys. | |
979 $cell_attributes = new Attribute($cell); | |
980 } | |
981 $variables['header'][$col_key] = []; | |
982 $variables['header'][$col_key]['tag'] = $is_header ? 'th' : 'td'; | |
983 $variables['header'][$col_key]['attributes'] = $cell_attributes; | |
984 $variables['header'][$col_key]['content'] = $cell_content; | |
985 } | |
986 } | |
987 $variables['header_columns'] = $header_columns; | |
988 | |
989 // Rows and footer have the same structure. | |
990 $sections = ['rows' , 'footer']; | |
991 foreach ($sections as $section) { | |
992 if (!empty($variables[$section])) { | |
993 foreach ($variables[$section] as $row_key => $row) { | |
994 $cells = $row; | |
995 $row_attributes = []; | |
996 | |
997 // Check if we're dealing with a simple or complex row | |
998 if (isset($row['data'])) { | |
999 $cells = $row['data']; | |
1000 $variables['no_striping'] = isset($row['no_striping']) ? $row['no_striping'] : FALSE; | |
1001 | |
1002 // Set the attributes array and exclude 'data' and 'no_striping'. | |
1003 $row_attributes = $row; | |
1004 unset($row_attributes['data']); | |
1005 unset($row_attributes['no_striping']); | |
1006 } | |
1007 | |
1008 // Build row. | |
1009 $variables[$section][$row_key] = []; | |
1010 $variables[$section][$row_key]['attributes'] = new Attribute($row_attributes); | |
1011 $variables[$section][$row_key]['cells'] = []; | |
1012 if (!empty($cells)) { | |
1013 // Reset the responsive index. | |
1014 $responsive_index = -1; | |
1015 foreach ($cells as $col_key => $cell) { | |
1016 // Increase the responsive index. | |
1017 $responsive_index++; | |
1018 | |
1019 if (!is_array($cell)) { | |
1020 $cell_content = $cell; | |
1021 $cell_attributes = []; | |
1022 $is_header = FALSE; | |
1023 } | |
1024 else { | |
1025 $cell_content = ''; | |
1026 if (isset($cell['data'])) { | |
1027 $cell_content = $cell['data']; | |
1028 unset($cell['data']); | |
1029 } | |
1030 | |
1031 // Flag the cell as a header or not and remove the flag. | |
1032 $is_header = !empty($cell['header']); | |
1033 unset($cell['header']); | |
1034 | |
1035 $cell_attributes = $cell; | |
1036 } | |
1037 // Active table sort information. | |
1038 if (isset($variables['header'][$col_key]['data']) && $variables['header'][$col_key]['data'] == $ts['name'] && !empty($variables['header'][$col_key]['field'])) { | |
1039 $variables[$section][$row_key]['cells'][$col_key]['active_table_sort'] = TRUE; | |
1040 } | |
1041 // Copy RESPONSIVE_PRIORITY_LOW/RESPONSIVE_PRIORITY_MEDIUM | |
1042 // class from header to cell as needed. | |
1043 if (isset($responsive_classes[$responsive_index])) { | |
1044 $cell_attributes['class'][] = $responsive_classes[$responsive_index]; | |
1045 } | |
1046 $variables[$section][$row_key]['cells'][$col_key]['tag'] = $is_header ? 'th' : 'td'; | |
1047 $variables[$section][$row_key]['cells'][$col_key]['attributes'] = new Attribute($cell_attributes); | |
1048 $variables[$section][$row_key]['cells'][$col_key]['content'] = $cell_content; | |
1049 } | |
1050 } | |
1051 } | |
1052 } | |
1053 } | |
1054 if (empty($variables['no_striping'])) { | |
1055 $variables['attributes']['data-striping'] = 1; | |
1056 } | |
1057 } | |
1058 | |
1059 /** | |
1060 * Prepares variables for item list templates. | |
1061 * | |
1062 * Default template: item-list.html.twig. | |
1063 * | |
1064 * @param array $variables | |
1065 * An associative array containing: | |
1066 * - items: An array of items to be displayed in the list. Each item can be | |
1067 * either a string or a render array. If #type, #theme, or #markup | |
1068 * properties are not specified for child render arrays, they will be | |
1069 * inherited from the parent list, allowing callers to specify larger | |
1070 * nested lists without having to explicitly specify and repeat the | |
1071 * render properties for all nested child lists. | |
1072 * - title: A title to be prepended to the list. | |
1073 * - list_type: The type of list to return (e.g. "ul", "ol"). | |
1074 * - wrapper_attributes: HTML attributes to be applied to the list wrapper. | |
1075 * | |
1076 * @see https://www.drupal.org/node/1842756 | |
1077 */ | |
1078 function template_preprocess_item_list(&$variables) { | |
1079 $variables['wrapper_attributes'] = new Attribute($variables['wrapper_attributes']); | |
1080 foreach ($variables['items'] as &$item) { | |
1081 $attributes = []; | |
1082 // If the item value is an array, then it is a render array. | |
1083 if (is_array($item)) { | |
1084 // List items support attributes via the '#wrapper_attributes' property. | |
1085 if (isset($item['#wrapper_attributes'])) { | |
1086 $attributes = $item['#wrapper_attributes']; | |
1087 } | |
1088 // Determine whether there are any child elements in the item that are not | |
1089 // fully-specified render arrays. If there are any, then the child | |
1090 // elements present nested lists and we automatically inherit the render | |
1091 // array properties of the current list to them. | |
1092 foreach (Element::children($item) as $key) { | |
1093 $child = &$item[$key]; | |
1094 // If this child element does not specify how it can be rendered, then | |
1095 // we need to inherit the render properties of the current list. | |
1096 if (!isset($child['#type']) && !isset($child['#theme']) && !isset($child['#markup'])) { | |
1097 // Since item-list.html.twig supports both strings and render arrays | |
1098 // as items, the items of the nested list may have been specified as | |
1099 // the child elements of the nested list, instead of #items. For | |
1100 // convenience, we automatically move them into #items. | |
1101 if (!isset($child['#items'])) { | |
1102 // This is the same condition as in | |
1103 // \Drupal\Core\Render\Element::children(), which cannot be used | |
1104 // here, since it triggers an error on string values. | |
1105 foreach ($child as $child_key => $child_value) { | |
1106 if ($child_key[0] !== '#') { | |
1107 $child['#items'][$child_key] = $child_value; | |
1108 unset($child[$child_key]); | |
1109 } | |
1110 } | |
1111 } | |
1112 // Lastly, inherit the original theme variables of the current list. | |
1113 $child['#theme'] = $variables['theme_hook_original']; | |
1114 $child['#list_type'] = $variables['list_type']; | |
1115 } | |
1116 } | |
1117 } | |
1118 | |
1119 // Set the item's value and attributes for the template. | |
1120 $item = [ | |
1121 'value' => $item, | |
1122 'attributes' => new Attribute($attributes), | |
1123 ]; | |
1124 } | |
1125 } | |
1126 | |
1127 /** | |
1128 * Prepares variables for container templates. | |
1129 * | |
1130 * Default template: container.html.twig. | |
1131 * | |
1132 * @param array $variables | |
1133 * An associative array containing: | |
1134 * - element: An associative array containing the properties of the element. | |
1135 * Properties used: #id, #attributes, #children. | |
1136 */ | |
1137 function template_preprocess_container(&$variables) { | |
1138 $variables['has_parent'] = FALSE; | |
1139 $element = $variables['element']; | |
1140 // Ensure #attributes is set. | |
1141 $element += ['#attributes' => []]; | |
1142 | |
1143 // Special handling for form elements. | |
1144 if (isset($element['#array_parents'])) { | |
1145 // Assign an html ID. | |
1146 if (!isset($element['#attributes']['id'])) { | |
1147 $element['#attributes']['id'] = $element['#id']; | |
1148 } | |
1149 $variables['has_parent'] = TRUE; | |
1150 } | |
1151 | |
1152 $variables['children'] = $element['#children']; | |
1153 $variables['attributes'] = $element['#attributes']; | |
1154 } | |
1155 | |
1156 /** | |
1157 * Prepares variables for maintenance task list templates. | |
1158 * | |
1159 * Default template: maintenance-task-list.html.twig. | |
1160 * | |
1161 * @param array $variables | |
1162 * An associative array containing: | |
1163 * - items: An associative array of maintenance tasks. | |
1164 * It's the caller's responsibility to ensure this array's items contain no | |
1165 * dangerous HTML such as <script> tags. | |
1166 * - active: The key for the currently active maintenance task. | |
1167 */ | |
1168 function template_preprocess_maintenance_task_list(&$variables) { | |
1169 $items = $variables['items']; | |
1170 $active = $variables['active']; | |
1171 | |
1172 $done = isset($items[$active]) || $active == NULL; | |
1173 foreach ($items as $k => $item) { | |
1174 $variables['tasks'][$k]['item'] = $item; | |
1175 $variables['tasks'][$k]['attributes'] = new Attribute(); | |
1176 if ($active == $k) { | |
1177 $variables['tasks'][$k]['attributes']->addClass('is-active'); | |
1178 $variables['tasks'][$k]['status'] = t('active'); | |
1179 $done = FALSE; | |
1180 } | |
1181 else { | |
1182 if ($done) { | |
1183 $variables['tasks'][$k]['attributes']->addClass('done'); | |
1184 $variables['tasks'][$k]['status'] = t('done'); | |
1185 } | |
1186 } | |
1187 } | |
1188 } | |
1189 | |
1190 /** | |
1191 * Adds a default set of helper variables for preprocessors and templates. | |
1192 * | |
1193 * This function is called for theme hooks implemented as templates only, not | |
1194 * for theme hooks implemented as functions. This preprocess function is the | |
1195 * first in the sequence of preprocessing functions that are called when | |
1196 * preparing variables for a template. | |
1197 * | |
1198 * See the @link themeable Default theme implementations topic @endlink for | |
1199 * details. | |
1200 */ | |
1201 function template_preprocess(&$variables, $hook, $info) { | |
1202 // Merge in variables that don't depend on hook and don't change during a | |
1203 // single page request. | |
1204 // Use the advanced drupal_static() pattern, since this is called very often. | |
1205 static $drupal_static_fast; | |
1206 if (!isset($drupal_static_fast)) { | |
1207 $drupal_static_fast['default_variables'] = &drupal_static(__FUNCTION__); | |
1208 } | |
1209 $default_variables = &$drupal_static_fast['default_variables']; | |
1210 if (!isset($default_variables)) { | |
1211 $default_variables = _template_preprocess_default_variables(); | |
1212 } | |
1213 $variables += $default_variables; | |
1214 | |
1215 // When theming a render element, merge its #attributes into | |
1216 // $variables['attributes']. | |
1217 if (isset($info['render element'])) { | |
1218 $key = $info['render element']; | |
1219 if (isset($variables[$key]['#attributes'])) { | |
1220 $variables['attributes'] = NestedArray::mergeDeep($variables['attributes'], $variables[$key]['#attributes']); | |
1221 } | |
1222 } | |
1223 } | |
1224 | |
1225 /** | |
1226 * Returns hook-independent variables to template_preprocess(). | |
1227 */ | |
1228 function _template_preprocess_default_variables() { | |
1229 // Variables that don't depend on a database connection. | |
1230 $variables = [ | |
1231 'attributes' => [], | |
1232 'title_attributes' => [], | |
1233 'content_attributes' => [], | |
1234 'title_prefix' => [], | |
1235 'title_suffix' => [], | |
1236 'db_is_active' => !defined('MAINTENANCE_MODE'), | |
1237 'is_admin' => FALSE, | |
1238 'logged_in' => FALSE, | |
1239 ]; | |
1240 | |
1241 // Give modules a chance to alter the default template variables. | |
1242 \Drupal::moduleHandler()->alter('template_preprocess_default_variables', $variables); | |
1243 | |
1244 // Tell all templates where they are located. | |
1245 $variables['directory'] = \Drupal::theme()->getActiveTheme()->getPath(); | |
1246 | |
1247 return $variables; | |
1248 } | |
1249 | |
1250 /** | |
1251 * Prepares variables for HTML document templates. | |
1252 * | |
1253 * Default template: html.html.twig. | |
1254 * | |
1255 * @param array $variables | |
1256 * An associative array containing: | |
1257 * - page: A render element representing the page. | |
1258 */ | |
1259 function template_preprocess_html(&$variables) { | |
1260 $variables['page'] = $variables['html']['page']; | |
1261 unset($variables['html']['page']); | |
1262 $variables['page_top'] = NULL; | |
1263 if (isset($variables['html']['page_top'])) { | |
1264 $variables['page_top'] = $variables['html']['page_top']; | |
1265 unset($variables['html']['page_top']); | |
1266 } | |
1267 $variables['page_bottom'] = NULL; | |
1268 if (isset($variables['html']['page_bottom'])) { | |
1269 $variables['page_bottom'] = $variables['html']['page_bottom']; | |
1270 unset($variables['html']['page_bottom']); | |
1271 } | |
1272 | |
1273 $variables['html_attributes'] = new Attribute(); | |
1274 | |
1275 // <html> element attributes. | |
1276 $language_interface = \Drupal::languageManager()->getCurrentLanguage(); | |
1277 $variables['html_attributes']['lang'] = $language_interface->getId(); | |
1278 $variables['html_attributes']['dir'] = $language_interface->getDirection(); | |
1279 | |
1280 if (isset($variables['db_is_active']) && !$variables['db_is_active']) { | |
1281 $variables['db_offline'] = TRUE; | |
1282 } | |
1283 | |
1284 // Add a variable for the root path. This can be used to create a class and | |
1285 // theme the page depending on the current path (e.g. node, admin, user) as | |
1286 // well as more specific data like path-frontpage. | |
1287 $is_front_page = \Drupal::service('path.matcher')->isFrontPage(); | |
1288 | |
1289 if ($is_front_page) { | |
1290 $variables['root_path'] = FALSE; | |
1291 } | |
1292 else { | |
1293 $system_path = \Drupal::service('path.current')->getPath(); | |
1294 $variables['root_path'] = explode('/', $system_path)[1]; | |
1295 } | |
1296 | |
1297 $site_config = \Drupal::config('system.site'); | |
1298 // Construct page title. | |
1299 if (isset($variables['page']['#title']) && is_array($variables['page']['#title'])) { | |
1300 // Do an early render if the title is a render array. | |
1301 $variables['page']['#title'] = (string) \Drupal::service('renderer')->render($variables['page']['#title']); | |
1302 } | |
1303 if (!empty($variables['page']['#title'])) { | |
1304 $head_title = [ | |
1305 // Marking the title as safe since it has had the tags stripped. | |
1306 'title' => Markup::create(trim(strip_tags($variables['page']['#title']))), | |
1307 'name' => $site_config->get('name'), | |
1308 ]; | |
1309 } | |
1310 // @todo Remove once views is not bypassing the view subscriber anymore. | |
1311 // @see https://www.drupal.org/node/2068471 | |
1312 elseif ($is_front_page) { | |
1313 $head_title = [ | |
1314 'title' => t('Home'), | |
1315 'name' => $site_config->get('name'), | |
1316 ]; | |
1317 } | |
1318 else { | |
1319 $head_title = ['name' => $site_config->get('name')]; | |
1320 if ($site_config->get('slogan')) { | |
1321 $head_title['slogan'] = strip_tags($site_config->get('slogan')); | |
1322 } | |
1323 } | |
1324 | |
1325 $variables['head_title'] = $head_title; | |
1326 // @deprecated in Drupal 8.0.0, will be removed before Drupal 9.0.0. | |
1327 $variables['head_title_array'] = $head_title; | |
1328 | |
1329 // Create placeholder strings for these keys. | |
1330 // @see \Drupal\Core\Render\HtmlResponseSubscriber | |
1331 $types = [ | |
1332 'styles' => 'css', | |
1333 'scripts' => 'js', | |
1334 'scripts_bottom' => 'js-bottom', | |
1335 'head' => 'head', | |
1336 ]; | |
1337 $variables['placeholder_token'] = Crypt::randomBytesBase64(55); | |
1338 foreach ($types as $type => $placeholder_name) { | |
1339 $placeholder = '<' . $placeholder_name . '-placeholder token="' . $variables['placeholder_token'] . '">'; | |
1340 $variables['#attached']['html_response_attachment_placeholders'][$type] = $placeholder; | |
1341 } | |
1342 } | |
1343 | |
1344 /** | |
1345 * Prepares variables for the page template. | |
1346 * | |
1347 * Default template: page.html.twig. | |
1348 * | |
1349 * See the page.html.twig template for the list of variables. | |
1350 */ | |
1351 function template_preprocess_page(&$variables) { | |
1352 $language_interface = \Drupal::languageManager()->getCurrentLanguage(); | |
1353 | |
1354 foreach (\Drupal::theme()->getActiveTheme()->getRegions() as $region) { | |
1355 if (!isset($variables['page'][$region])) { | |
1356 $variables['page'][$region] = []; | |
1357 } | |
1358 } | |
1359 | |
1360 $variables['base_path'] = base_path(); | |
1361 $variables['front_page'] = \Drupal::url('<front>'); | |
1362 $variables['language'] = $language_interface; | |
1363 | |
1364 // An exception might be thrown. | |
1365 try { | |
1366 $variables['is_front'] = \Drupal::service('path.matcher')->isFrontPage(); | |
1367 } | |
1368 catch (Exception $e) { | |
1369 // If the database is not yet available, set default values for these | |
1370 // variables. | |
1371 $variables['is_front'] = FALSE; | |
1372 $variables['db_is_active'] = FALSE; | |
1373 } | |
1374 | |
1375 if ($node = \Drupal::routeMatch()->getParameter('node')) { | |
1376 $variables['node'] = $node; | |
1377 } | |
1378 } | |
1379 | |
1380 /** | |
1381 * Generate an array of suggestions from path arguments. | |
1382 * | |
1383 * This is typically called for adding to the suggestions in | |
1384 * hook_theme_suggestions_HOOK_alter() or adding to 'attributes' class key | |
1385 * variables from within preprocess functions, when wanting to base the | |
1386 * additional suggestions or classes on the path of the current page. | |
1387 * | |
1388 * @param $args | |
1389 * An array of path arguments. | |
1390 * @param $base | |
1391 * A string identifying the base 'thing' from which more specific suggestions | |
1392 * are derived. For example, 'page' or 'html'. | |
1393 * @param $delimiter | |
1394 * The string used to delimit increasingly specific information. The default | |
1395 * of '__' is appropriate for theme hook suggestions. '-' is appropriate for | |
1396 * extra classes. | |
1397 * | |
1398 * @return | |
1399 * An array of suggestions, suitable for adding to | |
1400 * hook_theme_suggestions_HOOK_alter() or to $variables['attributes']['class'] | |
1401 * if the suggestions represent extra CSS classes. | |
1402 */ | |
1403 function theme_get_suggestions($args, $base, $delimiter = '__') { | |
1404 | |
1405 // Build a list of suggested theme hooks in order of | |
1406 // specificity. One suggestion is made for every element of the current path, | |
1407 // though numeric elements are not carried to subsequent suggestions. For | |
1408 // example, for $base='page', http://www.example.com/node/1/edit would result | |
1409 // in the following suggestions: | |
1410 // | |
1411 // page__node | |
1412 // page__node__% | |
1413 // page__node__1 | |
1414 // page__node__edit | |
1415 | |
1416 $suggestions = []; | |
1417 $prefix = $base; | |
1418 foreach ($args as $arg) { | |
1419 // Remove slashes or null per SA-CORE-2009-003 and change - (hyphen) to _ | |
1420 // (underscore). | |
1421 // | |
1422 // When we discover templates in @see drupal_find_theme_templates, | |
1423 // hyphens (-) are converted to underscores (_) before the theme hook | |
1424 // is registered. We do this because the hyphens used for delimiters | |
1425 // in hook suggestions cannot be used in the function names of the | |
1426 // associated preprocess functions. Any page templates designed to be used | |
1427 // on paths that contain a hyphen are also registered with these hyphens | |
1428 // converted to underscores so here we must convert any hyphens in path | |
1429 // arguments to underscores here before fetching theme hook suggestions | |
1430 // to ensure the templates are appropriately recognized. | |
1431 $arg = str_replace(["/", "\\", "\0", '-'], ['', '', '', '_'], $arg); | |
1432 // The percent acts as a wildcard for numeric arguments since | |
1433 // asterisks are not valid filename characters on many filesystems. | |
1434 if (is_numeric($arg)) { | |
1435 $suggestions[] = $prefix . $delimiter . '%'; | |
1436 } | |
1437 $suggestions[] = $prefix . $delimiter . $arg; | |
1438 if (!is_numeric($arg)) { | |
1439 $prefix .= $delimiter . $arg; | |
1440 } | |
1441 } | |
1442 if (\Drupal::service('path.matcher')->isFrontPage()) { | |
1443 // Front templates should be based on root only, not prefixed arguments. | |
1444 $suggestions[] = $base . $delimiter . 'front'; | |
1445 } | |
1446 | |
1447 return $suggestions; | |
1448 } | |
1449 | |
1450 /** | |
1451 * Prepares variables for maintenance page templates. | |
1452 * | |
1453 * Default template: maintenance-page.html.twig. | |
1454 * | |
1455 * @param array $variables | |
1456 * An associative array containing: | |
1457 * - content - An array of page content. | |
1458 * | |
1459 * @see system_page_attachments() | |
1460 */ | |
1461 function template_preprocess_maintenance_page(&$variables) { | |
1462 // @todo Rename the templates to page--maintenance + page--install. | |
1463 template_preprocess_page($variables); | |
1464 | |
1465 // @see system_page_attachments() | |
1466 $variables['#attached']['library'][] = 'system/maintenance'; | |
1467 | |
1468 // Maintenance page and install page need branding info in variables because | |
1469 // there is no blocks. | |
1470 $site_config = \Drupal::config('system.site'); | |
1471 $variables['logo'] = theme_get_setting('logo.url'); | |
1472 $variables['site_name'] = $site_config->get('name'); | |
1473 $variables['site_slogan'] = $site_config->get('slogan'); | |
1474 | |
1475 // Maintenance page and install page need page title in variable because there | |
1476 // are no blocks. | |
1477 $variables['title'] = $variables['page']['#title']; | |
1478 } | |
1479 | |
1480 /** | |
1481 * Prepares variables for install page templates. | |
1482 * | |
1483 * Default template: install-page.html.twig. | |
1484 * | |
1485 * @param array $variables | |
1486 * An associative array containing: | |
1487 * - content - An array of page content. | |
1488 * | |
1489 * @see template_preprocess_maintenance_page() | |
1490 */ | |
1491 function template_preprocess_install_page(&$variables) { | |
1492 template_preprocess_maintenance_page($variables); | |
1493 | |
1494 // Override the site name that is displayed on the page, since Drupal is | |
1495 // still in the process of being installed. | |
1496 $distribution_name = drupal_install_profile_distribution_name(); | |
1497 $variables['site_name'] = $distribution_name; | |
1498 $variables['site_version'] = drupal_install_profile_distribution_version(); | |
1499 } | |
1500 | |
1501 /** | |
1502 * Prepares variables for region templates. | |
1503 * | |
1504 * Default template: region.html.twig. | |
1505 * | |
1506 * Prepares the values passed to the theme_region function to be passed into a | |
1507 * pluggable template engine. Uses the region name to generate a template file | |
1508 * suggestions. | |
1509 * | |
1510 * @param array $variables | |
1511 * An associative array containing: | |
1512 * - elements: An associative array containing properties of the region. | |
1513 */ | |
1514 function template_preprocess_region(&$variables) { | |
1515 // Create the $content variable that templates expect. | |
1516 $variables['content'] = $variables['elements']['#children']; | |
1517 $variables['region'] = $variables['elements']['#region']; | |
1518 } | |
1519 | |
1520 /** | |
1521 * Prepares variables for field templates. | |
1522 * | |
1523 * Default template: field.html.twig. | |
1524 * | |
1525 * @param array $variables | |
1526 * An associative array containing: | |
1527 * - element: A render element representing the field. | |
1528 * - attributes: A string containing the attributes for the wrapping div. | |
1529 * - title_attributes: A string containing the attributes for the title. | |
1530 */ | |
1531 function template_preprocess_field(&$variables, $hook) { | |
1532 $element = $variables['element']; | |
1533 | |
1534 // Creating variables for the template. | |
1535 $variables['entity_type'] = $element['#entity_type']; | |
1536 $variables['field_name'] = $element['#field_name']; | |
1537 $variables['field_type'] = $element['#field_type']; | |
1538 $variables['label_display'] = $element['#label_display']; | |
1539 | |
1540 $variables['label_hidden'] = ($element['#label_display'] == 'hidden'); | |
1541 // Always set the field label - allow themes to decide whether to display it. | |
1542 // In addition the label should be rendered but hidden to support screen | |
1543 // readers. | |
1544 $variables['label'] = $element['#title']; | |
1545 | |
1546 $variables['multiple'] = $element['#is_multiple']; | |
1547 | |
1548 static $default_attributes; | |
1549 if (!isset($default_attributes)) { | |
1550 $default_attributes = new Attribute(); | |
1551 } | |
1552 | |
1553 // Merge attributes when a single-value field has a hidden label. | |
1554 if ($element['#label_display'] == 'hidden' && !$variables['multiple'] && !empty($element['#items'][0]->_attributes)) { | |
1555 $variables['attributes'] = NestedArray::mergeDeep($variables['attributes'], (array) $element['#items'][0]->_attributes); | |
1556 } | |
1557 | |
1558 // We want other preprocess functions and the theme implementation to have | |
1559 // fast access to the field item render arrays. The item render array keys | |
1560 // (deltas) should always be numerically indexed starting from 0, and looping | |
1561 // on those keys is faster than calling Element::children() or looping on all | |
1562 // keys within $element, since that requires traversal of all element | |
1563 // properties. | |
1564 $variables['items'] = []; | |
1565 $delta = 0; | |
1566 while (!empty($element[$delta])) { | |
1567 $variables['items'][$delta]['content'] = $element[$delta]; | |
1568 | |
1569 // Modules (e.g., rdf.module) can add field item attributes (to | |
1570 // $item->_attributes) within hook_entity_prepare_view(). Some field | |
1571 // formatters move those attributes into some nested formatter-specific | |
1572 // element in order have them rendered on the desired HTML element (e.g., on | |
1573 // the <a> element of a field item being rendered as a link). Other field | |
1574 // formatters leave them within $element['#items'][$delta]['_attributes'] to | |
1575 // be rendered on the item wrappers provided by field.html.twig. | |
1576 $variables['items'][$delta]['attributes'] = !empty($element['#items'][$delta]->_attributes) ? new Attribute($element['#items'][$delta]->_attributes) : clone($default_attributes); | |
1577 $delta++; | |
1578 } | |
1579 } | |
1580 | |
1581 /** | |
1582 * Prepares variables for individual form element templates. | |
1583 * | |
1584 * Default template: field-multiple-value-form.html.twig. | |
1585 * | |
1586 * Combines multiple values into a table with drag-n-drop reordering. | |
1587 * | |
1588 * @param array $variables | |
1589 * An associative array containing: | |
1590 * - element: A render element representing the form element. | |
1591 */ | |
1592 function template_preprocess_field_multiple_value_form(&$variables) { | |
1593 $element = $variables['element']; | |
1594 $variables['multiple'] = $element['#cardinality_multiple']; | |
1595 | |
1596 if ($variables['multiple']) { | |
1597 $table_id = Html::getUniqueId($element['#field_name'] . '_values'); | |
1598 $order_class = $element['#field_name'] . '-delta-order'; | |
1599 $header_attributes = new Attribute(['class' => ['label']]); | |
1600 if (!empty($element['#required'])) { | |
1601 $header_attributes['class'][] = 'js-form-required'; | |
1602 $header_attributes['class'][] = 'form-required'; | |
1603 } | |
1604 $header = [ | |
1605 [ | |
1606 'data' => [ | |
1607 '#prefix' => '<h4' . $header_attributes . '>', | |
1608 '#markup' => $element['#title'], | |
1609 '#suffix' => '</h4>', | |
1610 ], | |
1611 'colspan' => 2, | |
1612 'class' => ['field-label'], | |
1613 ], | |
1614 t('Order', [], ['context' => 'Sort order']), | |
1615 ]; | |
1616 $rows = []; | |
1617 | |
1618 // Sort items according to '_weight' (needed when the form comes back after | |
1619 // preview or failed validation). | |
1620 $items = []; | |
1621 $variables['button'] = []; | |
1622 foreach (Element::children($element) as $key) { | |
1623 if ($key === 'add_more') { | |
1624 $variables['button'] = &$element[$key]; | |
1625 } | |
1626 else { | |
1627 $items[] = &$element[$key]; | |
1628 } | |
1629 } | |
1630 usort($items, '_field_multiple_value_form_sort_helper'); | |
1631 | |
1632 // Add the items as table rows. | |
1633 foreach ($items as $item) { | |
1634 $item['_weight']['#attributes']['class'] = [$order_class]; | |
1635 | |
1636 // Remove weight form element from item render array so it can be rendered | |
1637 // in a separate table column. | |
1638 $delta_element = $item['_weight']; | |
1639 unset($item['_weight']); | |
1640 | |
1641 $cells = [ | |
1642 ['data' => '', 'class' => ['field-multiple-drag']], | |
1643 ['data' => $item], | |
1644 ['data' => $delta_element, 'class' => ['delta-order']], | |
1645 ]; | |
1646 $rows[] = [ | |
1647 'data' => $cells, | |
1648 'class' => ['draggable'], | |
1649 ]; | |
1650 } | |
1651 | |
1652 $variables['table'] = [ | |
1653 '#type' => 'table', | |
1654 '#header' => $header, | |
1655 '#rows' => $rows, | |
1656 '#attributes' => [ | |
1657 'id' => $table_id, | |
1658 'class' => ['field-multiple-table'], | |
1659 ], | |
1660 '#tabledrag' => [ | |
1661 [ | |
1662 'action' => 'order', | |
1663 'relationship' => 'sibling', | |
1664 'group' => $order_class, | |
1665 ], | |
1666 ], | |
1667 ]; | |
1668 | |
1669 if (!empty($element['#description'])) { | |
1670 $description_id = $element['#attributes']['aria-describedby']; | |
1671 $description_attributes['id'] = $description_id; | |
1672 $variables['description']['attributes'] = new Attribute($description_attributes); | |
1673 $variables['description']['content'] = $element['#description']; | |
1674 | |
1675 // Add the description's id to the table aria attributes. | |
1676 $variables['table']['#attributes']['aria-describedby'] = $element['#attributes']['aria-describedby']; | |
1677 } | |
1678 } | |
1679 else { | |
1680 $variables['elements'] = []; | |
1681 foreach (Element::children($element) as $key) { | |
1682 $variables['elements'][] = $element[$key]; | |
1683 } | |
1684 } | |
1685 } | |
1686 | |
1687 /** | |
1688 * Prepares variables for breadcrumb templates. | |
1689 * | |
1690 * Default template: breadcrumb.html.twig. | |
1691 * | |
1692 * @param array $variables | |
1693 * An associative array containing: | |
1694 * - links: A list of \Drupal\Core\Link objects which should be rendered. | |
1695 */ | |
1696 function template_preprocess_breadcrumb(&$variables) { | |
1697 $variables['breadcrumb'] = []; | |
1698 /** @var \Drupal\Core\Link $link */ | |
1699 foreach ($variables['links'] as $key => $link) { | |
1700 $variables['breadcrumb'][$key] = ['text' => $link->getText(), 'url' => $link->getUrl()->toString()]; | |
1701 } | |
1702 } | |
1703 | |
1704 /** | |
1705 * Callback for usort() within template_preprocess_field_multiple_value_form(). | |
1706 * | |
1707 * Sorts using ['_weight']['#value'] | |
1708 */ | |
1709 function _field_multiple_value_form_sort_helper($a, $b) { | |
1710 $a_weight = (is_array($a) && isset($a['_weight']['#value']) ? $a['_weight']['#value'] : 0); | |
1711 $b_weight = (is_array($b) && isset($b['_weight']['#value']) ? $b['_weight']['#value'] : 0); | |
1712 return $a_weight - $b_weight; | |
1713 } | |
1714 | |
1715 /** | |
1716 * Provides theme registration for themes across .inc files. | |
1717 */ | |
1718 function drupal_common_theme() { | |
1719 return [ | |
1720 // From theme.inc. | |
1721 'html' => [ | |
1722 'render element' => 'html', | |
1723 ], | |
1724 'page' => [ | |
1725 'render element' => 'page', | |
1726 ], | |
1727 'page_title' => [ | |
1728 'variables' => ['title' => NULL], | |
1729 ], | |
1730 'region' => [ | |
1731 'render element' => 'elements', | |
1732 ], | |
1733 'time' => [ | |
1734 'variables' => ['timestamp' => NULL, 'text' => NULL, 'attributes' => []], | |
1735 ], | |
1736 'datetime_form' => [ | |
1737 'render element' => 'element', | |
1738 ], | |
1739 'datetime_wrapper' => [ | |
1740 'render element' => 'element', | |
1741 ], | |
1742 'status_messages' => [ | |
1743 'variables' => ['status_headings' => [], 'message_list' => NULL], | |
1744 ], | |
1745 'links' => [ | |
1746 'variables' => ['links' => [], 'attributes' => ['class' => ['links']], 'heading' => [], 'set_active_class' => FALSE], | |
1747 ], | |
1748 'dropbutton_wrapper' => [ | |
1749 'variables' => ['children' => NULL], | |
1750 ], | |
1751 'image' => [ | |
1752 // HTML 4 and XHTML 1.0 always require an alt attribute. The HTML 5 draft | |
1753 // allows the alt attribute to be omitted in some cases. Therefore, | |
1754 // default the alt attribute to an empty string, but allow code providing | |
1755 // variables to image.html.twig templates to pass explicit NULL for it to | |
1756 // be omitted. Usually, neither omission nor an empty string satisfies | |
1757 // accessibility requirements, so it is strongly encouraged for code | |
1758 // building variables for image.html.twig templates to pass a meaningful | |
1759 // value for the alt variable. | |
1760 // - http://www.w3.org/TR/REC-html40/struct/objects.html#h-13.8 | |
1761 // - http://www.w3.org/TR/xhtml1/dtds.html | |
1762 // - http://dev.w3.org/html5/spec/Overview.html#alt | |
1763 // The title attribute is optional in all cases, so it is omitted by | |
1764 // default. | |
1765 'variables' => ['uri' => NULL, 'width' => NULL, 'height' => NULL, 'alt' => '', 'title' => NULL, 'attributes' => [], 'sizes' => NULL, 'srcset' => [], 'style_name' => NULL], | |
1766 ], | |
1767 'breadcrumb' => [ | |
1768 'variables' => ['links' => []], | |
1769 ], | |
1770 'table' => [ | |
1771 'variables' => ['header' => NULL, 'rows' => NULL, 'footer' => NULL, 'attributes' => [], 'caption' => NULL, 'colgroups' => [], 'sticky' => FALSE, 'responsive' => TRUE, 'empty' => ''], | |
1772 ], | |
1773 'tablesort_indicator' => [ | |
1774 'variables' => ['style' => NULL], | |
1775 ], | |
1776 'mark' => [ | |
1777 'variables' => ['status' => MARK_NEW], | |
1778 ], | |
1779 'item_list' => [ | |
1780 'variables' => ['items' => [], 'title' => '', 'list_type' => 'ul', 'wrapper_attributes' => [], 'attributes' => [], 'empty' => NULL, 'context' => []], | |
1781 ], | |
1782 'feed_icon' => [ | |
1783 'variables' => ['url' => NULL, 'title' => NULL], | |
1784 ], | |
1785 'progress_bar' => [ | |
1786 'variables' => ['label' => NULL, 'percent' => NULL, 'message' => NULL], | |
1787 ], | |
1788 'indentation' => [ | |
1789 'variables' => ['size' => 1], | |
1790 ], | |
1791 // From theme.maintenance.inc. | |
1792 'maintenance_page' => [ | |
1793 'render element' => 'page', | |
1794 ], | |
1795 'install_page' => [ | |
1796 'render element' => 'page', | |
1797 ], | |
1798 'maintenance_task_list' => [ | |
1799 'variables' => ['items' => NULL, 'active' => NULL, 'variant' => NULL], | |
1800 ], | |
1801 'authorize_report' => [ | |
1802 'variables' => ['messages' => [], 'attributes' => []], | |
1803 'includes' => ['core/includes/theme.maintenance.inc'], | |
1804 'template' => 'authorize-report', | |
1805 ], | |
1806 // From pager.inc. | |
1807 'pager' => [ | |
1808 'render element' => 'pager', | |
1809 ], | |
1810 // From menu.inc. | |
1811 'menu' => [ | |
1812 'variables' => ['menu_name' => NULL, 'items' => [], 'attributes' => []], | |
1813 ], | |
1814 'menu_local_task' => [ | |
1815 'render element' => 'element', | |
1816 ], | |
1817 'menu_local_action' => [ | |
1818 'render element' => 'element', | |
1819 ], | |
1820 'menu_local_tasks' => [ | |
1821 'variables' => ['primary' => [], 'secondary' => []], | |
1822 ], | |
1823 // From form.inc. | |
1824 'input' => [ | |
1825 'render element' => 'element', | |
1826 ], | |
1827 'select' => [ | |
1828 'render element' => 'element', | |
1829 ], | |
1830 'fieldset' => [ | |
1831 'render element' => 'element', | |
1832 ], | |
1833 'details' => [ | |
1834 'render element' => 'element', | |
1835 ], | |
1836 'radios' => [ | |
1837 'render element' => 'element', | |
1838 ], | |
1839 'checkboxes' => [ | |
1840 'render element' => 'element', | |
1841 ], | |
1842 'form' => [ | |
1843 'render element' => 'element', | |
1844 ], | |
1845 'textarea' => [ | |
1846 'render element' => 'element', | |
1847 ], | |
1848 'form_element' => [ | |
1849 'render element' => 'element', | |
1850 ], | |
1851 'form_element_label' => [ | |
1852 'render element' => 'element', | |
1853 ], | |
1854 'vertical_tabs' => [ | |
1855 'render element' => 'element', | |
1856 ], | |
1857 'container' => [ | |
1858 'render element' => 'element', | |
1859 ], | |
1860 // From field system. | |
1861 'field' => [ | |
1862 'render element' => 'element', | |
1863 ], | |
1864 'field_multiple_value_form' => [ | |
1865 'render element' => 'element', | |
1866 ], | |
1867 ]; | |
1868 } |