PageSourceSearch

https://www.tarideal.com/wp-content/plugins/jet-engine/assets/js/frontend.js?ver=3.6.7.1

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