PageSourceSearch

https://pacforum.org/wp-content/plugins/jet-engine/assets/js/frontend.js?ver=3.7.7

js pacforum.org collected 2026-09-24 09:30:51 UTC 72,905 bytes, 2,765 lines download raw bytes

1( function( $ ) {
2
3	"use strict";
4
5	var JetEngineRegisteredStores = window.JetEngineRegisteredStores || {};
6	var JetEngineStores           = window.JetEngineStores || {};
7
8	var JetEngine = {
9
10		currentMonth: null,
11		currentRequest: {},
12		activeCalendarDay: null,
13		lazyLoading: false,
14		addedScripts: [],
15		addedStyles: [],
16		addedPostCSS: [],
17		assetsPromises: [],
18
19		initDone: false,
20
21		commonInit: function() {
22
23			JetEngine.commonEvents();
24
25			$( window ).on( 'jet-popup/render-content/ajax/success', JetEngine.initStores );
26
27			window.JetPlugins.hooks.addFilter(
28				'jet-popup.show-popup.data',
29				'JetEngine.popupData',
30				( popupData, $popup, $triggeredBy ) => {
31
32					if ( ! $triggeredBy ) {
33						return popupData;
34					}
35
36					if ( $triggeredBy.data( 'popupIsJetEngine' ) ) {
37						popupData = JetEngine.prepareJetPopup( popupData, { 'is-jet-engine': true }, $triggeredBy );
38					}
39
40					return popupData;
41				}
42			);
43
44			JetEngine.initStores();
45			JetEngine.customUrlActions.init();
46
47		},
48
49		commonEvents: function( $scope ) {
50			$scope = $scope || $( document );
51
52			$scope
53				.on( 'jet-filter-content-rendered', JetEngine.calendarCache.clear )
54				.on( 'change.JetEngine', '.jet-calendar-caption__date-select', JetEngine.selectCalendarMonth )
55				.on( 'click.JetEngine', '.jet-calendar-nav__link', JetEngine.switchCalendarMonth )
56				.on( 'click.JetEngine', '.jet-calendar-week__day-mobile-overlay', JetEngine.showCalendarEvent )
57				.on( 'click.JetEngine', '.jet-listing-dynamic-link__link[data-delete-link="1"]', JetEngine.showConfirmDeleteDialog )
58				.on( 'jet-filter-content-rendered', JetEngine.maybeReinitSlider )
59				.on( 'click.JetEngine', '.jet-add-to-store', JetEngine.addToStore )
60				.on( 'click.JetEngine', '.jet-remove-from-store', JetEngine.removeFromStore )
61				.on( 'click.JetEngine', '.jet-engine-listing-overlay-wrap:not([data-url*="event=hover"])', JetEngine.handleListingItemClick )
62				.on( 'jet-filter-content-rendered', JetEngine.filtersCompatibility )
63				.on( 'click.JetEngine', '.jet-container[data-url]', JetEngine.handleContainerURL )
64				.on( 'change.JetEngine', '.jet-listing-dynamic-link .qty', JetEngine.handleProductQuantityChange );
65		},
66
67		handleProductQuantityChange: function ( event ) {
68			event.preventDefault();
69			event.stopPropagation();
70
71			const $this = $( this );
72
73			$this.closest( ".jet-listing-dynamic-link" ).find( ".jet-woo-add-to-cart" ).data( "quantity", $this.val() ).attr( "data-quantity", $this.val() );
74		},
75
76		handleContainerURL: function() {
77			var $this  = $( this ),
78				url    = $this.data( 'url' ),
79				target = $this.data( 'target' );
80
81			if ( ! target ) {
82				window.location = url;
83			} else {
84				window.open( url, '_blank' ).focus();
85			}
86
87		},
88
89		filtersCompatibility: function( event, $provider, filtersInstance, providerType ) {
90
91			let providers = {
92				'jet-engine': true,
93				'jet-engine-calendar': true,
94				'jet-data-table': true,
95			};
96
97			if ( ! providers[ providerType ] ) {
98				return;
99			}
100
101			/*
102			No need anymore to manually re-init the block.
103			JetSmartFilters automatically re-init blocks.
104
105			var $blocksListing = $provider.closest( '.jet-listing-grid--blocks' );
106
107			if ( $blocksListing.length ) {
108				JetEngine.widgetListingGrid( $blocksListing );
109			}
110			*/
111
112			if ( window.JetPopupFrontend && window.JetPopupFrontend.initAttachedPopups ) {
113				window.JetPopupFrontend.initAttachedPopups( $provider );
114			}
115		},
116
117		init: function() {
118
119			var widgets = {
120				'jet-listing-dynamic-field.default' : JetEngine.widgetDynamicField,
121				'jet-listing-grid.default': JetEngine.widgetListingGrid,
122			};
123
124			$.each( widgets, function( widget, callback ) {
125				window.elementorFrontend.hooks.addAction( 'frontend/element_ready/' + widget, callback );
126			});
127
128			// Re-init sliders in nested tabs
129			window.elementorFrontend.elements.$window.on(
130				'elementor/nested-tabs/activate',
131				( event, content ) => {
132					const $content = $( content );
133
134					setTimeout( () => {
135						JetEngine.maybeReinitSlider( event, $content );
136						JetEngine.widgetDynamicField( $content );
137					} );
138				}
139			);
140
141			window.elementorFrontend.hooks.addFilter(
142				'jet-popup/widget-extensions/popup-data',
143				JetEngine.prepareJetPopup
144			);
145
146			window.JetPlugins.hooks.addFilter(
147				'jet-popup.show-popup.data',
148				'JetEngine.popupData',
149				( popupData, $popup, $triggeredBy ) => {
150
151					if ( ! $triggeredBy ) {
152						return popupData;
153					}
154
155					if ( $triggeredBy.data( 'popupIsJetEngine' ) ) {
156						popupData = JetEngine.prepareJetPopup( popupData, { 'is-jet-engine': true }, $triggeredBy );
157					}
158
159					return popupData;
160				}
161			);
162
163			JetEngine.updateAddedStyles();
164		},
165
166		initBricks: function( $scope ) {
167
168			if ( window.bricksIsFrontend ) {
169				return;
170			}
171
172			$scope = $scope || $( 'body' );
173			JetEngine.initBlocks( $scope );
174
175		},
176
177		initBlocks: function( $scope ) {
178
179			$scope = $scope || $( 'body' );
180
181			window.JetPlugins.init( $scope, [
182				{
183					block: 'jet-engine/listing-grid',
184					callback: JetEngine.widgetListingGrid
185				},
186				{
187					block: 'jet-engine/dynamic-field',
188					callback: JetEngine.widgetDynamicField
189				}
190			] );
191		},
192
193		initFrontStores: function( $scope ) {
194
195			$scope = $scope || $( 'body' );
196
197			$( '.jet-add-to-store.is-front-store', $scope ).each( function() {
198
199				var $this = $( this ),
200					args  = $this.data( 'args' ),
201					store = JetEngineStores[ args.store.type ],
202					count = 0;
203
204				args = JetEngine.ensureJSON( args );
205
206				if ( ! store ) {
207					return;
208				}
209
210				if ( store.inStore( args.store.slug, '' + args.post_id ) ) {
211					JetEngine.switchDataStoreStatus( $this );
212				}
213
214			} );
215
216			$( '.jet-remove-from-store.is-front-store', $scope ).each( function() {
217
218				var $this = $( this ),
219					args  = $this.data( 'args' ),
220					store = JetEngineStores[ args.store.type ],
221					count = 0;
222
223				args = JetEngine.ensureJSON( args );
224
225				if ( ! store ) {
226					return;
227				}
228
229				if ( ! store.inStore( args.store.slug, '' + args.post_id ) ) {
230					$this.addClass( 'is-hidden' );
231				} else {
232					$this.removeClass( 'is-hidden' );
233				}
234
235			} );
236
237		},
238
239		initStores: function() {
240
241			JetEngine.initFrontStores();
242
243			$.each( JetEngineRegisteredStores, function( storeSlug, storeType ) {
244
245				var store = JetEngineStores[ storeType ],
246					storeData = null,
247					count = 0;
248
249				if ( ! store ) {
250					return;
251				}
252
253				storeData = store.getStore( storeSlug );
254
255				if ( storeData && storeData.length ) {
256					count = storeData.length;
257				}
258
259				$( 'span.jet-engine-data-store-count[data-store="' + storeSlug + '"]' ).text( count );
260
261			} );
262
263			JetEngine.loadFrontStoresItems();
264
265		},
266
267		loadFrontStoresItems: function( $scope ) {
268
269			$scope = $scope || $( 'body' );
270
271			$( '.jet-listing-not-found.jet-listing-grid__items', $scope ).each( function() {
272
273				var $this   = $( this ),
274					nav     = $this.data( 'nav' ),
275					isStore = $this.data( 'is-store-listing' ),
276					query   = nav.query || {};
277
278				nav = JetEngine.ensureJSON( nav );
279
280				if ( query && query.post__in && query.post__in.length && 0 >= query.post__in.indexOf( 'is-front' ) ) {
281
282					var storeType  = query.post__in[1],
283						storeSlug  = query.post__in[2],
284						store      = JetEngineStores[ storeType ],
285						posts      = [],
286						$container = $this.closest( '.jet-listing-grid' );
287
288					if ( ! store ) {
289						return;
290					}
291
292					//Context Gutenberg
293					if ( ! $container.length ) {
294						$container = $this.closest( '.jet-listing-grid--blocks' );
295					}
296
297					// Context Bricks
298					if ( ! $container.length ) {
299						$container = $this.closest( '.brxe-jet-engine-listing-grid' )
300					}
301
302					posts = store.getStore( storeSlug );
303
304					if ( ! posts.length ) {
305						return;
306					}
307
308					query.front_store__in = posts;
309					query.is_front_store = true;
310
311					JetEngine.ajaxGetListing( {
312						handler: 'get_listing',
313						container: $container,
314						masonry: false,
315						slider: false,
316						append: false,
317						query: query,
318						widgetSettings: nav.widget_settings,
319					}, function( response ) {
320						JetEngine.widgetListingGrid( $container );
321					} );
322
323				} else if ( isStore ) {
324					$( document ).trigger( 'jet-listing-grid-init-store', $this );
325				}
326
327			} );
328		},
329
330		dataStores: {
331			queues: {},
332			getQueue: function( store ) {
333				if ( ! ( this.queues?.[ store ] instanceof Promise ) ) {
334					this.queues[ store ] = Promise.resolve();
335				}
336
337				return this.queues[ store ];
338			},
339			addToQueue: function( store, callback ) {
340				this.queues[ store ] = this.getQueue( store ).then( callback );
341			},
342		},
343
344		removeFromStore: function( event ) {
345
346			event.preventDefault();
347			event.stopPropagation();
348
349			var $this = $( this ),
350				args  = $this.data( 'args' ),
351				isDataStoreBtn = $this.hasClass( 'jet-data-store-link' );
352
353			args = JetEngine.ensureJSON( args );
354
355			if ( args.store.is_front ) {
356
357				var store = JetEngineStores[ args.store.type ],
358					count = 0;
359
360				if ( ! store ) {
361					return;
362				}
363
364				if ( ! store.inStore( args.store.slug, '' + args.post_id ) ) {
365					var storePosts = store.getStore( args.store.slug );
366					count = storePosts.length;
367				} else {
368					count = store.remove( args.store.slug, args.post_id );
369				}
370
371				$( '.jet-add-to-store[data-store="' + args.store.slug + '"][data-post="' + args.post_id + '"]' ).each( function() {
372					JetEngine.switchDataStoreStatus( $( this ), true );
373				} );
374
375				$( '.jet-data-store-link.jet-remove-from-store[data-store="' + args.store.slug + '"][data-post="' + args.post_id + '"]' ).each( function() {
376					JetEngine.switchDataStoreStatus( $( this ), true );
377				} );
378
379				$( 'span.jet-engine-data-store-count[data-store="' + args.store.slug + '"]' ).text( count );
380
381				if ( args.remove_from_listing ) {
382					$this.closest( '.jet-listing-dynamic-post-' + args.post_id ).remove();
383				}
384
385				JetEngine.dataStoreSyncListings( args );
386
387				$( document ).trigger( 'jet-engine-data-stores-on-remove', args );
388
389				return;
390
391			}
392
393			if ( $this.hasClass( 'jet-store-processing' ) ) {
394				return;
395			}
396
397			$this.css( 'opacity', 0.3 );
398			$this.addClass( 'jet-store-processing' );
399
400			JetEngine.dataStores.addToQueue( args.store.slug, () => {
401				return $.ajax({
402					url: JetEngineSettings.ajaxurl,
403					type: 'POST',
404					dataType: 'json',
405					data: {
406						action: 'jet_engine_remove_from_store_' + args.store.slug,
407						store: args.store.slug,
408						post_id: args.post_id,
409					},
410				}).done( function( response ) {
411
412					$this.css( 'opacity', 1 );
413					$this.removeClass( 'jet-store-processing' );
414
415					if ( response.success ) {
416
417						if ( ! isDataStoreBtn ) {
418							$this.addClass( 'is-hidden' );
419						}
420
421						$( '.jet-add-to-store[data-store="' + args.store.slug + '"][data-post="' + args.post_id + '"]' ).each( function() {
422							JetEngine.switchDataStoreStatus( $( this ), true );
423						} );
424
425						$( '.jet-data-store-link.jet-remove-from-store[data-store="' + args.store.slug + '"][data-post="' + args.post_id + '"]' ).each( function() {
426							JetEngine.switchDataStoreStatus( $( this ), true );
427						} );
428
429						JetEngine.dataStoreSyncListings( args );
430
431						if ( args.remove_from_listing ) {
432							$this.closest( '.jet-listing-grid__item[data-post="' + args.post_id + '"]' ).remove();
433						}
434
435						if ( response.data.fragments ) {
436							$.each( response.data.fragments, function( selector, value ) {
437								$( selector ).html( value );
438							} );
439						}
440
441						$( document ).trigger( 'jet-engine-data-stores-on-remove', args );
442
443					} else {
444						alert( response.data.message );
445					}
446
447					return response;
448
449				} ).done( function( response ) {
450
451					if ( args.remove_from_listing ) {
452						$this.closest( '.jet-listing-grid__item' ).remove();
453					}
454
455					if ( response.success ) {
456						$( 'span.jet-engine-data-store-count[data-store="' + args.store.slug + '"]' ).text( response.data.count );
457					}
458
459				} ).fail( function( jqXHR, textStatus, errorThrown ) {
460					$this.css( 'opacity', 1 );
461					$this.removeClass( 'jet-store-processing' );
462					alert( errorThrown );
463				} );
464			} );
465
466		},
467
468		triggerPopup: function( popupID, isJetEngine, postID ) {
469
470			if ( ! popupID ) {
471				return;
472			}
473
474			var popupData = {
475				popupId: 'jet-popup-' + popupID,
476			};
477
478			if ( isJetEngine ) {
479				popupData.isJetEngine = true;
480				popupData.postId      = postID;
481			}
482
483			$( window ).trigger( {
484				type: 'jet-popup-open-trigger',
485				popupData: popupData
486			} );
487
488		},
489
490		dataStoreSyncListings: function( args ) {
491			if ( ! args.synch_id || typeof args.synch_id !== 'string' ) {
492				return;
493			}
494
495			const ids = args.synch_id.split( /[\s,]+/ ).map( ( id ) => id.replace( /\s/, '' ) ).filter( ( id ) => !! id );
496
497			ids.forEach( function ( id ) {
498				let $container = $( '#' + id ),
499				$elemContainer = $container.find( '> .elementor-widget-container' );
500
501				if ( ! $container.length ) {
502					return;
503				}
504
505				let $items         = $container.find( '.jet-listing-grid__items' ),
506				    posts          = [],
507				    nav            = $items.data( 'nav' ) || {},
508				    query          = nav.query || {},
509					postID         = window.elementorFrontendConfig?.post?.id || 0;
510
511				nav = JetEngine.ensureJSON( nav );
512
513				// Context Bricks
514				if ( $container.hasClass( 'brxe-jet-engine-listing-grid' ) ) {
515					postID = window.bricksData.postId;
516				}
517
518				// Context Gutenberg
519				if ( $container.hasClass( 'jet-listing-grid--blocks' )) {
520					postID = JetEngineSettings.post_id;
521				}
522
523				if ( args?.store?.is_front && Object.keys( query ).length ) {
524					let store = JetEngineStores[ args.store.type ];
525
526					posts = store.getStore( args.store.slug );
527
528					if ( ! posts.length ) {
529						posts = [ 'is-front', args.store.type, args.store.slug ];
530					}
531
532					query.front_store__in = posts;
533					query.is_front_store = true;
534				}
535
536				let options = {
537					handler: 'get_listing',
538					container: $elemContainer.length ? $elemContainer : $container,
539					masonry: false,
540					slider: false,
541					append: false,
542					query: query,
543					widgetSettings: nav.widget_settings,
544					postID: postID,
545					elementID: $container.data( 'id' ),
546				};
547
548				JetEngine.ajaxGetListing( options, function( response ) {
549					JetEngine.widgetListingGrid( $container );
550				} );
551			} );
552		},
553
554		addToStore: function( event ) {
555
556			event.preventDefault();
557			event.stopPropagation();
558
559			var $this = $( this ),
560				args  = $this.data( 'args' );
561
562			args = JetEngine.ensureJSON( args );
563
564			if ( $this.hasClass( 'in-store' ) ) {
565				if ( args.popup ) {
566					JetEngine.triggerPopup( args.popup, args.isJetEngine, args.post_id );
567				} else if ( '_blank' === $this.attr( 'target' ) ) {
568					window.open( $this.attr( 'href' ) );
569				} else {
570					window.location = $this.attr( 'href' );
571				}
572				return;
573			}
574
575			if ( args.store.is_front ) {
576
577				var store = JetEngineStores[ args.store.type ],
578					count = 0;
579
580				if ( ! store ) {
581					return;
582				}
583
584				if ( store.inStore( args.store.slug, '' + args.post_id ) ) {
585					var storePosts = store.getStore( args.store.slug );
586					count = storePosts.length;
587				} else {
588
589					count = store.addToStore( args.store.slug, args.post_id, args.store.size );
590
591					if ( false === count ) {
592						return;
593					}
594
595				}
596
597				if ( args.popup ) {
598					JetEngine.triggerPopup( args.popup, args.isJetEngine, args.post_id );
599				}
600
601				JetEngine.switchDataStoreStatus( $this );
602				$( 'span.jet-engine-data-store-count[data-store="' + args.store.slug + '"]' ).text( count );
603				$( '.jet-remove-from-store[data-store="' + args.store.slug + '"][data-post="' + args.post_id + '"]' ).removeClass( 'is-hidden' );
604
605				JetEngine.dataStoreSyncListings( args );
606
607				$( document ).trigger( 'jet-engine-data-stores-on-add', args );
608
609				return;
610			}
611
612			if ( $this.hasClass( 'jet-store-processing' ) ) {
613				return;
614			}
615
616			$this.css( 'opacity', 0.3 );
617			$this.addClass( 'jet-store-processing' );
618
619			$( document ).trigger( 'jet-engine-on-add-to-store', [ $this, args ] );
620
621			JetEngine.dataStores.addToQueue( args.store.slug, () => {
622				return $.ajax({
623					url: JetEngineSettings.ajaxurl,
624					type: 'POST',
625					dataType: 'json',
626					data: {
627						action: 'jet_engine_add_to_store_' + args.store.slug,
628						store: args.store.slug,
629						post_id: args.post_id,
630					},
631				}).done( function( response ) {
632
633					$this.css( 'opacity', 1 );
634					$this.removeClass( 'jet-store-processing' );
635
636					if ( response.success ) {
637
638						JetEngine.switchDataStoreStatus( $this );
639						$( '.jet-remove-from-store[data-store="' + args.store.slug + '"][data-post="' + args.post_id + '"]' ).removeClass( 'is-hidden' );
640
641						if ( response.data.fragments ) {
642							$.each( response.data.fragments, function( selector, value ) {
643								$( selector ).html( value );
644							} );
645						}
646
647						JetEngine.dataStoreSyncListings( args );
648
649						if ( args.popup ) {
650							JetEngine.triggerPopup( args.popup, args.isJetEngine, args.post_id );
651						}
652
653					} else {
654						alert( response.data.message );
655					}
656
657					$( document ).trigger( 'jet-engine-data-stores-on-add', args );
658
659					return response;
660
661				} ).done( function( response ) {
662
663					if ( response.success ) {
664						$( 'span.jet-engine-data-store-count[data-store="' + args.store.slug + '"]' ).text( response.data.count );
665					}
666
667				} ).fail( function( jqXHR, textStatus, errorThrown ) {
668					$this.css( 'opacity', 1 );
669					$this.removeClass( 'jet-store-processing' );
670					alert( errorThrown );
671				} );
672			} );
673
674		},
675
676		switchDataStoreStatus: function( $item, toInitial ) {
677
678			var isDataStoreLink = $item.hasClass( 'jet-data-store-link' ),
679				$label = $item.find( '.jet-listing-dynamic-link__label, .jet-data-store-link__label' ),
680				$icon  = $item.find( '.jet-listing-dynamic-link__icon, .jet-data-store-link__icon' ),
681				args   = $item.data( 'args' ),
682				replaceLabel,
683				replaceURL,
684				replaceIcon;
685
686			args = JetEngine.ensureJSON( args );
687
688			toInitial = toInitial || false;
689
690			if ( isDataStoreLink ) {
691
692				switch ( args.action_after_added ) {
693					case 'remove_from_store':
694
695						if ( toInitial ) {
696							$item.addClass( 'jet-add-to-store' );
697							$item.removeClass( 'jet-remove-from-store' );
698
699							$item.removeClass( 'in-store' );
700						} else {
701							$item.addClass( 'jet-remove-from-store' );
702							$item.removeClass( 'jet-add-to-store' );
703
704							$item.addClass( 'in-store' );
705
706						}
707
708						break;
709
710					case 'hide':
711
712						if ( toInitial ) {
713							$item.removeClass( 'is-hidden' );
714						} else {
715							$item.addClass( 'is-hidden' );
716						}
717
718						return;
719				}
720
721			}
722
723			if ( toInitial ) {
724				replaceLabel = args.label;
725				replaceIcon  = args.icon;
726				replaceURL   = '#';
727			} else {
728				replaceLabel = args.added_label;
729				replaceIcon  = args.added_icon;
730				replaceURL   = args.added_url;
731			}
732
733			if ( $label.length ) {
734				$label.replaceWith( replaceLabel );
735			} else {
736				$item.append( replaceLabel );
737			}
738
739			if ( $icon.length ) {
740				$icon.replaceWith( replaceIcon );
741			} else {
742				$item.prepend( replaceIcon );
743			}
744
745			if ( isDataStoreLink && 'remove_from_store' === args.action_after_added ) {
746				return;
747			}
748
749			$item.attr( 'href', replaceURL );
750
751			if ( toInitial ) {
752				$item.removeClass( 'in-store' );
753			} else if ( ! $item.hasClass( 'in-store' ) ) {
754				$item.addClass( 'in-store' );
755			}
756
757
758		},
759
760		showConfirmDeleteDialog: function( event ) {
761			event.preventDefault();
762			event.stopPropagation();
763
764			var $this = $( this );
765
766			if ( window.confirm( $this.data( 'delete-message' ) ) ) {
767				window.location = $this.attr( 'href' );
768			}
769
770		},
771
772		handleListingItemClick: function( event ) {
773
774			var url    = $( this ).data( 'url' ),
775				target = $( this ).data( 'target' ) || false;
776
777			if ( url ) {
778
779				event.preventDefault();
780
781				if ( window.elementorFrontend && window.elementorFrontend.isEditMode() ) {
782					return;
783				}
784
785				if ( -1 !== url.indexOf( '#jet-engine-action' ) ) {
786
787					JetEngine.customUrlActions.runAction( url );
788
789				} else {
790
791					if ( '_blank' === target ) {
792						window.open( url );
793						return;
794					}
795
796					window.location = url;
797				}
798			}
799
800		},
801
802		customUrlActions: {
803			selectorOnClick: 'a[href^="#jet-engine-action"][href*="event=click"]',
804			selectorOnHover: 'a[href^="#jet-engine-action"][href*="event=hover"], [data-url^="#jet-engine-action"][data-url*="event=hover"]',
805
806			init: function() {
807				var timeout = null;
808
809				$( document ).on( 'click.JetEngine', this.selectorOnClick, function( event ) {
810					event.preventDefault();
811					JetEngine.customUrlActions.actionHandler( event )
812				} );
813
814				$( document ).on( 'click.JetEngine', this.selectorOnHover, function( event ) {
815					if ( 'A' === event.currentTarget.nodeName ) {
816						event.preventDefault();
817					}
818				} );
819
820				$( document ).on( {
821					'mouseenter.JetEngine': function( event ) {
822
823						if ( timeout ) {
824							clearTimeout( timeout );
825						}
826
827						timeout = setTimeout( function() {
828							JetEngine.customUrlActions.actionHandler( event )
829						}, window.JetEngineSettings.hoverActionTimeout );
830					},
831					'mouseleave.JetEngine': function() {
832						if ( timeout ) {
833							clearTimeout( timeout );
834							timeout = null;
835						}
836					},
837				}, this.selectorOnHover );
838			},
839
840			actions: {},
841
842			addAction: function( name, callback ) {
843				this.actions[ name ] = callback;
844			},
845
846			actionHandler: function( event ) {
847				var url = $( event.currentTarget ).attr( 'href' ) || $( event.currentTarget ).attr( 'data-url' );
848
849				this.runAction( url );
850			},
851
852			runAction: function( url ) {
853				var queryParts = url.split( '&' ),
854					settings = {};
855
856				queryParts.forEach( function( item ) {
857					if ( -1 !== item.indexOf( '=' ) ) {
858						var pair = item.split( '=' );
859
860						settings[ pair[0] ] = decodeURIComponent( pair[1] );
861					}
862				} );
863
864				if ( ! settings.action ) {
865					return;
866				}
867
868				var actionCb = this.actions[ settings.action ];
869
870				if ( ! actionCb ) {
871					return;
872				}
873
874				actionCb( settings );
875			}
876		},
877
878		prepareJetPopup: function( popupData, widgetData, $scope ) {
879
880			var postId = null;
881
882			if ( widgetData['is-jet-engine'] ) {
883				popupData['isJetEngine'] = true;
884
885				var $gridItems     = $scope.closest( '.jet-listing-grid__items' ),
886					$gridItem      = $scope.closest( '.jet-listing-grid__item' ),
887					$calendarItem  = $scope.closest( '.jet-calendar-week__day-event' ),
888					$itemObject    = $scope.closest( '[data-item-object]' ),
889					filterProvider = false,
890					filterQueryId  = 'default';
891
892				if ( $gridItems.length ) {
893					popupData['listingSource'] = $gridItems.data( 'listing-source' );
894					popupData['listingId']     = $gridItems.data( 'listing-id' );
895					popupData['queryId']       = $gridItems.data( 'query-id' );
896				} else {
897
898					var $queryItems    = $scope.closest( '[data-query-id]' ),
899						$listingSource = $scope.closest( '[data-listing-source]' );
900
901					if ( $queryItems.length ) {
902						popupData['queryId'] = $queryItems.data( 'query-id' );
903					}
904
905					if ( $listingSource.length ) {
906						popupData['listingSource'] = $listingSource.data( 'listing-source' );
907					}
908				}
909
910				if ( $itemObject?.length ) {
911					popupData['postId'] = $itemObject.data( 'item-object' );
912
913					filterProvider = $itemObject.data( 'render-type' );
914
915					if ( ! filterProvider && $itemObject.hasClass( 'jet-dynamic-table__row' ) ) {
916						filterProvider = 'jet-data-table';
917					}
918				} else if ( $gridItem.length ) {
919					popupData['postId'] = $gridItem.data( 'post-id' );
920					filterProvider = 'jet-engine';
921				} else if ( $calendarItem.length ) {
922					popupData['postId'] = $calendarItem.data( 'post-id' );
923					filterProvider = 'jet-engine-calendar';
924				} else if ( window.elementorFrontendConfig && window.elementorFrontendConfig.post ) {
925					popupData['postId'] = window.elementorFrontendConfig.post.id;
926				}
927
928				if ( window.JetEngineFormsEditor && window.JetEngineFormsEditor.hasEditor ) {
929					popupData['hasEditor'] = true;
930				}
931
932				// Add the filtered query to the popup data
933				if ( window.JetSmartFilters ) {
934
935					switch ( filterProvider ) {
936						case 'jet-engine':
937							var nav = $gridItems.data( 'nav' );
938
939							if ( nav.widget_settings?._element_id ) {
940								filterQueryId = nav.widget_settings._element_id;
941							}
942							break;
943
944						case 'jet-engine-calendar':
945							var settings = $calendarItem.closest( '.jet-listing-calendar' ).data( 'settings' );
946
947							if ( settings._element_id ) {
948								filterQueryId = settings._element_id;
949							}
950							break;
951
952						case 'jet-data-table':
953							const table = $scope.closest( '.jet-dynamic-table' );
954							const queryId = table[0].dataset.queryId;
955							const customIds = JetEngineSettings.query_builder.custom_ids;
956
957							if ( customIds.length !== 0 && customIds?.[ queryId ] ) {
958								filterQueryId = customIds[ queryId ];
959							}
960							break;
961					}
962
963					filterProvider = window.JetPlugins.hooks.applyFilters( 'jet-engine.prepareJetPopupData.filterProvider', filterProvider, $scope, widgetData );
964					filterQueryId  = window.JetPlugins.hooks.applyFilters( 'jet-engine.prepareJetPopupData.filterQueryId', filterQueryId, $scope, widgetData );
965
966					if ( popupData.queryId && filterProvider
967						&& window.JetSmartFilters?.filterGroups?.[ filterProvider + '/' + filterQueryId ]?.currentQuery
968					) {
969						popupData['filtered_query'] = window.JetSmartFilters.filterGroups[ filterProvider + '/' + filterQueryId ].currentQuery;
970					}
971				}
972
973			}
974
975			return popupData;
976
977		},
978
979		showCalendarEvent: function( event ) {
980
981			var $this       = $( this ),
982				$day        = $this.closest( '.jet-calendar-week__day' ),
983				$week       = $day.closest( '.jet-calendar-week' ),
984				$events     = $day.find( '.jet-calendar-week__day-content' ),
985				activeClass = 'calendar-event-active';
986
987			if ( $day.hasClass( activeClass ) ) {
988				$day.removeClass( activeClass );
989				JetEngine.activeCalendarDay.remove();
990				JetEngine.activeCalendarDay = null;
991				return;
992			}
993
994			if ( JetEngine.activeCalendarDay ) {
995				JetEngine.activeCalendarDay.remove();
996				$( '.' + activeClass ).removeClass( activeClass );
997				JetEngine.activeCalendarDay = null;
998			}
999
1000			$day.addClass( 'calendar-event-active' );
1001
1002			JetEngine.activeCalendarDay = $( '<tr class="jet-calendar-week"><td colspan="7" class="jet-calendar-week__day jet-calendar-week__day-mobile"><div class="jet-calendar-week__day-mobile-event">' + $events.html() + '</div></td></tr>' );
1003
1004			// Need for re-init popup events
1005			JetEngine.activeCalendarDay.find( '.jet-popup-attach-event-inited' ).removeClass( 'jet-popup-attach-event-inited' );
1006			JetEngine.initElementsHandlers( JetEngine.activeCalendarDay );
1007
1008			JetEngine.activeCalendarDay.insertAfter( $week );
1009
1010		},
1011
1012		widgetListingGrid: function( $scope ) {
1013
1014			var widgetID    = $scope.closest( '.elementor-widget' ).data( 'id' ),
1015				$wrapper    = $scope.find( '.jet-listing-grid' ).first(),
1016				hasLazyLoad = $wrapper.hasClass( 'jet-listing-grid--lazy-load' ),
1017				$listing    = $scope.find( '.jet-listing-grid__items' ).first(),
1018				$slider     = $listing.parent( '.jet-listing-grid__slider' ),
1019				$masonry    = $listing.hasClass( 'jet-listing-grid__masonry' ) ? $listing : false,
1020				navSettings = $listing.data( 'nav' ),
1021				masonryGrid = false,
1022				listingType = 'elementor';
1023
1024			if ( ! widgetID ) {
1025				widgetID    = $scope.data( 'element-id' );
1026				listingType = $scope.data( 'listing-type' );
1027			}
1028
1029			navSettings = JetEngine.ensureJSON( navSettings );
1030
1031			if ( hasLazyLoad ) {
1032
1033				var lazyLoadOptions = $wrapper.data( 'lazy-load' ),
1034					$container = $scope.find( '.elementor-widget-container' ),
1035					widgetSettings = false;
1036
1037				if ( ! $container.length ) {
1038					$container = $scope;
1039				}
1040
1041				// Get widget settings from `elementorFrontend` in Editor.
1042				if ( window.elementorFrontend && window.elementorFrontend.isEditMode()
1043					&& $wrapper.closest( '.elementor[data-elementor-type]' ).hasClass( 'elementor-edit-mode' )
1044				) {
1045					widgetSettings = JetEngine.getEditorElementSettings( $scope.closest( '.elementor-widget' ) );
1046					widgetID       = false; // for avoid get widget settings from document in editor
1047				}
1048
1049				if ( ! widgetSettings ) {
1050					widgetSettings = $scope.data( 'widget-settings' );
1051				}
1052
1053				JetEngine.lazyLoadListing( {
1054					container:      $container,
1055					elementID:      widgetID,
1056					postID:         lazyLoadOptions.post_id,
1057					queriedID:      lazyLoadOptions.queried_id || false,
1058					offset:         lazyLoadOptions.offset || '0px',
1059					query:          lazyLoadOptions.query || {},
1060					listingType:    listingType,
1061					widgetSettings: widgetSettings,
1062					extraProps:     lazyLoadOptions.extra_props || false,
1063				} );
1064
1065				return;
1066			}
1067
1068			if ( $slider.length ) {
1069				JetEngine.initSlider( $slider );
1070			}
1071
1072			if ( $masonry && $masonry.length ) {
1073
1074				JetEngine.initMasonry( $masonry );
1075
1076				/* Keep masonry re-init for Bricks */
1077				if ( $scope.hasClass( 'brxe-jet-engine-listing-grid' ) ) {
1078					$( window ).on( 'load', function() {
1079						JetEngine.runMasonry( $masonry );
1080					} );
1081				}
1082
1083			}
1084
1085			if ( navSettings && navSettings.enabled ) {
1086
1087				JetEngine.loadMoreListing( {
1088					container: $listing,
1089					settings: navSettings,
1090					masonry: $masonry,
1091					slider: $slider,
1092					elementID: widgetID,
1093				} );
1094
1095			}
1096
1097			// Init elements handlers in editor.
1098			if ( window.elementorFrontend && window.elementorFrontend.isEditMode()
1099				&& $wrapper.closest( '.elementor-element-edit-mode' ).length
1100			) {
1101				JetEngine.initElementsHandlers( $wrapper );
1102			}
1103
1104		},
1105
1106		initMasonry: function( $masonry, masonrySettings ) {
1107			imagesLoaded( $masonry, function() {
1108				JetEngine.runMasonry( $masonry, masonrySettings );
1109			} );
1110		},
1111
1112		runMasonry: function( $masonry, masonrySettings ) {
1113			var defaultSettings = {
1114				itemSelector: '> .jet-listing-grid__item',
1115				columnsKey:   'columns',
1116			};
1117
1118			masonrySettings = masonrySettings || {};
1119			masonrySettings = $.extend( {}, defaultSettings, masonrySettings );
1120
1121			var $eWidget     = $masonry.closest( '.elementor-widget' ),
1122				$items       = $( masonrySettings.itemSelector, $masonry ),
1123				options      = $masonry.data( 'masonry-grid-options' ) || {};
1124
1125			options = JetEngine.ensureJSON( options );
1126
1127			// Reset masonry
1128			$items.css( {
1129				marginTop: ''
1130			} );
1131
1132			// Bricks margin
1133			const { gap } = options;
1134			let margin = null;
1135
1136			if ( gap ) {
1137				margin = {
1138					x: +gap.horizontal,
1139					y: +gap.vertical,
1140				};
1141			}
1142
1143			var args = {
1144				container: $masonry[0],
1145				margin: margin ? margin : 0,
1146			};
1147
1148			if ( $eWidget.length ) {
1149				var settings     = JetEngine.getElementorElementSettings( $eWidget ),
1150					breakpoints  = {},
1151					eBreakpoints = window.elementorFrontend.config.responsive.activeBreakpoints,
1152					columnsKey   = masonrySettings.columnsKey;
1153
1154				args.columns = settings[columnsKey + '_widescreen'] ? +settings[columnsKey + '_widescreen'] : +settings[columnsKey];
1155
1156				Object.keys( eBreakpoints ).reverse().forEach( function( breakpointName ) {
1157
1158					if ( settings[columnsKey + '_' + breakpointName] ) {
1159						if ( 'widescreen' === breakpointName ) {
1160							breakpoints[eBreakpoints[breakpointName].value - 1] = +settings[columnsKey];
1161						} else {
1162							breakpoints[eBreakpoints[breakpointName].value] = +settings[columnsKey + '_' + breakpointName];
1163						}
1164					}
1165
1166				} );
1167
1168				args.breakAt = breakpoints;
1169
1170			} else {
1171				args.columns = options.columns.desktop;
1172				args.breakAt = {
1173					1025: options.columns.tablet,
1174					768:  options.columns.mobile,
1175				};
1176			}
1177
1178			var masonryInstance = Macy( args );
1179
1180			masonryInstance.runOnImageLoad( function () {
1181				masonryInstance.recalculate( true );
1182			}, true );
1183
1184			// Event to recalculate current masonry listings.
1185			$masonry.on( 'jet-engine/listing/recalculate-masonry-listing', function() {
1186				masonryInstance.runOnImageLoad( function () {
1187					masonryInstance.recalculate( true );
1188				}, true );
1189			} );
1190
1191			// Event to recalculate all masonry listings.
1192			$( document ).on( 'jet-engine/listing/recalculate-masonry', function() {
1193				masonryInstance.recalculate( true );
1194			} );
1195
1196		},
1197
1198		ajaxGetListing: function( options, doneCallback, failCallback ) {
1199
1200			var container = options.container || false,
1201				handler = options.handler || false,
1202				masonry = options.masonry || false,
1203				slider = options.slider || false,
1204				append = options.append || false,
1205				query = options.query || {},
1206				widgetSettings = options.widgetSettings || {},
1207				postID = options.postID || false,
1208				queriedID = options.queriedID || false,
1209				elementID = options.elementID || false,
1210				page = options.page || 1,
1211				preventCSS = options.preventCSS || false,
1212				listingType = options.listingType || false,
1213				extraProps = options.extraProps || false,
1214				isEditMode = window.elementorFrontend && window.elementorFrontend.isEditMode();
1215
1216			doneCallback = doneCallback || function( response ) {};
1217
1218			if ( ! container|| ! handler ) {
1219				return;
1220			}
1221
1222			if ( ! preventCSS ) {
1223				container.css({
1224					pointerEvents: 'none',
1225					opacity: '0.5',
1226					cursor: 'default',
1227				});
1228			}
1229
1230			var requestData = {
1231					action: 'jet_engine_ajax',
1232					handler: handler,
1233					query: query,
1234					widget_settings: widgetSettings,
1235					page_settings: {
1236						post_id: postID,
1237						queried_id: queriedID,
1238						element_id: elementID,
1239						page: page,
1240					},
1241					listing_type: listingType,
1242					isEditMode: isEditMode,
1243					addedPostCSS: JetEngine.addedPostCSS
1244				};
1245
1246			if ( extraProps ) {
1247				Object.assign( requestData, extraProps );
1248			}
1249
1250			$.ajax({
1251				url: JetEngineSettings.ajaxlisting,
1252				type: 'POST',
1253				dataType: 'json',
1254				data: requestData,
1255			}).done( function( response ) {
1256
1257				// container.removeAttr( 'style' );
1258
1259				// Manual reset container style to prevent removal of masonry styles.
1260				if ( !preventCSS ) {
1261					container.css( {
1262						pointerEvents: '',
1263						opacity: '',
1264						cursor: '',
1265					} );
1266				}
1267
1268				if ( response.success ) {
1269
1270					JetEngine.enqueueAssetsFromResponse( response );
1271
1272					container.data( 'page', page );
1273
1274					var $html = $( response.data.html );
1275
1276					JetEngine.initFrontStores( $html );
1277
1278					if ( slider && slider.length ) {
1279
1280						var $slider = slider.find( '> .jet-listing-grid__items' );
1281
1282						if ( ! $slider.hasClass( 'slick-initialized' ) ) {
1283
1284							if ( append ) {
1285								container.append( $html );
1286							} else {
1287								container.html( $html );
1288							}
1289
1290							var itemsCount = container.find( '> .jet-listing-grid__item' ).length;
1291
1292							slider.addClass( 'jet-listing-grid__slider' );
1293							JetEngine.initSlider( slider, { itemsCount: itemsCount } );
1294
1295						} else {
1296							$html.each( function( index, el ) {
1297								$slider.slick( 'slickAdd', el );
1298							});
1299						}
1300
1301					} else {
1302
1303						if ( append ) {
1304							container.append( $html );
1305						} else {
1306							container.html( $html );
1307						}
1308
1309						if ( masonry && masonry.length ) {
1310							//JetEngine.initMasonry( masonry );
1311							masonry.trigger( 'jet-engine/listing/recalculate-masonry-listing' );
1312						}
1313
1314					}
1315
1316					// Re-init Bricks scripts
1317					JetEngine.reinitBricksScripts( elementID );
1318
1319					Promise.all( JetEngine.assetsPromises ).then( function() {
1320						JetEngine.initElementsHandlers( $html );
1321						JetEngine.assetsPromises = [];
1322					} );
1323
1324					if ( response.data.fragments ) {
1325						for ( var selector in response.data.fragments ) {
1326							var $selector = $( selector );
1327
1328							if ( $selector.length ) {
1329								$selector.html( response.data.fragments[ selector ] );
1330							}
1331						}
1332					}
1333				}
1334
1335				$( document ).trigger( 'jet-engine/listing/ajax-get-listing/done', [ $html, options ] );
1336
1337			} ).done( doneCallback ).fail( function() {
1338				container.removeAttr( 'style' );
1339				if ( failCallback ) {
1340					failCallback.call();
1341				}
1342
1343			} );
1344
1345		},
1346
1347		loadMoreListing: function( args ) {
1348
1349			var instance = {
1350
1351				setup: function() {
1352					this.container = args.container;
1353					this.masonry   = args.masonry;
1354					this.slider    = args.slider;
1355					this.settings  = args.settings;
1356					this.elementID  = args.elementID;
1357
1358					this.wrapper = this.container.closest( '.jet-listing-grid' );
1359
1360					this.type      = this.settings.type || 'click';
1361					this.page      = parseInt( this.container.data( 'page' ), 10 ) || 0;
1362					this.pages     = parseInt( this.container.data( 'pages' ), 10 ) || 0;
1363					this.queriedID = this.container.data( 'queried-id' ) || false;
1364				},
1365
1366				init: function() {
1367
1368					this.setup();
1369
1370					switch ( this.type ) {
1371						case 'click':
1372
1373							this.handleMore();
1374
1375							break;
1376
1377						case 'scroll':
1378
1379							if ( ( ! window.elementorFrontend || ! window.elementorFrontend.isEditMode() ) && ! this.slider.length ) {
1380								this.handleInfiniteScroll();
1381							}
1382
1383							break;
1384					}
1385				},
1386
1387				handleMore: function() {
1388
1389					if ( ! this.settings.more_el ) {
1390						return;
1391					}
1392
1393					var self    = this,
1394						$button = $( this.settings.more_el );
1395
1396					if ( ! $button.length ) {
1397						return;
1398					}
1399
1400					if ( ! this.pages || this.page === this.pages && ! window.elementor ) {
1401						$button.css( 'display', 'none' );
1402					} else {
1403						$button.removeAttr( 'style' );
1404					}
1405
1406					$( document )
1407						.off( 'click', this.settings.more_el )
1408						.on( 'click', this.settings.more_el, function( event ) {
1409							event.preventDefault();
1410
1411							if ( ! self.pages || self.page >= self.pages) {
1412								$button.css( 'display', 'none' );
1413								return;
1414							}
1415
1416							$button.css( {
1417								pointerEvents: 'none',
1418								opacity: '0.5',
1419								cursor: 'default',
1420							} );
1421
1422							self.ajaxGetItems( function( response ) {
1423									$button.removeAttr( 'style' );
1424
1425									if ( response.success && self.page === self.pages ) {
1426										$button.css( 'display', 'none' );
1427									}
1428								}, function() {
1429									$button.button.removeAttr( 'style' );
1430								}
1431							);
1432						} );
1433				},
1434
1435				handleInfiniteScroll: function() {
1436
1437					if ( this.container.hasClass( 'jet-listing-not-found' ) ) {
1438						return;
1439					}
1440
1441					if ( ! this.pages || this.page === this.pages ) {
1442						return;
1443					}
1444
1445					var self     = this,
1446						$trigger = this.wrapper.find( '.jet-listing-grid__loader' ),
1447						offset   = '0%';
1448
1449					if ( ! $trigger.length ) {
1450						$trigger = $( '<div>', {
1451							class: 'jet-listing-grid__loading-trigger'
1452						} );
1453
1454						this.wrapper.append( $trigger );
1455					}
1456
1457					// Prepare offset value.
1458					if ( this.settings.widget_settings && this.settings.widget_settings.load_more_offset ) {
1459						var offsetValue = this.settings.widget_settings.load_more_offset;
1460
1461						switch ( typeof offsetValue ) {
1462							case 'object':
1463								var size = offsetValue.size ? offsetValue.size : '0',
1464									unit = offsetValue.unit ? offsetValue.unit : 'px';
1465
1466								offset = size + unit;
1467								break;
1468
1469							case 'number':
1470							case 'string':
1471								offset = offsetValue + 'px';
1472								break;
1473						}
1474					}
1475
1476					var observer = new IntersectionObserver(
1477						function( entries, observer ) {
1478
1479							if ( entries[0].isIntersecting ) {
1480
1481								self.ajaxGetItems( function() {
1482
1483									// Re-init observer if the last page is not loaded
1484									if ( self.page !== self.pages ) {
1485										setTimeout( function() {
1486											observer.observe( entries[0].target );
1487										}, 250 );
1488									}
1489
1490								} );
1491
1492								// Detach observer
1493								observer.unobserve( entries[0].target );
1494							}
1495						},
1496						{
1497							rootMargin: '0% 0% ' + offset + ' 0%',
1498						}
1499					);
1500
1501					observer.observe( $trigger[0] );
1502				},
1503
1504				ajaxGetItems: function( doneCallback, failCallback ) {
1505					var self = this;
1506
1507					this.page++;
1508
1509					this.wrapper.addClass( 'jet-listing-grid-loading' );
1510
1511					JetEngine.ajaxGetListing( {
1512							handler:        'listing_load_more',
1513							container:      this.container,
1514							masonry:        this.masonry,
1515							slider:         this.slider,
1516							append:         true,
1517							query:          this.settings.query,
1518							widgetSettings: this.settings.widget_settings,
1519							page:           this.page,
1520							elementID:      this.elementID,
1521							queriedID:      this.queriedID,
1522							preventCSS:     !! this.wrapper.find( '.jet-listing-grid__loader' ).length, // Prevent CSS if listing has the loader.
1523						}, function( response ) {
1524
1525							JetEngine.lazyLoading = false;
1526							self.wrapper.removeClass( 'jet-listing-grid-loading' );
1527
1528							if ( doneCallback ) {
1529								doneCallback( response );
1530							}
1531
1532							$( document ).trigger( 'jet-engine/listing-grid/after-load-more', [args, response] );
1533
1534						}, function() {
1535
1536							JetEngine.lazyLoading = false;
1537							self.wrapper.removeClass( 'jet-listing-grid-loading' );
1538
1539							if ( failCallback ) {
1540								failCallback();
1541							}
1542
1543					} );
1544				},
1545			};
1546
1547			instance.init();
1548		},
1549
1550		lazyLoadListing: function( args ) {
1551
1552			var $wrapper = args.container.find( '.jet-listing-grid' ),
1553				observer = new IntersectionObserver(
1554					function( entries, observer ) {
1555
1556						if ( entries[0].isIntersecting ) {
1557
1558							JetEngine.lazyLoading = true;
1559
1560							if ( ! $wrapper.length ) {
1561								$wrapper = args.container;
1562							}
1563
1564							$wrapper.addClass( 'jet-listing-grid-loading' );
1565
1566							JetEngine.ajaxGetListing( {
1567								handler: 'get_listing',
1568								container: args.container,
1569								masonry: false,
1570								slider: false,
1571								append: false,
1572								elementID: args.elementID,
1573								postID: args.postID,
1574								queriedID: args.queriedID,
1575								query: args.query,
1576								widgetSettings: args.widgetSettings,
1577								listingType: args.listingType,
1578								preventCSS: true,
1579								extraProps: args.extraProps,
1580							}, function( response ) {
1581
1582								$wrapper.removeClass( 'jet-listing-grid-loading' );
1583
1584								var $widget = args.container.closest( '.elementor-widget' );
1585
1586								if ( ! $widget.length ) {
1587									$widget = args.container.closest( '.jet-listing-grid--blocks' );
1588								}
1589
1590								if ( ! $widget.length ) {
1591									$widget = args.container;
1592								}
1593
1594								if ( $widget.length ) {
1595									$widget.find( '.jet-listing-grid' ).first().removeClass( 'jet-listing-grid--lazy-load' );
1596								}
1597
1598								JetEngine.widgetListingGrid( $widget );
1599								JetEngine.loadFrontStoresItems( $widget );
1600								JetEngine.lazyLoading = false;
1601
1602								let needReInitFilters = false;
1603								let isFrontend = JetEngine.isFrontend();
1604
1605								if ( isFrontend && window.JetSmartFilterSettings ) {
1606
1607									if ( response.data.filters_data ) {
1608										$.each( response.data.filters_data, function( param, data ) {
1609											if ( 'extra_props' === param ) {
1610												window.JetSmartFilterSettings[ param ] = $.extend(
1611													{},
1612													window.JetSmartFilterSettings[ param ],
1613													data
1614												);
1615											} else {
1616												if ( window.JetSmartFilterSettings[ param ]['jet-engine'] ) {
1617													window.JetSmartFilterSettings[ param ]['jet-engine'] = $.extend(
1618														{},
1619														window.JetSmartFilterSettings[ param ]['jet-engine'],
1620														data
1621													);
1622												} else {
1623													window.JetSmartFilterSettings[ param ]['jet-engine'] = data;
1624												}
1625											}
1626										});
1627
1628										needReInitFilters = true;
1629									}
1630
1631									if ( response.data.indexer_data ) {
1632										const {
1633											provider = false,
1634											query = {}
1635										} = response.data.indexer_data;
1636
1637										window.JetSmartFilters.setIndexedData( provider, query );
1638									}
1639								}
1640
1641								// ReInit filters
1642								if ( needReInitFilters && window.JetSmartFilters ) {
1643									window.JetSmartFilters.reinitFilters();
1644								}
1645
1646								$( document ).trigger( 'jet-engine/listing-grid/after-lazy-load', [ args, response ] );
1647
1648							}, function() {
1649								JetEngine.lazyLoading = false;
1650
1651								if ( ! $wrapper.length ) {
1652									$wrapper = args.container;
1653								}
1654
1655								$wrapper.removeClass( 'jet-listing-grid-loading' );
1656							} );
1657
1658							// Detach observer after the first load the listing
1659							observer.unobserve( entries[0].target );
1660						}
1661					},
1662					{
1663						rootMargin: '0% 0% ' + args.offset + ' 0%'
1664					}
1665				);
1666
1667			observer.observe( args.container[0] );
1668		},
1669
1670		ensureJSON: function( maybeJSON ) {
1671
1672			if ( ! maybeJSON ) {
1673				return maybeJSON;
1674			}
1675
1676			if ( 'string' === typeof maybeJSON ) {
1677				console.log( maybeJSON );
1678				//maybeJSON = JSON.parse( maybeJSON );
1679			}
1680
1681			return maybeJSON;
1682
1683		},
1684
1685		initSlider: function( $slider, customOptions ) {
1686			var $eWidget    = $slider.closest( '.elementor-widget' ),
1687				options     = $slider.data( 'slider_options' ),
1688				windowWidth = $( window ).width(),
1689				tabletBP    = 1025,
1690				mobileBP    = 768,
1691				tabletSlides, mobileSlides, defaultOptions, slickOptions;
1692
1693			options = JetEngine.ensureJSON( options );
1694
1695			customOptions = customOptions || {};
1696
1697			options = $.extend( {}, options, customOptions );
1698
1699			if ( $eWidget.length ) {
1700
1701				var settings     = JetEngine.getElementorElementSettings( $eWidget ),
1702					responsive   = [],
1703					deviceMode   = elementorFrontend.getCurrentDeviceMode(),
1704					eBreakpoints = window.elementorFrontend.config.responsive.activeBreakpoints;
1705
1706				options.slidesToShow = settings.columns_widescreen ? +settings.columns_widescreen : +settings.columns;
1707
1708				Object.keys( eBreakpoints ).reverse().forEach( function( breakpointName ) {
1709
1710					if ( settings['columns_' + breakpointName] ) {
1711
1712						if ( 'widescreen' === breakpointName ) {
1713
1714							responsive.push( {
1715								breakpoint: eBreakpoints[breakpointName].value,
1716								settings: {
1717									slidesToShow: +settings['columns'],
1718								}
1719							} );
1720
1721						} else {
1722							var breakpointSettings = {
1723									breakpoint: eBreakpoints[breakpointName].value + 1,
1724									settings:   {
1725										slidesToShow: +settings['columns_' + breakpointName],
1726									}
1727								};
1728
1729							if ( options.slidesToScroll > breakpointSettings.settings.slidesToShow ) {
1730								breakpointSettings.settings.slidesToScroll = breakpointSettings.settings.slidesToShow;
1731							}
1732
1733							// if ( 'mobile' === breakpointName ) {
1734							// 	breakpointSettings.settings.slidesToScroll = 1;
1735							// }
1736
1737							responsive.push( breakpointSettings );
1738						}
1739					}
1740
1741				} );
1742
1743				options.responsive = responsive;
1744
1745			} else {
1746
1747				// Ensure we have at least some options to avoid errors
1748				if ( ! options.slidesToShow ) {
1749					options.slidesToShow = {
1750						desktop: 3,
1751						tablet: 1,
1752						mobile: 1,
1753					}
1754				}
1755
1756				if ( options.itemsCount <= options.slidesToShow.desktop && windowWidth >= tabletBP ) { // 1025 - ...
1757					$slider.removeClass( 'jet-listing-grid__slider' );
1758					return;
1759				} else if ( options.itemsCount <= options.slidesToShow.tablet && tabletBP > windowWidth && windowWidth >= mobileBP ) { // 768 - 1024
1760					$slider.removeClass( 'jet-listing-grid__slider' );
1761					return;
1762				} else if ( options.itemsCount <= options.slidesToShow.mobile && windowWidth < mobileBP ) { // 0 - 767
1763					$slider.removeClass( 'jet-listing-grid__slider' );
1764					return;
1765				}
1766
1767				if ( options.slidesToShow.tablet ) {
1768					tabletSlides = options.slidesToShow.tablet;
1769				} else {
1770					tabletSlides = 1 === options.slidesToShow.desktop ? 1 : 2;
1771				}
1772
1773				if ( options.slidesToShow.mobile ) {
1774					mobileSlides = options.slidesToShow.mobile;
1775				} else {
1776					mobileSlides = 1;
1777				}
1778
1779				options.slidesToShow = options.slidesToShow.desktop;
1780
1781				options.responsive = [
1782					{
1783						breakpoint: 1025,
1784						settings: {
1785							slidesToShow: tabletSlides,
1786							slidesToScroll: options.slidesToScroll > tabletSlides ? tabletSlides : options.slidesToScroll
1787						}
1788					},
1789					{
1790						breakpoint: 768,
1791						settings: {
1792							slidesToShow: mobileSlides,
1793							slidesToScroll: 1
1794						}
1795					}
1796				];
1797			}
1798
1799			defaultOptions = {
1800				customPaging: function( slider, i ) {
1801					return $( '<span />' ).text( i + 1 ).attr( 'role', 'tab' );
1802				},
1803				slide: '.jet-listing-grid__item',
1804				dotsClass: 'jet-slick-dots',
1805			};
1806
1807			slickOptions = $.extend( {}, defaultOptions, options );
1808
1809			var $sliderItems = $slider.find( '> .jet-listing-grid__items' );
1810
1811			if ( slickOptions.infinite ) {
1812				$sliderItems.on( 'init', function() {
1813					var $items        = $( this ),
1814						$clonedSlides = $( '> .slick-list > .slick-track > .slick-cloned.jet-listing-grid__item', $items );
1815
1816					if ( !$clonedSlides.length ) {
1817						return;
1818					}
1819
1820					JetEngine.initElementsHandlers( $clonedSlides );
1821
1822					if ( $slider.find('.bricks-lazy-hidden').length ) {
1823						bricksLazyLoad();
1824					}
1825				} );
1826			}
1827
1828			// Temporary solution issue with Lazy Load images + RTL on Chrome.
1829			// Remove after fix in Chrome.
1830			// See: https://github.com/Crocoblock/issues-tracker/issues/7552
1831			if ( slickOptions.rtl ) {
1832				$sliderItems.on( 'init', function() {
1833					var $items      = $( this ),
1834						$lazyImages = $( 'img[loading=lazy]', $items ),
1835						lazyImageObserver = new IntersectionObserver(
1836							function( entries, observer ) {
1837								entries.forEach( function( entry ) {
1838									if ( entry.isIntersecting ) {
1839										// If an image does not load, need to remove the `loading` attribute.
1840										if ( ! entry.target.complete ) {
1841											entry.target.removeAttribute( 'loading' );
1842										}
1843
1844										// Detach observer
1845										observer.unobserve( entry.target );
1846									}
1847								} );
1848							}
1849						);
1850
1851					$lazyImages.each( function() {
1852						const $img = $( this );
1853						lazyImageObserver.observe( $img[0] );
1854					} );
1855				} );
1856			}
1857
1858			if ( $sliderItems.hasClass( 'slick-initialized' ) ) {
1859				$sliderItems.slick( 'refresh', true );
1860				return;
1861			}
1862
1863			if ( slickOptions.variableWidth ) {
1864				slickOptions.slidesToShow = 1;
1865				slickOptions.slidesToScroll = 1;
1866				slickOptions.responsive = null;
1867			}
1868
1869			$sliderItems.on(
1870				'init.JetEngine',
1871				() => {
1872					$sliderItems.find( '.slick-active' ).each(
1873						( i, el ) => {
1874							JetEngine.rerunElementorAnimation( $( el ) );
1875						}
1876					);
1877				}
1878			);
1879
1880			$sliderItems.on(
1881				'afterChange.JetEngine',
1882				() => {
1883					$sliderItems.find( '.slick-active' ).each(
1884						( i, el ) => {
1885							JetEngine.rerunElementorAnimation( $( el ) );
1886						}
1887					);
1888				}
1889			);
1890
1891			$sliderItems.slick( slickOptions );
1892
1893			$sliderItems.off( 'init.JetEngine' );
1894		},
1895
1896		maybeReinitSlider: function( event, $scope ) {
1897			var $slider = $scope.find( '.jet-listing-grid__slider' );
1898
1899			if ( $slider.length ) {
1900				$slider.each( function() {
1901					JetEngine.initSlider( $( this ) );
1902				} );
1903
1904			}
1905		},
1906
1907		rerunElementorAnimation: function( $scope, forceRerun = false ) {
1908			let selector = '.elementor-element[data-settings*="_animation"]';
1909
1910			if ( ! forceRerun ) {
1911				selector += ':is( .elementor-invisible, :not(.jet-engine-animation-rerun) )';
1912			}
1913
1914			$scope.find( selector ).each(
1915				( i, el ) => {
1916					const settings = JSON.parse( el.dataset.settings || '{}' );
1917					const $el = $( el );
1918
1919					if ( settings._animation ) {
1920						const classes = `animated ${settings._animation}`;
1921						$el.removeClass( classes );
1922
1923						setTimeout(
1924							() => {
1925								$el.removeClass( 'elementor-invisible' ).addClass( classes );
1926								$el.addClass( 'jet-engine-animation-rerun' );
1927							},
1928							settings._animation_delay
1929						);
1930
1931					}
1932				}
1933			);
1934		},
1935
1936		widgetDynamicField: function( $scope ) {
1937
1938			var $slider = $scope.find( '.jet-engine-gallery-slider' );
1939
1940			if ( $slider.length ) {
1941				if ( $.isFunction( $.fn.imagesLoaded ) ) {
1942					$slider.imagesLoaded().always( function( instance ) {
1943
1944						var $eWidget = $slider.closest( '.elementor-widget' );
1945
1946						if ( $slider.hasClass( 'slick-initialized' ) ) {
1947							$slider.slick( 'refresh', true );
1948						} else {
1949							var atts = $slider.data( 'atts' );
1950
1951							atts = JetEngine.ensureJSON( atts );
1952
1953							if ( $eWidget.length ) {
1954								var settings     = JetEngine.getElementorElementSettings( $scope ),
1955									eBreakpoints = window.elementorFrontend.config.responsive.activeBreakpoints,
1956									responsive   = [];
1957
1958								if ( settings.img_slider_cols || settings.img_slider_cols_widescreen ) {
1959									atts.slidesToShow = settings.img_slider_cols_widescreen ? +settings.img_slider_cols_widescreen : +settings.img_slider_cols;
1960								}
1961
1962								Object.keys( eBreakpoints ).reverse().forEach( function( breakpointName ) {
1963
1964									if ( settings['img_slider_cols_' + breakpointName] ) {
1965
1966										if ( 'widescreen' === breakpointName ) {
1967
1968											responsive.push( {
1969												breakpoint: eBreakpoints[breakpointName].value,
1970												settings:   {
1971													slidesToShow: +settings['img_slider_cols'],
1972												}
1973											} );
1974
1975										} else {
1976											var breakpointSettings = {
1977												breakpoint: eBreakpoints[breakpointName].value + 1,
1978												settings:   {
1979													slidesToShow: +settings['img_slider_cols_' + breakpointName],
1980												}
1981											};
1982
1983											responsive.push( breakpointSettings );
1984										}
1985									}
1986
1987								} );
1988
1989								atts.responsive = responsive;
1990							}
1991
1992							$slider.slick( atts );
1993						}
1994					} );
1995				}
1996			}
1997
1998			$slider.on('init', function (event, slick) {
1999
2000				const slider = event.target;
2001
2002				if (!slider.classList.contains('jet-engine-gallery-lightbox') || ! window?.PhotoSwipeLightbox) {
2003					return;
2004				}
2005
2006				let lightbox = new PhotoSwipeLightbox({
2007					mainClass: 'brx',
2008					gallery: slider,
2009					children: 'a',
2010					showHideAnimationType: 'none',
2011					zoomAnimationDuration: false,
2012					pswpModule: PhotoSwipe5,
2013				});
2014
2015				lightbox.addFilter('numItems', numItems => slick.slideCount);
2016
2017				lightbox.addFilter('clickedIndex', function (clickedIndex, e) {
2018					const slide = e.target.closest('.slick-slide');
2019
2020					if (!slide) {
2021						return clickedIndex;
2022					}
2023
2024					if (clickedIndex >= slick.slideCount) {
2025						return clickedIndex % slick.slideCount;
2026					}
2027
2028					return clickedIndex;
2029				});
2030
2031				lightbox.addFilter('thumbEl', (thumbnail, itemData, index) => {
2032					return thumbnail;
2033				});
2034
2035				lightbox.addFilter('thumbBounds', (thumbBounds, itemData, index) => {
2036					return thumbBounds;
2037				});
2038
2039				lightbox.init();
2040			});
2041
2042			// Masonry init
2043			var $masonry = $scope.find( '.jet-engine-gallery-grid--masonry' );
2044
2045			if ( $masonry.length ) {
2046				JetEngine.initMasonry( $masonry, {
2047					columnsKey: 'img_columns',
2048					itemSelector: '> .jet-engine-gallery-grid__item',
2049				} );
2050			}
2051
2052		},
2053
2054		calendarCache: {
2055
2056			entries: {},
2057
2058			//introduced because Firefox does not have forEach method for iterators
2059			iterate: function( iterator, callback ) {
2060				if ( typeof iterator?.forEach === 'function' ) {
2061					iterator.forEach( callback );
2062				} else if ( typeof iterator?.next === 'function' ) {
2063					let next;
2064					while ( next = iterator.next(), ! next.done ) {
2065						callback.call( this, next.value );
2066					}
2067				}
2068			},
2069
2070			get: function ( cacheId, month ) {
2071				return JetEngine.calendarCache.entries[ cacheId ]?.get( month ) || false;
2072			},
2073
2074			set: function ( cacheId, month, content, settings = {}, timestamp = false ) {
2075				if ( ! JetEngine.calendarCache.entries[ cacheId ] ) {
2076					JetEngine.calendarCache.entries[ cacheId ] = new Map();
2077				}
2078
2079				if ( ! JetEngine.calendarCache.entries[ cacheId ].has( month )
2080					&& JetEngine.calendarCache.entries[ cacheId ].size > ( settings['max_cache'] ?? 12 ) - 1
2081				) {
2082					let deletedKey;
2083
2084					const mapKeys = JetEngine.calendarCache.entries[ cacheId ].keys();
2085
2086					if ( settings['__switch_direction'] < 0 ) {
2087						let maxDate = false;
2088
2089						JetEngine.calendarCache.iterate(
2090							mapKeys,
2091							function ( key ) {
2092								const parsedDate = Date.parse( key );
2093
2094								if ( ! maxDate || parsedDate > maxDate ) {
2095									maxDate = parsedDate;
2096									deletedKey = key;
2097								}
2098							}
2099						);
2100					} else {
2101						let minDate = false;
2102
2103						JetEngine.calendarCache.iterate(
2104							mapKeys,
2105							function ( key ) {
2106								const parsedDate = Date.parse( key );
2107
2108								if ( ! minDate || parsedDate < minDate ) {
2109									minDate = parsedDate;
2110									deletedKey = key;
2111								}
2112							}
2113						);
2114					}
2115
2116					JetEngine.calendarCache.entries[ cacheId ].delete( deletedKey );
2117				}
2118
2119				if ( ! timestamp ) {
2120					timestamp = Date.now();
2121				}
2122
2123				JetEngine.calendarCache.entries[ cacheId ].set( month, [ content, timestamp ] );
2124			},
2125
2126			update: function ( cacheId, month, content, settings = {} ) {
2127				let cached = JetEngine.calendarCache.get( cacheId, month );
2128				JetEngine.calendarCache.set( cacheId, month, content, settings, cached[1] ?? false );
2129			},
2130
2131			deleteExpiredEntries: function ( cacheId, cacheTimeout ) {
2132				//delete possible orphaned caches
2133				for ( const cacheId in JetEngine.calendarCache.entries ) {
2134					if ( ! document.querySelector( `.jet-calendar[data-cache-id="${cacheId}"]` ) ) {
2135						delete JetEngine.calendarCache.entries[ cacheId ];
2136					}
2137				}
2138
2139				if ( ! JetEngine.calendarCache.entries[ cacheId ] ) {
2140					return;
2141				}
2142
2143				JetEngine.calendarCache.iterate(
2144					JetEngine.calendarCache.entries[ cacheId ].keys(),
2145					function ( month ) {
2146						if ( JetEngine.calendarCache.isExpired( cacheId, month, cacheTimeout ) ) {
2147							JetEngine.calendarCache.entries[ cacheId ].delete( month );
2148						}
2149					}
2150				);
2151			},
2152
2153			isExpired: function ( cacheId, month, cacheTimeout ) {
2154				if ( cacheTimeout < 0 ) {
2155					return false;
2156				}
2157
2158				const cached = JetEngine.calendarCache.get( cacheId, month );
2159
2160				if ( ! cached || ! Array.isArray( cached ) ) {
2161					return true;
2162				}
2163
2164				return ! cached[1] || cached[1] < Date.now() - cacheTimeout;
2165			},
2166
2167			clear: function( e, $calendar ) {
2168				const cacheId = $calendar.data( 'cache-id' ) || false;
2169
2170				if ( ! cacheId ) {
2171					return;
2172				}
2173
2174				JetEngine.calendarCache.entries[ cacheId ] = new Map();
2175			},
2176
2177			modifyJetSmartFiltersSetiings: function( $widget, widgetType, monthData ) {
2178				if ( ! window.JetSmartFilterSettings || ! window.JetSmartFilterSettings.settings ) {
2179					return;
2180				}
2181
2182				if ( ! window.JetSmartFilterSettings.settings['jet-engine-calendar'] ) {
2183					return;
2184				}
2185
2186				monthData = monthData.split( ' ' );
2187
2188				const month = monthData[0],
2189				      year = monthData[1];
2190
2191				let widgetId;
2192
2193				switch ( widgetType ) {
2194					case 'block':
2195						widgetId = $widget.closest( '.jet-listing-calendar-block' )[0].id;
2196
2197						if ( ! widgetId ) {
2198							widgetId = 'default';
2199						}
2200
2201						if ( window.JetSmartFilterSettings.settings['jet-engine-calendar'][ widgetId ] ) {
2202							window.JetSmartFilterSettings.settings['jet-engine-calendar'][ widgetId ]['start_from_month'] = month;
2203							window.JetSmartFilterSettings.settings['jet-engine-calendar'][ widgetId ]['start_from_year'] = year;
2204						}
2205
2206						break;
2207					case 'bricks':
2208						widgetId = $widget.data( 'element-id' );
2209
2210						if ( ! widgetId ) {
2211							break;
2212						}
2213
2214						for ( const id in window.JetSmartFilterSettings.settings['jet-engine-calendar'] ) {
2215							if ( window.JetSmartFilterSettings.settings['jet-engine-calendar'][ id ]?._id === widgetId ) {
2216								window.JetSmartFilterSettings.settings['jet-engine-calendar'][ id ]['start_from_month'] = month;
2217								window.JetSmartFilterSettings.settings['jet-engine-calendar'][ id ]['start_from_year'] = year;
2218								break;
2219							}
2220						}
2221
2222						break;
2223					case 'elementor':
2224						widgetId = $widget.closest( '.elementor-widget-jet-listing-calendar' )[0].id;
2225
2226						if ( ! widgetId ) {
2227							widgetId = 'default';
2228						}
2229
2230						if ( window.JetSmartFilterSettings.settings['jet-engine-calendar']?.[ widgetId ] ) {
2231							window.JetSmartFilterSettings.settings['jet-engine-calendar'][ widgetId ]['start_from_month'] = month;
2232							window.JetSmartFilterSettings.settings['jet-engine-calendar'][ widgetId ]['start_from_year'] = year;
2233						}
2234
2235						break;
2236				}
2237			},
2238		},
2239
2240		selectCalendarMonth: function ( $event ) {
2241			let wrapper = this.closest( '.jet-calendar-caption__dates' );
2242
2243			if ( ! JetEngine.updateDateSelectLabels( wrapper ) ) {
2244				return;
2245			}
2246
2247			JetEngine.switchCalendarMonth.bind( wrapper )()
2248		},
2249
2250		updateDateSelectLabels: function( wrapper ) {
2251			let month = wrapper.querySelector( '.jet-calendar-caption__date-select.select-month' ),
2252			    year = wrapper.querySelector( '.jet-calendar-caption__date-select.select-year' );
2253
2254			if ( ! month || ! year ) {
2255				return false;
2256			}
2257
2258			let monthLabel = wrapper.querySelector( '.jet-calendar-caption__date-select-label.select-month' ),
2259				yearLabel = wrapper.querySelector( '.jet-calendar-caption__date-select-label.select-year' );
2260
2261			wrapper.setAttribute( 'data-month', month.value + ' ' + year.value );
2262
2263			const monthOption = month.querySelector( `option[value="${month.value}"]` ),
2264			      yearOption = year.querySelector( `option[value="${year.value}"]` );
2265
2266			monthLabel.innerHTML = monthOption.innerHTML;
2267			yearLabel.innerHTML = yearOption.innerHTML;
2268
2269			return true;
2270		},
2271
2272		switchCalendarMonth: function( $event ) {
2273
2274			var $this   = $( this ),
2275				$calendar = $this.closest( '.jet-calendar' ),
2276				$widget   = $this.closest( '.elementor-widget-jet-listing-calendar' ),
2277				widgetID  = $widget.closest( '.elementor-widget' ).data( 'id' ),
2278				settings  = $calendar.data( 'settings' ),
2279				post      = $calendar.data( 'post' ),
2280				month     = $this.data( 'month' );
2281
2282			settings = JetEngine.ensureJSON( settings );
2283
2284			if ( this.classList.contains( 'nav-link-prev' ) ) {
2285				settings['__switch_direction'] = -1;
2286			} else if ( this.classList.contains( 'nav-link-next' ) ) {
2287				settings['__switch_direction'] = 1;
2288			} else {
2289				settings['__switch_direction'] = 0;
2290			}
2291
2292			let widgetType = 'elementor';
2293
2294			// Context Gutenberg
2295			if ( ! $widget.length ) {
2296				$widget = $calendar.closest( '.jet-listing-calendar-block' );
2297				widgetType = 'block';
2298			}
2299
2300			// Context Bricks
2301			if ( ! $widget.length ) {
2302				$widget = $calendar.closest( '.brxe-jet-listing-calendar' );
2303				widgetID = $widget.data( 'element-id' );
2304				widgetType = 'bricks';
2305			}
2306
2307			JetEngine.calendarCache.modifyJetSmartFiltersSetiings( $widget, widgetType, month );
2308
2309			const cacheId = $calendar.data( 'cache-id' ) || false,
2310			      cacheTimeout = ( settings['cache_timeout'] ?? 0 ) * 1000;
2311
2312			if ( cacheId && cacheTimeout ) {
2313
2314				JetEngine.calendarCache.deleteExpiredEntries( cacheId, cacheTimeout );
2315
2316				// Remove the 'listening' and 'brx-open' classes from all matched elements to prevent
2317				// reinitialization issues in the accordion.
2318				if ( window.bricksIsFrontend ) {
2319					$calendar.find('.accordion-item.listening, .brxe-accordion-nested > .listening')
2320						.removeClass('listening brx-open');
2321				}
2322
2323				JetEngine.calendarCache.update( cacheId, settings['prev_month'], $calendar.prop('outerHTML'), settings );
2324
2325				const cached = JetEngine.calendarCache.get( cacheId, month );
2326
2327				if ( cached?.length && cached[0] && ! JetEngine.calendarCache.isExpired( cacheId, month, cacheTimeout ) ) {
2328					let replacement = $( cached[0] );
2329					replacement.removeClass( 'jet-calendar-loading' );
2330					$calendar.replaceWith( replacement[0] );
2331					JetEngine.initElementsHandlers( $widget );
2332					JetEngine.updateDateSelectLabels( $widget[0] );
2333					// Re-init Bricks scripts
2334					JetEngine.reinitBricksScripts( widgetID );
2335
2336					$( document ).trigger( 'jet-engine-request-calendar-cached', [ $widget ] );
2337
2338					return;
2339				}
2340			}
2341
2342			$calendar.addClass( 'jet-calendar-loading' );
2343
2344			JetEngine.currentRequest = {
2345				jet_engine_action: 'jet_engine_calendar_get_month',
2346				month: month,
2347				settings: settings,
2348				post: post,
2349			};
2350
2351			$( document ).trigger( 'jet-engine-request-calendar' );
2352
2353			$.ajax({
2354				url: JetEngineSettings.ajaxlisting,
2355				type: 'POST',
2356				dataType: 'json',
2357				data: JetEngine.currentRequest,
2358			}).done( function( response ) {
2359				if ( response.success ) {
2360					$calendar.replaceWith( response.data.content );
2361
2362					if ( cacheId && cacheTimeout ) {
2363						JetEngine.calendarCache.set( cacheId, month, response.data.content, settings );
2364					}
2365
2366					JetEngine.initElementsHandlers( $widget );
2367					// Re-init Bricks scripts
2368					JetEngine.reinitBricksScripts( widgetID );
2369
2370					$( document ).trigger( 'jet-engine-request-calendar-done', [ $widget ] );
2371				}
2372				$calendar.removeClass( 'jet-calendar-loading' );
2373			} );
2374		},
2375
2376		initElementsHandlers: function( $selector ) {
2377
2378			// Actual init
2379			window.JetPlugins.init( $selector );
2380
2381			// Legacy Elementor-only init
2382			$selector.find( '[data-element_type]' ).each( function() {
2383
2384				var $this       = $( this ),
2385					elementType = $this.data( 'element_type' );
2386
2387				if ( !elementType ) {
2388					return;
2389				}
2390
2391				if ( ! window?.elementorFrontend?.hooks?.doAction ) {
2392					return;
2393				}
2394
2395				if ( 'widget' === elementType ) {
2396					elementType = $this.data( 'widget_type' );
2397					window.elementorFrontend.hooks.doAction( 'frontend/element_ready/widget', $this, $ );
2398				}
2399
2400				window.elementorFrontend.hooks.doAction( 'frontend/element_ready/global', $this, $ );
2401				window.elementorFrontend.hooks.doAction( 'frontend/element_ready/' + elementType, $this, $ );
2402
2403			} );
2404
2405			if ( window.elementorFrontend ) {
2406				const elementorLazyLoad = new Event( "elementor/lazyload/observe" );
2407				document.dispatchEvent( elementorLazyLoad );
2408			}
2409
2410			if ( window.JetPopupFrontend && window.JetPopupFrontend.initAttachedPopups ) {
2411				$selector.find( '.jet-popup-attach-event-inited' ).removeClass( 'jet-popup-attach-event-inited' );
2412				window.JetPopupFrontend.initAttachedPopups( $selector );
2413			}
2414
2415		},
2416
2417		getElementorElementSettings: function( $scope ) {
2418
2419			if ( window.elementorFrontend && window.elementorFrontend.isEditMode() && $scope.hasClass( 'elementor-element-edit-mode' ) ) {
2420				return JetEngine.getEditorElementSettings( $scope );
2421			}
2422
2423			return $scope.data( 'settings' ) || {};
2424		},
2425
2426		getEditorElementSettings: function( $scope ) {
2427			var modelCID = $scope.data( 'model-cid' ),
2428				elementData;
2429
2430			if ( ! modelCID ) {
2431				return {};
2432			}
2433
2434			if ( ! window.elementorFrontend.hasOwnProperty( 'config' ) ) {
2435				return {};
2436			}
2437
2438			if ( ! window.elementorFrontend.config.hasOwnProperty( 'elements' ) ) {
2439				return {};
2440			}
2441
2442			if ( ! window.elementorFrontend.config.elements.hasOwnProperty( 'data' ) ) {
2443				return {};
2444			}
2445
2446			elementData = window.elementorFrontend.config.elements.data[ modelCID ];
2447
2448			if ( ! elementData ) {
2449				return {};
2450			}
2451
2452			return elementData.toJSON();
2453		},
2454
2455		debounce: function( threshold, callback ) {
2456			var timeout;
2457
2458			return function debounced( $event ) {
2459				function delayed() {
2460					callback.call( this, $event );
2461					timeout = null;
2462				}
2463
2464				if ( timeout ) {
2465					clearTimeout( timeout );
2466				}
2467
2468				timeout = setTimeout( delayed, threshold );
2469			};
2470		},
2471
2472		updateAddedStyles: function() {
2473			if ( window.JetEngineSettings && window.JetEngineSettings.addedPostCSS ) {
2474				$.each( window.JetEngineSettings.addedPostCSS, function( ind, cssID ) {
2475					JetEngine.addedStyles.push( 'elementor-post-' + cssID );
2476					JetEngine.addedPostCSS.push( cssID );
2477				} );
2478			}
2479		},
2480
2481		enqueueAssetsFromResponse: function( response ) {
2482			if ( response.data.scripts ) {
2483				JetEngine.enqueueScripts( response.data.scripts );
2484			}
2485
2486			if ( response.data.styles ) {
2487				JetEngine.enqueueStyles( response.data.styles );
2488			}
2489		},
2490
2491		enqueueScripts: function( scripts ) {
2492			$.each( scripts, function( handle, scriptHtml ) {
2493				JetEngine.enqueueScript( handle, scriptHtml )
2494			} );
2495		},
2496
2497		enqueueStyles: function( styles ) {
2498			$.each( styles, function( handle, styleHtml ) {
2499				JetEngine.enqueueStyle( handle, styleHtml )
2500			} );
2501		},
2502
2503		enqueueScript: function( handle, scriptHtml ) {
2504
2505			if ( -1 !== JetEngine.addedScripts.indexOf( handle ) ) {
2506				return;
2507			}
2508
2509			if ( ! scriptHtml ) {
2510				return;
2511			}
2512
2513			var selector = 'script[id="' + handle + '-js"]';
2514
2515			if ( $( selector ).length ) {
2516				return;
2517			}
2518
2519			//$( 'body' ).append( scriptHtml );
2520
2521			var scriptsTags = scriptHtml.match( /<script[\s\S]*?<\/script>/gm );
2522
2523			if ( scriptsTags.length ) {
2524
2525				for ( var i = 0; i < scriptsTags.length; i++ ) {
2526
2527					JetEngine.assetsPromises.push(
2528						new Promise( function( resolve, reject ) {
2529
2530							var $tag = $( scriptsTags[i] );
2531
2532							if ( $tag[0].src ) {
2533
2534								var tag = document.createElement( 'script' );
2535
2536								tag.type   = $tag[0].type;
2537								tag.src    = $tag[0].src;
2538								tag.id     = $tag[0].id;
2539								tag.async  = false;
2540								tag.onload = function() {
2541									resolve();
2542								};
2543
2544								document.body.append( tag );
2545							} else {
2546								$( 'body' ).append( scriptsTags[i] );
2547								resolve();
2548							}
2549						} )
2550					);
2551				}
2552			}
2553
2554			JetEngine.addedScripts.push( handle );
2555		},
2556
2557		enqueueStyle: function( handle, styleHtml ) {
2558
2559			if ( -1 !== handle.indexOf( 'google-fonts' ) ) {
2560				JetEngine.enqueueGoogleFonts( handle, styleHtml );
2561				return;
2562			}
2563
2564			if ( -1 !== JetEngine.addedStyles.indexOf( handle ) ) {
2565				return;
2566			}
2567
2568			var selector = 'link[id="' + handle + '-css"],style[id="' + handle + '"]';
2569
2570			if ( $( selector ).length ) {
2571				return;
2572			}
2573
2574			$( 'head' ).append( styleHtml );
2575
2576			JetEngine.addedStyles.push( handle );
2577
2578			if ( -1 !== handle.indexOf( 'elementor-post' ) ) {
2579				var postID = handle.replace( 'elementor-post-', '' );
2580				JetEngine.addedPostCSS.push( postID );
2581			}
2582		},
2583
2584		enqueueGoogleFonts: function( handle, styleHtml ) {
2585
2586			var selector = 'link[id="' + handle + '-css"]';
2587
2588			if ( $( selector ).length ) {}
2589
2590			$( 'head' ).append( styleHtml );
2591		},
2592
2593		isFrontend: function () {
2594			// Check the Elementor
2595			if (typeof window.elementorFrontend !== 'undefined') {
2596				return !window.elementorFrontend.isEditMode();
2597			}
2598
2599			// Check the Bricks
2600			if (typeof window.bricksIsFrontend !== 'undefined') {
2601				return window.bricksIsFrontend;
2602			}
2603
2604			// If no builders are found, we assume it is frontend.
2605			return true;
2606		},
2607
2608		reinitBricksScripts: function (elementId) {
2609			if (!window.bricksIsFrontend) {
2610				return;
2611			}
2612
2613			document.dispatchEvent(
2614				new CustomEvent("bricks/ajax/query_result/displayed", {
2615					detail: {
2616						queryId: elementId || null
2617					}
2618				})
2619			);
2620		},
2621
2622		filters: ( function() {
2623
2624			var callbacks = {};
2625
2626			return {
2627
2628				addFilter: function( name, callback ) {
2629
2630					if ( ! callbacks.hasOwnProperty( name ) ) {
2631						callbacks[name] = [];
2632					}
2633
2634					callbacks[name].push(callback);
2635
2636				},
2637
2638				applyFilters: function( name, value, args ) {
2639
2640					if ( ! callbacks.hasOwnProperty( name ) ) {
2641						return value;
2642					}
2643
2644					if ( args === undefined ) {
2645						args = [];
2646					}
2647
2648					var container = callbacks[ name ];
2649					var cbLen     = container.length;
2650
2651					for (var i = 0; i < cbLen; i++) {
2652						if (typeof container[i] === 'function') {
2653							value = container[i](value, args);
2654						}
2655					}
2656
2657					return value;
2658				}
2659
2660			};
2661
2662		})()
2663
2664	};
2665
2666	$( window ).on( 'elementor/frontend/init', JetEngine.init );
2667
2668	window.JetEngine = JetEngine;
2669
2670	document.addEventListener( 'jet-smart-filters/inited', function() {
2671		window.JetSmartFilters.events.subscribe( 'ajaxFilters/updated', function( provider, queryId ) {
2672			window.JetEngine.initFrontStores( window.JetSmartFilters?.filterGroups?.[ provider + '/' + queryId ]?.$provider);
2673		} );
2674	} );
2675
2676	JetEngine.commonInit();
2677
2678	window.addEventListener( 'DOMContentLoaded', function() {
2679		setTimeout( () => JetEngine.initBlocks() );
2680		JetEngine.initDone = true;
2681	} );
2682
2683	window.jetEngineBricks = function() {
2684		JetEngine.initBricks();
2685	}
2686
2687	$( window ).trigger( 'jet-engine/frontend/loaded' );
2688
2689	const initFilterConflictHandler = function() {
2690		const conflictHandler = class FilterConflictHandler {
2691
2692			isResolving = false;
2693
2694			constructor() {
2695				this.init();
2696			}
2697
2698			init( e ) {
2699				JetSmartFilters.events.subscribe( 'fiter/change', ( filter ) => {
2700					if ( this.isResolving || filter?.filterConflictHandlerBlocked ) {
2701						return;
2702					}
2703
2704					this.isResolving = true;
2705
2706					if ( ! [ 'map-sync', 'user-geolocation', 'location-distance' ].includes( filter?.name ) ) {
2707						return;
2708					}
2709
2710					let conflictingTypes = [];
2711
2712					switch ( filter.name ) {
2713						case 'map-sync':
2714							conflictingTypes = [ 'user-geolocation', 'location-distance' ];
2715							break;
2716						case 'location-distance':
2717							conflictingTypes = [ 'map-sync', 'user-geolocation' ];
2718							break;
2719						default:
2720							conflictingTypes = [ 'map-sync' ];
2721					}
2722
2723					this.resetConflictingFilters( filter, conflictingTypes );
2724				} );
2725			}
2726
2727			resetConflictingFilters( filter, conflictingTypes ) {
2728				for ( const conflictingFilter of this.getFilters( filter, conflictingTypes ) ) {
2729					conflictingFilter.reset();
2730					conflictingFilter.dataValue = false;
2731					conflictingFilter.wasChanged ? conflictingFilter.wasChanged() : conflictingFilter.wasСhanged();
2732				}
2733
2734				this.isResolving = false;
2735			}
2736
2737			getFilters( filter, types ) {
2738				if ( ! types.length ) {
2739					return [];
2740				}
2741
2742				let filters = [];
2743
2744				filter.filterGroup.filters.forEach(
2745					( f ) => {
2746						if ( ! types.includes( f.name ) ) {
2747							return;
2748						}
2749
2750						filters.push( f );
2751					}
2752				);
2753
2754				return filters;
2755			}
2756
2757		};
2758
2759		new conflictHandler();
2760
2761	}
2762
2763	document.addEventListener( 'jet-smart-filters/inited', initFilterConflictHandler );
2764
2765}( jQuery ) );

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.