257 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			257 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * @file
							 | 
						||
| 
								 | 
							
								 * Builds a nested accordion widget.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Invoke on an HTML list element with the jQuery plugin pattern.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @example
							 | 
						||
| 
								 | 
							
								 * $('.toolbar-menu').drupalToolbarMenu();
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								(function ($, Drupal, drupalSettings) {
							 | 
						||
| 
								 | 
							
								  /**
							 | 
						||
| 
								 | 
							
								   * Store the open menu tray.
							 | 
						||
| 
								 | 
							
								   */
							 | 
						||
| 
								 | 
							
								  let activeItem = Drupal.url(drupalSettings.path.currentPath);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /**
							 | 
						||
| 
								 | 
							
								   * Maintains active tab in horizontal orientation.
							 | 
						||
| 
								 | 
							
								   */
							 | 
						||
| 
								 | 
							
								  $.fn.drupalToolbarMenuHorizontal = function () {
							 | 
						||
| 
								 | 
							
								    let currentPath = drupalSettings.path.currentPath;
							 | 
						||
| 
								 | 
							
								    const menu = once('toolbar-menu-horizontal', this);
							 | 
						||
| 
								 | 
							
								    if (menu.length) {
							 | 
						||
| 
								 | 
							
								      const $menu = $(menu);
							 | 
						||
| 
								 | 
							
								      if (activeItem) {
							 | 
						||
| 
								 | 
							
								        const count = currentPath.split('/').length;
							 | 
						||
| 
								 | 
							
								        // Find the deepest link with its parent info and start
							 | 
						||
| 
								 | 
							
								        // marking active.
							 | 
						||
| 
								 | 
							
								        for (let i = 0; i < count; i++) {
							 | 
						||
| 
								 | 
							
								          const $menuItem = $menu.find(
							 | 
						||
| 
								 | 
							
								            `a[data-drupal-link-system-path="${currentPath}"]`,
							 | 
						||
| 
								 | 
							
								          );
							 | 
						||
| 
								 | 
							
								          if ($menuItem.length !== 0) {
							 | 
						||
| 
								 | 
							
								            $menuItem.closest('a').addClass('is-active');
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								          const lastIndex = currentPath.lastIndexOf('/');
							 | 
						||
| 
								 | 
							
								          currentPath = currentPath.slice(0, lastIndex);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  $.fn.drupalToolbarMenu = function () {
							 | 
						||
| 
								 | 
							
								    const ui = {
							 | 
						||
| 
								 | 
							
								      handleOpen: Drupal.t('Extend'),
							 | 
						||
| 
								 | 
							
								      handleClose: Drupal.t('Collapse'),
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Toggle the open/close state of a list is a menu.
							 | 
						||
| 
								 | 
							
								     *
							 | 
						||
| 
								 | 
							
								     * @param {jQuery} $item
							 | 
						||
| 
								 | 
							
								     *   The li item to be toggled.
							 | 
						||
| 
								 | 
							
								     *
							 | 
						||
| 
								 | 
							
								     * @param {Boolean} switcher
							 | 
						||
| 
								 | 
							
								     *   A flag that forces toggleClass to add or a remove a class, rather than
							 | 
						||
| 
								 | 
							
								     *   simply toggling its presence.
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    function toggleList($item, switcher) {
							 | 
						||
| 
								 | 
							
								      const $toggle = $item
							 | 
						||
| 
								 | 
							
								        .children('.toolbar-box')
							 | 
						||
| 
								 | 
							
								        .children('.toolbar-handle');
							 | 
						||
| 
								 | 
							
								      switcher =
							 | 
						||
| 
								 | 
							
								        typeof switcher !== 'undefined' ? switcher : !$item.hasClass('open');
							 | 
						||
| 
								 | 
							
								      // Toggle the item open state.
							 | 
						||
| 
								 | 
							
								      $item.toggleClass('open', switcher);
							 | 
						||
| 
								 | 
							
								      // Twist the toggle.
							 | 
						||
| 
								 | 
							
								      $toggle.toggleClass('open', switcher);
							 | 
						||
| 
								 | 
							
								      // Adjust the toggle text.
							 | 
						||
| 
								 | 
							
								      $toggle.find('.action').each((index, element) => {
							 | 
						||
| 
								 | 
							
								        // Expand Structure, Collapse Structure.
							 | 
						||
| 
								 | 
							
								        element.textContent = switcher ? ui.handleClose : ui.handleOpen;
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Handle clicks from the disclosure button on an item with sub-items.
							 | 
						||
| 
								 | 
							
								     *
							 | 
						||
| 
								 | 
							
								     * @param {Object} event
							 | 
						||
| 
								 | 
							
								     *   A jQuery Event object.
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    function toggleClickHandler(event) {
							 | 
						||
| 
								 | 
							
								      const $toggle = $(event.target);
							 | 
						||
| 
								 | 
							
								      const $item = $toggle.closest('li');
							 | 
						||
| 
								 | 
							
								      // Toggle the list item.
							 | 
						||
| 
								 | 
							
								      toggleList($item);
							 | 
						||
| 
								 | 
							
								      // Close open sibling menus.
							 | 
						||
| 
								 | 
							
								      const $openItems = $item.siblings().filter('.open');
							 | 
						||
| 
								 | 
							
								      toggleList($openItems, false);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Handle clicks from a menu item link.
							 | 
						||
| 
								 | 
							
								     *
							 | 
						||
| 
								 | 
							
								     * @param {Object} event
							 | 
						||
| 
								 | 
							
								     *   A jQuery Event object.
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    function linkClickHandler(event) {
							 | 
						||
| 
								 | 
							
								      // If the toolbar is positioned fixed (and therefore hiding content
							 | 
						||
| 
								 | 
							
								      // underneath), then users expect clicks in the administration menu tray
							 | 
						||
| 
								 | 
							
								      // to take them to that destination but for the menu tray to be closed
							 | 
						||
| 
								 | 
							
								      // after clicking: otherwise the toolbar itself is obstructing the view
							 | 
						||
| 
								 | 
							
								      // of the destination they chose.
							 | 
						||
| 
								 | 
							
								      if (!Drupal.toolbar.models.toolbarModel.get('isFixed')) {
							 | 
						||
| 
								 | 
							
								        Drupal.toolbar.models.toolbarModel.set('activeTab', null);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      // Stopping propagation to make sure that once a toolbar-box is clicked
							 | 
						||
| 
								 | 
							
								      // (the whitespace part), the page is not redirected anymore.
							 | 
						||
| 
								 | 
							
								      event.stopPropagation();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Add markup to the menu elements.
							 | 
						||
| 
								 | 
							
								     *
							 | 
						||
| 
								 | 
							
								     * Items with sub-elements have a list toggle attached to them. Menu item
							 | 
						||
| 
								 | 
							
								     * links and the corresponding list toggle are wrapped with in a div
							 | 
						||
| 
								 | 
							
								     * classed with .toolbar-box. The .toolbar-box div provides a positioning
							 | 
						||
| 
								 | 
							
								     * context for the item list toggle.
							 | 
						||
| 
								 | 
							
								     *
							 | 
						||
| 
								 | 
							
								     * @param {jQuery} $menu
							 | 
						||
| 
								 | 
							
								     *   The root of the menu to be initialized.
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    function initItems($menu) {
							 | 
						||
| 
								 | 
							
								      const options = {
							 | 
						||
| 
								 | 
							
								        class: 'toolbar-icon toolbar-handle',
							 | 
						||
| 
								 | 
							
								        action: ui.handleOpen,
							 | 
						||
| 
								 | 
							
								        text: '',
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								      // Initialize items and their links.
							 | 
						||
| 
								 | 
							
								      $menu.find('li > a').wrap('<div class="toolbar-box">');
							 | 
						||
| 
								 | 
							
								      // Add a handle to each list item if it has a menu.
							 | 
						||
| 
								 | 
							
								      $menu.find('li').each((index, element) => {
							 | 
						||
| 
								 | 
							
								        const $item = $(element);
							 | 
						||
| 
								 | 
							
								        if ($item.children('ul.toolbar-menu').length) {
							 | 
						||
| 
								 | 
							
								          const $box = $item.children('.toolbar-box');
							 | 
						||
| 
								 | 
							
								          const $link = $box.find('a');
							 | 
						||
| 
								 | 
							
								          options.text = Drupal.t('@label', {
							 | 
						||
| 
								 | 
							
								            '@label': $link.length ? $link[0].textContent : '',
							 | 
						||
| 
								 | 
							
								          });
							 | 
						||
| 
								 | 
							
								          $item
							 | 
						||
| 
								 | 
							
								            .children('.toolbar-box')
							 | 
						||
| 
								 | 
							
								            .append(
							 | 
						||
| 
								 | 
							
								              $(Drupal.theme('toolbarMenuItemToggle', options))
							 | 
						||
| 
								 | 
							
								                .hide()
							 | 
						||
| 
								 | 
							
								                .fadeIn(150),
							 | 
						||
| 
								 | 
							
								            );
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * Adds a level class to each list based on its depth in the menu.
							 | 
						||
| 
								 | 
							
								     *
							 | 
						||
| 
								 | 
							
								     * This function is called recursively on each sub level of lists elements
							 | 
						||
| 
								 | 
							
								     * until the depth of the menu is exhausted.
							 | 
						||
| 
								 | 
							
								     *
							 | 
						||
| 
								 | 
							
								     * @param {jQuery} $lists
							 | 
						||
| 
								 | 
							
								     *   A jQuery object of ul elements.
							 | 
						||
| 
								 | 
							
								     *
							 | 
						||
| 
								 | 
							
								     * @param {number} level
							 | 
						||
| 
								 | 
							
								     *   The current level number to be assigned to the list elements.
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    function markListLevels($lists, level) {
							 | 
						||
| 
								 | 
							
								      level = !level ? 1 : level;
							 | 
						||
| 
								 | 
							
								      const $lis = $lists.children('li').addClass(`level-${level}`);
							 | 
						||
| 
								 | 
							
								      $lists = $lis.children('ul');
							 | 
						||
| 
								 | 
							
								      if ($lists.length) {
							 | 
						||
| 
								 | 
							
								        markListLevels($lists, level + 1);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * On page load, open the active menu item.
							 | 
						||
| 
								 | 
							
								     *
							 | 
						||
| 
								 | 
							
								     * Marks the trail of the active link in the menu back to the root of the
							 | 
						||
| 
								 | 
							
								     * menu with .menu-item--active-trail.
							 | 
						||
| 
								 | 
							
								     *
							 | 
						||
| 
								 | 
							
								     * @param {jQuery} $menu
							 | 
						||
| 
								 | 
							
								     *   The root of the menu.
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    function openActiveItem($menu) {
							 | 
						||
| 
								 | 
							
								      let currentPath = drupalSettings.path.currentPath;
							 | 
						||
| 
								 | 
							
								      const pathItem = $menu.find(`a[href="${window.location.pathname}"]`);
							 | 
						||
| 
								 | 
							
								      if (pathItem.length && !activeItem) {
							 | 
						||
| 
								 | 
							
								        activeItem = window.location.pathname;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      if (activeItem) {
							 | 
						||
| 
								 | 
							
								        const $activeItem = $menu
							 | 
						||
| 
								 | 
							
								          .find(`a[href="${activeItem}"]`)
							 | 
						||
| 
								 | 
							
								          .addClass('menu-item--active');
							 | 
						||
| 
								 | 
							
								        if (pathItem.length === 0 && activeItem) {
							 | 
						||
| 
								 | 
							
								          const count = currentPath.split('/').length;
							 | 
						||
| 
								 | 
							
								          // Find the deepest link with its parent info and start
							 | 
						||
| 
								 | 
							
								          // marking active.
							 | 
						||
| 
								 | 
							
								          for (let i = 0; i < count; i++) {
							 | 
						||
| 
								 | 
							
								            const $menuItem = $menu.find(
							 | 
						||
| 
								 | 
							
								              `a[data-drupal-link-system-path="${currentPath}"]`,
							 | 
						||
| 
								 | 
							
								            );
							 | 
						||
| 
								 | 
							
								            if ($menuItem.length !== 0) {
							 | 
						||
| 
								 | 
							
								              const $activeTrail = $menuItem
							 | 
						||
| 
								 | 
							
								                .parentsUntil('.root', 'li')
							 | 
						||
| 
								 | 
							
								                .addClass('menu-item--active-trail');
							 | 
						||
| 
								 | 
							
								              toggleList($activeTrail, true);
							 | 
						||
| 
								 | 
							
								              break;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            const lastIndex = currentPath.lastIndexOf('/');
							 | 
						||
| 
								 | 
							
								            currentPath = currentPath.slice(0, lastIndex);
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								          const $activeTrail = $activeItem
							 | 
						||
| 
								 | 
							
								            .parentsUntil('.root', 'li')
							 | 
						||
| 
								 | 
							
								            .addClass('menu-item--active-trail');
							 | 
						||
| 
								 | 
							
								          toggleList($activeTrail, true);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Return the jQuery object.
							 | 
						||
| 
								 | 
							
								    return this.each(function (selector) {
							 | 
						||
| 
								 | 
							
								      const menu = once('toolbar-menu-vertical', this);
							 | 
						||
| 
								 | 
							
								      if (menu.length) {
							 | 
						||
| 
								 | 
							
								        const $menu = $(menu);
							 | 
						||
| 
								 | 
							
								        // Bind event handlers.
							 | 
						||
| 
								 | 
							
								        $menu
							 | 
						||
| 
								 | 
							
								          .on('click.toolbar', '.toolbar-box', toggleClickHandler)
							 | 
						||
| 
								 | 
							
								          .on('click.toolbar', '.toolbar-box a', linkClickHandler);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        $menu.addClass('root');
							 | 
						||
| 
								 | 
							
								        initItems($menu);
							 | 
						||
| 
								 | 
							
								        markListLevels($menu);
							 | 
						||
| 
								 | 
							
								        // Restore previous and active states.
							 | 
						||
| 
								 | 
							
								        openActiveItem($menu);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /**
							 | 
						||
| 
								 | 
							
								   * A toggle is an interactive element often bound to a click handler.
							 | 
						||
| 
								 | 
							
								   *
							 | 
						||
| 
								 | 
							
								   * @param {object} options
							 | 
						||
| 
								 | 
							
								   *   Options for the button.
							 | 
						||
| 
								 | 
							
								   * @param {string} options.class
							 | 
						||
| 
								 | 
							
								   *   Class to set on the button.
							 | 
						||
| 
								 | 
							
								   * @param {string} options.action
							 | 
						||
| 
								 | 
							
								   *   Action for the button.
							 | 
						||
| 
								 | 
							
								   * @param {string} options.text
							 | 
						||
| 
								 | 
							
								   *   Used as label for the button.
							 | 
						||
| 
								 | 
							
								   *
							 | 
						||
| 
								 | 
							
								   * @return {string}
							 | 
						||
| 
								 | 
							
								   *   A string representing a DOM fragment.
							 | 
						||
| 
								 | 
							
								   */
							 | 
						||
| 
								 | 
							
								  Drupal.theme.toolbarMenuItemToggle = function (options) {
							 | 
						||
| 
								 | 
							
								    return `<button class="${options.class}"><span class="action">${options.action}</span> <span class="label">${options.text}</span></button>`;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								})(jQuery, Drupal, drupalSettings);
							 |