[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-content/themes/twentytwentyone/assets/js/ -> primary-navigation.js (source)

   1  /**
   2   * File primary-navigation.js.
   3   *
   4   * Required to open and close the mobile navigation.
   5   */
   6  
   7  /**
   8   * Toggle an attribute's value
   9   *
  10   * @param {Element} el - The element.
  11   * @param {boolean} withListeners - Whether we want to add/remove listeners or not.
  12   * @since Twenty Twenty-One 1.0
  13   */
  14  function twentytwentyoneToggleAriaExpanded( el, withListeners ) {
  15      if ( 'true' !== el.getAttribute( 'aria-expanded' ) ) {
  16          el.setAttribute( 'aria-expanded', 'true' );
  17          twentytwentyoneSubmenuPosition( el.parentElement );
  18          if ( withListeners ) {
  19              document.addEventListener( 'click', twentytwentyoneCollapseMenuOnClickOutside );
  20          }
  21      } else {
  22          el.setAttribute( 'aria-expanded', 'false' );
  23          if ( withListeners ) {
  24              document.removeEventListener( 'click', twentytwentyoneCollapseMenuOnClickOutside );
  25          }
  26      }
  27  }
  28  
  29  function twentytwentyoneCollapseMenuOnClickOutside( event ) {
  30      if ( ! document.getElementById( 'site-navigation' ).contains( event.target ) ) {
  31          document.getElementById( 'site-navigation' ).querySelectorAll( '.sub-menu-toggle' ).forEach( function( button ) {
  32              button.setAttribute( 'aria-expanded', 'false' );
  33          } );
  34      }
  35  }
  36  
  37  /**
  38   * Changes the position of submenus so they always fit the screen horizontally.
  39   *
  40   * @param {Element} li - The li element.
  41   */
  42  function twentytwentyoneSubmenuPosition( li ) {
  43      var subMenu = li.querySelector( 'ul.sub-menu' ),
  44          rect,
  45          right,
  46          left,
  47          windowWidth;
  48  
  49      if ( ! subMenu ) {
  50          return;
  51      }
  52  
  53      rect = subMenu.getBoundingClientRect();
  54      right = Math.round( rect.right );
  55      left = Math.round( rect.left );
  56      windowWidth = Math.round( window.innerWidth );
  57  
  58      if ( right > windowWidth ) {
  59          subMenu.classList.add( 'submenu-reposition-right' );
  60      } else if ( document.body.classList.contains( 'rtl' ) && left < 0 ) {
  61          subMenu.classList.add( 'submenu-reposition-left' );
  62      }
  63  }
  64  
  65  /**
  66   * Handle clicks on submenu toggles.
  67   *
  68   * @param {Element} el - The element.
  69   */
  70  function twentytwentyoneExpandSubMenu( el ) { // jshint ignore:line
  71      // Close other expanded items.
  72      el.closest( 'nav' ).querySelectorAll( '.sub-menu-toggle' ).forEach( function( button ) {
  73          if ( button !== el ) {
  74              button.setAttribute( 'aria-expanded', 'false' );
  75          }
  76      } );
  77  
  78      // Toggle aria-expanded on the button.
  79      twentytwentyoneToggleAriaExpanded( el, true );
  80  
  81      // On tab-away collapse the menu.
  82      el.parentNode.querySelectorAll( 'ul > li:last-child > a' ).forEach( function( linkEl ) {
  83          linkEl.addEventListener( 'blur', function( event ) {
  84              if ( ! el.parentNode.contains( event.relatedTarget ) ) {
  85                  el.setAttribute( 'aria-expanded', 'false' );
  86              }
  87          } );
  88      } );
  89  }
  90  
  91  ( function() {
  92      /**
  93       * Menu Toggle Behaviors
  94       *
  95       * @param {string} id - The ID.
  96       */
  97      var navMenu = function( id ) {
  98          var wrapper = document.body, // this is the element to which a CSS class is added when a mobile nav menu is open
  99              mobileButton = document.getElementById( id + '-mobile-menu' );
 100  
 101          if ( mobileButton ) {
 102              mobileButton.onclick = function() {
 103                  wrapper.classList.toggle( id + '-navigation-open' );
 104                  wrapper.classList.toggle( 'lock-scrolling' );
 105                  twentytwentyoneToggleAriaExpanded( mobileButton );
 106                  mobileButton.focus();
 107              };
 108          }
 109          /**
 110           * Trap keyboard navigation in the menu modal.
 111           * Adapted from TwentyTwenty
 112           */
 113          document.addEventListener( 'keydown', function( event ) {
 114              var modal, elements, selectors, lastEl, firstEl, activeEl, tabKey, shiftKey, escKey;
 115              if ( ! wrapper.classList.contains( id + '-navigation-open' ) ) {
 116                  return;
 117              }
 118  
 119              modal = document.querySelector( '.' + id + '-navigation' );
 120              selectors = 'input, a, button';
 121              elements = modal.querySelectorAll( selectors );
 122              elements = Array.prototype.slice.call( elements );
 123              tabKey = event.keyCode === 9;
 124              shiftKey = event.shiftKey;
 125              escKey = event.keyCode === 27;
 126              activeEl = document.activeElement; // eslint-disable-line @wordpress/no-global-active-element
 127              lastEl = elements[ elements.length - 1 ];
 128              firstEl = elements[0];
 129  
 130              if ( escKey ) {
 131                  event.preventDefault();
 132                  wrapper.classList.remove( id + '-navigation-open', 'lock-scrolling' );
 133                  twentytwentyoneToggleAriaExpanded( mobileButton );
 134                  mobileButton.focus();
 135              }
 136  
 137              if ( ! shiftKey && tabKey && lastEl === activeEl ) {
 138                  event.preventDefault();
 139                  firstEl.focus();
 140              }
 141  
 142              if ( shiftKey && tabKey && firstEl === activeEl ) {
 143                  event.preventDefault();
 144                  lastEl.focus();
 145              }
 146  
 147              // If there are no elements in the menu, don't move the focus
 148              if ( tabKey && firstEl === lastEl ) {
 149                  event.preventDefault();
 150              }
 151          } );
 152  
 153          /**
 154           * Close menu and scroll to anchor when an anchor link is clicked.
 155           * Adapted from TwentyTwenty.
 156           */
 157          document.addEventListener( 'click', function( event ) {
 158              // If target onclick is <a> with # within the href attribute
 159              if ( event.target.hash && event.target.hash.includes( '#' ) ) {
 160                  wrapper.classList.remove( id + '-navigation-open', 'lock-scrolling' );
 161                  twentytwentyoneToggleAriaExpanded( mobileButton );
 162                  // Wait 550 and scroll to the anchor.
 163                  setTimeout(function () {
 164                      var anchor = document.getElementById(event.target.hash.slice(1));
 165                      anchor.scrollIntoView();
 166                  }, 550);
 167              }
 168          } );
 169  
 170          document.getElementById( 'site-navigation' ).querySelectorAll( '.menu-wrapper > .menu-item-has-children' ).forEach( function( li ) {
 171              li.addEventListener( 'mouseenter', function() {
 172                  this.querySelector( '.sub-menu-toggle' ).setAttribute( 'aria-expanded', 'true' );
 173                  twentytwentyoneSubmenuPosition( li );
 174              } );
 175              li.addEventListener( 'mouseleave', function() {
 176                  this.querySelector( '.sub-menu-toggle' ).setAttribute( 'aria-expanded', 'false' );
 177              } );
 178          } );
 179      };
 180  
 181      window.addEventListener( 'load', function() {
 182          new navMenu( 'primary' );
 183      } );
 184  }() );


Generated: Mon May 17 01:00:05 2021 Cross-referenced by PHPXref 0.7.1