(function() { /** * Debounce. * * @param {Function} func * @param {number} wait * @param {boolean} immediate */ function debounce(func, wait, immediate) { 'use strict'; var timeout; wait = (typeof wait !== 'undefined') ? wait : 20; immediate = (typeof immediate !== 'undefined') ? immediate : true; return function() { var context = this, args = arguments; var later = function() { timeout = null; if (!immediate) { func.apply(context, args); } }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) { func.apply(context, args); } }; } /** * Prepends an element to a container. * * @param {Element} container * @param {Element} element */ function prependElement(container, element) { if (container.firstChild.nextSibling) { return container.insertBefore(element, container.firstChild.nextSibling); } else { return container.appendChild(element); } } /** * Shows an element by adding a hidden className. * * @param {Element} element */ function showButton(element) { // classList.remove is not supported in IE11. element.className = element.className.replace('is-empty', ''); } /** * Hides an element by removing the hidden className. * * @param {Element} element */ function hideButton(element) { // classList.add is not supported in IE11. if (!element.classList.contains('is-empty')) { element.className += ' is-empty'; } } /** * Returns the currently available space in the menu container. * * @returns {number} Available space */ function getAvailableSpace( button, container ) { return container.offsetWidth - button.offsetWidth - 22; } /** * Returns whether the current menu is overflowing or not. * * @returns {boolean} Is overflowing */ function isOverflowingNavivation( list, button, container ) { return list.offsetWidth > getAvailableSpace( button, container ); } /** * Set menu container variable. */ var navContainer = document.querySelector('.main-navigation'); var breaks = []; /** * Let’s bail if we our menu doesn't exist. */ if ( ! navContainer ) { return; } /** * Refreshes the list item from the menu depending on the menu size. */ function updateNavigationMenu( container ) { /** * Let’s bail if our menu is empty. */ if ( ! container.parentNode.querySelector('.main-menu[id]') ) { return; } // Adds the necessary UI to operate the menu. var visibleList = container.parentNode.querySelector('.main-menu[id]'); var hiddenList = visibleList.parentNode.nextElementSibling.querySelector('.hidden-links'); var toggleButton = visibleList.parentNode.nextElementSibling.querySelector('.main-menu-more-toggle'); if ( isOverflowingNavivation( visibleList, toggleButton, container ) ) { // Record the width of the list. breaks.push( visibleList.offsetWidth ); // Move last item to the hidden list. prependElement( hiddenList, ! visibleList.lastChild || null === visibleList.lastChild ? visibleList.previousElementSibling : visibleList.lastChild ); // Show the toggle button. showButton( toggleButton ); } else { // There is space for another item in the nav. if ( getAvailableSpace( toggleButton, container ) > breaks[breaks.length - 1] ) { // Move the item to the visible list. visibleList.appendChild( hiddenList.firstChild.nextSibling ); breaks.pop(); } // Hide the dropdown btn if hidden list is empty. if (breaks.length < 2) { hideButton( toggleButton ); } } // Recur if the visible list is still overflowing the nav. if ( isOverflowingNavivation( visibleList, toggleButton, container ) ) { updateNavigationMenu( container ); } } /** * Run our priority+ function as soon as the document is `ready`. */ document.addEventListener( 'DOMContentLoaded', function() { updateNavigationMenu( navContainer ); // Also, run our priority+ function on selective refresh in the customizer. var hasSelectiveRefresh = ( 'undefined' !== typeof wp && wp.customize && wp.customize.selectiveRefresh && wp.customize.navMenusPreview.NavMenuInstancePartial ); if ( hasSelectiveRefresh ) { // Re-run our priority+ function on Nav Menu partial refreshes. wp.customize.selectiveRefresh.bind( 'partial-content-rendered', function ( placement ) { var isNewNavMenu = ( placement && placement.partial.id.includes( 'nav_menu_instance' ) && 'null' !== placement.container[0].parentNode && placement.container[0].parentNode.classList.contains( 'main-navigation' ) ); if ( isNewNavMenu ) { updateNavigationMenu( placement.container[0].parentNode ); } }); } }); /** * Run our priority+ function on load. */ window.addEventListener( 'load', function() { updateNavigationMenu( navContainer ); }); /** * Run our priority+ function every time the window resizes. */ var isResizing = false; window.addEventListener( 'resize', debounce( function() { if ( isResizing ) { return; } isResizing = true; setTimeout( function() { updateNavigationMenu( navContainer ); isResizing = false; }, 150 ); } ) ); /** * Run our priority+ function. */ updateNavigationMenu( navContainer ); })();