angelovcom.net

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

priority-menu.js (5375B)


      1 (function() {
      2 
      3 	/**
      4 	 * Debounce.
      5 	 *
      6 	 * @param {Function} func
      7 	 * @param {number} wait
      8 	 * @param {boolean} immediate
      9 	 */
     10 	function debounce(func, wait, immediate) {
     11 		'use strict';
     12 
     13 		var timeout;
     14 		wait      = (typeof wait !== 'undefined') ? wait : 20;
     15 		immediate = (typeof immediate !== 'undefined') ? immediate : true;
     16 
     17 		return function() {
     18 
     19 			var context = this, args = arguments;
     20 			var later = function() {
     21 				timeout = null;
     22 
     23 				if (!immediate) {
     24 					func.apply(context, args);
     25 				}
     26 			};
     27 
     28 			var callNow = immediate && !timeout;
     29 
     30 			clearTimeout(timeout);
     31 			timeout = setTimeout(later, wait);
     32 
     33 			if (callNow) {
     34 				func.apply(context, args);
     35 			}
     36 		};
     37 	}
     38 
     39 	/**
     40 	 * Prepends an element to a container.
     41 	 *
     42 	 * @param {Element} container
     43 	 * @param {Element} element
     44 	 */
     45 	function prependElement(container, element) {
     46 		if (container.firstChild.nextSibling) {
     47 			return container.insertBefore(element, container.firstChild.nextSibling);
     48 		} else {
     49 			return container.appendChild(element);
     50 		}
     51 	}
     52 
     53 	/**
     54 	 * Shows an element by adding a hidden className.
     55 	 *
     56 	 * @param {Element} element
     57 	 */
     58 	function showButton(element) {
     59 		// classList.remove is not supported in IE11.
     60 		element.className = element.className.replace('is-empty', '');
     61 	}
     62 
     63 	/**
     64 	 * Hides an element by removing the hidden className.
     65 	 *
     66 	 * @param {Element} element
     67 	 */
     68 	function hideButton(element) {
     69 		// classList.add is not supported in IE11.
     70 		if (!element.classList.contains('is-empty')) {
     71 			element.className += ' is-empty';
     72 		}
     73 	}
     74 
     75 	/**
     76 	 * Returns the currently available space in the menu container.
     77 	 *
     78 	 * @returns {number} Available space
     79 	 */
     80 	function getAvailableSpace( button, container ) {
     81 		return container.offsetWidth - button.offsetWidth - 22;
     82 	}
     83 
     84 	/**
     85 	 * Returns whether the current menu is overflowing or not.
     86 	 *
     87 	 * @returns {boolean} Is overflowing
     88 	 */
     89 	function isOverflowingNavivation( list, button, container ) {
     90 		return list.offsetWidth > getAvailableSpace( button, container );
     91 	}
     92 
     93 	/**
     94 	 * Set menu container variable.
     95 	 */
     96 	var navContainer = document.querySelector('.main-navigation');
     97 	var breaks       = [];
     98 
     99 	/**
    100 	 * Let’s bail if we our menu doesn't exist.
    101 	 */
    102 	if ( ! navContainer ) {
    103 		return;
    104 	}
    105 
    106 	/**
    107 	 * Refreshes the list item from the menu depending on the menu size.
    108 	 */
    109 	function updateNavigationMenu( container ) {
    110 
    111 		/**
    112 		 * Let’s bail if our menu is empty.
    113 		 */
    114 		if ( ! container.parentNode.querySelector('.main-menu[id]') ) {
    115 			return;
    116 		}
    117 
    118 		// Adds the necessary UI to operate the menu.
    119 		var visibleList  = container.parentNode.querySelector('.main-menu[id]');
    120 		var hiddenList   = visibleList.parentNode.nextElementSibling.querySelector('.hidden-links');
    121 		var toggleButton = visibleList.parentNode.nextElementSibling.querySelector('.main-menu-more-toggle');
    122 
    123 		if ( isOverflowingNavivation( visibleList, toggleButton, container ) ) {
    124 
    125 			// Record the width of the list.
    126 			breaks.push( visibleList.offsetWidth );
    127 			// Move last item to the hidden list.
    128 			prependElement( hiddenList, ! visibleList.lastChild || null === visibleList.lastChild ? visibleList.previousElementSibling : visibleList.lastChild );
    129 			// Show the toggle button.
    130 			showButton( toggleButton );
    131 
    132 		} else {
    133 
    134 			// There is space for another item in the nav.
    135 			if ( getAvailableSpace( toggleButton, container ) > breaks[breaks.length - 1] ) {
    136 				// Move the item to the visible list.
    137 				visibleList.appendChild( hiddenList.firstChild.nextSibling );
    138 				breaks.pop();
    139 			}
    140 
    141 			// Hide the dropdown btn if hidden list is empty.
    142 			if (breaks.length < 2) {
    143 				hideButton( toggleButton );
    144 			}
    145 		}
    146 
    147 		// Recur if the visible list is still overflowing the nav.
    148 		if ( isOverflowingNavivation( visibleList, toggleButton, container ) ) {
    149 			updateNavigationMenu( container );
    150 		}
    151 	}
    152 
    153 	/**
    154 	 * Run our priority+ function as soon as the document is `ready`.
    155 	 */
    156 	document.addEventListener( 'DOMContentLoaded', function() {
    157 
    158 		updateNavigationMenu( navContainer );
    159 
    160 		// Also, run our priority+ function on selective refresh in the customizer.
    161 		var hasSelectiveRefresh = (
    162 			'undefined' !== typeof wp &&
    163 			wp.customize &&
    164 			wp.customize.selectiveRefresh &&
    165 			wp.customize.navMenusPreview.NavMenuInstancePartial
    166 		);
    167 
    168 		if ( hasSelectiveRefresh ) {
    169 			// Re-run our priority+ function on Nav Menu partial refreshes.
    170 			wp.customize.selectiveRefresh.bind( 'partial-content-rendered', function ( placement ) {
    171 
    172 				var isNewNavMenu = (
    173 					placement &&
    174 					placement.partial.id.includes( 'nav_menu_instance' ) &&
    175 					'null' !== placement.container[0].parentNode &&
    176 					placement.container[0].parentNode.classList.contains( 'main-navigation' )
    177 				);
    178 
    179 				if ( isNewNavMenu ) {
    180 					updateNavigationMenu( placement.container[0].parentNode );
    181 				}
    182 			});
    183         }
    184 	});
    185 
    186 	/**
    187 	 * Run our priority+ function on load.
    188 	 */
    189 	window.addEventListener( 'load', function() {
    190 		updateNavigationMenu( navContainer );
    191 	});
    192 
    193 	/**
    194 	 * Run our priority+ function every time the window resizes.
    195 	 */
    196 	var isResizing = false;
    197 	window.addEventListener( 'resize',
    198 		debounce( function() {
    199 			if ( isResizing ) {
    200 				return;
    201 			}
    202 
    203 			isResizing = true;
    204 			setTimeout( function() {
    205 				updateNavigationMenu( navContainer );
    206 				isResizing = false;
    207 			}, 150 );
    208 		} )
    209 	);
    210 
    211 	/**
    212 	 * Run our priority+ function.
    213 	 */
    214 	updateNavigationMenu( navContainer );
    215 
    216 })();