/* ------------------------------------------------------------------------- Basho theme main js file. ----------------------------------------------------------------------------- */ 'use strict'; var basho = basho || {}; /** * Offcanvas navigation. */ basho.offcanvasNavigation = { init: function() { var offcanvasNav = document.getElementById( 'offcanvas-navigation' ); if ( ! offcanvasNav ) { return; } this.shown( offcanvasNav ); this.hidden( offcanvasNav ); this.keepFocusInModal( offcanvasNav ); }, shown: function( offcanvasNav ) { // When the menu is show. UIkit.util.on( offcanvasNav, 'shown', function () { // Focus on the first menu link. offcanvasNav.querySelector( 'ul > li:first-of-type a' ).focus(); } ); }, hidden: function( offcanvasNav ) { // When the menu is hidden. UIkit.util.on( offcanvasNav, 'hidden', function () { // Focus on the navigation toggle button. document.getElementById( 'offcanvas-navigation-toggle' ).focus(); } ); }, keepFocusInModal: function( offcanvasNav ) { var _doc = document; _doc.addEventListener( 'keydown', function( event ) { var closeBtn, firstEl, lastEl, tabKey, shiftKey, enterKey, activeEl = _doc.activeElement; // body has .uk-offcanvas-container class when offcanvas menu is open. if ( activeEl && _doc.body.classList.contains( 'uk-offcanvas-container' ) ) { closeBtn = offcanvasNav.querySelector( '.uk-offcanvas-close' ); firstEl = offcanvasNav.querySelector( 'ul.offcanvas-navigation > li:first-of-type a' ); lastEl = offcanvasNav.querySelector( 'ul.offcanvas-navigation > li:last-of-type a' ); tabKey = event.code === "Tab"; shiftKey = event.shiftKey; enterKey = event.code === "Enter"; // If 'Enter' key is pressed to open sub menu, then focus on the parent node (by itself it focuses on the first nav item). if ( enterKey && activeEl.parentNode.classList.contains( 'uk-parent' ) ) { setTimeout( function() { activeEl.parentNode.querySelector( 'a' ).focus(); }, 250 ); } // If 'Tab' key is pressed when last menu item was active, then we should focus on close button. if ( ! shiftKey && tabKey && activeEl.isSameNode( lastEl ) ) { event.preventDefault(); closeBtn.focus(); } // When 'Shift' + 'Tab' keys are pressed when first element is active, then focus on close button. if ( shiftKey && tabKey && activeEl.isSameNode( firstEl ) ) { event.preventDefault(); closeBtn.focus(); } // When 'Shift' + 'Tab' keys are pressed when close button is active, on last menu element. if ( shiftKey && tabKey && activeEl.isSameNode( closeBtn ) ) { event.preventDefault(); lastEl.focus(); } } } ); } } /** * Main navigation in the navbar. */ basho.mainNavigation = { init: function() { var mainNav = document.getElementById( 'main-navigation' ); if ( ! mainNav ) { return; } this.handleKeyboardNavigation( mainNav ); }, handleKeyboardNavigation: function( mainNav ) { var _doc = document; _doc.addEventListener( 'keydown', function( event ) { var tabKey, shiftKey, arrowDownKey, arrowUpKey, enterKey, activeEl = _doc.activeElement; // If there is an active element in the document & this element is inside the navbar menu. if ( activeEl && mainNav.contains( activeEl ) ) { tabKey = event.keyCode === 9; shiftKey = event.shiftKey; arrowDownKey = event.code === "ArrowDown"; arrowUpKey = event.code === "ArrowUp"; enterKey = event.code === "Enter"; // If 'Tab' key is pressed when focus is on a parent menu item and dropdown is closed. if ( ! shiftKey && tabKey && activeEl.parentNode.classList.contains( 'menu-item-has-children' ) && ! activeEl.classList.contains( 'uk-open' ) ) { event.preventDefault(); UIkit.dropdown( activeEl.nextElementSibling ).show(); } // If 'Enter' key is pressed when focus is on a parent menu item -> visit parent link. if ( enterKey && activeEl.parentNode.classList.contains( 'menu-item-has-children' ) ) { event.preventDefault(); window.location.href = activeEl.href; } // If 'ArrowDown' key is pressed when focus is on a parent menu item and dropdown is closed -> open dropdown and focus on the first link. if ( ! shiftKey && arrowDownKey && activeEl.parentNode.classList.contains( 'menu-item-has-children' ) && ! activeEl.classList.contains( 'uk-open' ) ) { event.preventDefault(); // When dropdown menu is shown, then focus on the first link. setTimeout( function() { activeEl.nextElementSibling.querySelector( '.uk-nav > li a' ).focus(); }, 150 ); // Show the dropdown menu. UIkit.dropdown( activeEl.nextElementSibling ).show(); } // If 'Tab' key is pressed when focus is on a parent menu item and dropdown is closed -> open dropdown and focus on the first link. if ( ! shiftKey && tabKey && activeEl.parentNode.classList.contains( 'menu-item-has-children' ) && ! activeEl.classList.contains( 'uk-open' ) ) { event.preventDefault(); // When dropdown menu is shown, then focus on the first link. setTimeout( function() { activeEl.nextElementSibling.querySelector( '.uk-nav > li a' ).focus(); }, 150 ); // Show the dropdown menu. UIkit.dropdown( activeEl.nextElementSibling ).show(); } // If 'Tab' key is pressed when focus is on a last link of the dropdown sub menu -> close current sub menu & focus on the next link of the parent menu. if ( ! shiftKey && tabKey && (activeEl.parentNode == activeEl.parentNode.parentNode.lastElementChild) && activeEl.parentNode.parentNode.classList.contains('sub-menu') ) { event.preventDefault(); // When dropdown is hidden, then focus on the next link of the parent menu. setTimeout( function() { activeEl.parentNode.parentNode.parentNode.parentNode.nextElementSibling.querySelector( 'a' ).focus(); }, 150 ); // Hide dropdown. UIkit.dropdown( activeEl.parentNode.parentNode.parentNode ).hide(false); } // If 'ArrowUp' key is pressed when focus is on a first link of the dropdown sub menu -> Close sub menu and focus on the parent link. if ( ! shiftKey && arrowUpKey && (activeEl.parentNode == activeEl.parentNode.parentNode.firstElementChild) && activeEl.parentNode.parentNode.classList.contains('sub-menu') ) { event.preventDefault(); // When dropdown menu is hidden, focus on the parent menu link. setTimeout( function() { activeEl.parentNode.parentNode.parentNode.parentNode.querySelector( 'a' ).focus(); }, 150 ); // Hide dropdown. UIkit.dropdown( activeEl.parentNode.parentNode.parentNode ).hide(false); } // If 'Shift' + 'Tab' keys where pressed when focus is on a first link of the dropdown sub menu -> Close sub menu and focus on the parent link. if ( shiftKey && tabKey && (activeEl.parentNode == activeEl.parentNode.parentNode.firstElementChild) && activeEl.parentNode.parentNode.classList.contains('sub-menu') ) { event.preventDefault(); // When dropdown menu is hidden, focus on the parent menu link. setTimeout( function() { activeEl.parentNode.parentNode.parentNode.parentNode.querySelector( 'a' ).focus(); }, 150 ); // Hide dropdown. UIkit.dropdown( activeEl.parentNode.parentNode.parentNode ).hide(false); } } } ); } } /** * Search modal. */ basho.searchModal = { init: function() { this.shown(); this.hidden(); this.keepFocusInModal(); }, shown: function() { // When search modal is shown. UIkit.util.on( '#search-modal', 'shown', function () { // Focus on input field. this.querySelector( 'input[type="search"]' ).focus(); } ); }, hidden: function() { // When the menu is hidden. UIkit.util.on( '#search-modal', 'hidden', function () { // Focus on the search modal toggle button. document.getElementById( 'search-modal-toggle' ).focus(); } ); }, keepFocusInModal: function() { var _doc = document; _doc.addEventListener( 'keydown', function( event ) { var modal, input, closeBtn, submitBtn, tabKey, shiftKey, activeEl = _doc.activeElement; // html element has .uk-modal-page class when modal is shown. if ( activeEl && _doc.documentElement.classList.contains( 'uk-modal-page' ) ) { modal = _doc.getElementById( 'search-modal' ); input = modal.querySelector( 'input[type="search"]' ); closeBtn = modal.querySelector( '.uk-modal-close-full' ); submitBtn = modal.querySelector( 'input[type="submit"]' ); tabKey = event.keyCode === 9; shiftKey = event.shiftKey; // If 'Tab' key is pressed when submit button was active, then we should focus on close button. if ( ! shiftKey && tabKey && activeEl.isSameNode( submitBtn ) ) { event.preventDefault(); closeBtn.focus(); } // If 'Shift' + 'Tab' keys are pressed when search input is active, then focus on close button. if ( shiftKey && tabKey && activeEl.isSameNode( input ) ) { event.preventDefault(); closeBtn.focus(); } // When 'Shift' + 'Tab' keys are pressed when close button is active, then focus on submit button. if ( shiftKey && tabKey && activeEl.isSameNode( closeBtn ) ) { event.preventDefault(); submitBtn.focus(); } } } ); } } /** * Is the DOM ready * * this implementation is coming from https://gomakethings.com/a-native-javascript-equivalent-of-jquerys-ready-method/ * * @param {Function} fn Callback function to run. */ function bashoDomReady( fn ) { if ( typeof fn !== 'function' ) { return; } if ( document.readyState === 'interactive' || document.readyState === 'complete' ) { return fn(); } document.addEventListener( 'DOMContentLoaded', fn, false ); } bashoDomReady( function() { basho.offcanvasNavigation.init(); // Handle offcanvas navigation events. basho.mainNavigation.init(); // Handle main navigation events. basho.searchModal.init(); // Handle search modal events. } );