Mercurial > hg > cmmr2012-drupal-site
comparison core/modules/toolbar/toolbar.module @ 0:c75dbcec494b
Initial commit from drush-created site
author | Chris Cannam |
---|---|
date | Thu, 05 Jul 2018 14:24:15 +0000 |
parents | |
children | 12f9dff5fda9 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c75dbcec494b |
---|---|
1 <?php | |
2 | |
3 /** | |
4 * @file | |
5 * Administration toolbar for quick access to top level administration items. | |
6 */ | |
7 | |
8 use Drupal\Core\Cache\CacheableMetadata; | |
9 use Drupal\Core\Menu\MenuTreeParameters; | |
10 use Drupal\Core\Render\Element; | |
11 use Drupal\Core\Routing\RouteMatchInterface; | |
12 use Drupal\Core\Template\Attribute; | |
13 use Drupal\Component\Utility\Crypt; | |
14 use Drupal\Core\Url; | |
15 | |
16 /** | |
17 * Implements hook_help(). | |
18 */ | |
19 function toolbar_help($route_name, RouteMatchInterface $route_match) { | |
20 switch ($route_name) { | |
21 case 'help.page.toolbar': | |
22 $output = '<h3>' . t('About') . '</h3>'; | |
23 $output .= '<p>' . t('The Toolbar module provides a toolbar for site administrators, which displays tabs and trays provided by the Toolbar module itself and other modules. For more information, see the <a href=":toolbar_docs">online documentation for the Toolbar module</a>.', [':toolbar_docs' => 'https://www.drupal.org/documentation/modules/toolbar']) . '</p>'; | |
24 $output .= '<h4>' . t('Terminology') . '</h4>'; | |
25 $output .= '<dl>'; | |
26 $output .= '<dt>' . t('Tabs') . '</dt>'; | |
27 $output .= '<dd>' . t('Tabs are buttons, displayed in a bar across the top of the screen. Some tabs execute an action (such as starting Edit mode), while other tabs toggle which tray is open.') . '</dd>'; | |
28 $output .= '<dt>' . t('Trays') . '</dt>'; | |
29 $output .= '<dd>' . t('Trays are usually lists of links, which can be hierarchical like a menu. If a tray has been toggled open, it is displayed either vertically or horizontally below the tab bar, depending on the browser width. Only one tray may be open at a time. If you click another tab, that tray will replace the tray being displayed. In wide browser widths, the user has the ability to toggle from vertical to horizontal, using a link at the bottom or right of the tray. Hierarchical menus only have open/close behavior in vertical mode; if you display a tray containing a hierarchical menu horizontally, only the top-level links will be available.') . '</dd>'; | |
30 $output .= '</dl>'; | |
31 return $output; | |
32 } | |
33 } | |
34 | |
35 /** | |
36 * Implements hook_theme(). | |
37 */ | |
38 function toolbar_theme($existing, $type, $theme, $path) { | |
39 $items['toolbar'] = [ | |
40 'render element' => 'element', | |
41 ]; | |
42 $items['menu__toolbar'] = [ | |
43 'base hook' => 'menu', | |
44 'variables' => ['items' => [], 'attributes' => []], | |
45 ]; | |
46 | |
47 return $items; | |
48 } | |
49 | |
50 /** | |
51 * Implements hook_page_top(). | |
52 * | |
53 * Add admin toolbar to the top of the page automatically. | |
54 */ | |
55 function toolbar_page_top(array &$page_top) { | |
56 $page_top['toolbar'] = [ | |
57 '#type' => 'toolbar', | |
58 '#access' => \Drupal::currentUser()->hasPermission('access toolbar'), | |
59 '#cache' => [ | |
60 'keys' => ['toolbar'], | |
61 'contexts' => ['user.permissions'], | |
62 ], | |
63 ]; | |
64 } | |
65 | |
66 /** | |
67 * Prepares variables for administration toolbar templates. | |
68 * | |
69 * Default template: toolbar.html.twig. | |
70 * | |
71 * @param array $variables | |
72 * An associative array containing: | |
73 * - element: An associative array containing the properties and children of | |
74 * the tray. Properties used: #children, #attributes and #bar. | |
75 */ | |
76 function template_preprocess_toolbar(&$variables) { | |
77 $element = $variables['element']; | |
78 | |
79 // Prepare the toolbar attributes. | |
80 $variables['attributes'] = $element['#attributes']; | |
81 $variables['toolbar_attributes'] = new Attribute($element['#bar']['#attributes']); | |
82 $variables['toolbar_heading'] = $element['#bar']['#heading']; | |
83 | |
84 // Prepare the trays and tabs for each toolbar item as well as the remainder | |
85 // variable that will hold any non-tray, non-tab elements. | |
86 $variables['trays'] = []; | |
87 $variables['tabs'] = []; | |
88 $variables['remainder'] = []; | |
89 foreach (Element::children($element) as $key) { | |
90 // Early rendering to collect the wrapper attributes from | |
91 // ToolbarItem elements. | |
92 if (!empty($element[$key])) { | |
93 Drupal::service('renderer')->render($element[$key]); | |
94 } | |
95 // Add the tray. | |
96 if (isset($element[$key]['tray'])) { | |
97 $attributes = []; | |
98 if (!empty($element[$key]['tray']['#wrapper_attributes'])) { | |
99 $attributes = $element[$key]['tray']['#wrapper_attributes']; | |
100 } | |
101 $variables['trays'][$key] = [ | |
102 'links' => $element[$key]['tray'], | |
103 'attributes' => new Attribute($attributes), | |
104 ]; | |
105 if (array_key_exists('#heading', $element[$key]['tray'])) { | |
106 $variables['trays'][$key]['label'] = $element[$key]['tray']['#heading']; | |
107 } | |
108 } | |
109 | |
110 // Add the tab. | |
111 if (isset($element[$key]['tab'])) { | |
112 $attributes = []; | |
113 // Pass the wrapper attributes along. | |
114 if (!empty($element[$key]['#wrapper_attributes'])) { | |
115 $attributes = $element[$key]['#wrapper_attributes']; | |
116 } | |
117 | |
118 $variables['tabs'][$key] = [ | |
119 'link' => $element[$key]['tab'], | |
120 'attributes' => new Attribute($attributes), | |
121 ]; | |
122 } | |
123 | |
124 // Add other non-tray, non-tab child elements to the remainder variable for | |
125 // later rendering. | |
126 foreach (Element::children($element[$key]) as $child_key) { | |
127 if (!in_array($child_key, ['tray', 'tab'])) { | |
128 $variables['remainder'][$key][$child_key] = $element[$key][$child_key]; | |
129 } | |
130 } | |
131 } | |
132 } | |
133 | |
134 /** | |
135 * Implements hook_toolbar(). | |
136 */ | |
137 function toolbar_toolbar() { | |
138 // The 'Home' tab is a simple link, with no corresponding tray. | |
139 $items['home'] = [ | |
140 '#type' => 'toolbar_item', | |
141 'tab' => [ | |
142 '#type' => 'link', | |
143 '#title' => t('Back to site'), | |
144 '#url' => Url::fromRoute('<front>'), | |
145 '#attributes' => [ | |
146 'title' => t('Return to site content'), | |
147 'class' => ['toolbar-icon', 'toolbar-icon-escape-admin'], | |
148 'data-toolbar-escape-admin' => TRUE, | |
149 ], | |
150 ], | |
151 '#wrapper_attributes' => [ | |
152 'class' => ['home-toolbar-tab'], | |
153 ], | |
154 '#attached' => [ | |
155 'library' => [ | |
156 'toolbar/toolbar.escapeAdmin', | |
157 ], | |
158 ], | |
159 '#weight' => -20, | |
160 ]; | |
161 | |
162 // To conserve bandwidth, we only include the top-level links in the HTML. | |
163 // The subtrees are fetched through a JSONP script that is generated at the | |
164 // toolbar_subtrees route. We provide the JavaScript requesting that JSONP | |
165 // script here with the hash parameter that is needed for that route. | |
166 // @see toolbar_subtrees_jsonp() | |
167 list($hash, $hash_cacheability) = _toolbar_get_subtrees_hash(); | |
168 $subtrees_attached['drupalSettings']['toolbar'] = [ | |
169 'subtreesHash' => $hash, | |
170 ]; | |
171 | |
172 // The administration element has a link that is themed to correspond to | |
173 // a toolbar tray. The tray contains the full administrative menu of the site. | |
174 $items['administration'] = [ | |
175 '#type' => 'toolbar_item', | |
176 'tab' => [ | |
177 '#type' => 'link', | |
178 '#title' => t('Manage'), | |
179 '#url' => Url::fromRoute('system.admin'), | |
180 '#attributes' => [ | |
181 'title' => t('Admin menu'), | |
182 'class' => ['toolbar-icon', 'toolbar-icon-menu'], | |
183 // A data attribute that indicates to the client to defer loading of | |
184 // the admin menu subtrees until this tab is activated. Admin menu | |
185 // subtrees will not render to the DOM if this attribute is removed. | |
186 // The value of the attribute is intentionally left blank. Only the | |
187 // presence of the attribute is necessary. | |
188 'data-drupal-subtrees' => '', | |
189 ], | |
190 ], | |
191 'tray' => [ | |
192 '#heading' => t('Administration menu'), | |
193 '#attached' => $subtrees_attached, | |
194 'toolbar_administration' => [ | |
195 '#pre_render' => [ | |
196 'toolbar_prerender_toolbar_administration_tray', | |
197 ], | |
198 '#type' => 'container', | |
199 '#attributes' => [ | |
200 'class' => ['toolbar-menu-administration'], | |
201 ], | |
202 ], | |
203 ], | |
204 '#weight' => -15, | |
205 ]; | |
206 $hash_cacheability->applyTo($items['administration']); | |
207 | |
208 return $items; | |
209 } | |
210 | |
211 /** | |
212 * Renders the toolbar's administration tray. | |
213 * | |
214 * @param array $element | |
215 * A renderable array. | |
216 * | |
217 * @return array | |
218 * The updated renderable array. | |
219 * | |
220 * @see \Drupal\Core\Render\RendererInterface::render() | |
221 */ | |
222 function toolbar_prerender_toolbar_administration_tray(array $element) { | |
223 $menu_tree = \Drupal::service('toolbar.menu_tree'); | |
224 // Load the administrative menu. The first level is the "Administration" link. | |
225 // In order to load the children of that link, start and end on the second | |
226 // level. | |
227 $parameters = new MenuTreeParameters(); | |
228 $parameters->setMinDepth(2)->setMaxDepth(2)->onlyEnabledLinks(); | |
229 // @todo Make the menu configurable in https://www.drupal.org/node/1869638. | |
230 $tree = $menu_tree->load('admin', $parameters); | |
231 $manipulators = [ | |
232 ['callable' => 'menu.default_tree_manipulators:checkAccess'], | |
233 ['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'], | |
234 ['callable' => 'toolbar_menu_navigation_links'], | |
235 ]; | |
236 $tree = $menu_tree->transform($tree, $manipulators); | |
237 $element['administration_menu'] = $menu_tree->build($tree); | |
238 return $element; | |
239 } | |
240 | |
241 /** | |
242 * Adds toolbar-specific attributes to the menu link tree. | |
243 * | |
244 * @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree | |
245 * The menu link tree to manipulate. | |
246 * | |
247 * @return \Drupal\Core\Menu\MenuLinkTreeElement[] | |
248 * The manipulated menu link tree. | |
249 */ | |
250 function toolbar_menu_navigation_links(array $tree) { | |
251 foreach ($tree as $element) { | |
252 if ($element->subtree) { | |
253 toolbar_menu_navigation_links($element->subtree); | |
254 } | |
255 | |
256 // Make sure we have a path specific ID in place, so we can attach icons | |
257 // and behaviors to the menu links. | |
258 $link = $element->link; | |
259 $url = $link->getUrlObject(); | |
260 if (!$url->isRouted()) { | |
261 // This is an unusual case, so just get a distinct, safe string. | |
262 $id = substr(Crypt::hashBase64($url->getUri()), 0, 16); | |
263 } | |
264 else { | |
265 $id = str_replace(['.', '<', '>'], ['-', '', ''], $url->getRouteName()); | |
266 } | |
267 | |
268 // Get the non-localized title to make the icon class. | |
269 $definition = $link->getPluginDefinition(); | |
270 | |
271 $element->options['attributes']['id'] = 'toolbar-link-' . $id; | |
272 $element->options['attributes']['class'][] = 'toolbar-icon'; | |
273 $element->options['attributes']['class'][] = 'toolbar-icon-' . strtolower(str_replace(['.', ' ', '_'], ['-', '-', '-'], $definition['id'])); | |
274 $element->options['attributes']['title'] = $link->getDescription(); | |
275 } | |
276 return $tree; | |
277 } | |
278 | |
279 /** | |
280 * Implements hook_preprocess_HOOK() for HTML document templates. | |
281 */ | |
282 function toolbar_preprocess_html(&$variables) { | |
283 if (!\Drupal::currentUser()->hasPermission('access toolbar')) { | |
284 return; | |
285 } | |
286 | |
287 $variables['attributes'] = new Attribute($variables['attributes']); | |
288 $variables['attributes']->addClass(['toolbar-tray-open', 'toolbar-horizontal', 'toolbar-fixed', 'toolbar-loading']); | |
289 } | |
290 | |
291 /** | |
292 * Returns the rendered subtree of each top-level toolbar link. | |
293 * | |
294 * @return array | |
295 * An array with the following key-value pairs: | |
296 * - 'subtrees': the rendered subtrees | |
297 * - 'cacheability: the associated cacheability. | |
298 */ | |
299 function toolbar_get_rendered_subtrees() { | |
300 $data = [ | |
301 '#pre_render' => ['_toolbar_do_get_rendered_subtrees'], | |
302 '#cache' => [ | |
303 'keys' => [ | |
304 'toolbar_rendered_subtrees', | |
305 ], | |
306 ], | |
307 '#cache_properties' => ['#subtrees'], | |
308 ]; | |
309 \Drupal::service('renderer')->renderPlain($data); | |
310 return [$data['#subtrees'], CacheableMetadata::createFromRenderArray($data)]; | |
311 } | |
312 | |
313 /** | |
314 * #pre_render callback for toolbar_get_rendered_subtrees(). | |
315 */ | |
316 function _toolbar_do_get_rendered_subtrees(array $data) { | |
317 $menu_tree = \Drupal::service('toolbar.menu_tree'); | |
318 // Load the administration menu. The first level is the "Administration" link. | |
319 // In order to load the children of that link and the subsequent two levels, | |
320 // start at the second level and end at the fourth. | |
321 $parameters = new MenuTreeParameters(); | |
322 $parameters->setMinDepth(2)->setMaxDepth(4)->onlyEnabledLinks(); | |
323 // @todo Make the menu configurable in https://www.drupal.org/node/1869638. | |
324 $tree = $menu_tree->load('admin', $parameters); | |
325 $manipulators = [ | |
326 ['callable' => 'menu.default_tree_manipulators:checkAccess'], | |
327 ['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'], | |
328 ['callable' => 'toolbar_menu_navigation_links'], | |
329 ]; | |
330 $tree = $menu_tree->transform($tree, $manipulators); | |
331 $subtrees = []; | |
332 // Calculated the combined cacheability of all subtrees. | |
333 $cacheability = new CacheableMetadata(); | |
334 foreach ($tree as $element) { | |
335 /** @var \Drupal\Core\Menu\MenuLinkInterface $link */ | |
336 $link = $element->link; | |
337 if ($element->subtree) { | |
338 $subtree = $menu_tree->build($element->subtree); | |
339 $output = \Drupal::service('renderer')->renderPlain($subtree); | |
340 $cacheability = $cacheability->merge(CacheableMetadata::createFromRenderArray($subtree)); | |
341 } | |
342 else { | |
343 $output = ''; | |
344 } | |
345 // Many routes have dots as route name, while some special ones like <front> | |
346 // have <> characters in them. | |
347 $url = $link->getUrlObject(); | |
348 $id = str_replace(['.', '<', '>'], ['-', '', ''], $url->isRouted() ? $url->getRouteName() : $url->getUri()); | |
349 | |
350 $subtrees[$id] = $output; | |
351 } | |
352 | |
353 // Store the subtrees, along with the cacheability metadata. | |
354 $cacheability->applyTo($data); | |
355 $data['#subtrees'] = $subtrees; | |
356 | |
357 return $data; | |
358 } | |
359 | |
360 /** | |
361 * Returns the hash of the per-user rendered toolbar subtrees. | |
362 * | |
363 * @return string | |
364 * The hash of the admin_menu subtrees. | |
365 */ | |
366 function _toolbar_get_subtrees_hash() { | |
367 list($subtrees, $cacheability) = toolbar_get_rendered_subtrees(); | |
368 $hash = Crypt::hashBase64(serialize($subtrees)); | |
369 return [$hash, $cacheability]; | |
370 } |