Commit b638f429 authored by Lauri Timmanee's avatar Lauri Timmanee
Browse files

fix: #3568566 Olivero's secondary menus inoperable when authenticated & BigPipe present

By: mherchel
By: mandclu
By: godotislate
By: lauriii
(cherry picked from commit 043432109bc5bc5398aea9d0d9e14814e5c3c664)
(cherry picked from commit 7cffd025)
parent 7fb11404
Loading
Loading
Loading
Loading
Loading
+111 −77
Original line number Diff line number Diff line
@@ -5,9 +5,11 @@

((Drupal) => {
  const { isDesktopNav } = Drupal.olivero;
  const secondLevelNavMenus = document.querySelectorAll(
    '[data-drupal-selector="primary-nav-menu-item-has-children"]',
  );

  /**
   * NodeList of second level navigation <ul>'s.
   */
  let secondLevelNavMenus;

  /**
   * Shows and hides the specified menu item's second level submenu.
@@ -77,6 +79,59 @@
    }, 200);
  }

  /**
   * Close all second level sub navigation menus.
   */
  function closeAllSubNav() {
    secondLevelNavMenus.forEach((el) => {
      // Return focus to the toggle button if the submenu contains focus.
      if (el.contains(document.activeElement)) {
        el.querySelector(
          '[data-drupal-selector="primary-nav-submenu-toggle-button"]',
        ).focus();
      }
      toggleSubNav(el, false);
    });
  }

  Drupal.olivero.closeAllSubNav = closeAllSubNav;

  /**
   * Checks if any sub navigation items are currently active.
   *
   * @return {boolean}
   *   If sub navigation is currently open.
   */
  function areAnySubNavsOpen() {
    let subNavsAreOpen = false;

    secondLevelNavMenus.forEach((el) => {
      const button = el.querySelector(
        '[data-drupal-selector="primary-nav-submenu-toggle-button"]',
      );
      const state = button.getAttribute('aria-expanded') === 'true';

      if (state) {
        subNavsAreOpen = true;
      }
    });

    return subNavsAreOpen;
  }

  Drupal.olivero.areAnySubNavsOpen = areAnySubNavsOpen;

  /**
   * Initializes second level navigation behavior.
   *
   * @param {Element} navElement
   *   The primary navigation menu element.
   */
  function init(navElement) {
    secondLevelNavMenus = navElement.querySelectorAll(
      '[data-drupal-selector="primary-nav-menu-item-has-children"]',
    );

    // Add event listeners onto each sub navigation parent and button.
    secondLevelNavMenus.forEach((el) => {
      const button = el.querySelector(
@@ -130,48 +185,8 @@
      el.addEventListener('blur', handleBlur, true);
    });

  /**
   * Close all second level sub navigation menus.
   */
  function closeAllSubNav() {
    secondLevelNavMenus.forEach((el) => {
      // Return focus to the toggle button if the submenu contains focus.
      if (el.contains(document.activeElement)) {
        el.querySelector(
          '[data-drupal-selector="primary-nav-submenu-toggle-button"]',
        ).focus();
      }
      toggleSubNav(el, false);
    });
  }

  Drupal.olivero.closeAllSubNav = closeAllSubNav;

  /**
   * Checks if any sub navigation items are currently active.
   *
   * @return {boolean}
   *   If sub navigation is currently open.
   */
  function areAnySubNavsOpen() {
    let subNavsAreOpen = false;

    secondLevelNavMenus.forEach((el) => {
      const button = el.querySelector(
        '[data-drupal-selector="primary-nav-submenu-toggle-button"]',
      );
      const state = button.getAttribute('aria-expanded') === 'true';

      if (state) {
        subNavsAreOpen = true;
      }
    });

    return subNavsAreOpen;
  }

  Drupal.olivero.areAnySubNavsOpen = areAnySubNavsOpen;

    // Add document-level listeners only once to prevent duplication.
    once('olivero-second-level-nav-document', document).forEach(() => {
      // Ensure that desktop submenus close when escape key is pressed.
      document.addEventListener('keyup', (e) => {
        if (e.key === 'Escape') {
@@ -194,4 +209,23 @@
        },
        { passive: true },
      );
    });
  }

  /**
   * Attaches the primary navigation behavior to the primary navigation list.
   *
   * @type {Drupal~behavior}
   *
   * @prop {Drupal~behaviorAttach} attach
   */
  Drupal.behaviors.secondLevelNav = {
    attach(context) {
      once(
        'second-level-navigation',
        '[data-drupal-selector="primary-nav-menu--level-1"]',
        context,
      ).forEach(init);
    },
  };
})(Drupal);