Chris@0: /** Chris@0: * @file Chris@0: * Builds a nested accordion widget. Chris@0: * Chris@0: * Invoke on an HTML list element with the jQuery plugin pattern. Chris@0: * Chris@0: * @example Chris@0: * $('.toolbar-menu').drupalToolbarMenu(); Chris@0: */ Chris@0: Chris@0: (function ($, Drupal, drupalSettings) { Chris@0: /** Chris@0: * Store the open menu tray. Chris@0: */ Chris@0: let activeItem = Drupal.url(drupalSettings.path.currentPath); Chris@0: Chris@0: $.fn.drupalToolbarMenu = function () { Chris@0: const ui = { Chris@0: handleOpen: Drupal.t('Extend'), Chris@0: handleClose: Drupal.t('Collapse'), Chris@0: }; Chris@0: Chris@0: /** Chris@0: * Handle clicks from the disclosure button on an item with sub-items. Chris@0: * Chris@0: * @param {Object} event Chris@0: * A jQuery Event object. Chris@0: */ Chris@0: function toggleClickHandler(event) { Chris@0: const $toggle = $(event.target); Chris@0: const $item = $toggle.closest('li'); Chris@0: // Toggle the list item. Chris@0: toggleList($item); Chris@0: // Close open sibling menus. Chris@0: const $openItems = $item.siblings().filter('.open'); Chris@0: toggleList($openItems, false); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Handle clicks from a menu item link. Chris@0: * Chris@0: * @param {Object} event Chris@0: * A jQuery Event object. Chris@0: */ Chris@0: function linkClickHandler(event) { Chris@0: // If the toolbar is positioned fixed (and therefore hiding content Chris@0: // underneath), then users expect clicks in the administration menu tray Chris@0: // to take them to that destination but for the menu tray to be closed Chris@0: // after clicking: otherwise the toolbar itself is obstructing the view Chris@0: // of the destination they chose. Chris@0: if (!Drupal.toolbar.models.toolbarModel.get('isFixed')) { Chris@0: Drupal.toolbar.models.toolbarModel.set('activeTab', null); Chris@0: } Chris@0: // Stopping propagation to make sure that once a toolbar-box is clicked Chris@0: // (the whitespace part), the page is not redirected anymore. Chris@0: event.stopPropagation(); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Toggle the open/close state of a list is a menu. Chris@0: * Chris@0: * @param {jQuery} $item Chris@0: * The li item to be toggled. Chris@0: * Chris@0: * @param {Boolean} switcher Chris@0: * A flag that forces toggleClass to add or a remove a class, rather than Chris@0: * simply toggling its presence. Chris@0: */ Chris@0: function toggleList($item, switcher) { Chris@0: const $toggle = $item.children('.toolbar-box').children('.toolbar-handle'); Chris@0: switcher = (typeof switcher !== 'undefined') ? switcher : !$item.hasClass('open'); Chris@0: // Toggle the item open state. Chris@0: $item.toggleClass('open', switcher); Chris@0: // Twist the toggle. Chris@0: $toggle.toggleClass('open', switcher); Chris@0: // Adjust the toggle text. Chris@0: $toggle Chris@0: .find('.action') Chris@0: // Expand Structure, Collapse Structure. Chris@0: .text((switcher) ? ui.handleClose : ui.handleOpen); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Add markup to the menu elements. Chris@0: * Chris@0: * Items with sub-elements have a list toggle attached to them. Menu item Chris@0: * links and the corresponding list toggle are wrapped with in a div Chris@0: * classed with .toolbar-box. The .toolbar-box div provides a positioning Chris@0: * context for the item list toggle. Chris@0: * Chris@0: * @param {jQuery} $menu Chris@0: * The root of the menu to be initialized. Chris@0: */ Chris@0: function initItems($menu) { Chris@0: const options = { Chris@0: class: 'toolbar-icon toolbar-handle', Chris@0: action: ui.handleOpen, Chris@0: text: '', Chris@0: }; Chris@0: // Initialize items and their links. Chris@0: $menu.find('li > a').wrap('