154 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			154 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/**
 | 
						|
 * @file
 | 
						|
 * Wide viewport search bar interactions.
 | 
						|
 */
 | 
						|
 | 
						|
((Drupal) => {
 | 
						|
  const searchWideButtonSelector =
 | 
						|
    '[data-drupal-selector="block-search-wide-button"]';
 | 
						|
  const searchWideButton = document.querySelector(searchWideButtonSelector);
 | 
						|
  const searchWideWrapperSelector =
 | 
						|
    '[data-drupal-selector="block-search-wide-wrapper"]';
 | 
						|
  const searchWideWrapper = document.querySelector(searchWideWrapperSelector);
 | 
						|
 | 
						|
  /**
 | 
						|
   * Determine if search is visible.
 | 
						|
   *
 | 
						|
   * @return {boolean}
 | 
						|
   *   True if the search wrapper contains "is-active" class, false if not.
 | 
						|
   */
 | 
						|
  function searchIsVisible() {
 | 
						|
    return searchWideWrapper.classList.contains('is-active');
 | 
						|
  }
 | 
						|
  Drupal.olivero.searchIsVisible = searchIsVisible;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Closes search bar when a click event does not happen at an (x,y) coordinate
 | 
						|
   * that does not overlap with either the search wrapper or button.
 | 
						|
   *
 | 
						|
   * @see https://bugs.webkit.org/show_bug.cgi?id=229895
 | 
						|
   *
 | 
						|
   * @param {Event} e click event
 | 
						|
   */
 | 
						|
  function watchForClickOut(e) {
 | 
						|
    const clickInSearchArea = e.target.matches(`
 | 
						|
      ${searchWideWrapperSelector},
 | 
						|
      ${searchWideWrapperSelector} *,
 | 
						|
      ${searchWideButtonSelector},
 | 
						|
      ${searchWideButtonSelector} *
 | 
						|
    `);
 | 
						|
    if (!clickInSearchArea && searchIsVisible()) {
 | 
						|
      // eslint-disable-next-line no-use-before-define
 | 
						|
      toggleSearchVisibility(false);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Closes search bar when focus moves to another target.
 | 
						|
   * Avoids closing search bar if event does not have related target - required for Safari.
 | 
						|
   *
 | 
						|
   * @see https://bugs.webkit.org/show_bug.cgi?id=229895
 | 
						|
   *
 | 
						|
   * @param {Event} e focusout event
 | 
						|
   */
 | 
						|
  function watchForFocusOut(e) {
 | 
						|
    if (e.relatedTarget) {
 | 
						|
      const inSearchBar = e.relatedTarget.matches(
 | 
						|
        `${searchWideWrapperSelector}, ${searchWideWrapperSelector} *`,
 | 
						|
      );
 | 
						|
      const inSearchButton = e.relatedTarget.matches(
 | 
						|
        `${searchWideButtonSelector}, ${searchWideButtonSelector} *`,
 | 
						|
      );
 | 
						|
 | 
						|
      if (!inSearchBar && !inSearchButton) {
 | 
						|
        // eslint-disable-next-line no-use-before-define
 | 
						|
        toggleSearchVisibility(false);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Closes search bar on escape keyup, if open.
 | 
						|
   *
 | 
						|
   * @param {Event} e keyup event
 | 
						|
   */
 | 
						|
  function watchForEscapeOut(e) {
 | 
						|
    if (e.key === 'Escape') {
 | 
						|
      // eslint-disable-next-line no-use-before-define
 | 
						|
      toggleSearchVisibility(false);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Set focus for the search input element.
 | 
						|
   */
 | 
						|
  function handleFocus() {
 | 
						|
    if (searchIsVisible()) {
 | 
						|
      searchWideWrapper.querySelector('input[type="search"]').focus();
 | 
						|
    } else if (searchWideWrapper.contains(document.activeElement)) {
 | 
						|
      // Return focus to button only if focus was inside of the search wrapper.
 | 
						|
      searchWideButton.focus();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Toggle search functionality visibility.
 | 
						|
   *
 | 
						|
   * @param {boolean} visibility
 | 
						|
   *   True if we want to show the form, false if we want to hide it.
 | 
						|
   */
 | 
						|
  function toggleSearchVisibility(visibility) {
 | 
						|
    searchWideButton.setAttribute('aria-expanded', visibility === true);
 | 
						|
    searchWideWrapper.classList.toggle('is-active', visibility === true);
 | 
						|
    searchWideWrapper.addEventListener('transitionend', handleFocus, {
 | 
						|
      once: true,
 | 
						|
    });
 | 
						|
 | 
						|
    if (visibility === true) {
 | 
						|
      Drupal.olivero.closeAllSubNav();
 | 
						|
 | 
						|
      document.addEventListener('click', watchForClickOut, { capture: true });
 | 
						|
      document.addEventListener('focusout', watchForFocusOut, {
 | 
						|
        capture: true,
 | 
						|
      });
 | 
						|
      document.addEventListener('keyup', watchForEscapeOut, { capture: true });
 | 
						|
    } else {
 | 
						|
      document.removeEventListener('click', watchForClickOut, {
 | 
						|
        capture: true,
 | 
						|
      });
 | 
						|
      document.removeEventListener('focusout', watchForFocusOut, {
 | 
						|
        capture: true,
 | 
						|
      });
 | 
						|
      document.removeEventListener('keyup', watchForEscapeOut, {
 | 
						|
        capture: true,
 | 
						|
      });
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Drupal.olivero.toggleSearchVisibility = toggleSearchVisibility;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Initializes the search wide button.
 | 
						|
   *
 | 
						|
   * @type {Drupal~behavior}
 | 
						|
   *
 | 
						|
   * @prop {Drupal~behaviorAttach} attach
 | 
						|
   *  Adds aria-expanded attribute to the search wide button.
 | 
						|
   */
 | 
						|
  Drupal.behaviors.searchWide = {
 | 
						|
    attach(context) {
 | 
						|
      const searchWideButtonEl = once(
 | 
						|
        'search-wide',
 | 
						|
        searchWideButtonSelector,
 | 
						|
        context,
 | 
						|
      ).shift();
 | 
						|
      if (searchWideButtonEl) {
 | 
						|
        searchWideButtonEl.setAttribute('aria-expanded', searchIsVisible());
 | 
						|
        searchWideButtonEl.addEventListener('click', () => {
 | 
						|
          toggleSearchVisibility(!searchIsVisible());
 | 
						|
        });
 | 
						|
      }
 | 
						|
    },
 | 
						|
  };
 | 
						|
})(Drupal);
 |