source:
branches/5.0/src/wp-content/themes/twentynineteen/js/priority-menu.js
@
43904
Last change on this file since 43904 was 43904, checked in by , 6 years ago | |
---|---|
File size: 4.7 KB |
Line | |
---|---|
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 - 50; |
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 | * Refreshes the list item from the menu depending on the menu size |
101 | */ |
102 | function updateNavigationMenu( container ) { |
103 | |
104 | // Adds the necessary UI to operate the menu. |
105 | var visibleList = container.parentNode.querySelector('.main-menu[id]'); |
106 | var hiddenList = visibleList.parentNode.nextElementSibling.querySelector('.hidden-links'); |
107 | var toggleButton = visibleList.parentNode.nextElementSibling.querySelector('.main-menu-more-toggle'); |
108 | |
109 | if ( isOverflowingNavivation( visibleList, toggleButton, container ) ) { |
110 | |
111 | // Record the width of the list |
112 | breaks.push( visibleList.offsetWidth ); |
113 | // Move last item to the hidden list |
114 | prependElement( hiddenList, ! visibleList.lastChild || null === visibleList.lastChild ? visibleList.previousElementSibling : visibleList.lastChild ); |
115 | // Show the toggle button |
116 | showButton( toggleButton ); |
117 | |
118 | } else { |
119 | |
120 | // There is space for another item in the nav |
121 | if ( getAvailableSpace( toggleButton, container ) > breaks[breaks.length - 1] ) { |
122 | // Move the item to the visible list |
123 | visibleList.appendChild( hiddenList.firstChild.nextSibling ); |
124 | breaks.pop(); |
125 | } |
126 | |
127 | // Hide the dropdown btn if hidden list is empty |
128 | if (breaks.length < 2) { |
129 | hideButton( toggleButton ); |
130 | } |
131 | } |
132 | |
133 | // Recur if the visible list is still overflowing the nav |
134 | if ( isOverflowingNavivation( visibleList, toggleButton, container ) ) { |
135 | updateNavigationMenu( container ); |
136 | } |
137 | } |
138 | |
139 | /** |
140 | * Run our priority+ function as soon as the document is `ready` |
141 | */ |
142 | document.addEventListener( 'DOMContentLoaded', function() { |
143 | |
144 | updateNavigationMenu( navContainer ); |
145 | |
146 | // Also, run our priority+ function on selective refresh in the customizer |
147 | var hasSelectiveRefresh = ( |
148 | 'undefined' !== typeof wp && |
149 | wp.customize && |
150 | wp.customize.selectiveRefresh |
151 | ); |
152 | |
153 | if ( hasSelectiveRefresh ) { |
154 | // Force a full refresh on partial content renders to re-run updateNavigationMenu() |
155 | wp.customize.selectiveRefresh.bind('partial-content-rendered', function () { |
156 | wp.customize.preview.send('refresh'); |
157 | }); |
158 | } |
159 | }); |
160 | |
161 | /** |
162 | * Run our priority+ function on load |
163 | */ |
164 | window.addEventListener('load', function() { |
165 | updateNavigationMenu( navContainer ); |
166 | }); |
167 | |
168 | /** |
169 | * Run our priority+ function every time the window resizes |
170 | */ |
171 | var isResizing = false; |
172 | window.addEventListener( 'resize', |
173 | debounce( function() { |
174 | if ( isResizing ) { |
175 | return; |
176 | } |
177 | |
178 | isResizing = true; |
179 | setTimeout( function() { |
180 | updateNavigationMenu( navContainer ); |
181 | isResizing = false; |
182 | }, 150 ); |
183 | } ) |
184 | ); |
185 | |
186 | /** |
187 | * Run our priority+ function |
188 | */ |
189 | updateNavigationMenu( navContainer ); |
190 | |
191 | })(); |
Note: See TracBrowser
for help on using the repository browser.