/** * File navigation.js. * * Handles toggling the navigation menu for small screens and enables TAB key * navigation support for dropdown menus, including keyboard accessibility. */ (function () { const siteNavigation = document.getElementById('site-navigation'); // Return early if the navigation doesn't exist. if (!siteNavigation) { return; } const button = siteNavigation.getElementsByTagName('button')[0]; // Return early if the button doesn't exist. if (typeof button === 'undefined') { return; } const menu = siteNavigation.getElementsByTagName('ul')[0]; // Hide menu toggle button if menu is empty and return early. if (typeof menu === 'undefined') { button.style.display = 'none'; return; } if (!menu.classList.contains('nav-menu')) { menu.classList.add('nav-menu'); } // Toggle the .toggled class and the aria-expanded value each time the button is clicked. button.addEventListener('click', function () { siteNavigation.classList.toggle('toggled'); const expanded = this.getAttribute('aria-expanded') === 'true' || false; this.setAttribute('aria-expanded', !expanded); }); // Also allow Enter or Space to toggle the mobile menu. button.addEventListener('keydown', function (e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); this.click(); } }); // Remove the .toggled class and set aria-expanded to false when the user clicks outside the navigation. document.addEventListener('click', function (event) { const isClickInside = siteNavigation.contains(event.target); if (!isClickInside) { siteNavigation.classList.remove('toggled'); button.setAttribute('aria-expanded', 'false'); } }); // Get all the link elements within the menu. const links = menu.getElementsByTagName('a'); // Get all the link elements with children within the menu. const linksWithChildren = menu.querySelectorAll('.menu-item-has-children > a, .page_item_has_children > a'); // Set ARIA attributes and add keyboard toggle for submenus. linksWithChildren.forEach(link => { link.setAttribute('aria-haspopup', 'true'); link.setAttribute('aria-expanded', 'false'); link.addEventListener('keydown', function (e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); const submenu = this.nextElementSibling; if (submenu && submenu.classList.contains('sub-menu')) { const expanded = this.getAttribute('aria-expanded') === 'true' || false; this.setAttribute('aria-expanded', !expanded); submenu.classList.toggle('toggled'); // Close other open submenus const otherSubmenus = menu.querySelectorAll('.sub-menu.toggled'); otherSubmenus.forEach(otherSubmenu => { if (otherSubmenu !== submenu) { otherSubmenu.classList.remove('toggled'); const otherLink = otherSubmenu.previousElementSibling; if (otherLink && otherLink.tagName === 'A') { otherLink.setAttribute('aria-expanded', 'false'); } } }); } } }); }); // Toggle focus each time a menu link is focused or blurred. for (const link of links) { link.addEventListener('focus', toggleFocus, true); link.addEventListener('blur', toggleFocus, true); } // Toggle focus each time a menu link with children receives a touch event. for (const link of linksWithChildren) { link.addEventListener('touchstart', toggleFocus, false); } /** * Sets or removes .focus class on an element. */ function toggleFocus(event) { if (event.type === 'focus' || event.type === 'blur') { let self = this; // Move up through the ancestors of the current link until we hit .nav-menu. while (!self.classList.contains('nav-menu')) { // On li elements toggle the class .focus. if (self.tagName.toLowerCase() === 'li') { self.classList.toggle('focus'); } self = self.parentNode; } } if (event.type === 'touchstart') { const menuItem = this.parentNode; event.preventDefault(); for (const link of menuItem.parentNode.children) { if (menuItem !== link) { link.classList.remove('focus'); } } menuItem.classList.toggle('focus'); } } })();