PageSourceSearch

https://kohdistamo.fi/wp-content/plugins/jet-menu/assets/public/js/jet-menu-public-scripts.js?ver=2.4.16

js kohdistamo.fi collected 2026-10-02 00:36:29 UTC 60,698 bytes, 1,881 lines download raw bytes

1( function( $ ) {
2	'use strict';
3
4	/**
5	 * JetMegaMenuClass
6	 */
7	class JetMegaMenuClass {
8
9		/**
10		 * [constructor description]
11		 * @return {[type]} [description]
12		 */
13		constructor( instance, options ) {
14			this.defaultSettings = {
15				menuId: '0',
16				menuUniqId: window.jetMenu.getUniqId(),
17				layout: 'horizontal',
18				subTrigger: 'item', // item, submarker
19				subEvent: 'click', // hover, click
20				subCloseBehavior: 'mouseleave', // mouseleave, outside
21				bottomGap: 12,
22				rollUp: true,
23				breakpoint: 768, // Minimal menu width, when this plugin activates
24				mouseLeaveDelay: 500,
25				megaWidthType: 'container',
26				megaWidthSelector: '',
27				megaAjaxLoad: false,
28				classes: {
29					instance: 'menu',
30					menuContainer: 'menu-container',
31					menuList: 'menu-list',
32					menuItem: 'menu-item',
33					menuItemLink: 'menu-item__link',
34					subMenuContainer: 'sub-menu',
35					subMenuList: 'sub-menu__list',
36					megaContainer: 'mega-container',
37				}
38			}
39
40			this.$instance = $( instance );
41			this.settings = $.extend( this.defaultSettings, options );
42			this.$window = $( window );
43			this.$document = $( document );
44			this.$body = $( 'body' );
45			this.isRTL = this.$body.hasClass( 'rtl' );
46			this.isDropdownState = false;
47
48			this._prevViewportWidth = window.innerWidth || document.documentElement.clientWidth;
49
50			this.isContentLoading   = false;
51			this._pendingMouseleave = false;
52
53			this.createInstance();
54		}
55
56		createInstance() {
57			this.$menuList = $( `.${ this.settings.classes.menuList }`, this.$instance );
58			this.$menuItems = $( `>.${ this.settings.classes.menuItem }:not(.${ this.settings.classes.menuItem }--roll-up)`, this.$menuList );
59			this.$rollUpItem = $( `>.${ this.settings.classes.menuItem }--roll-up`, this.$menuList );
60
61			this.menuItemsData = this.$menuItems.toArray().map( function( item ) {
62				return {
63					element: item,
64					outerWidth: $( item ).outerWidth( true ),
65					offsetLeft: $( item )[0].offsetLeft,
66				}
67			} );
68
69			this.initWatcher( 50 );
70			this.initEvents();
71			this.maybeRollUpItems();
72			this.rebuildSubContainers();
73
74			document.addEventListener( 'DOMContentLoaded', ( event ) => {
75				setTimeout( () => {
76					this.watchTick();
77				}, 250 );
78			} );
79
80			this.$instance.addClass( `${ this.settings.classes.instance }--inited` );
81			this.$document.trigger( 'JetMegaMenuInited' );
82		}
83
84		initEvents() {
85			let debounceTimer,
86				eventHandler = 'JetMegaMenu',
87				$itemTargetSelector = 'item' === this.settings.subTrigger ? `.${ this.settings.classes.menuItem } > .${ this.settings.classes.menuItem }__inner` : `.${ this.settings.classes.menuItem } > .${ this.settings.classes.menuItem }__inner .${ this.settings.classes.menuItem }__dropdown`;
88
89			const subCloseBehavior   = this.settings.subCloseBehavior || 'mouseleave';
90			const isHoverMode        = this.settings.subEvent === 'hover';
91			const isClickMode        = this.settings.subEvent === 'click';
92			const shouldCloseOnLeave = isHoverMode || ( isClickMode && subCloseBehavior === 'mouseleave' );
93			const shouldCloseOnOutside = isClickMode && subCloseBehavior === 'outside';
94
95			const clearInlineScroll = ( $root ) => {
96				$root
97					.find( `.${ this.settings.classes.subMenuContainer }, .${ this.settings.classes.megaContainer }` )
98					.each( (_, wrap) => {
99						const $wrap  = $( wrap );
100						const $list  = $wrap.children( `.${ this.settings.classes.subMenuList }:first` );
101						const $inner = $wrap.children( `.${ this.settings.classes.megaContainer }__inner:first` );
102						$wrap.add( $list ).add( $inner ).css( { 'max-height':'', 'overflow-y':'', 'overflow-x':'' } );
103					});
104			};
105
106			switch ( this.settings.subEvent ) {
107				case 'hover':
108					this.$instance.on( `mouseenter.${ eventHandler }`, `.${ this.settings.classes.menuItem } > .${ this.settings.classes.menuItem }__inner`, { instance: this }, ( event ) => {
109						let $target       = $( event.target ),
110							$menuItem     = $target.parents( `.${ this.settings.classes.menuItem }` ),
111							$subContainer = $( `.${ this.settings.classes.subMenuContainer }:first, .${ this.settings.classes.megaContainer }:first`, $menuItem ),
112							templateContent = $subContainer.data( 'template-content' ) || false,
113							templateId    = $subContainer.data( 'template-id' ) || false;
114
115						$( `.${ this.settings.classes.menuItem }--hover`, this.$instance ).removeClass( `${ this.settings.classes.menuItem }--hover` );
116
117						if ( $menuItem.hasClass( `${ this.settings.classes.menuItem }-has-children` ) ) {
118							$menuItem.addClass( `${ this.settings.classes.menuItem }--hover` );
119
120							if ( $menuItem.hasClass( `${ this.settings.classes.menuItem }--top-level` ) ) {
121								this.applySmartScroll( $menuItem );
122							}
123
124							$menuItem
125								.find( '[role="button"][aria-haspopup="true"]' )
126								.attr( 'aria-expanded', 'true' );
127
128							if ( templateId ) {
129								this.maybeTemplateLoad( templateId, templateContent, $subContainer );
130							}
131						}
132					} );
133
134					this.$instance.on( `mouseleave.${ eventHandler }`, `.${ this.settings.classes.menuItem } > .${ this.settings.classes.menuItem }__inner`, ( event ) => { /* Item Mouse Leave Event */ } );
135					break;
136
137				case 'click':
138
139					this.$instance.on( `click.${ eventHandler }`, $itemTargetSelector, ( event ) => {
140						event.preventDefault();
141						event.stopPropagation();
142
143						let $currentTarget  = $( event.currentTarget ),
144						    $menuItem       = $currentTarget.closest( `.${this.settings.classes.menuItem}` ),
145						    $menuItemLink   = $( '.jet-mega-menu-item__link', $menuItem ).first(),
146						    $siblingsItems  = $menuItem.siblings( `.${this.settings.classes.menuItem}-has-children` ),
147						    $subContainer   = $( `.${this.settings.classes.subMenuContainer}:first, .${this.settings.classes.megaContainer}`, $menuItem ),
148						    templateContent = $subContainer.data( 'template-content' ) || false,
149						    templateId      = $subContainer.data( 'template-id' ) || false;
150
151						if ( $siblingsItems.length ) {
152							$siblingsItems.removeClass( `${ this.settings.classes.menuItem }--hover` );
153							$( `.${ this.settings.classes.menuItem }-has-children`, $siblingsItems ).removeClass( `${ this.settings.classes.menuItem }--hover` );
154						}
155
156						if ( $menuItem.hasClass( `${ this.settings.classes.menuItem }-has-children` ) ) {
157							if ( ! $menuItem.hasClass( `${ this.settings.classes.menuItem }--hover` ) ) {
158								$menuItem.addClass( `${ this.settings.classes.menuItem }--hover` );
159
160								$menuItem
161									.find( '[role="button"][aria-haspopup="true"]' )
162									.attr( 'aria-expanded', 'true' );
163
164							} else {
165								$menuItem.removeClass( `${ this.settings.classes.menuItem }--hover` );
166
167								$menuItem
168									.find( '[role="button"][aria-haspopup="true"]' )
169									.attr( 'aria-expanded', 'false' );
170							}
171
172							if ( templateId ) {
173								this.maybeTemplateLoad( templateId, templateContent, $subContainer );
174							}
175
176							if ( $menuItem.hasClass( `${ this.settings.classes.menuItem }--top-level` )
177								&& $menuItem.hasClass( `${ this.settings.classes.menuItem }--hover`) ) {
178								this.applySmartScroll( $menuItem );
179							}
180
181						} else {
182							let itemLink = $menuItemLink.attr( 'href' ) || '#',
183							    target   = $menuItemLink.attr( 'target' ) || '_self';
184
185							window.open( itemLink, target );
186
187							return false;
188						}
189					} );
190					break;
191			}
192
193			this.$instance.on( `mouseenter.${ eventHandler }`, `.${ this.settings.classes.subMenuContainer }, .${ this.settings.classes.megaContainer }`, ( event ) => {
194				clearTimeout( debounceTimer );
195			} );
196
197			this.$instance.on( `mouseenter.${ eventHandler }`, ( event ) => {
198				clearTimeout( debounceTimer );
199			} );
200
201			this.$instance.on( `mouseleave.${ eventHandler }`, ( event ) => {
202
203				if ( ! shouldCloseOnLeave ) {
204					return;
205				}
206
207				if ( this.isContentLoading ) {
208					clearTimeout( debounceTimer );
209					this._pendingMouseleave = true;
210
211					return;
212				}
213
214				debounceTimer = setTimeout( () => {
215					$( `.${ this.settings.classes.menuItem }--hover`, this.$instance ).removeClass( `${ this.settings.classes.menuItem }--hover` );
216
217					this.$instance
218						.find( '[role="button"][aria-haspopup="true"]' )
219						.attr( 'aria-expanded', 'false' );
220
221					clearInlineScroll( this.$instance );
222				}, this.settings.mouseLeaveDelay );
223			} );
224
225			this.$document.on( `click.${ eventHandler }`, ( event ) => {
226
227				if ( ! shouldCloseOnOutside ) {
228					return;
229				}
230
231				this.closeOnOutside( event );
232				clearInlineScroll( this.$instance );
233			} );
234
235			this.$window.on( `orientationchange.${ eventHandler } resize.${ eventHandler }`, ( event ) => {
236				const viewportWidth = window.innerWidth || document.documentElement.clientWidth;
237
238				if ( viewportWidth === this._prevViewportWidth ) {
239					return;
240				}
241
242				this._prevViewportWidth = viewportWidth;
243
244				$( `.${ this.settings.classes.menuItem }`, this.$instance ).removeClass( `${ this.settings.classes.menuItem }--hover` );
245				this.$instance.removeClass( `${ this.settings.classes.instance }--dropdown-open` );
246
247				clearInlineScroll( this.$instance );
248			} );
249
250			this.$document.on( `touchend.${ eventHandler }`, ( event ) => {
251				this.closeOnOutside( event );
252				clearInlineScroll(this.$instance);
253			} );
254
255			this.$instance.on( 'watchTickEventResetRegularState', ( event ) => {
256				this.resetRegularState();
257
258				if ( this.$rollUpItem[0] ) {
259					$( `.${ this.settings.classes.subMenuList }:first`, this.$rollUpItem ).empty();
260					this.$rollUpItem[0].hidden = true;
261				}
262
263				for ( let index = 0; index < this.menuItemsData.length; index++ ) {
264					this.menuItemsData[ index ].element.hidden = false;
265				}
266			} );
267
268			this.$instance.on( 'watchTickEventResetDropdownState', ( event ) => {
269				this.resetDropdownState();
270				this.$instance.removeClass( `${ this.settings.classes.instance }--dropdown-open` );
271			} );
272
273			this.$instance.on('watchTickEventDropdown watchTickEventResetDropdownState', () => {
274				clearInlineScroll(this.$instance);
275			});
276
277			this.$instance.on( `click.${ eventHandler }`, `.${ this.settings.classes.instance }-toggle`,   ( event ) => {
278
279				if ( ! this.$instance.hasClass( `${ this.settings.classes.instance }--dropdown-open` ) ) {
280					this.$instance.addClass( `${ this.settings.classes.instance }--dropdown-open` );
281				} else {
282					this.$instance.removeClass( `${ this.settings.classes.instance }--dropdown-open` );
283				}
284			} );
285
286			this.$instance.on( `keydown.${ eventHandler }`, `.${ this.settings.classes.menuItem }__inner[role="button"], .${ this.settings.classes.menuItem }__dropdown[role="button"]`, ( event ) => {
287
288				if ( event.key === 'Enter' || event.key === ' ' ) {
289					event.preventDefault();
290
291					if ( this.settings.subEvent === 'click' ) {
292						$( event.currentTarget ).trigger( 'click' );
293					}
294
295					if ( this.settings.subEvent === 'hover' ) {
296						$( event.currentTarget ).trigger( 'mouseenter' );
297					}
298				}
299
300			});
301
302		}
303
304		/**
305		 * Init watcher function.
306		 *
307		 * @param  {number} Watcher debounce delay.
308		 * @return {void}
309		 */
310		initWatcher( delay = 10 ) {
311			$( window ).off( `resize.JetMegaMenu${ this.settings['menuUniqId'] }` ).on( `resize.JetMegaMenu${ this.settings['menuUniqId'] } orientationchange.JetMegaMenu${ this.settings['menuUniqId'] }`, this.debounce( delay, this.watchTick.bind( this ) ) );
312			this.$instance.trigger( 'containerResize' );
313		}
314
315		/**
316		 * Close submenu when a pointer event happens outside of the menu.
317		 *
318		 * @param  {Event} event ( click/touchend )
319		 * @return {void}
320		 */
321		closeOnOutside( event ) {
322
323			if ( $( event.target ).closest( `.${ this.settings.classes.menuItem }, .${ this.settings.classes.subMenuContainer }, .${ this.settings.classes.megaContainer }` ).length ) {
324				return;
325			}
326
327			$( `.${ this.settings.classes.menuItem }`, this.$instance ).removeClass( `${ this.settings.classes.menuItem }--hover` );
328			this.$instance.find( '[role="button"][aria-haspopup="true"]' ).attr( 'aria-expanded', 'false' );
329		}
330
331		/**
332		 * Responsive menu watcher callback.
333		 *
334		 * @param  {Object} Resize or Orientationchange event.
335		 * @return {void}
336		 */
337		watchTick( event ) {
338
339			if ( this.isDropdown() ) {
340
341				if ( ! this.isDropdownState ) {
342					this.$instance.trigger( 'watchTickEventResetRegularState' );
343				}
344
345				this.isDropdownState = true;
346				this.$instance.removeClass( `${ this.settings.classes.instance }--layout-horizontal ${ this.settings.classes.instance }--layout-vertical` );
347				this.$instance.addClass( `${ this.settings.classes.instance }--layout-dropdown` );
348				this.$instance.trigger( 'watchTickEventDropdown' );
349			} else {
350
351				if ( this.isDropdownState ) {
352					this.$instance.trigger( 'watchTickEventResetDropdownState' );
353				}
354
355				this.isDropdownState = false;
356				this.$instance.removeClass( `${ this.settings.classes.instance }--layout-dropdown` );
357				this.$instance.addClass( `${ this.settings.classes.instance }--layout-${ this.settings.layout }` );
358				this.$instance.trigger( `watchTickEventRegular` );
359				this.$instance.trigger( `watchTickEventRegular--${ this.settings.layout }` );
360			}
361
362			this.$instance.trigger( 'watchTickEvent' );
363		}
364
365		/**
366		 * Rollup rebuilding function.
367		 *
368		 * @return {void}
369		 */
370		maybeRollUpItems() {
371			this.$instance.on( 'watchTickEventRegular--horizontal', ( event ) => {
372
373				if ( ! this.settings.rollUp ) {
374					return false;
375				}
376
377				let mainMenuWidth     = this.$instance.width(),
378					rollUpWidth = this.$rollUpItem.outerWidth( true ),
379				    visibleItemsArray = [],
380				    hiddenItemsArray  = [];
381
382				const minOffset = Math.min(...this.menuItemsData.map( d => d.offsetLeft ) );
383
384				for ( let index = 0; index < this.menuItemsData.length; index++ ) {
385					let itemData     = this.menuItemsData[ index ],
386					    nextItemData = this.menuItemsData[ index + 1 ] || false,
387						rightEdge    = ( nextItemData ? nextItemData.offsetLeft : itemData.offsetLeft + itemData.outerWidth ) - minOffset,
388					    item         = itemData.element;
389
390					if ( rightEdge + rollUpWidth > mainMenuWidth ) {
391						item.hidden = true;
392						hiddenItemsArray.push( item );
393					} else {
394						item.hidden = false;
395						visibleItemsArray.push( item );
396					}
397				}
398
399				$( `.${ this.settings.classes.subMenuList }:first`, this.$rollUpItem ).empty();
400
401				for ( let hiddenMenuItem of hiddenItemsArray ) {
402					let $hiddenClone = $( hiddenMenuItem ).clone();
403
404					$hiddenClone[0].hidden = false;
405
406					$( `>.${ this.settings.classes.menuItem }__inner >.${ this.settings.classes.menuItemLink }`, $hiddenClone ).toggleClass( `${ this.settings.classes.menuItemLink }--top-level ${ this.settings.classes.menuItemLink }--sub-level` );
407					$( `.${ this.settings.classes.subMenuList }:first`, this.$rollUpItem ).append( $hiddenClone );
408				}
409
410				if ( this.$rollUpItem[0] ) {
411					this.$rollUpItem[0].hidden = hiddenItemsArray.length ? false : true;
412				}
413
414				this.$instance.trigger( 'rollUpItemsEvent' );
415			} )
416		}
417
418		/**
419		 * Rebuild SubContainers function.
420		 *
421		 * @return {void}
422		 */
423		rebuildSubContainers() {
424			this.$instance.on( 'watchTickEventRegular--horizontal', ( event ) => {
425				let $megaMenuList   = $( `.${ this.settings.classes.megaContainer }`, this.$instance ),
426				    $subMenuList    = $( `.${ this.settings.classes.subMenuContainer }`, this.$instance ),
427				    subInverseClass = `${ this.settings.classes.subMenuContainer }--inverse`,
428				    instanceWidth   = this.$instance.width(),
429				    instanceOffset  = this.$instance.offset();
430
431				$subMenuList.each( ( index, element ) => {
432					let $element = $( element );
433
434					if ( this.isOffscreenX( element ) ) {
435						$element.addClass( subInverseClass );
436					} else {
437						$element.removeClass( subInverseClass );
438					}
439				} );
440
441				switch( this.settings.megaWidthType ) {
442					case 'container':
443						$megaMenuList.each( ( index, element ) => {
444							let $element           = $( element ),
445							    $elementPosition = $element.data( 'position' ),
446							    elementOffset      = $element.offset(),
447							    elementDeltaOffset = 'default' === $elementPosition ? Math.ceil( instanceOffset.left - elementOffset.left ) : 0;
448
449							$element.css( {
450								'--jmm-submenu-width': `${ instanceWidth }px`,
451								'--jmm-submenu-delta-x-offset': `${ elementDeltaOffset }px`
452							} );
453						} );
454
455						break;
456					case 'selector':
457						let $customSelector = $( this.settings.megaWidthSelector );
458
459						if ( $customSelector[0] ) {
460							let selectorWidth = $customSelector.width(),
461							    selectorOffset = Math.round( $customSelector.offset().left );
462
463							document.fonts.ready.then( () => {
464								$megaMenuList.each( ( index, element ) => {
465									let $element           = $( element ),
466										$elementPosition   = $element.data( 'position' ),
467										elementOffset      = Math.round( $element.offset().left ),
468										elementDeltaOffset = 'default' === $elementPosition ? Math.round( selectorOffset - elementOffset ) : 0;
469
470									$element.css( {
471										'--jmm-submenu-width': `${ selectorWidth }px`,
472										'--jmm-submenu-delta-x-offset': `${ elementDeltaOffset }px`
473									} );
474								} );
475							} );
476
477						}
478
479						break;
480					case 'items':
481						let $lastItem        = $( `.${ this.settings.classes.menuItem }--top-level:not([hidden]):last`, this.$instance ),
482						    $firstItem        = $( `.${ this.settings.classes.menuItem }--top-level:not([hidden]):first`, this.$instance ),
483						    lastItemBounding = $lastItem[0].getBoundingClientRect(),
484						    firstItemBounding = $firstItem[0].getBoundingClientRect(),
485						    itemsWidth       = lastItemBounding.x + lastItemBounding.width  - firstItemBounding.x;
486
487						$megaMenuList.each( ( index, element ) => {
488							let $element           = $( element ),
489							    $elementPosition   = $element.data( 'position' ),
490							    elementOffset      = $element.offset(),
491							    elementDeltaOffset = 'default' === $elementPosition ? Math.ceil( instanceOffset.left - elementOffset.left ) : 0;
492
493							$element.css( {
494								'--jmm-submenu-width': `${ itemsWidth }px`,
495								'--jmm-submenu-delta-x-offset': `${ elementDeltaOffset }px`
496							} );
497						} );
498						break;
499				}
500			} );
501
502			this.$instance.on( 'watchTickEventRegular--vertical', ( event ) => {
503				let $megaMenuList    = $( `.${ this.settings.classes.megaContainer }`, this.$instance ),
504				    $subMenuList     = $( `.${ this.settings.classes.subMenuContainer }`, this.$instance ),
505				    instanceWidth    = this.$instance.width(),
506				    instanceHeight   = this.$instance.height(),
507				    instanceOffset   = this.$instance.offset(),
508					windowWidth      = this.$window.outerWidth( true ),
509					subInverseClass  = `${ this.settings.classes.subMenuContainer }--inverse`,
510					megaInverseClass = `${ this.settings.classes.megaContainer }--inverse`;
511
512				$subMenuList.each( ( index, element ) => {
513					let $element = $( element );
514
515					if ( this.isOffscreenX( element ) ) {
516						$element.addClass( subInverseClass );
517					} else {
518						$element.removeClass( subInverseClass );
519					}
520				} );
521
522				$megaMenuList.each( ( index, element ) => {
523					let $element            = $( element ),
524					    $elementPosition    = $element.data( 'position' ),
525					    $parentElement      = $element.parent(),
526					    elementOffset       = $element.offset(),
527					    elementDeltaOffsetX = ( instanceOffset.left - elementOffset.left ) + instanceWidth,
528					    elementDeltaOffsetY = 'default' === $elementPosition ? ( instanceOffset.top - elementOffset.top ) : 0,
529					    elementDeltaWidth   = ( elementDeltaOffsetX + $element.width() );
530
531					if ( $parentElement.hasClass(`${ this.settings.classes.menuItem }--top-level` ) ) {
532						$element.css( {
533							//'--jmm-submenu-width': `${ instanceWidth }px`,
534							'--jmm-submenu-min-height': `${ instanceHeight }px`,
535							//'--jmm-submenu-delta-x-offset': `${ elementDeltaOffsetX }px`,
536							'--jmm-submenu-delta-y-offset': `${ elementDeltaOffsetY }px`
537						} );
538					}
539
540					if ( this.isOffscreenX( element ) ) {
541						$element.addClass( megaInverseClass );
542					} else {
543						$element.removeClass( megaInverseClass );
544					}
545				} );
546			} );
547		}
548
549		/**
550		 * Reset Regular State
551		 *
552		 * @return {void}
553		 */
554		resetRegularState() {}
555
556		/**
557		 * Reset Dropdown State
558		 *
559		 * @return {void}
560		 */
561		resetDropdownState() {}
562
563		/**
564		 * Get mobile status.
565		 *
566		 * @return {boolean} Mobile Status
567		 */
568		isDropdown() {
569			return ( this.$window.width() < this.settings.breakpoint || 'dropdown' === this.settings.layout ) ? true : false;
570		}
571
572		/**
573		 *
574		 * @param element
575		 * @returns {boolean}
576		 */
577		isOffscreenX( element ) {
578			let rect = element.getBoundingClientRect();
579
580			return (
581				rect.x < 0 || ( rect.x + rect.width ) > window.innerWidth
582			);
583		}
584
585		/**
586		 * Mobile and tablet check funcion.
587		 *
588		 * @return {boolean} Mobile Status
589		 */
590		mobileAndTabletcheck() {
591			let check = false;
592
593			(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
594
595			return check;
596		}
597
598		/**
599		 * Debounce the function call
600		 *
601		 * @param  {number}   threshold The delay.
602		 * @param  {Function} callback  The function.
603		 */
604		debounce( threshold, callback ) {
605			let timeout;
606
607			return function debounced( $event ) {
608				function delayed() {
609					callback.call( this, $event );
610					timeout = null;
611				}
612
613				if ( timeout ) {
614					clearTimeout( timeout );
615				}
616
617				timeout = setTimeout( delayed, threshold );
618			};
619		}
620
621		maybeTemplateLoad( templateId, templateContent, $templateContainer ) {
622
623			if ( ! this.settings.megaAjaxLoad ) {
624				return;
625			}
626
627			if ( $templateContainer.hasClass( 'template-loaded' ) ) {
628				return;
629			}
630
631			let getMegaContentUrl = 'default' === templateContent ? window.jetMenuPublicSettings.getBlocksTemplateApiUrl : window.jetMenuPublicSettings.getElementorTemplateApiUrl;
632
633			let signatures = this.settings['signatures'];
634			let signature = '';
635
636			if ( signatures.hasOwnProperty(`template_${templateId}`) ) {
637				signature = signatures[`template_${templateId}`].signature;
638			}
639
640			this.isContentLoading = true;
641
642			const self = this;
643
644			$.ajax( {
645				type: 'GET',
646				url: getMegaContentUrl,
647				dataType: 'json',
648				data: {
649					'id': templateId,
650					'dev': window.jetMenuPublicSettings.devMode,
651					'signature': signature
652				},
653				beforeSend: function( jqXHR, ajaxSettings ) {
654					jqXHR.setRequestHeader( 'X-WP-Nonce', window.jetMenuPublicSettings.restNonce );
655				},
656				success: function( responce, textStatus, jqXHR ) {
657					const {content, contentElements} = responce;
658					const templateData = {
659						content,
660						contentElements,
661						contentType: templateContent,
662					}
663
664					$templateContainer.addClass( 'template-loaded' );
665
666					jetMenu.megaContentRender( $( '.jet-mega-menu-mega-container__inner', $templateContainer ), templateData );
667				},
668				complete: function() {
669					self.isContentLoading = false;
670
671					if ( self._pendingMouseleave ) {
672						self._pendingMouseleave = false;
673						self.$instance.triggerHandler( 'mouseleave' );
674					}
675
676				}
677			} );
678		}
679
680		getNum( val ) {
681			val = parseFloat( val );
682			return isNaN( val ) ? 0 : val;
683		}
684
685		applySmartScroll( $menuItem ) {
686			if ( this.settings.layout !== 'horizontal' || this.isDropdown() ) return;
687
688			const $subContainer = $menuItem.children(
689				`.${ this.settings.classes.subMenuContainer }, .${ this.settings.classes.megaContainer }`
690			);
691
692			if ( ! $subContainer[0] ) return;
693
694			let $targetContainer = $subContainer.children( `.${ this.settings.classes.subMenuList }:first` );
695
696			if ( ! $targetContainer[0] ) {
697				$targetContainer = $subContainer.children( `.${ this.settings.classes.megaContainer }__inner:first` );
698			}
699
700			const element = $targetContainer[0] || $subContainer[0];
701
702			$subContainer.add( $targetContainer ).css( {
703				'max-height' : '',
704				'overflow-y' : '',
705				'overflow-x' : ''
706			} );
707
708			const elementRect = element.getBoundingClientRect();
709
710			const elementMarginTop = this.getNum( getComputedStyle( element ).marginTop );
711
712			const adminBarHeight = document.body.classList.contains( 'admin-bar' )
713				? ( window.innerWidth < 783 ? 46 : 32 )
714				: 0;
715
716			const htmlMarginTop = parseFloat( getComputedStyle( document.documentElement ).marginTop ) || 0;
717			const bodyMarginTop = parseFloat( getComputedStyle( document.body ).marginTop ) || 0;
718
719			const adminBarCompensation = ( htmlMarginTop >= adminBarHeight - 1 || bodyMarginTop >= adminBarHeight - 1 )
720				? 0
721				: adminBarHeight;
722
723			const bottomGap = this.settings.bottomGap ?? 12;
724
725			const availableHeight = Math.max(
726				0,
727				window.innerHeight - elementRect.top - ( elementMarginTop + adminBarCompensation + bottomGap )
728			);
729
730			if ( element.scrollHeight > availableHeight ) {
731				$targetContainer.css( {
732					'max-height' : availableHeight + 'px',
733					'overflow-y' : 'auto',
734					'overflow-x' : 'hidden',
735					'-webkit-overflow-scrolling' : 'touch',
736					'overscroll-behavior' : 'contain',
737				} );
738			}
739		}
740
741	}
742
743	// jQuery plugin
744	$.fn.JetMegaMenu = function( options ) {
745		return this.each( function() {
746			let $this         = $( this ),
747				pluginOptions = ( 'object' === typeof options ) ? options : {};
748
749			if ( ! $this.data( 'JetMegaMenu' ) ) {
750				// create plugin instance (only if not exists) and expose the entire instance API
751				$this.data( 'JetMegaMenu', new JetMegaMenuClass( this, pluginOptions ) );
752			}
753		} );
754	};
755} ( jQuery ));
756
757// JetMenu Public Scripts
758( function( $ ) {
759	'use strict';
760
761	window.jetMenu = {
762
763		addedScripts: {},
764
765		addedStyles: {},
766
767		addedAssetsPromises: [],
768
769		initedMobileRenderInstance: [],
770
771		eventBus: new Vue(),
772
773		$body: $( 'body' ),
774
775		init: function() {
776			this.initLocationMenuRender();
777			this.mobileVueComponents();
778			this.initMobileRender();
779
780			window.addEventListener( 'jetMenu/editor/templateRenderer/renderSuccess', ( event ) => {
781				this.initLocationMenuRender();
782				this.mobileVueComponents();
783				this.initMobileRender();
784			}, false );
785
786			$( window ).on( 'jet-menu/ajax/frontend-init', ( event, payload ) => {
787
788				switch ( payload.contentType ) {
789					case 'elementor':
790						jetMenu.maybeElementorFrontendInit( payload.$container );
791						break;
792					case 'default':
793						jetMenu.maybeDefaultFrontendInit( payload );
794						break
795				}
796			} );
797
798			$( window ).on( 'jet-menu/ajax/frontend-init/after', ( event, payload ) => {
799				this.initLocationMenuRender();
800				this.mobileVueComponents();
801				this.initMobileRender();
802				this.megaContentHandler(event, payload);
803
804				if ( window.elementorFrontend ) {
805					const elementorLazyLoad = new CustomEvent( "elementor/lazyload/observe" );
806					document.dispatchEvent( elementorLazyLoad );
807				}
808			} );
809
810			wp.hooks.addAction( 'jet-plugins.frontend.element-ready.jet-menu.mega-menu', 'jet-popup', ( $popupContainer, contentType ) => {
811				this.initLocationMenuRender();
812				this.mobileVueComponents();
813				this.initMobileRender();
814			} );
815
816			// Init Vue for hamburger menu block in Gutenberg ( also on DOM change )
817			if ( document.body.classList.contains( 'block-editor-page' ) ) {
818				const tryObserve = () => {
819					const target = document.querySelector( '.block-editor-block-list__layout' );
820
821					if ( target ) {
822						const initedMenus = new Set();
823
824						const observer = new MutationObserver( () => {
825							const menus = document.querySelectorAll( '.jet-mobile-menu--location-wp-nav' );
826
827							menus.forEach( (menu) => {
828								const menuId = menu.getAttribute( 'id' );
829
830								if ( menuId && ! initedMenus.has( menuId ) ) {
831									jetMenu.initMobileRender();
832									initedMenus.add( menuId );
833								}
834
835							});
836						});
837
838						observer.observe( target, { childList: true, subtree: true } );
839					} else {
840						requestAnimationFrame( tryObserve );
841					}
842				};
843
844				requestAnimationFrame( tryObserve );
845			}
846
847		},
848
849		initLocationMenuRender: function() {
850
851			let $megaMenuList = $( '.jet-mega-menu--location-wp-nav' );
852
853			if ( ! $megaMenuList[0] ) {
854				return false;
855			}
856
857			$megaMenuList.each( function() {
858				let $this    = $( this ),
859				    settings = $this.data( 'settings' );
860
861				$this.JetMegaMenu( {
862					rollUp: settings.rollUp,
863					layout: settings.layout,
864					subTrigger: settings.subTrigger,
865					subEvent: settings.subEvent,
866					subCloseBehavior: settings.subCloseBehavior,
867					mouseLeaveDelay: settings.mouseLeaveDelay,
868					breakpoint: settings.breakpoint,
869					megaWidthType: settings.megaWidthType,
870					megaWidthSelector: settings.megaWidthSelector,
871					megaAjaxLoad: settings.megaAjaxLoad,
872					classes: {
873						instance: 'jet-mega-menu',
874						menuContainer: 'jet-mega-menu-container',
875						menuList: 'jet-mega-menu-list',
876						menuItem: 'jet-mega-menu-item',
877						menuItemLink: 'jet-mega-menu-item__link',
878						subMenuContainer: 'jet-mega-menu-sub-menu',
879						subMenuList: 'jet-mega-menu-sub-menu__list',
880						megaContainer: 'jet-mega-menu-mega-container',
881					}
882				} );
883			} );
884		},
885
886		megaContentHandler: function(event, payload) {
887			const container = payload.$container[0];
888			const mobileMenu = container.closest('.jet-mobile-menu');
889
890			if ( ! mobileMenu ) {
891				return;
892			}
893
894			const { menuOptions } = mobileMenu.dataset;
895			const { menuUniqId } = JSON.parse( menuOptions );
896
897			container.addEventListener('click', function (event) {
898				const link = event.target.closest('a');
899
900				if (!link) {
901					return;
902				}
903
904				if (link.getAttribute('href')[0] !== '#') {
905					return;
906				}
907
908				window.jetMenu.eventBus.$emit('closeMenu', {
909					menuUniqId: menuUniqId,
910				});
911			});
912		},
913
914		initMobileRender: function() {
915
916			let mobileMenuList = $( '.jet-mobile-menu--location-wp-nav' );
917
918			if ( ! mobileMenuList[0] ) {
919				return false;
920			}
921
922			if ( 'true' === window.jetMenuPublicSettings.devMode ) {
923				Vue.config.devtools = true;
924			}
925
926			mobileMenuList.each( function() {
927				let $this          = $( this ),
928					menuInstanceId = $this.attr( 'id' ),
929					menuId         = $this.data( 'menu-id' ) || false,
930					menuOptions    = $this.data( 'menu-options' ) || {};
931
932				jetMenu.createMobileRenderInstance( menuInstanceId, menuId, menuOptions );
933			} );
934		},
935
936		createMobileRenderInstance: function( menuInstanceId, menuId, menuOptions ) {
937
938			if ( jetMenu.initedMobileRenderInstance.includes( menuInstanceId ) ) {
939				return;
940			}
941
942			jetMenu.initedMobileRenderInstance.push( menuInstanceId );
943
944			let mobileRenderInstance = new Vue( {
945				el: '#' + menuInstanceId,
946				data: {
947					uniqId: menuInstanceId,
948					menuOptions: menuOptions,
949					refsHtml: {},
950				},
951				mounted: function() {
952					let refsHtml = {};
953
954					for ( var ref in this.$refs ) {
955						Object.assign( refsHtml, { [ ref ]: this.$refs[ ref ].innerHTML } );
956					}
957
958					this.refsHtml = refsHtml;
959				}
960			} );
961		},
962
963		mobileVueComponents: function() {
964
965			Vue.component( 'mobile-menu-item', {
966				template: '#mobile-menu-item-template',
967
968				props: {
969					itemDataObject: Object,
970					depth: Number
971				},
972
973				data: function() {
974					return ( {
975						ajaxRequest: null,
976						templateLoadStatus: false,
977						subDropdownVisible: false
978					} )
979				},
980
981				computed: {
982
983					itemClasses: function() {
984						let itemClasses = [
985							'jet-mobile-menu__item',
986							'jet-menu-item-' + this.itemDataObject.itemId,
987							'jet-mobile-menu__item--sub-trigger-' + ( this.$root.menuOptions.subTrigger || 'item' ),
988						];
989
990						let customClasses = this.itemDataObject.classes;
991
992						if ( 0 !== customClasses.length ) {
993							itemClasses = itemClasses.concat( customClasses );
994						}
995
996						const { href } = window.location;
997						let pageURL = null;
998
999						if ( href.includes('?') ) {
1000							pageURL = href.substring(0, href.indexOf('?'));
1001						} else {
1002							pageURL = href;
1003						}
1004
1005						if ( pageURL === this.itemDataObject.url ) {
1006							itemClasses.push( 'jet-mobile-menu__item--active' );
1007						}
1008
1009						return itemClasses;
1010					},
1011
1012					itemLinkClasses: function() {
1013						let classes = [
1014							'mobile-link',
1015							0 === this.depth ? 'mobile-top-level-link' : 'mobile-sub-level-link',
1016						];
1017
1018						return classes;
1019					},
1020
1021					isСhildrenDefine: function() {
1022						return this.itemDataObject.children ? true : false;
1023					},
1024
1025					isTemplateDefine: function() {
1026						return false !== this.itemDataObject.megaTemplateId ? true : false;
1027					},
1028
1029					megaContentType: function() {
1030						return this.itemDataObject.megaContentType;
1031					},
1032
1033					isAjaxLoadingEnabled: function() {
1034						return this.$root.menuOptions.megaAjaxLoad === true;
1035					},
1036
1037					getTemplateUrl: function() {
1038						return 'default' === this.megaContentType ? window.jetMenuPublicSettings.getBlocksTemplateApiUrl : window.jetMenuPublicSettings.getElementorTemplateApiUrl;
1039					},
1040
1041					isSub: function() {
1042						return this.isСhildrenDefine || this.isTemplateDefine ? true : false;
1043					},
1044
1045					isTopLevel: function() {
1046						return 0 === this.depth ? true : false;
1047					},
1048
1049					isDropdownLayout: function() {
1050						return this.isSub && ! this.isTemplateDefine && 'dropdown' === this.$root.menuOptions.subOpenLayout;
1051					},
1052
1053					depthClass: function() {
1054						return 0 === this.depth ? 'mobile-top-level-link' : 'mobile-sub-level-link';
1055					},
1056
1057					dropdownIconHtml: function() {
1058						let dropdownIcon = this.$root.refsHtml.dropdownIcon ? this.$root.refsHtml.dropdownIcon : '<span class="dashicons dashicons-arrow-right"></span>',
1059							dropdownOpenedIcon = this.$root.refsHtml.dropdownOpenedIcon ? this.$root.refsHtml.dropdownOpenedIcon : '<span class="dashicons dashicons-arrow-down"></span>';
1060
1061						if ( this.subDropdownVisible ) {
1062							dropdownIcon = dropdownOpenedIcon;
1063						}
1064
1065						return dropdownIcon;
1066					},
1067
1068					itemIconHtml: function() {
1069						return this.itemDataObject.itemIcon;
1070					},
1071
1072					isIconVisible: function() {
1073						let iconVisible = this.$root.menuOptions.itemIconVisible;
1074
1075						return ! iconVisible || '' === this.itemDataObject.itemIcon || ! this.itemDataObject.itemIcon ? false : true;
1076					},
1077
1078					isBadgeVisible: function() {
1079						let badgeVisible = this.$root.menuOptions.itemBadgeVisible;
1080
1081						return false === badgeVisible || '' === this.itemDataObject.badgeContent || ! this.itemDataObject.badgeContent ? false : true;
1082					},
1083
1084					isLabelVisible: function() {
1085						let labelVisible = ! this.itemDataObject.hideItemText;
1086
1087						return false === labelVisible || '' === this.itemDataObject.name || ! this.itemDataObject.name ? false : true;
1088					},
1089
1090					isDescVisible: function() {
1091						let descVisible = this.$root.menuOptions.itemDescVisible;
1092
1093						return false === descVisible || '' === this.itemDataObject.description || ! this.itemDataObject.description ? false : true;
1094					},
1095
1096					loaderColor: function() {
1097						return this.$root.menuOptions.loaderColor || '#3a3a3a';
1098					},
1099				},
1100
1101				methods: {
1102					itemSubHandler: function( event ) {
1103						let target     = event.target,
1104							mobileLink = $( target ).closest( '.mobile-link' );
1105
1106						if ( 'item' !== this.$root.menuOptions.subTrigger ) {
1107							return;
1108						}
1109
1110						if ( this.isSub && mobileLink ) {
1111							event.preventDefault();
1112						}
1113
1114						if ( ! this.isSub && mobileLink && this.$root.menuOptions.closeAfterNavigate ) {
1115							jetMenu.eventBus.$emit( 'closeMenu', {
1116								menuUniqId: this.$root.menuOptions.menuUniqId,
1117							} );
1118						}
1119
1120						this.switchToSub( event );
1121					},
1122
1123					markerSubHandler: function( event ) {
1124
1125						if ( 'submarker' !== this.$root.menuOptions.subTrigger ) {
1126							return;
1127						}
1128
1129						this.switchToSub( event );
1130					},
1131
1132					switchToSub: function( event ) {
1133
1134						if ( ! this.isSub ) {
1135							return;
1136						}
1137
1138						if ( ! this.isTemplateDefine ) {
1139
1140							if ( this.isDropdownLayout ) {
1141								this.subDropdownVisible = !this.subDropdownVisible;
1142
1143								return;
1144							}
1145
1146							jetMenu.eventBus.$emit( 'itemsSubSwitch', {
1147								menuUniqId: this.$root.menuOptions.menuUniqId,
1148								id: this.itemDataObject.id,
1149								name: this.itemDataObject.name,
1150								children: this.itemDataObject.children || false
1151							} );
1152						} else {
1153							if ( this.isAjaxLoadingEnabled && ! this.itemDataObject.megaContentLoaded ) {
1154								this.getMegaTemplate();
1155							} else {
1156								jetMenu.eventBus.$emit( 'showTemplateContent', {
1157									menuUniqId: this.$root.menuOptions.menuUniqId,
1158									id: this.itemDataObject.id,
1159									name: this.itemDataObject.name,
1160									megaContent: this.itemDataObject.megaContent,
1161									megaContentType: this.itemDataObject.megaContentType,
1162								} );
1163							}
1164						}
1165					},
1166
1167					getMegaTemplate: function() {
1168						var vueInstance = this;
1169
1170						if ( ! this.isAjaxLoadingEnabled ) {
1171							return;
1172						}
1173
1174						var signature = vueInstance.itemDataObject.signature || '';
1175
1176						vueInstance.ajaxRequest = $.ajax( {
1177							type: 'GET',
1178							url: vueInstance.getTemplateUrl,
1179							dataType: 'json',
1180							data: {
1181								'id': vueInstance.itemDataObject.megaTemplateId,
1182								'dev': window.jetMenuPublicSettings.devMode,
1183								'signature': signature
1184							},
1185							beforeSend: function( jqXHR, ajaxSettings ) {
1186
1187								if ( null !== vueInstance.ajaxRequest ) {
1188									vueInstance.ajaxRequest.abort();
1189								}
1190
1191								vueInstance.templateLoadStatus = true;
1192
1193								jqXHR.setRequestHeader( 'X-WP-Nonce', window.jetMenuPublicSettings.restNonce );
1194							},
1195							success: function( responce, textStatus, jqXHR ) {
1196								let templateContent = responce['content'],
1197									contentElements = responce['contentElements'];
1198
1199								vueInstance.templateLoadStatus = false;
1200								vueInstance.itemDataObject.megaContent = templateContent;
1201								vueInstance.itemDataObject.megaContentLoaded = true;
1202
1203								jetMenu.eventBus.$emit( 'showTemplateContent', {
1204									menuUniqId: vueInstance.$root.menuOptions.menuUniqId,
1205									id: vueInstance.itemDataObject.id,
1206									name: vueInstance.itemDataObject.name,
1207									megaContent: vueInstance.itemDataObject.megaContent,
1208									megaContentType: vueInstance.itemDataObject.megaContentType,
1209								} );
1210							}
1211						} );
1212					}
1213				}
1214
1215			});
1216
1217			Vue.component( 'mobile-menu-list', {
1218				template: '#mobile-menu-list-template',
1219				props: {
1220					depth: Number,
1221					childrenObject: Object
1222				}
1223			} );
1224
1225			Vue.component( 'mobile-menu', {
1226				template: '#mobile-menu-template',
1227
1228				data: function() {
1229					return ( {
1230						menuOpen: false,
1231						children: false,
1232						itemsRawData: {},
1233						trail:[],
1234						breadcrumbsData: [],
1235						animation: 'items-next-animation',
1236						ajaxRequest: null,
1237						templateVisible: false,
1238						instanceLoadStatus: false,
1239						itemTemplateContent: false,
1240						headerTemplate: this.$root.menuOptions['headerTemplate'] || 0,
1241						headerContent: false,
1242						beforeTemplate: this.$root.menuOptions['beforeTemplate'] || 0,
1243						beforeContent: false,
1244						afterTemplate: this.$root.menuOptions['afterTemplate'] || 0,
1245						afterContent: false,
1246						ajaxPromises: [],
1247					} )
1248				},
1249
1250				mounted: function() {
1251					const vueInstance = this;
1252
1253					if ( this.menuOpen ) {
1254						jetMenu.$body.addClass( 'jet-mobile-menu-visible' );
1255
1256						if ( 'slide-out' === this.$root.menuOptions.menuLayout ) {
1257							jetMenu.$body.addClass( 'jet-menu-body-blocker' );
1258						}
1259					}
1260
1261					let menuInstanceRenderData = false,
1262						renderDataElement = document.getElementById( 'jetMenuMobileWidgetRenderData' + this.$root.menuOptions.menuUniqId );
1263
1264					try {
1265						menuInstanceRenderData = JSON.parse( renderDataElement.textContent );
1266					} catch ( error ) {
1267						menuInstanceRenderData = false;
1268					}
1269
1270					if ( menuInstanceRenderData ) {
1271						this.itemsRawData = menuInstanceRenderData['items'];
1272
1273						const headerTemplateData = menuInstanceRenderData.headerTemplateData || false,
1274							beforeTemplateData = menuInstanceRenderData.beforeTemplateData || false,
1275							afterTemplateData = menuInstanceRenderData.afterTemplateData || false;
1276
1277						if ( headerTemplateData ) {
1278							this.headerContent = headerTemplateData.content;
1279						}
1280
1281						if ( beforeTemplateData ) {
1282							this.beforeContent = beforeTemplateData.content;
1283						}
1284
1285						if ( afterTemplateData ) {
1286							this.afterContent = afterTemplateData.content;
1287						}
1288					} else {
1289						this.ajaxPromises.push(
1290							new Promise( function( resolve, reject ) {
1291
1292								$.ajax( {
1293									type: 'GET',
1294									url: window.jetMenuPublicSettings.menuItemsApiUrl,
1295									dataType: 'json',
1296									data: {
1297										'menu_id': vueInstance.menuId,
1298										'dev': window.jetMenuPublicSettings.devMode,
1299										'lang': window.jetMenuPublicSettings.wpmlLanguageCode || false
1300									},
1301									beforeSend: function( jqXHR, ajaxSettings ) {
1302										jqXHR.setRequestHeader( 'X-WP-Nonce', window.jetMenuPublicSettings.restNonce );
1303									},
1304									success: function( responce, textStatus, jqXHR ) {
1305										let responceData = responce.data.items;
1306
1307										vueInstance.itemsRawData = responceData;
1308
1309										resolve();
1310									}
1311								} );
1312							} )
1313						);
1314
1315						if ( 0 !== +this.headerTemplate ) {
1316							this.ajaxPromises.push(
1317								new Promise( function( resolve, reject ) {
1318									$.ajax( {
1319										type: 'GET',
1320										url: window.jetMenuPublicSettings.getElementorTemplateApiUrl,
1321										dataType: 'json',
1322										data: {
1323											'id': vueInstance.headerTemplate,
1324											'dev': window.jetMenuPublicSettings.devMode,
1325											'nocache': new Date().getTime(),
1326										},
1327										beforeSend: function( jqXHR, ajaxSettings ) {
1328											jqXHR.setRequestHeader( 'X-WP-Nonce', window.jetMenuPublicSettings.restNonce );
1329										},
1330										success: function( responce, textStatus, jqXHR ) {
1331											let templateContent = responce['content'],
1332												templateScripts = responce['scripts'],
1333												templateStyles  = responce['styles'];
1334
1335											for ( let scriptHandler in templateScripts ) {
1336												jetMenu.addedAssetsPromises.push( jetMenu.loadScriptAsync( scriptHandler, templateScripts[ scriptHandler ] ) );
1337											}
1338
1339											for ( let styleHandler in templateStyles ) {
1340												jetMenu.addedAssetsPromises.push( jetMenu.loadStyle( styleHandler, templateStyles[ styleHandler ] ) );
1341											}
1342
1343											vueInstance.headerContent = templateContent;
1344
1345											resolve();
1346										}
1347									} );
1348								} )
1349							);
1350						}
1351
1352						if ( 0 !== +this.beforeTemplate ) {
1353                            this.ajaxPromises.push(
1354                                new Promise( function( resolve, reject ) {
1355                                    $.ajax( {
1356                                        type: 'GET',
1357                                        url: window.jetMenuPublicSettings.getElementorTemplateApiUrl,
1358                                        dataType: 'json',
1359                                        data: {
1360                                            'id': vueInstance.beforeTemplate,
1361                                            'dev': window.jetMenuPublicSettings.devMode,
1362                                            'nocache': new Date().getTime(),
1363                                        },
1364                                        beforeSend: function( jqXHR, ajaxSettings ) {
1365                                            jqXHR.setRequestHeader( 'X-WP-Nonce', window.jetMenuPublicSettings.restNonce );
1366                                        },
1367                                        success: function( responce, textStatus, jqXHR ) {
1368                                            let templateContent = responce['content'],
1369                                                templateScripts = responce['scripts'],
1370                                                templateStyles  = responce['styles'];
1371
1372                                            for ( let scriptHandler in templateScripts ) {
1373                                                jetMenu.addedAssetsPromises.push( jetMenu.loadScriptAsync( scriptHandler, templateScripts[ scriptHandler ] ) );
1374                                            }
1375
1376                                            for ( let styleHandler in templateStyles ) {
1377                                                jetMenu.addedAssetsPromises.push( jetMenu.loadStyle( styleHandler, templateStyles[ styleHandler ] ) );
1378                                            }
1379
1380                                            vueInstance.beforeContent = templateContent;
1381
1382                                            resolve();
1383                                        }
1384                                    } );
1385                                } )
1386                            );
1387                        }
1388
1389                        if ( 0 !== +this.afterTemplate ) {
1390                            this.ajaxPromises.push(
1391                                new Promise( function( resolve, reject ) {
1392                                    $.ajax( {
1393                                        type: 'GET',
1394                                        url: window.jetMenuPublicSettings.getElementorTemplateApiUrl,
1395                                        dataType: 'json',
1396                                        data: {
1397                                            'id': vueInstance.afterTemplate,
1398                                            'dev': window.jetMenuPublicSettings.devMode,
1399                                            'nocache': new Date().getTime(),
1400                                        },
1401                                        beforeSend: function( jqXHR, ajaxSettings ) {
1402                                            jqXHR.setRequestHeader( 'X-WP-Nonce', window.jetMenuPublicSettings.restNonce );
1403                                        },
1404                                        success: function( responce, textStatus, jqXHR ) {
1405                                            let templateContent = responce['content'],
1406                                                templateScripts = responce['scripts'],
1407                                                templateStyles  = responce['styles'];
1408
1409                                            for ( let scriptHandler in templateScripts ) {
1410                                                jetMenu.addedAssetsPromises.push( jetMenu.loadScriptAsync( scriptHandler, templateScripts[ scriptHandler ] ) );
1411                                            }
1412
1413                                            for ( let styleHandler in templateStyles ) {
1414                                                jetMenu.addedAssetsPromises.push( jetMenu.loadStyle( styleHandler, templateStyles[ styleHandler ] ) );
1415                                            }
1416
1417                                            vueInstance.afterContent = templateContent;
1418                                            resolve();
1419                                        }
1420                                    } );
1421                                } )
1422                            );
1423                        }
1424					}
1425
1426
1427
1428					this.instanceLoadStatus = true;
1429
1430					Promise.all( this.ajaxPromises ).then( function() {
1431						vueInstance.instanceLoadStatus = false;
1432						//vueInstance.initTemplatesContent();
1433					}, function( reason ) {
1434						console.log( 'Script Loaded Error' );
1435					} );
1436
1437					jetMenu.eventBus.$on( 'itemsSubSwitch', function ( payLoad ) {
1438
1439						if ( vueInstance.$root.menuOptions.menuUniqId !== payLoad.menuUniqId ) {
1440							return;
1441						}
1442
1443						vueInstance.trail.push( payLoad.children );
1444						vueInstance.children = payLoad.children;
1445						vueInstance.animation = 'items-next-animation';
1446						vueInstance.breadcrumbsData.push( payLoad.name );
1447					} );
1448
1449					jetMenu.eventBus.$on( 'showTemplateContent', function ( payLoad ) {
1450
1451						if ( vueInstance.$root.menuOptions.menuUniqId !== payLoad.menuUniqId ) {
1452							return;
1453						}
1454
1455						vueInstance.itemTemplateContent = payLoad.megaContent.content;
1456						vueInstance.templateVisible = true;
1457						vueInstance.breadcrumbsData.push( payLoad.name );
1458						vueInstance.animation = 'items-next-animation';
1459
1460						const templateData = {
1461							content: payLoad.megaContent.content !== undefined
1462								? payLoad.megaContent.content
1463								: payLoad.megaContent,
1464							contentElements: payLoad.megaContent.contentElements,
1465							contentType: payLoad.megaContentType,
1466						}
1467
1468						vueInstance.showTemplateContent( templateData );
1469					} );
1470
1471					jetMenu.eventBus.$on( 'closeMenu', function( payLoad ) {
1472
1473						if ( vueInstance.$root.menuOptions.menuUniqId !== payLoad.menuUniqId ) {
1474							return;
1475						}
1476
1477						vueInstance.closeMenu();
1478					} );
1479
1480				},
1481
1482				watch: {
1483					menuOpen: function( curr, prev ) {
1484
1485						if ( curr ) {
1486							jetMenu.$body.addClass( 'jet-mobile-menu-visible' );
1487
1488							if ( 'slide-out' === this.$root.menuOptions.menuLayout ) {
1489								jetMenu.$body.addClass( 'jet-menu-body-blocker' );
1490							}
1491
1492							this.initTemplatesContent();
1493						}
1494
1495						if ( ! curr ) {
1496							jetMenu.$body.removeClass( 'jet-mobile-menu-visible' );
1497
1498							if ( 'slide-out' === this.$root.menuOptions.menuLayout ) {
1499								jetMenu.$body.removeClass( 'jet-menu-body-blocker' );
1500							}
1501
1502							this.clearStates();
1503						}
1504					}
1505				},
1506
1507				computed: {
1508					instanceClass: function() {
1509
1510						let classes = [
1511							'jet-mobile-menu__instance',
1512							'jet-mobile-menu__instance--' + this.$root.menuOptions.menuLayout + '-layout',
1513							this.$root.menuOptions.menuPosition + '-container-position',
1514							( this.$root.menuOptions.togglePosition || 'default' ) + '-toggle-position',
1515							this.$root.menuOptions.fillSvgIcon ? 'fill-svg-icon' : '',
1516						];
1517
1518						return classes;
1519					},
1520
1521					menuContainerVisible: function() {
1522						return this.menuOpen && !this.instanceLoadStatus;
1523					},
1524
1525					menuId: function() {
1526
1527						if ( this.$root.menuOptions.mobileMenuId && window.jetMenuPublicSettings.isMobile === 'true' ) {
1528							return this.$root.menuOptions.mobileMenuId;
1529						}
1530
1531						return this.$root.menuOptions.menuId;
1532					},
1533
1534					coverVisible: function() {
1535
1536						let avaliableForLayout = [
1537							'slide-out'
1538						];
1539
1540						return avaliableForLayout.includes( this.$root.menuOptions.menuLayout );
1541					},
1542
1543					itemsList: function() {
1544
1545						if ( ! this.children ) {
1546							return this.itemsRawData;
1547						}
1548
1549						return this.children;
1550					},
1551
1552					isClose: function() {
1553						let avaliableForLayout = [
1554							'slide-out'
1555						];
1556
1557						return avaliableForLayout.includes( this.$root.menuOptions.menuLayout );
1558					},
1559
1560					isBack: function() {
1561						return this.children || this.templateVisible ? true : false;
1562					},
1563
1564					isBreadcrumbs: function() {
1565						return this.$root.menuOptions.useBreadcrumb && 0 !== this.breadcrumbsData.length ? true : false;
1566					},
1567
1568					breadcrumbsPathData: function() {
1569
1570						if ( 'minimal' === this.$root.$root.menuOptions.breadcrumbPath && 1 < this.breadcrumbsData.length ) {
1571							return this.breadcrumbsData.filter( ( item, index, breadcrumbsData ) => {
1572								return 	index === breadcrumbsData.length - 1;
1573							} );
1574						}
1575
1576						return this.breadcrumbsData;
1577					},
1578
1579					depth: function() {
1580						return this.trail.length;
1581					},
1582
1583					containerPosition: function() {
1584						return this.$root.menuOptions.menuPosition;
1585					},
1586
1587					showAnimation: function() {
1588
1589						let animation = false;
1590
1591						switch( this.$root.menuOptions.menuLayout ) {
1592
1593							case 'slide-out':
1594								animation = 'right' === this.containerPosition ? 'menu-container-left-animation' : 'menu-container-right-animation';
1595								break;
1596
1597							case 'dropdown':
1598								animation = 'menu-container-dropdown-animation';
1599								break;
1600
1601							case 'push':
1602								animation = 'menu-container-expand-animation';
1603								break;
1604						}
1605
1606						return animation;
1607					},
1608
1609					toggleClosedIcon: function() {
1610						return this.$root.refsHtml.toggleClosedIcon || '';
1611					},
1612
1613					toggleOpenedIcon: function() {
1614						return this.$root.refsHtml.toggleOpenedIcon || '';
1615					},
1616
1617					toggleText: function() {
1618						return '' !== this.$root.menuOptions.toggleText ? this.$root.menuOptions.toggleText : false;
1619					},
1620
1621					closeIcon: function() {
1622						return this.$root.refsHtml.closeIcon || '';
1623					},
1624
1625					backIcon: function() {
1626						let backIcon = this.$root.refsHtml.backIcon || '',
1627							backText = '' !== this.$root.menuOptions.backText ? '<span>' + this.$root.menuOptions.backText + '</span>' : '',
1628							backHtml = backIcon + backText;
1629
1630						return backHtml;
1631					},
1632
1633					backText: function() {
1634						return '' !== this.$root.menuOptions.backText ? this.$root.menuOptions.backText : false;
1635					},
1636
1637					breadcrumbIcon: function() {
1638						return this.$root.refsHtml.breadcrumbIcon || '';
1639					},
1640
1641					loaderColor: function() {
1642						return this.$root.menuOptions.loaderColor || '#3a3a3a';
1643					},
1644
1645					toggleLoaderVisible: function() {
1646						return this.$root.menuOptions.toggleLoader && this.instanceLoadStatus && this.menuOpen ? true : false;
1647					},
1648
1649					headerTemplateVisible: function() {
1650						return this.headerContent ? true : false;
1651					},
1652
1653					beforeTemplateVisible: function() {
1654						return this.beforeContent ? true : false;
1655					},
1656
1657					afterTemplateVisible: function() {
1658						return this.afterContent ? true : false;
1659					}
1660
1661				},
1662
1663				methods: {
1664					menuToggle: function() {
1665						this.menuOpen = ! this.menuOpen;
1666					},
1667
1668					closeMenu: function() {
1669						this.menuOpen = false;
1670					},
1671
1672					clearStates: function() {
1673						this.trail = [];
1674						this.children = false;
1675						this.breadcrumbsData = [];
1676						this.templateVisible = false;
1677					},
1678
1679					goBack: function() {
1680
1681						this.animation = 'items-prev-animation';
1682
1683						if ( ! this.templateVisible ) {
1684							this.$delete( this.trail, this.trail.length - 1 );
1685							this.children = this.trail.slice(-1)[0] || false;
1686						} else {
1687							this.templateVisible = false;
1688						}
1689
1690						this.$delete(this.breadcrumbsData, this.breadcrumbsData.length - 1);
1691					},
1692
1693					escapeKeyHandler: function() {
1694
1695						if ( this.isBack ) {
1696							this.goBack();
1697						} else {
1698							this.closeMenu();
1699						}
1700					},
1701
1702					showTemplateContent: function( templateData = {} ) {
1703						let vueInstance = this;
1704
1705						this.$nextTick( function() {
1706							let $templateContainer = $( vueInstance.$refs['template-content'] ).find( '.jet-mobile-menu__template-content' );
1707
1708							jetMenu.megaContentRender( $templateContainer, templateData );
1709						} );
1710					},
1711
1712					initTemplatesContent: function() {
1713						let vueInstance = this;
1714
1715						this.$nextTick( function() {
1716
1717							if ( vueInstance.headerContent ) {
1718								let $headerContainer = $( vueInstance.$refs['header-template-content'] );
1719
1720								jetMenu.megaContentRender( $headerContainer, { contentType: 'elementor' } );
1721							}
1722
1723							if ( vueInstance.beforeContent ) {
1724								let $beforeContainer = $( vueInstance.$refs['before-template-content'] );
1725
1726								jetMenu.megaContentRender( $beforeContainer, { contentType: 'elementor' } );
1727							}
1728
1729							if ( vueInstance.afterContent ) {
1730								let $afterContainer = $( vueInstance.$refs['after-template-content'] );
1731
1732								jetMenu.megaContentRender( $afterContainer, { contentType: 'elementor' } );
1733							}
1734						} );
1735					},
1736
1737					breadcrumbHandle: function( index ) {
1738
1739						if ( index === this.breadcrumbsData.length ) {
1740							return;
1741						}
1742
1743						if ( 'minimal' === this.$root.menuOptions.breadcrumbPath ) {
1744							this.goBack();
1745
1746							return;
1747						}
1748
1749						this.animation = 'items-prev-animation';
1750						this.trail = this.trail.slice( 0, index );
1751						this.children = this.trail.slice( -1 )[0] || false;
1752						this.templateVisible = false;
1753						this.breadcrumbsData = this.breadcrumbsData.slice( 0, index );
1754					}
1755
1756				}
1757			});
1758		},
1759
1760		loadScriptAsync: function( script, uri ) {
1761
1762			if ( jetMenu.addedScripts.hasOwnProperty( script ) ) {
1763				return script;
1764			}
1765
1766			jetMenu.addedScripts[ script ] = uri;
1767
1768			return new Promise( function( resolve, reject ) {
1769				var tag = document.createElement( 'script' );
1770
1771					tag.src    = uri;
1772					tag.async  = true;
1773					tag.onload = function() {
1774						resolve( script );
1775					};
1776
1777				document.head.appendChild( tag );
1778			} );
1779		},
1780
1781		loadStyle: function( style, uri ) {
1782
1783			if ( jetMenu.addedStyles.hasOwnProperty( style ) && jetMenu.addedStyles[ style ] ===  uri) {
1784				return style;
1785			}
1786
1787			jetMenu.addedStyles[ style ] = uri;
1788
1789			return new Promise( function( resolve, reject ) {
1790				var tag = document.createElement( 'link' );
1791
1792					tag.id      = style;
1793					tag.rel     = 'stylesheet';
1794					tag.href    = uri;
1795					tag.type    = 'text/css';
1796					tag.media   = 'all';
1797					tag.onload  = function() {
1798						resolve( style );
1799					};
1800
1801				document.head.appendChild( tag );
1802			});
1803		},
1804
1805		megaContentRender: function( $templateContainer, templateData = {} ) {
1806
1807			if ( templateData.content ) {
1808				$templateContainer.html( templateData.content );
1809			}
1810
1811			const data = {
1812				$container: $templateContainer,
1813				...templateData
1814			}
1815
1816			Promise.all( jetMenu.addedAssetsPromises ).then( function( value ) {
1817				// Before ajax frontend init
1818				$( window ).trigger( 'jet-menu/ajax/frontend-init/before', data );
1819
1820				// Frontend init
1821				$( window ).trigger( 'jet-menu/ajax/frontend-init', data );
1822
1823				// after ajax frontend init
1824				$( window ).trigger( 'jet-menu/ajax/frontend-init/after', data );
1825			}, function( reason ) {
1826				console.log( 'Script Loaded Error' );
1827			});
1828		},
1829
1830		maybeElementorFrontendInit: function( $templateContainer ) {
1831
1832			$templateContainer.find( 'div[data-element_type]' ).each( function() {
1833				var $this       = $( this ),
1834					elementType = $this.data( 'element_type' );
1835
1836				if ( ! elementType ) {
1837					return;
1838				}
1839
1840				try {
1841					if ( 'widget' === elementType ) {
1842						elementType = $this.data( 'widget_type' );
1843
1844						if ( window.elementorFrontend && window.elementorFrontend.hooks ) {
1845							window.elementorFrontend.hooks.doAction( 'frontend/element_ready/widget', $this, $ );
1846						}
1847					}
1848
1849					if ( window.elementorFrontend && window.elementorFrontend.hooks ) {
1850						window.elementorFrontend.hooks.doAction( 'frontend/element_ready/global', $this, $ );
1851						window.elementorFrontend.hooks.doAction( 'frontend/element_ready/' + elementType, $this, $ );
1852					}
1853
1854				} catch ( err ) {
1855					console.log(err);
1856					$this.remove();
1857
1858					return false;
1859				}
1860			} );
1861		},
1862
1863		maybeDefaultFrontendInit: function ( payload ) {
1864			const contentElements = payload.contentElements || [],
1865				$container = payload.$container;
1866
1867			$container.find( '[data-is-block*="/"]' ).each( ( index, el ) => {
1868				window.JetPlugins.hooks.doAction( window.JetPlugins.hookNameFromBlock( el.dataset.isBlock ), jQuery( el ) );
1869			} );
1870		},
1871
1872		getUniqId: function() {
1873			return Math.random().toString( 36 ).substr( 2, 9 );
1874		},
1875
1876	};
1877
1878	jetMenu.init();
1879
1880} ( jQuery ) );
1881

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.