PageSourceSearch

https://typischich.at/wp-content/themes/minimer/js/nav.js?ver=1677669132

js typischich.at collected 2026-10-02 13:40:18 UTC 9,107 bytes, 319 lines download raw bytes

1/**
2 * Polyfill for IE11 - adds NodeList.foreach().
3 *
4 * @see https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach
5 */
6if ( window.NodeList && ! NodeList.prototype.forEach ) {
7    NodeList.prototype.forEach = function( callback, thisArg ) {
8        thisArg = thisArg || window;
9        for ( var i = 0; i < this.length; i++ ) { // eslint-disable-line vars-on-top
10            callback.call( thisArg, this[ i ], i, this );
11        }
12    };
13}
14
15window.alxMediaMenu = {
16
17	/**
18	 *
19	 * @param {Object} args - The arguments.
20	 * @param {string} args.selector - The navigation selector.
21	 * @param {int}    args.breakpoint - The breakpoint in pixels.
22	 */
23	init: function( args ) {
24		var self = this,
25			navs = document.querySelectorAll( args.selector );
26
27		if ( ! navs.length ) {
28			return;
29		}
30
31		navs.forEach( function( nav ) {
32			var menuToggler = nav.querySelector( '.menu-toggle' );
33
34			// Hide menu toggle button if menu is empty and return early.
35			if ( ! nav.querySelector( 'ul' ) && nav.querySelector( '.menu-toggle' ) ) {
36				nav.querySelector( '.menu-toggle' ).style.display = 'none';
37			}
38
39			// Add nav-menu class.
40			if ( ! nav.classList.contains( 'nav-menu' ) ) {
41				nav.classList.add( 'nav-menu' );
42			}
43
44			// Toggle the hover event listeners.
45			self.toggleHoverEventListeners( nav );
46
47			// Toggle focus classes on links.
48			nav.querySelectorAll( 'a,button' ).forEach( function( link ) {
49				link.addEventListener( 'focus', window.alxMediaMenu.toggleFocus, true );
50				link.addEventListener( 'blur', window.alxMediaMenu.toggleFocus, true );
51			});
52
53			menuToggler.addEventListener( 'click', function() {
54				if ( nav.classList.contains( 'toggled' ) ) {
55					menuToggler.setAttribute( 'aria-expanded', 'false' );
56					nav.classList.remove( 'toggled' );
57				} else {
58					menuToggler.setAttribute( 'aria-expanded', 'true' );
59					nav.classList.add( 'toggled' );
60				}
61			});
62
63			// If on mobile nav, close it when clicking outside.
64			// If on desktop, close expanded submenus when clicking outside.
65			document.addEventListener( 'click', function( event ) {
66				if ( ! nav.contains( event.target ) ) {
67
68					// Mobile.
69					nav.classList.remove( 'toggled' );
70
71					// Desktop.
72					nav.querySelectorAll( 'button.active,.sub-menu.active' ).forEach( function( el ) {
73						el.classList.remove( 'active' );
74					});
75
76					menuToggler.setAttribute( 'aria-expanded', 'false' );
77				}
78			});
79		});
80
81		// Toggle mobile classes on initial load.
82		window.alxMediaMenu.toggleMobile( args.selector, args.breakpoint );
83
84		// Toggle mobile classes on resize.
85		window.addEventListener( 'resize', function() {
86
87			// If timer is null, reset it to our bounceDelay and run, otherwise wait until timer is cleared.
88			if ( ! window.resizeDebouncedTimeout ) {
89				window.resizeDebouncedTimeout = setTimeout( function() {
90					window.resizeDebouncedTimeout = null;
91					window.alxMediaMenu.toggleMobile( args.selector, args.breakpoint );
92				}, 250 );
93			}
94		});
95
96		// Toggle focus classes to allow submenu access on tables.
97		document.querySelectorAll( args.selector ).forEach( function( el ) {
98			window.alxMediaMenu.toggleFocusTouch( el );
99		});
100	},
101
102	/**
103	 * Expand a menu item.
104	 *
105	 * @param {Element} - The menu item (DOM element).
106	 * @return {void}
107	 */
108	toggleItem: function( el ) {
109		var parentLi = this.helper.firstAncestorMatch( el, 'li' ),
110			parentUl = this.helper.firstAncestorMatch( el, 'ul' ),
111			ul = parentLi.querySelector( 'ul.sub-menu' );
112
113		parentLi.classList.remove( 'hover' );
114
115		ul.setAttribute( 'tabindex', '-1' );
116		this.helper.toggleClass( ul, 'active' );
117		this.helper.toggleClass( el, 'active' );
118
119		// Go one level up in the list, and close other items that are already open.
120		parentUl.querySelectorAll( 'ul.sub-menu' ).forEach( function( subMenu ) {
121			var subMenuButton;
122			if ( ! parentLi.contains( subMenu ) ) {
123				subMenu.classList.remove( 'active' );
124				subMenuButton = subMenu.parentNode.querySelector( 'button.active' );
125				if ( subMenuButton ) {
126					subMenuButton.classList.remove( 'active' );
127				}
128			}
129		});
130	},
131
132	/**
133	 * Toggles a mobile class to elements matching our selector,
134	 * depending on the defined breakpoint.
135	 *
136	 * @param {string} selector - The elements where we want to toggle our mobile class.
137	 * @param {string} className - The class-name we want to toggle.
138	 * @param {int} breakpoint - The breakpoint.
139	 * @return {void}
140	 */
141	toggleMobile: function( selector, breakpoint ) {
142		var self = this,
143			screenWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
144			navs = document.body.querySelectorAll( selector ),
145			isMobile;
146
147		breakpoint = breakpoint || 720;
148		isMobile = breakpoint > screenWidth;
149
150		if ( isMobile ) {
151			navs.forEach( function( nav ) {
152				if ( ! nav.classList.contains( 'mobile' ) ) {
153					nav.classList.add( 'mobile' );
154					self.toggleHoverEventListeners( nav );
155				}
156			});
157		} else {
158			navs.forEach( function( nav ) {
159				if ( nav.classList.contains( 'mobile' ) ) {
160					nav.classList.remove( 'mobile' );
161					self.toggleHoverEventListeners( nav );
162				}
163			});
164		}
165	},
166
167	/**
168	 * Add a "hover" class.
169	 *
170	 * @return {void}
171	 */
172	liMouseEnterEvent: function() {
173		this.classList.add( 'hover' );
174	},
175
176	/**
177	 * Remove the "hover" class.
178	 *
179	 * @return {void}
180	 */
181	liMouseLeaveEvent: function() {
182		this.classList.remove( 'hover' );
183	},
184
185	/**
186	 *
187	 * @param {Element} nav - The nav element.
188	 * @return {void}
189	 */
190	toggleHoverEventListeners: function( nav ) {
191		if ( nav.classList.contains( 'mobile' ) ) {
192			this.removeHoverEventListeners( nav );
193		} else {
194			this.addHoverEventListeners( nav );
195		}
196	},
197
198	/**
199	 * Add event-listeners for hover events.
200	 *
201	 * @param {Element} nav - The nav element.
202	 * @return {void}
203	 */
204	addHoverEventListeners: function( nav ) {
205		nav.querySelectorAll( 'li' ).forEach( function( li ) {
206			li.addEventListener( 'mouseenter', window.alxMediaMenu.liMouseEnterEvent );
207			li.addEventListener( 'mouseleave', window.alxMediaMenu.liMouseLeaveEvent );
208		});
209	},
210
211	/**
212	 * Remove event-listeners for hover events.
213	 *
214	 * @param {Element} nav - The nav element.
215	 * @return {void}
216	 */
217	removeHoverEventListeners: function( nav ) {
218		nav.querySelectorAll( 'li' ).forEach( function( li ) {
219			li.removeEventListener( 'mouseenter', window.alxMediaMenu.liMouseEnterEvent );
220			li.removeEventListener( 'mouseleave', window.alxMediaMenu.liMouseLeaveEvent );
221		});
222	},
223
224	/**
225	 * Sets or removes .focus class on an element.
226	 *
227	 * @return {void}
228	 */
229	toggleFocus: function() {
230		var self = this;
231
232		// Move up through the ancestors of the current link until we hit .nav-menu.
233		while ( -1 === self.className.indexOf( 'nav-menu' ) ) {
234			// On li elements toggle the class .focus.
235			if ( 'li' === self.tagName.toLowerCase() ) {
236				if ( -1 !== self.className.indexOf( 'focus' ) ) {
237					self.className = self.className.replace( ' focus', '' );
238				} else {
239					self.className += ' focus';
240				}
241			}
242
243			self = self.parentElement;
244		}
245	},
246
247	/**
248	 * Toggle focus classes to allow submenu access on tables.
249	 *
250	 * @param {Element} el - The menu element.
251	 * @return {void}
252	 */
253	toggleFocusTouch: function( el ) {
254		var touchStartFn,
255			parentLinks = el.querySelectorAll( '.menu-item-has-children > a, .page_item_has_children > a' );
256
257		if ( 'ontouchstart' in window ) {
258			touchStartFn = function( e ) {
259				var menuItem = this.parentNode;
260
261				if ( ! menuItem.classList.contains( 'focus' ) ) {
262					e.preventDefault();
263					menuItem.parentNode.children.forEach( function( child ) {
264						if ( menuItem !== child ) {
265							child.classList.remove( 'focus' );
266						}
267					});
268					menuItem.classList.add( 'focus' );
269				} else {
270					menuItem.classList.remove( 'focus' );
271				}
272			};
273
274			parentLinks.forEach( function( parentLink ) {
275				parentLink.addEventListener( 'touchstart', touchStartFn, false );
276			});
277		}
278	},
279
280	/**
281	 * Helper methods.
282	 */
283	helper: {
284
285		/**
286		 * Toggle a class to an element.
287		 *
288		 * @param {Element} el - The element.
289		 * @param {string} className - The class we want to toggle.
290		 * @return {void}
291		 */
292		toggleClass: function( el, className ) {
293			if ( el.classList.contains( className ) ) {
294				el.classList.remove( className );
295			} else {
296				el.classList.add( className );
297			}
298		},
299
300		/**
301		 * Get the 1st ancestor of an element that matches our selector.
302		 *
303		 * @param {Element} el - The element.
304		 * @param {string} selector - The class we want to toggle.
305		 * @return {Element}
306		 */
307		firstAncestorMatch: function( el, selector ) {
308			if ( el.parentNode.matches( selector ) ) {
309				return el.parentNode;
310			}
311			return this.firstAncestorMatch( el.parentNode, selector );
312		}
313	}
314};
315
316window.alxMediaMenu.init({
317	selector: '.main-navigation.nav-menu',
318	breakpoint: 720
319});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.