WordPress/wp-content/themes/twentynineteen/js/priority-menu.js

217 lines
5.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(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 = [];
/**
* Lets 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 ) {
/**
* Lets 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 );
})();