Initial Drupal 11 with DDEV setup
This commit is contained in:
		
							
								
								
									
										227
									
								
								web/core/themes/olivero/js/navigation-utils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								web/core/themes/olivero/js/navigation-utils.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,227 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Controls the visibility of desktop navigation.
 | 
			
		||||
 *
 | 
			
		||||
 * Shows and hides the desktop navigation based on scroll position and controls
 | 
			
		||||
 * the functionality of the button that shows/hides the navigation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* eslint-disable no-inner-declarations */
 | 
			
		||||
((Drupal) => {
 | 
			
		||||
  /**
 | 
			
		||||
   * Olivero helper functions.
 | 
			
		||||
   *
 | 
			
		||||
   * @namespace
 | 
			
		||||
   */
 | 
			
		||||
  Drupal.olivero = {};
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Checks if the mobile navigation button is visible.
 | 
			
		||||
   *
 | 
			
		||||
   * @return {boolean}
 | 
			
		||||
   *   True if navButtons is hidden, false if not.
 | 
			
		||||
   */
 | 
			
		||||
  function isDesktopNav() {
 | 
			
		||||
    const navButtons = document.querySelector(
 | 
			
		||||
      '[data-drupal-selector="mobile-buttons"]',
 | 
			
		||||
    );
 | 
			
		||||
    return navButtons
 | 
			
		||||
      ? window.getComputedStyle(navButtons).getPropertyValue('display') ===
 | 
			
		||||
          'none'
 | 
			
		||||
      : false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Drupal.olivero.isDesktopNav = isDesktopNav;
 | 
			
		||||
 | 
			
		||||
  const stickyHeaderToggleButton = document.querySelector(
 | 
			
		||||
    '[data-drupal-selector="sticky-header-toggle"]',
 | 
			
		||||
  );
 | 
			
		||||
  const siteHeaderFixable = document.querySelector(
 | 
			
		||||
    '[data-drupal-selector="site-header-fixable"]',
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Checks if the sticky header is enabled.
 | 
			
		||||
   *
 | 
			
		||||
   * @return {boolean}
 | 
			
		||||
   *   True if sticky header is enabled, false if not.
 | 
			
		||||
   */
 | 
			
		||||
  function stickyHeaderIsEnabled() {
 | 
			
		||||
    return stickyHeaderToggleButton.getAttribute('aria-checked') === 'true';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Save the current sticky header expanded state to localStorage, and set
 | 
			
		||||
   * it to expire after two weeks.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {boolean} expandedState
 | 
			
		||||
   *   Current state of the sticky header button.
 | 
			
		||||
   */
 | 
			
		||||
  function setStickyHeaderStorage(expandedState) {
 | 
			
		||||
    if (!expandedState) {
 | 
			
		||||
      localStorage.removeItem('Drupal.olivero.stickyHeaderState');
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    const now = new Date();
 | 
			
		||||
 | 
			
		||||
    const item = {
 | 
			
		||||
      value: expandedState,
 | 
			
		||||
      expiry: now.getTime() + 20160000, // 2 weeks from now.
 | 
			
		||||
    };
 | 
			
		||||
    localStorage.setItem(
 | 
			
		||||
      'Drupal.olivero.stickyHeaderState',
 | 
			
		||||
      JSON.stringify(item),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Update the expiration date if the sticky header expanded state is set.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {boolean} expandedState
 | 
			
		||||
   *   Current state of the sticky header button.
 | 
			
		||||
   */
 | 
			
		||||
  function updateStickyHeaderStorage(expandedState) {
 | 
			
		||||
    const stickyHeaderState = localStorage.getItem(
 | 
			
		||||
      'Drupal.olivero.stickyHeaderState',
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (stickyHeaderState !== null) {
 | 
			
		||||
      setStickyHeaderStorage(expandedState);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Toggle the state of the sticky header between always pinned and
 | 
			
		||||
   * only pinned when scrolled to the top of the viewport.
 | 
			
		||||
   *
 | 
			
		||||
   * @param {boolean} pinnedState
 | 
			
		||||
   *   State to change the sticky header to.
 | 
			
		||||
   */
 | 
			
		||||
  function toggleStickyHeaderState(pinnedState) {
 | 
			
		||||
    if (isDesktopNav()) {
 | 
			
		||||
      siteHeaderFixable.classList.toggle('is-expanded', pinnedState);
 | 
			
		||||
      stickyHeaderToggleButton.setAttribute('aria-checked', pinnedState);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Return the sticky header's stored state from localStorage.
 | 
			
		||||
   *
 | 
			
		||||
   * @return {boolean}
 | 
			
		||||
   *   Stored state of the sticky header.
 | 
			
		||||
   */
 | 
			
		||||
  function getStickyHeaderStorage() {
 | 
			
		||||
    const stickyHeaderState = localStorage.getItem(
 | 
			
		||||
      'Drupal.olivero.stickyHeaderState',
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (!stickyHeaderState) return false;
 | 
			
		||||
 | 
			
		||||
    const item = JSON.parse(stickyHeaderState);
 | 
			
		||||
    const now = new Date();
 | 
			
		||||
 | 
			
		||||
    // Compare the expiry time of the item with the current time.
 | 
			
		||||
    if (now.getTime() > item.expiry) {
 | 
			
		||||
      // If the item is expired, delete the item from storage and return null.
 | 
			
		||||
      localStorage.removeItem('Drupal.olivero.stickyHeaderState');
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    return item.value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const fixableElements = document.querySelectorAll(
 | 
			
		||||
    '[data-drupal-selector="site-header-fixable"], [data-drupal-selector="social-bar-inner"]',
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  function toggleDesktopNavVisibility(entries) {
 | 
			
		||||
    if (!isDesktopNav()) return;
 | 
			
		||||
 | 
			
		||||
    entries.forEach((entry) => {
 | 
			
		||||
      // Firefox doesn't seem to support entry.isIntersecting properly,
 | 
			
		||||
      // so we check the intersectionRatio.
 | 
			
		||||
      fixableElements.forEach((el) =>
 | 
			
		||||
        el.classList.toggle('is-fixed', entry.intersectionRatio < 1),
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Gets the root margin by checking for various toolbar classes.
 | 
			
		||||
   *
 | 
			
		||||
   * @return {string}
 | 
			
		||||
   *   Root margin for the Intersection Observer options object.
 | 
			
		||||
   */
 | 
			
		||||
  function getRootMargin() {
 | 
			
		||||
    let rootMarginTop = 72;
 | 
			
		||||
    const { body } = document;
 | 
			
		||||
 | 
			
		||||
    if (body.classList.contains('toolbar-fixed')) {
 | 
			
		||||
      rootMarginTop -= 39;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (
 | 
			
		||||
      body.classList.contains('toolbar-horizontal') &&
 | 
			
		||||
      body.classList.contains('toolbar-tray-open')
 | 
			
		||||
    ) {
 | 
			
		||||
      rootMarginTop -= 40;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return `${rootMarginTop}px 0px 0px 0px`;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Monitor the navigation position.
 | 
			
		||||
   */
 | 
			
		||||
  function monitorNavPosition() {
 | 
			
		||||
    const primaryNav = document.querySelector(
 | 
			
		||||
      '[data-drupal-selector="site-header"]',
 | 
			
		||||
    );
 | 
			
		||||
    const options = {
 | 
			
		||||
      rootMargin: getRootMargin(),
 | 
			
		||||
      threshold: [0.999, 1],
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const observer = new IntersectionObserver(
 | 
			
		||||
      toggleDesktopNavVisibility,
 | 
			
		||||
      options,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (primaryNav) {
 | 
			
		||||
      observer.observe(primaryNav);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (stickyHeaderToggleButton) {
 | 
			
		||||
    stickyHeaderToggleButton.addEventListener('click', () => {
 | 
			
		||||
      const pinnedState = !stickyHeaderIsEnabled();
 | 
			
		||||
      toggleStickyHeaderState(pinnedState);
 | 
			
		||||
      setStickyHeaderStorage(pinnedState);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // If header is pinned open and a header element gains focus, scroll to the
 | 
			
		||||
  // top of the page to ensure that the header elements can be seen.
 | 
			
		||||
  const siteHeaderInner = document.querySelector(
 | 
			
		||||
    '[data-drupal-selector="site-header-inner"]',
 | 
			
		||||
  );
 | 
			
		||||
  if (siteHeaderInner) {
 | 
			
		||||
    siteHeaderInner.addEventListener('focusin', () => {
 | 
			
		||||
      if (isDesktopNav() && !stickyHeaderIsEnabled()) {
 | 
			
		||||
        const header = document.querySelector(
 | 
			
		||||
          '[data-drupal-selector="site-header"]',
 | 
			
		||||
        );
 | 
			
		||||
        const headerNav = header.querySelector(
 | 
			
		||||
          '[data-drupal-selector="header-nav"]',
 | 
			
		||||
        );
 | 
			
		||||
        const headerMargin = header.clientHeight - headerNav.clientHeight;
 | 
			
		||||
        if (window.scrollY > headerMargin) {
 | 
			
		||||
          window.scrollTo(0, headerMargin);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  monitorNavPosition();
 | 
			
		||||
  updateStickyHeaderStorage(getStickyHeaderStorage());
 | 
			
		||||
  toggleStickyHeaderState(getStickyHeaderStorage());
 | 
			
		||||
})(Drupal);
 | 
			
		||||
		Reference in New Issue
	
	Block a user