Security update for Core, with self-updated composer
[yaffs-website] / web / core / modules / toolbar / js / toolbar.menu.es6.js
diff --git a/web/core/modules/toolbar/js/toolbar.menu.es6.js b/web/core/modules/toolbar/js/toolbar.menu.es6.js
new file mode 100644 (file)
index 0000000..03fd41f
--- /dev/null
@@ -0,0 +1,192 @@
+/**
+ * @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);
+
+  $.fn.drupalToolbarMenu = function () {
+    const ui = {
+      handleOpen: Drupal.t('Extend'),
+      handleClose: Drupal.t('Collapse'),
+    };
+
+    /**
+     * 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();
+    }
+
+    /**
+     * 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')
+        // Expand Structure, Collapse Structure.
+        .text((switcher) ? ui.handleClose : ui.handleOpen);
+    }
+
+    /**
+     * 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');
+          options.text = Drupal.t('@label', { '@label': $box.find('a').text() });
+          $item.children('.toolbar-box')
+            .append(Drupal.theme('toolbarMenuItemToggle', options));
+        }
+      });
+    }
+
+    /**
+     * 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) {
+      const pathItem = $menu.find(`a[href="${location.pathname}"]`);
+      if (pathItem.length && !activeItem) {
+        activeItem = location.pathname;
+      }
+      if (activeItem) {
+        const $activeItem = $menu.find(`a[href="${activeItem}"]`).addClass('menu-item--active');
+        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 = $(this).once('toolbar-menu');
+      if ($menu.length) {
+        // 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));