Chris@0
|
1 /**
|
Chris@0
|
2 * @file
|
Chris@0
|
3 * Builds a nested accordion widget.
|
Chris@0
|
4 *
|
Chris@0
|
5 * Invoke on an HTML list element with the jQuery plugin pattern.
|
Chris@0
|
6 *
|
Chris@0
|
7 * @example
|
Chris@0
|
8 * $('.toolbar-menu').drupalToolbarMenu();
|
Chris@0
|
9 */
|
Chris@0
|
10
|
Chris@17
|
11 (function($, Drupal, drupalSettings) {
|
Chris@0
|
12 /**
|
Chris@0
|
13 * Store the open menu tray.
|
Chris@0
|
14 */
|
Chris@0
|
15 let activeItem = Drupal.url(drupalSettings.path.currentPath);
|
Chris@0
|
16
|
Chris@17
|
17 $.fn.drupalToolbarMenu = function() {
|
Chris@0
|
18 const ui = {
|
Chris@0
|
19 handleOpen: Drupal.t('Extend'),
|
Chris@0
|
20 handleClose: Drupal.t('Collapse'),
|
Chris@0
|
21 };
|
Chris@0
|
22
|
Chris@0
|
23 /**
|
Chris@17
|
24 * Toggle the open/close state of a list is a menu.
|
Chris@17
|
25 *
|
Chris@17
|
26 * @param {jQuery} $item
|
Chris@17
|
27 * The li item to be toggled.
|
Chris@17
|
28 *
|
Chris@17
|
29 * @param {Boolean} switcher
|
Chris@17
|
30 * A flag that forces toggleClass to add or a remove a class, rather than
|
Chris@17
|
31 * simply toggling its presence.
|
Chris@17
|
32 */
|
Chris@17
|
33 function toggleList($item, switcher) {
|
Chris@17
|
34 const $toggle = $item
|
Chris@17
|
35 .children('.toolbar-box')
|
Chris@17
|
36 .children('.toolbar-handle');
|
Chris@17
|
37 switcher =
|
Chris@17
|
38 typeof switcher !== 'undefined' ? switcher : !$item.hasClass('open');
|
Chris@17
|
39 // Toggle the item open state.
|
Chris@17
|
40 $item.toggleClass('open', switcher);
|
Chris@17
|
41 // Twist the toggle.
|
Chris@17
|
42 $toggle.toggleClass('open', switcher);
|
Chris@17
|
43 // Adjust the toggle text.
|
Chris@17
|
44 $toggle
|
Chris@17
|
45 .find('.action')
|
Chris@17
|
46 // Expand Structure, Collapse Structure.
|
Chris@17
|
47 .text(switcher ? ui.handleClose : ui.handleOpen);
|
Chris@17
|
48 }
|
Chris@17
|
49
|
Chris@17
|
50 /**
|
Chris@0
|
51 * Handle clicks from the disclosure button on an item with sub-items.
|
Chris@0
|
52 *
|
Chris@0
|
53 * @param {Object} event
|
Chris@0
|
54 * A jQuery Event object.
|
Chris@0
|
55 */
|
Chris@0
|
56 function toggleClickHandler(event) {
|
Chris@0
|
57 const $toggle = $(event.target);
|
Chris@0
|
58 const $item = $toggle.closest('li');
|
Chris@0
|
59 // Toggle the list item.
|
Chris@0
|
60 toggleList($item);
|
Chris@0
|
61 // Close open sibling menus.
|
Chris@0
|
62 const $openItems = $item.siblings().filter('.open');
|
Chris@0
|
63 toggleList($openItems, false);
|
Chris@0
|
64 }
|
Chris@0
|
65
|
Chris@0
|
66 /**
|
Chris@0
|
67 * Handle clicks from a menu item link.
|
Chris@0
|
68 *
|
Chris@0
|
69 * @param {Object} event
|
Chris@0
|
70 * A jQuery Event object.
|
Chris@0
|
71 */
|
Chris@0
|
72 function linkClickHandler(event) {
|
Chris@0
|
73 // If the toolbar is positioned fixed (and therefore hiding content
|
Chris@0
|
74 // underneath), then users expect clicks in the administration menu tray
|
Chris@0
|
75 // to take them to that destination but for the menu tray to be closed
|
Chris@0
|
76 // after clicking: otherwise the toolbar itself is obstructing the view
|
Chris@0
|
77 // of the destination they chose.
|
Chris@0
|
78 if (!Drupal.toolbar.models.toolbarModel.get('isFixed')) {
|
Chris@0
|
79 Drupal.toolbar.models.toolbarModel.set('activeTab', null);
|
Chris@0
|
80 }
|
Chris@0
|
81 // Stopping propagation to make sure that once a toolbar-box is clicked
|
Chris@0
|
82 // (the whitespace part), the page is not redirected anymore.
|
Chris@0
|
83 event.stopPropagation();
|
Chris@0
|
84 }
|
Chris@0
|
85
|
Chris@0
|
86 /**
|
Chris@0
|
87 * Add markup to the menu elements.
|
Chris@0
|
88 *
|
Chris@0
|
89 * Items with sub-elements have a list toggle attached to them. Menu item
|
Chris@0
|
90 * links and the corresponding list toggle are wrapped with in a div
|
Chris@0
|
91 * classed with .toolbar-box. The .toolbar-box div provides a positioning
|
Chris@0
|
92 * context for the item list toggle.
|
Chris@0
|
93 *
|
Chris@0
|
94 * @param {jQuery} $menu
|
Chris@0
|
95 * The root of the menu to be initialized.
|
Chris@0
|
96 */
|
Chris@0
|
97 function initItems($menu) {
|
Chris@0
|
98 const options = {
|
Chris@0
|
99 class: 'toolbar-icon toolbar-handle',
|
Chris@0
|
100 action: ui.handleOpen,
|
Chris@0
|
101 text: '',
|
Chris@0
|
102 };
|
Chris@0
|
103 // Initialize items and their links.
|
Chris@0
|
104 $menu.find('li > a').wrap('<div class="toolbar-box">');
|
Chris@0
|
105 // Add a handle to each list item if it has a menu.
|
Chris@0
|
106 $menu.find('li').each((index, element) => {
|
Chris@0
|
107 const $item = $(element);
|
Chris@0
|
108 if ($item.children('ul.toolbar-menu').length) {
|
Chris@0
|
109 const $box = $item.children('.toolbar-box');
|
Chris@17
|
110 options.text = Drupal.t('@label', {
|
Chris@17
|
111 '@label': $box.find('a').text(),
|
Chris@17
|
112 });
|
Chris@17
|
113 $item
|
Chris@17
|
114 .children('.toolbar-box')
|
Chris@0
|
115 .append(Drupal.theme('toolbarMenuItemToggle', options));
|
Chris@0
|
116 }
|
Chris@0
|
117 });
|
Chris@0
|
118 }
|
Chris@0
|
119
|
Chris@0
|
120 /**
|
Chris@0
|
121 * Adds a level class to each list based on its depth in the menu.
|
Chris@0
|
122 *
|
Chris@0
|
123 * This function is called recursively on each sub level of lists elements
|
Chris@0
|
124 * until the depth of the menu is exhausted.
|
Chris@0
|
125 *
|
Chris@0
|
126 * @param {jQuery} $lists
|
Chris@0
|
127 * A jQuery object of ul elements.
|
Chris@0
|
128 *
|
Chris@0
|
129 * @param {number} level
|
Chris@0
|
130 * The current level number to be assigned to the list elements.
|
Chris@0
|
131 */
|
Chris@0
|
132 function markListLevels($lists, level) {
|
Chris@17
|
133 level = !level ? 1 : level;
|
Chris@0
|
134 const $lis = $lists.children('li').addClass(`level-${level}`);
|
Chris@0
|
135 $lists = $lis.children('ul');
|
Chris@0
|
136 if ($lists.length) {
|
Chris@0
|
137 markListLevels($lists, level + 1);
|
Chris@0
|
138 }
|
Chris@0
|
139 }
|
Chris@0
|
140
|
Chris@0
|
141 /**
|
Chris@0
|
142 * On page load, open the active menu item.
|
Chris@0
|
143 *
|
Chris@0
|
144 * Marks the trail of the active link in the menu back to the root of the
|
Chris@0
|
145 * menu with .menu-item--active-trail.
|
Chris@0
|
146 *
|
Chris@0
|
147 * @param {jQuery} $menu
|
Chris@0
|
148 * The root of the menu.
|
Chris@0
|
149 */
|
Chris@0
|
150 function openActiveItem($menu) {
|
Chris@17
|
151 const pathItem = $menu.find(`a[href="${window.location.pathname}"]`);
|
Chris@0
|
152 if (pathItem.length && !activeItem) {
|
Chris@17
|
153 activeItem = window.location.pathname;
|
Chris@0
|
154 }
|
Chris@0
|
155 if (activeItem) {
|
Chris@17
|
156 const $activeItem = $menu
|
Chris@17
|
157 .find(`a[href="${activeItem}"]`)
|
Chris@17
|
158 .addClass('menu-item--active');
|
Chris@17
|
159 const $activeTrail = $activeItem
|
Chris@17
|
160 .parentsUntil('.root', 'li')
|
Chris@17
|
161 .addClass('menu-item--active-trail');
|
Chris@0
|
162 toggleList($activeTrail, true);
|
Chris@0
|
163 }
|
Chris@0
|
164 }
|
Chris@0
|
165
|
Chris@0
|
166 // Return the jQuery object.
|
Chris@17
|
167 return this.each(function(selector) {
|
Chris@0
|
168 const $menu = $(this).once('toolbar-menu');
|
Chris@0
|
169 if ($menu.length) {
|
Chris@0
|
170 // Bind event handlers.
|
Chris@0
|
171 $menu
|
Chris@0
|
172 .on('click.toolbar', '.toolbar-box', toggleClickHandler)
|
Chris@0
|
173 .on('click.toolbar', '.toolbar-box a', linkClickHandler);
|
Chris@0
|
174
|
Chris@0
|
175 $menu.addClass('root');
|
Chris@0
|
176 initItems($menu);
|
Chris@0
|
177 markListLevels($menu);
|
Chris@0
|
178 // Restore previous and active states.
|
Chris@0
|
179 openActiveItem($menu);
|
Chris@0
|
180 }
|
Chris@0
|
181 });
|
Chris@0
|
182 };
|
Chris@0
|
183
|
Chris@0
|
184 /**
|
Chris@0
|
185 * A toggle is an interactive element often bound to a click handler.
|
Chris@0
|
186 *
|
Chris@0
|
187 * @param {object} options
|
Chris@0
|
188 * Options for the button.
|
Chris@0
|
189 * @param {string} options.class
|
Chris@0
|
190 * Class to set on the button.
|
Chris@0
|
191 * @param {string} options.action
|
Chris@0
|
192 * Action for the button.
|
Chris@0
|
193 * @param {string} options.text
|
Chris@0
|
194 * Used as label for the button.
|
Chris@0
|
195 *
|
Chris@0
|
196 * @return {string}
|
Chris@0
|
197 * A string representing a DOM fragment.
|
Chris@0
|
198 */
|
Chris@17
|
199 Drupal.theme.toolbarMenuItemToggle = function(options) {
|
Chris@17
|
200 return `<button class="${options.class}"><span class="action">${
|
Chris@17
|
201 options.action
|
Chris@17
|
202 }</span> <span class="label">${options.text}</span></button>`;
|
Chris@0
|
203 };
|
Chris@17
|
204 })(jQuery, Drupal, drupalSettings);
|