PageSourceSearch

https://www.stemco.com/wp-content/plugins/jet-tricks/assets/js/jet-tricks-frontend.js?ver=2.0.1

js stemco.com collected 2026-09-25 14:02:11 UTC 65,411 bytes, 2,060 lines download raw bytes

1( function( $, elementor ) {
2
3	'use strict';
4
5	var JetTricks = {
6
7		init: function() {
8			var frontend = window.elementorFrontend || elementor;
9
10			if ( ! frontend || ! frontend.hooks ) {
11				return;
12			}
13
14			frontend.hooks.addAction( 'frontend/element_ready/section', JetTricks.elementorSection );
15			frontend.hooks.addAction( 'frontend/element_ready/section', JetTricks.elementorColumn );
16			frontend.hooks.addAction( 'frontend/element_ready/section', JetTricks.elementorWidget );
17			frontend.hooks.addAction( 'frontend/element_ready/container', JetTricks.elementorSection );
18			frontend.hooks.addAction( 'frontend/element_ready/container', JetTricks.elementorColumn );
19			frontend.hooks.addAction( 'frontend/element_ready/column', JetTricks.elementorColumn );
20			frontend.hooks.addAction( 'frontend/element_ready/column', JetTricks.elementorWidget );
21			frontend.hooks.addAction( 'frontend/element_ready/widget', JetTricks.elementorWidget );
22			frontend.hooks.addAction( 'frontend/element_ready/container', JetTricks.elementorWidget );
23
24			var widgets = {
25				'jet-view-more.default' : JetTricks.widgetViewMore,
26				'jet-unfold.default' : JetTricks.widgetUnfold,
27				'jet-hotspots.default' : JetTricks.widgetHotspots
28			};
29
30			$.each( widgets, function( widget, callback ) {
31				frontend.hooks.addAction( 'frontend/element_ready/' + widget, callback );
32			});
33
34			// Re-init widgets in nested tabs
35			if ( frontend.elements && frontend.elements.$window ) {
36				frontend.elements.$window.on(
37					'elementor/nested-tabs/activate',
38					( event, content ) => {
39
40					const $content = $( content );
41
42					var $button  = $content.find( '.jet-unfold__button' );
43
44					$button.off( 'click.jetUnfold' );
45
46					JetTricks.initWidgetsHandlers( $content );
47					JetTricks.elementorSection( $content );
48
49				}
50			);
51			}
52
53			// Add an action when the Swiper Loop Carousel widget is ready on the frontend
54			var loopCarouselTypes = [
55				'loop-carousel.post',
56				'loop-carousel.product',
57				'loop-carousel.post_taxonomy',
58				'loop-carousel.product_taxonomy'
59			];
60			
61			loopCarouselTypes.forEach( function( carouselType ) {
62				frontend.hooks.addAction( 'frontend/element_ready/' + carouselType, function( $scope, $ ) {
63					
64					$( window ).on( 'load', function() {
65						var loopCarousel = $scope.find( '.swiper' ),
66							swiperInstance = loopCarousel.data( 'swiper' ),
67							$button = $scope.find( '.jet-unfold__button' );
68						
69						if ( swiperInstance && $button ) {
70				
71							$button.off( 'click.jetUnfold' );
72							JetTricks.initLoopCarouselHandlers( $scope );
73				
74							swiperInstance.on( 'slideChange', function() {
75								$button.off( 'click.jetUnfold' );
76								JetTricks.initLoopCarouselHandlers( $scope );
77							});
78						}
79					});
80				});
81			});
82		},
83
84		getDeviceMode: function() {
85			if ( window.elementorFrontend && typeof window.elementorFrontend.getCurrentDeviceMode === 'function' ) {
86				return window.elementorFrontend.getCurrentDeviceMode();
87			}
88			var w = window.innerWidth || document.documentElement.clientWidth || 0;
89			if ( w < 768 ) {
90				return 'mobile';
91			}
92			if ( w < 1025 ) {
93				return 'tablet';
94			}
95			return 'desktop';
96			console.log( 'JetTricks.getDeviceMode', w );
97		},
98
99		initLoopCarouselHandlers: function( $selector ) {
100			$selector.find( '.elementor-widget-jet-unfold' ).each( function() {
101
102				var $this  = $( this ),
103
104				elementType = $this.data( 'element_type' );
105
106				if ( !elementType ) {
107					return;
108				}
109
110				if ( 'widget' === elementType ) {
111					elementType = $this.data( 'widget_type' );
112					window.elementorFrontend.hooks.doAction( 'frontend/element_ready/widget', $this, $ );
113				}
114
115				window.elementorFrontend.hooks.doAction( 'frontend/element_ready/global', $this, $ );
116				window.elementorFrontend.hooks.doAction( 'frontend/element_ready/' + elementType, $this, $ );
117
118
119			} );
120		},
121
122		initWidgetsHandlers: function( $selector ) {
123
124				$selector.find( '[data-element_type]' ).each( function() {
125
126					var excludeWidgets = [
127						'jet-woo-product-gallery-slider.default',
128						'accordion.default',
129						'jet-form-builder-form.default',
130						'nav-menu.default'
131					];
132
133					var $this  = $( this ),
134
135					elementType = $this.data( 'element_type' );
136
137					if ( !elementType ) {
138						return;
139					}
140
141					if ( 'widget' === elementType ) {
142
143						elementType = $this.data( 'widget_type' );
144						
145						if ( excludeWidgets.includes( elementType ) ) {
146							return;
147						}
148						
149						window.elementorFrontend.hooks.doAction( 'frontend/element_ready/widget', $this, $ );
150					}
151
152					window.elementorFrontend.hooks.doAction( 'frontend/element_ready/global', $this, $ );
153					window.elementorFrontend.hooks.doAction( 'frontend/element_ready/' + elementType, $this, $ );
154
155
156				} );
157		},
158
159		loadParticles: function( $scope, instanceId, jsonConfig ) {
160			$scope.prepend( '<div id="' + instanceId + '" class="jet-tricks-particles-section__instance"></div>' );
161
162			if ( typeof tsParticles !== 'undefined' && tsParticles.load ) {
163				if ( tsParticles.version && tsParticles.version.startsWith( '3.' ) ) {
164					tsParticles.load( { id: instanceId, options: jsonConfig } );
165				} else {
166					tsParticles.load( instanceId, jsonConfig );
167				}
168			}
169		},
170
171		elementorSection: function( $scope ) {
172			var $target        = $scope,
173				sectionId      = $scope.data( 'id' ),
174				editMode       = Boolean( elementor && elementor.isEditMode() ),
175				jetListing     = $target.parents( '.elementor-widget-jet-listing-grid' ).data( 'id' ),
176				settings       = {};
177
178			if ( window.JetTricksSettings && window.JetTricksSettings.elements_data.sections.hasOwnProperty( sectionId ) ) {
179				settings = window.JetTricksSettings.elements_data.sections[ sectionId ];
180			}
181
182			if ( editMode ) {
183				settings = JetTricks.sectionEditorSettings( $scope );
184			}
185
186			if ( ! settings ) {
187				return false;
188			}
189
190			if ( jQuery.isEmptyObject( settings ) ) {
191				return false;
192			}
193
194			if ( 'false' === settings.particles || '' === settings.particles_json ) {
195				return false;
196			}
197
198			// Compatibility jet tricks particles with jet listing
199
200			if ( jetListing && $target.parent().data( 'elementor-type' ) === 'jet-listing-items' ){
201				sectionId += jetListing + $target.parents( '.jet-listing-grid__item' ).data( 'post-id' );
202			}
203
204			JetTricks.loadParticles( $scope, 'jet-tricks-particles-instance-' + sectionId, JSON.parse( settings.particles_json ) );
205
206		},
207
208		elementorColumn: function( $scope ) {
209			var $target  = $scope,
210				$parentSection = $scope.closest( '.elementor-section' ),
211				isLegacyModeActive = !!$target.find( '> .elementor-column-wrap' ).length,
212				$window  = $( window ),
213				columnId = $target.data( 'id' ),
214				editMode = Boolean( elementor && elementor.isEditMode() ),
215				settings = {},
216				stickyInstance = null,
217				stickyInstanceOptions = {
218					topSpacing: 50,
219					bottomSpacing: 50,
220					containerSelector: isLegacyModeActive ? '.elementor-row' : '.elementor-container, .e-con-inner',
221					innerWrapperSelector: isLegacyModeActive ? '.elementor-column-wrap' : '.elementor-widget-wrap',
222				},
223				$observerTarget = $target.find('.elementor-element');
224
225			if ( ! editMode ) {
226				settings = $target.data( 'jet-settings' );
227
228				if ( $target.hasClass( 'jet-sticky-column' ) ) {
229					if ( -1 !== settings['stickyOn'].indexOf( JetTricks.getDeviceMode() ) ) {
230						$target.each( function() {
231							var $this  = $( this ),
232								elementType = $this.data( 'element_type' );
233		
234							if ( settings['behavior'] === 'fixed' ) {
235								initFixedSticky( $this, settings );
236							} else if ( elementType !== 'container' && elementType !== 'section' ) {
237								initSidebarSticky( $this, settings, stickyInstanceOptions );
238							} else if ( settings['behavior'] === 'scroll_until_end' ) {
239								initScrollUntilEndSticky( $this, settings );
240							} else {
241								initDefaultSticky( $this, settings );
242							}
243						});
244					}
245				}
246			}
247
248			function initFixedSticky($element, settings) {
249				var offsetTop = parseInt(settings['topSpacing']) || 0;
250				var bottomSpacing = parseInt(settings['bottomSpacing']) || 0;
251				var $window = $(window);
252				var elementId = $element.data('id');
253				var originalOffsetTop = $element.offset().top;
254				var originalHeight = $element.outerHeight();
255				var scrollVisibility = settings['scrollVisibility'] || 'both';
256				var scrollOffset = parseInt( settings['scrollOffset'], 10 );
257				var lastScrollTop = $window.scrollTop();
258				var lastDirection = null;
259
260				if ( isNaN( scrollOffset ) || scrollOffset < 0 ) {
261					scrollOffset = 12;
262				}
263			
264				var $allStickyElements = $('.jet-sticky-column').filter(function() {
265					var $this = $(this);
266					var elementSettings = $this.data('jet-settings');
267
268					return elementSettings && elementSettings.stickyOn.indexOf( JetTricks.getDeviceMode() ) !== -1;
269				});
270
271				var currentIndex = $allStickyElements.index($element);
272				var $nextSticky = currentIndex + 1 < $allStickyElements.length ? $allStickyElements.eq(currentIndex + 1) : null;
273				var $stopper = null;
274				if ($nextSticky) {
275					$stopper = $nextSticky.closest('.elementor-top-section, .e-parent');
276					if (!$stopper.length) {
277						$stopper = $nextSticky;
278					}
279				}
280			
281				const $placeholder = $('<div></div>')
282					.addClass('jet-sticky-placeholder')
283					.css({
284						display: 'none',
285						height: originalHeight,
286						width: $element.outerWidth(),
287						visibility: 'hidden'
288					});
289			
290				$element.before($placeholder);				
291
292				$element.css({
293					'--jet-tricks-sticky-offset': offsetTop + 'px',
294				});
295
296				function withTransitionDisabled( callback ) {
297					$element.addClass( 'jet-sticky-container--no-transition' );
298					callback();
299
300					requestAnimationFrame( function() {
301						requestAnimationFrame( function() {
302							$element.removeClass( 'jet-sticky-container--no-transition' );
303						} );
304					} );
305				}
306			
307				function enableSticky() {
308					$placeholder.show();
309					$element.addClass('jet-sticky-container--stuck');
310			
311					var stopperTop = $stopper?.offset()?.top;
312					var stopPoint = stopperTop ? (stopperTop - $element.outerHeight() - offsetTop - bottomSpacing) : null;
313					var diff = 0;
314			
315					if (stopPoint && stopPoint < $window.scrollTop()) {
316						diff = (stopPoint - $window.scrollTop());
317					}
318			
319					$element.css({
320						position: 'fixed',
321						top: diff + 'px',
322						left: $placeholder.offset().left + 'px',
323						width: $placeholder.outerWidth() + 'px',
324						zIndex: settings['zIndex'] || ''
325					});
326				}
327			
328				function disableSticky() {
329					$placeholder.hide();
330					$element.removeClass('jet-sticky-container--stuck jet-sticky-container--hidden jet-sticky-container--scrolled');
331			
332					$element.css({
333						position: '',
334						top: '',
335						left: '',
336						width: '',
337						zIndex: ''
338					});
339				}
340
341				function updateStickyState( direction, isScrolled ) {
342					var shouldHide = false;
343
344					if ( ! isScrolled ) {
345						withTransitionDisabled( function() {
346							$element.removeClass( 'jet-sticky-container--hidden jet-sticky-container--scrolled' );
347						} );
348						return;
349					}
350
351					if ( ! direction ) {
352						$element.removeClass( 'jet-sticky-container--hidden' );
353						$element.toggleClass( 'jet-sticky-container--scrolled', !! isScrolled );
354						return;
355					}
356
357					if ( scrollVisibility === 'up' ) {
358						shouldHide = direction === 'down';
359					} else if ( scrollVisibility === 'down' ) {
360						shouldHide = direction === 'up';
361					}
362
363					$element.toggleClass( 'jet-sticky-container--hidden', shouldHide );
364					$element.toggleClass( 'jet-sticky-container--scrolled', !! isScrolled );
365				}
366			
367				function onScroll() {
368					var scrollTop = $window.scrollTop();
369					var isScrolled = scrollTop > scrollOffset;
370
371					if ( Math.abs( scrollTop - lastScrollTop ) >= scrollOffset ) {
372						lastDirection = scrollTop > lastScrollTop ? 'down' : 'up';
373						lastScrollTop = scrollTop;
374					}
375
376					if (scrollTop >= originalOffsetTop) {
377						enableSticky();
378						updateStickyState( lastDirection, isScrolled );
379					} else {
380						disableSticky();
381						lastScrollTop = scrollTop;
382					}
383				}
384			
385				function onResize() {
386					originalOffsetTop = $placeholder.offset().top;
387					originalHeight = $element.outerHeight();
388			
389					$placeholder.css({
390						height: originalHeight,
391						width: $element.outerWidth()
392					});
393			
394					onScroll();
395				}
396			
397				let ticking = false;
398				$window.on('scroll.jetStickyHeader-' + elementId, function() {
399					if (!ticking) {
400						requestAnimationFrame(function() {
401							onScroll();
402							ticking = false;
403						});
404						ticking = true;
405					}
406				});
407			
408				$window.on('resize.jetStickyHeader-' + elementId, JetTricksTools.debounce(100, onResize));
409				onScroll();
410			
411				$window.on('resize.jetStickyHeader-' + elementId, JetTricksTools.debounce(100, function() {
412					if (-1 === settings['stickyOn'].indexOf( JetTricks.getDeviceMode() )) {
413						cleanupSticky($element, $placeholder, elementId);
414					}
415				}));
416			}
417			
418			function cleanupSticky( $element, $placeholder, elementId ) {
419				$placeholder.remove();
420				$element.css({
421					position: '',
422					top: '',
423					left: '',
424					width: '',
425					zIndex: '',
426					transition: '',
427					willChange: '',
428					'--jet-tricks-sticky-offset': ''
429				});
430				$element.removeClass('jet-sticky-container--stuck jet-sticky-container--hidden jet-sticky-container--scrolled');
431				$window.off('scroll.jetStickyHeader-' + elementId);
432				$window.off('resize.jetStickyHeader-' + elementId);
433			}
434
435			function initSidebarSticky( $element, settings, options ) {
436				options.topSpacing = settings['topSpacing'];
437				options.bottomSpacing = settings['bottomSpacing'];
438
439				imagesLoaded( $parentSection, function() {
440					$target.data( 'stickyColumnInit', true );
441					stickyInstance = new StickySidebar( $target[0], options );
442				});
443
444				var targetMutation = $target[0],
445					config = { attributes: true, childList: true, subtree: true };
446
447				var observer = new MutationObserver( function( mutations ) {
448					for( var mutation of mutations ) {
449						if ( 'attributes' === mutation.type && mutation.attributeName !== 'style' ) {
450							$target[0].style.height = 'auto';
451						}
452					}
453				});
454
455				observer.observe( targetMutation, config );
456
457				$window.on( 'resize.JetTricksStickyColumn orientationchange.JetTricksStickyColumn', 
458					JetTricksTools.debounce( 50, resizeDebounce ) );
459
460				var observer = new MutationObserver( function( mutations ) {
461					if ( stickyInstance ) {
462						mutations.forEach( function(mutation){
463							if (mutation.attributeName === 'class') {
464								setTimeout( function() {
465									stickyInstance.destroy();
466									stickyInstance = new StickySidebar( $target[0], options );
467								}, 100 );
468							}
469						});
470					}
471				});
472
473				$observerTarget.each( function(){
474					observer.observe( $( this )[0], {
475						attributes: true
476					});
477				});
478			}
479
480			function initScrollUntilEndSticky( $element, settings ) {
481				const stickyHeight = $element.outerHeight();
482				const stickyContentBottom = $element.offset().top + stickyHeight;
483				const stickyViewportOffset = $window.height() - stickyHeight - settings['bottomSpacing'];
484
485				$('body').addClass('jet-sticky-container');
486
487				$window.on( 'scroll.jetSticky', function () {
488					const scrollPosition = $window.scrollTop();
489
490					if ( scrollPosition + $window.height() >= stickyContentBottom ) {
491						$element.css({
492							position: 'sticky',
493							top: stickyViewportOffset + 'px',
494							bottom: 'auto',
495							left: 'auto',
496							zIndex: settings['zIndex'],
497						});
498					}
499				});
500
501				$observerTarget.on( 'destroy.jetSticky', function () {
502					$window.off( 'scroll.jetSticky' );
503					$('body').removeClass('jet-sticky-container');
504				});
505			}
506
507			function initDefaultSticky( $element, settings ) {
508				$('body').addClass('jet-sticky-container');
509				$element.addClass( 'jet-sticky-container-sticky' );
510				$element.css({ 
511					'top': settings['topSpacing'], 
512					'bottom': settings['bottomSpacing']
513				});
514			}
515
516			function resizeDebounce() {
517				var currentDeviceMode = JetTricks.getDeviceMode(),
518					availableDevices  = settings['stickyOn'] || [],
519					isInit            = $target.data( 'stickyColumnInit' );
520
521				if ( -1 !== availableDevices.indexOf( currentDeviceMode ) ) {
522					if ( ! isInit ) {
523						$target.data( 'stickyColumnInit', true );
524						stickyInstance = new StickySidebar( $target[0], stickyInstanceOptions );
525						stickyInstance.updateSticky();
526					}
527				} else {
528					$target.data( 'stickyColumnInit', false );
529					stickyInstance.destroy();
530				}
531			}
532		},
533
534		elementorWidget: function( $scope ) {
535			var parallaxInstance = null,
536				satelliteInstance = null,
537				tooltipInstance = null,
538				scrollRevealInstance = null;
539
540			parallaxInstance = new jetWidgetParallax( $scope );
541			parallaxInstance.init();
542
543			satelliteInstance = new jetWidgetSatellite( $scope );
544			satelliteInstance.init();
545
546			tooltipInstance = new jetWidgetTooltip( $scope );
547			tooltipInstance.init();
548
549			scrollRevealInstance = new jetWidgetScrollReveal( $scope );
550			scrollRevealInstance.init();
551
552		},
553
554		getElementorElementSettings: function( $scope ) {
555
556			if ( window.elementorFrontend && window.elementorFrontend.isEditMode() && $scope.hasClass( 'elementor-element-edit-mode' ) ) {
557				return JetTricks.getEditorElementSettings( $scope );
558			}
559
560			return $scope.data( 'settings' ) || {};
561		},
562
563		getEditorElementSettings: function( $scope ) {
564			var modelCID = $scope.data( 'model-cid' ),
565				elementData;
566
567			if ( ! modelCID ) {
568				return {};
569			}
570
571			if ( ! elementor.hasOwnProperty( 'config' ) ) {
572				return {};
573			}
574
575			if ( ! elementor.config.hasOwnProperty( 'elements' ) ) {
576				return {};
577			}
578
579			if ( ! elementor.config.elements.hasOwnProperty( 'data' ) ) {
580				return {};
581			}
582
583			elementData = elementor.config.elements.data[ modelCID ];
584
585			if ( ! elementData ) {
586				return {};
587			}
588
589			return elementData.toJSON();
590		},
591
592		widgetViewMore: function( $scope ) {
593			var $target         = $scope.find( '.jet-view-more' ),
594				instance        = null,
595				settings        = $target.data( 'settings' );
596
597			instance = new jetViewMore( $target, settings );
598			instance.init();
599		},
600
601		widgetUnfold: function( $scope ) {
602			var $target                = $scope.find( '.jet-unfold' ),
603				$button                = $( '.jet-unfold__button', $target ),
604				$mask                  = $( '.jet-unfold__mask', $target ),
605				$content               = $( '.jet-unfold__content', $target ),
606				$contentInner          = $( '.jet-unfold__content-inner', $target),
607				$trigger               = $( '.jet-unfold__trigger', $target),
608				$separator             = $( '.jet-unfold__separator', $target ),
609				baseSettings           = $target.data( 'settings' ) || {},
610				elemSettings           = ( typeof elementor !== 'undefined' && JetTricks.getElementorElementSettings ) ? ( JetTricks.getElementorElementSettings( $scope ) || {} ) : {},
611				settings               = $.extend( {}, baseSettings, elemSettings ),
612				maskBreakpointsHeights = [],
613				prevBreakpoint         = '',
614				unfoldDuration         = settings['unfoldDuration'] || settings['unfold_duration'],
615				foldDuration           = settings['foldDuration'] || settings['fold_duration'],
616				unfoldEasing           = settings['unfoldEasing'] || settings['unfold_easing'],
617				foldEasing             = settings['foldEasing'] || settings['fold_easing'],
618				maskHeightAdv          = 20,
619				heightCalc             = '',
620				autoHide               = settings['autoHide'] || false,
621				autoHideTime           = settings['autoHideTime'] && 0 != settings['autoHideTime']['size'] ? settings['autoHideTime']['size'] : 5,
622				hideOutsideClick       = settings['hideOutsideClick'] || false,
623				heightControlType      = settings['heightControlType'] || 'height',
624				wordCount              = settings['wordCount'] || 20,
625				autoHideTrigger,
626				activeBreakpoints      = ( window.elementor && window.elementor.config && window.elementor.config.responsive && window.elementor.config.responsive.activeBreakpoints ) ? window.elementor.config.responsive.activeBreakpoints : {},
627				initialLoaded          = false,
628				isTrue                 = function( v ) { return v === true || v === 'true'; };
629
630			function updateMaskGradientClass() {
631				if (settings.separatorType === 'gradient') {
632					if ($target.hasClass('jet-unfold-state') || $trigger.is(':hidden')) {
633						$mask.removeClass('jet-unfold__mask-gradient');
634					} else {
635						$mask.addClass('jet-unfold__mask-gradient');
636					}
637				}
638			}
639
640			function calculateHeightByWordCount() {
641				var text = $contentInner.text().trim();
642				if (!text) {
643					return 0;
644				}
645
646				var words = text.split(/\s+/);
647				var wordsToShow = Math.min(getDeviceWordCount(), words.length);
648				if (wordsToShow >= words.length) {
649					return $contentInner.outerHeight();
650				}
651
652				var visibleText = words.slice(0, wordsToShow).join(' ');
653				var range = document.createRange();
654				var walker = document.createTreeWalker($contentInner[0], NodeFilter.SHOW_TEXT, null, false);
655				var endNode = null;
656				var endOffset = 0;
657				var wordsCounted = 0;
658
659				while (walker.nextNode()) {
660					var node = walker.currentNode;
661					var nodeText = node.textContent;
662					var match;
663					var wordPattern = /\S+/g;
664
665					while ((match = wordPattern.exec(nodeText)) !== null) {
666						wordsCounted++;
667
668						if (wordsCounted === wordsToShow) {
669							endOffset = match.index + match[0].length;
670							endNode = node;
671							break;
672						}
673					}
674
675					if (endNode) {
676						break;
677					}
678				}
679
680				if (!endNode) {
681					return $contentInner.outerHeight();
682				}
683
684				try {
685					range.selectNodeContents($contentInner[0]);
686					range.setEnd(endNode, endOffset);
687					var rect = range.getBoundingClientRect();
688					var containerRect = $contentInner[0].getBoundingClientRect();
689					return Math.ceil(rect.bottom - containerRect.top);
690				} catch (e) {
691					var $temp = $contentInner.clone().empty().css({ position: 'absolute', visibility: 'hidden', width: $contentInner.outerWidth() }).html('<p>' + visibleText + '</p>');
692					$contentInner.after($temp);
693					var h = $temp.outerHeight();
694					$temp.remove();
695					return h;
696				}
697			}
698
699			maskBreakpointsHeights['desktop']    = [];
700			maskBreakpointsHeights['widescreen'] = [];
701
702			maskBreakpointsHeights['desktop']['maskHeight'] = (settings['mask_height'] && settings['mask_height']['size'] && '' != settings['mask_height']['size']) ? settings['mask_height']['size'] : 50;
703
704			prevBreakpoint = 'desktop';
705
706			Object.keys(  activeBreakpoints ).reverse().forEach(  function( breakpointName ) {
707
708				if ( 'widescreen' === breakpointName ) {
709					maskBreakpointsHeights['widescreen']['maskHeight'] = (settings['mask_height_widescreen'] && settings['mask_height_widescreen']['size'] && '' != settings['mask_height_widescreen']['size']) ? settings['mask_height_widescreen']['size'] : maskBreakpointsHeights['desktop']['maskHeight'];
710				} else {
711					maskBreakpointsHeights[breakpointName] = [];
712
713					var breakpointSetting = settings['mask_height_' + breakpointName];
714					maskBreakpointsHeights[breakpointName]['maskHeight'] = (breakpointSetting && breakpointSetting['size'] && '' != breakpointSetting['size']) ? breakpointSetting['size'] : maskBreakpointsHeights[prevBreakpoint]['maskHeight'];
715
716					prevBreakpoint = breakpointName;
717				}
718			} );
719
720			onLoaded();
721
722			if ( typeof ResizeObserver !== 'undefined' ) {
723				new ResizeObserver( function( entries ) {
724					if ( $target.hasClass( 'jet-unfold-state' ) ) {
725						$mask.css( {
726							'height': $contentInner.outerHeight()
727						} );
728					}
729				} ).observe( $contentInner[0] );
730			}
731			
732			if ( isTrue( hideOutsideClick ) ) {
733				$( window ).on( 'mouseup.jetUnfold', function( event ) {
734					let container = $target;
735					if ( !container.is( event.target ) && 0 === container.has( event.target ).length && $target.hasClass( 'jet-unfold-state' ) ) {
736						$button.trigger( 'click', {
737							scrollOnFold: false
738						} );
739					}
740				} )
741			}
742
743			$target.one('transitionend webkitTransitionEnd oTransitionEnd', function() {
744				if ( !initialLoaded ) {
745					onLoaded();
746					initialLoaded = true;
747				}
748			});
749
750			function onLoaded() {
751				initialLoaded = true;
752
753				var deviceHeight = getDeviceHeight();
754
755				heightCalc = +deviceHeight + maskHeightAdv;
756
757				if ( heightCalc < $contentInner.height() ) {
758
759					if ( ! $target.hasClass( 'jet-unfold-state' ) ) {
760						$separator.css( {
761							'opacity': '1'
762						} );
763					}
764
765					if ( ! $target.hasClass( 'jet-unfold-state' ) ) {
766						$mask.css( {
767							'height': deviceHeight
768						} );
769					} else {
770						$mask.css( {
771							'height': $contentInner.outerHeight()
772						} );
773					}
774					$trigger.css( 'display', 'flex' );
775					updateMaskGradientClass();
776				} else {
777					$trigger.hide();
778					$mask.css( {
779						'height': '100%'
780					} );
781					$content.css( {
782						'max-height': 'none'
783					} );
784					$separator.css( {
785						'opacity': '0'
786					} );
787					updateMaskGradientClass();
788				}
789			}
790
791			$( window ).on( 'resize.jetWidgetUnfold orientationchange.jetWidgetUnfold', JetTricksTools.debounce( 50, function(){
792				initialLoaded = false;
793				onLoaded();
794			} ) );
795
796			$button.keypress( function( e ) {
797				if ( e.which == 13 ) {
798					$button.click();
799					return false;
800				}
801			} );
802
803			$button.on( 'click.jetUnfold', function( e, options ) {
804				var $this         = $( this ),
805					$buttonText   = $( '.jet-unfold__button-text', $this ),
806					unfoldText    = settings['unfoldText'] || '',
807					foldText      = settings['foldText'] || '',
808					$buttonIcon   = $( '.jet-unfold__button-icon', $this ),
809					unfoldIcon    = settings['unfoldIcon'] || '',
810					foldIcon      = settings['foldIcon'] || '',
811					contentHeight = $contentInner.outerHeight(),
812					deviceHeight  = getDeviceHeight(),
813					shouldScrollOnFold = ! options || false !== options.scrollOnFold;
814
815				e.preventDefault();
816
817				if ( typeof anime !== 'undefined' ) {
818					anime.remove( $mask[0] );
819				}
820
821				if ( ! $target.hasClass( 'jet-unfold-state' ) ) {
822					$target.addClass( 'jet-unfold-state' );
823
824					$separator.css( {
825						'opacity': '0'
826					} );
827
828					$buttonIcon.html( foldIcon );
829					$buttonText.html( foldText );
830
831					// Force recalculation of content height after state change
832					setTimeout(function() {
833						contentHeight = $contentInner.outerHeight();
834						var duration = ( unfoldDuration && unfoldDuration.size != null ? unfoldDuration.size : 300 );
835						if ( typeof anime !== 'undefined' ) {
836							anime( {
837								targets: $mask[0],
838								height: contentHeight,
839								duration: duration,
840								easing: unfoldEasing || 'ease',
841								complete: function( anim ) {
842									$( document ).trigger( 'jet-engine/listing/recalculate-masonry' );
843								}
844							} );
845						} else {
846							$mask.css( 'height', contentHeight );
847							$( document ).trigger( 'jet-engine/listing/recalculate-masonry' );
848						}
849					}, 0);
850
851					if ( isTrue( autoHide ) ) {
852						autoHideTrigger = setTimeout( function() {
853							$button.trigger( 'click', {
854								scrollOnFold: false
855							} );
856						}, autoHideTime * 1000 );
857					}
858				} else {
859					clearTimeout( autoHideTrigger );
860
861					$target.removeClass( 'jet-unfold-state' );
862
863					$separator.css( {
864						'opacity': '1'
865					} );
866
867					$buttonIcon.html( unfoldIcon );
868					$buttonText.html( unfoldText );
869
870					var foldDurationVal = ( foldDuration && foldDuration.size != null ? foldDuration.size : 300 );
871					var onFoldComplete = function() {
872						if ( shouldScrollOnFold && isTrue( settings['foldScrolling'] ) && settings['foldScrollOffset'] ) {
873							$( 'html, body' ).animate( {
874								scrollTop: $target.offset().top - ( settings['foldScrollOffset']['size'] || 0 )
875							}, 'slow' );
876						}
877						$( document ).trigger( 'jet-engine/listing/recalculate-masonry' );
878					};
879					if ( typeof anime !== 'undefined' ) {
880						anime( {
881							targets: $mask[0],
882							height: deviceHeight,
883							duration: foldDurationVal,
884							easing: foldEasing || 'ease',
885							complete: onFoldComplete
886						} );
887					} else {
888						$mask.css( 'height', deviceHeight );
889						onFoldComplete();
890					}
891				}
892				
893				updateMaskGradientClass();
894			} );
895
896			function getDeviceMode() {
897				return ( typeof elementorFrontend !== 'undefined' && elementorFrontend.getCurrentDeviceMode ) ? elementorFrontend.getCurrentDeviceMode() : 'desktop';
898			}
899
900			function getDeviceHeight() {
901				if (heightControlType === 'word_count') {
902					return calculateHeightByWordCount();
903				}
904
905				var device = getDeviceMode();
906				var heightSettings;
907
908				switch ( device ) {
909
910					case 'mobile':
911						heightSettings = settings.mask_height_mobile;
912						break;
913
914					case 'tablet':
915						heightSettings = settings.mask_height_tablet;
916						break;
917
918					default:
919						heightSettings = settings.mask_height || settings.height;
920
921				}
922
923				if ( ! heightSettings || ( heightSettings.size == null || heightSettings.size === '' ) ) {
924					heightSettings = settings.mask_height || settings.height || { size: 50, unit: 'px' };
925				}
926
927				var unit = heightSettings.unit || 'px';
928				var size = heightSettings.size != null ? heightSettings.size : 50;
929
930				switch ( unit ) {
931
932					case 'vh':
933						return ( window.innerHeight * size ) / 100;
934
935					case '%':
936						var parentHeight = $contentInner.parent().height();
937						return ( parentHeight * size ) / 100;
938
939					default:
940						return size;
941				}
942			}
943
944			function getDeviceWordCount() {
945				var device = getDeviceMode();
946				var value;
947
948				switch ( device ) {
949					case 'mobile':
950						value = settings.word_count_mobile || settings.wordCount;
951						break;
952					case 'tablet':
953						value = settings.word_count_tablet || settings.wordCount;
954						break;
955					default:
956						value = settings.word_count || settings.wordCount;
957				}
958
959				return ( value !== null && value !== undefined ) ? parseInt( value, 10 ) : 20;
960			}
961		},
962
963		widgetHotspots: function( $scope ) {
964			var $target   = $scope.find( '.jet-hotspots' ),
965				$hotspots = $( '.jet-hotspots__item', $target),
966				settings  = $target.data( 'settings' ),
967				editMode  = Boolean( elementor && elementor.isEditMode() ),
968				itemActiveClass = 'jet-hotspots__item--active';
969
970			$target.imagesLoaded().progress( function() {
971				$target.addClass( 'image-loaded' );
972			} );
973
974			$hotspots.each( function( index ) {
975				var $this          = $( this ),
976					horizontal     = $this.data( 'horizontal-position' ),
977					vertical       = $this.data( 'vertical-position' ),
978					tooltipWidth   = $this.data( 'tooltip-width' ) || null,
979					showOnInit     = $this.data( 'show-on-init' ),
980					itemSelector   = $this[0],
981					options        = {};
982
983				$this.css( {
984					'left': horizontal + '%',
985					'top': vertical + '%'
986				} );
987
988				if ( itemSelector._tippy ) {
989					itemSelector._tippy.destroy();
990				}
991
992				options = {
993					content: $this.data('tippy-content'),
994					arrow: settings['tooltipArrow'] ? true : false,
995					placement: settings['tooltipPlacement'],
996					trigger: settings['tooltipTrigger'],
997					appendTo: editMode ? document.body : $target[0],
998					hideOnClick: 'manual' !== settings['tooltipTrigger'],
999					maxWidth: 'none',
1000					offset: [0, settings['tooltipDistance']['size']],
1001					allowHTML: true,
1002					interactive: settings['tooltipInteractive'] ? true : false,
1003					onShow( instance ) {
1004						$( itemSelector ).addClass( itemActiveClass );
1005
1006						if ( tooltipWidth ) {
1007							instance.popper.querySelector( '.tippy-box' ).style.width = tooltipWidth;
1008						}
1009
1010					},
1011					onHidden( instance ) {
1012						$( itemSelector ).removeClass( itemActiveClass );
1013					}
1014				}
1015
1016				if ( 'manual' != settings['tooltipTrigger'] ) {
1017					options['duration']  = [ settings['tooltipShowDuration']['size'], settings['tooltipHideDuration']['size'] ];
1018					options['animation'] = settings['tooltipAnimation'];
1019					options['delay']     = settings['tooltipDelay'];
1020				}
1021
1022				tippy( [ itemSelector ], options );
1023
1024				if ( 'manual' === settings['tooltipTrigger'] && itemSelector._tippy ) {
1025					itemSelector._tippy.show();
1026				}
1027			
1028				if ( ( showOnInit === 'yes' || settings['tooltipShowOnInit'] ) && itemSelector._tippy ) {
1029					itemSelector._tippy.show();
1030				}
1031
1032			} );
1033		},
1034
1035		columnEditorSettings: function( columnId ) {
1036			var editorElements = null,
1037				columnData     = {};
1038
1039			if ( ! window.elementor.hasOwnProperty( 'elements' ) ) {
1040				return false;
1041			}
1042
1043			editorElements = window.elementor.elements;
1044
1045			if ( ! editorElements.models ) {
1046				return false;
1047			}
1048
1049			$.each( editorElements.models, function( index, obj ) {
1050
1051				$.each( obj.attributes.elements.models, function( index, obj ) {
1052					if ( columnId == obj.id ) {
1053						columnData = obj.attributes.settings.attributes;
1054					}
1055				} );
1056
1057			} );
1058
1059			return {
1060				'sticky': columnData['jet_tricks_column_sticky'] || false,
1061				'topSpacing': columnData['jet_tricks_top_spacing'] || 50,
1062				'bottomSpacing': columnData['jet_tricks_bottom_spacing'] || 50,
1063				'stickyOn': columnData['jet_tricks_column_sticky_on'] || [ 'desktop', 'tablet', 'mobile']
1064			}
1065
1066		},
1067
1068		sectionEditorSettings: function( $scope ) {
1069			var editorElements = null,
1070				sectionData     = {};
1071
1072			if ( ! window.elementor.hasOwnProperty( 'elements' ) ) {
1073				return false;
1074			}
1075
1076			sectionData = JetTricks.getElementorElementSettings( $scope );
1077
1078			return {
1079				'particles': sectionData['section_jet_tricks_particles'] || 'false',
1080				'particles_json': sectionData['section_jet_tricks_particles_json'] || '',
1081			}
1082
1083		}
1084
1085	};
1086
1087	$( window ).on( 'elementor/frontend/init', JetTricks.init );
1088
1089	JetTricks.initBlocks = function() {
1090		if ( window.JetPlugins ) {
1091			window.JetPlugins.bulkBlocksInit( [
1092				{ block: 'jet-tricks/view-more', callback: JetTricks.widgetViewMore },
1093				{ block: 'jet-tricks/unfold', callback: JetTricks.widgetUnfold },
1094				{ block: 'jet-tricks/hotspots', callback: JetTricks.widgetHotspots },
1095			] );
1096		}
1097	};
1098
1099	var JetTricksTools = {
1100		debounce: function( threshold, callback ) {
1101			var timeout;
1102
1103			return function debounced( $event ) {
1104				function delayed() {
1105					callback.call( this, $event );
1106					timeout = null;
1107				}
1108
1109				if ( timeout ) {
1110					clearTimeout( timeout );
1111				}
1112
1113				timeout = setTimeout( delayed, threshold );
1114			};
1115		},
1116
1117		widgetEditorSettings: function( widgetId ) {
1118			var editorElements = null,
1119				widgetData = {};
1120		
1121			if ( !window.elementor.hasOwnProperty( 'elements' ) || !window.elementor.elements.models ) {
1122				return false;
1123			}
1124		
1125			editorElements = window.elementor.elements;
1126		
1127			function findWidgetById( models, widgetId ) {
1128				let foundData = null;
1129		
1130				$.each( models, function( index, obj ) {
1131					if ( obj.id === widgetId ) {
1132						foundData = obj.attributes.settings.attributes;
1133						return false;
1134					}
1135					if ( obj.attributes.elements && obj.attributes.elements.models ) {
1136						foundData = findWidgetById( obj.attributes.elements.models, widgetId );
1137						if ( foundData ) {
1138							return false;
1139						}
1140					}
1141				});
1142		
1143				return foundData;
1144			}
1145		
1146			widgetData = findWidgetById( editorElements.models, widgetId ) || {};
1147
1148			return {
1149				'speed': widgetData['jet_tricks_widget_parallax_speed'] || { 'size': 50, 'unit': '%'},
1150				'parallax': widgetData['jet_tricks_widget_parallax'] || 'false',
1151				'invert': widgetData['jet_tricks_widget_parallax_invert'] || 'false',
1152				'stickyOn': widgetData['jet_tricks_widget_parallax_on'] || [ 'desktop', 'tablet', 'mobile'],
1153				'satellite': widgetData['jet_tricks_widget_satellite'] || 'false',
1154				'satelliteType': widgetData['jet_tricks_widget_satellite_type'] || 'text',
1155				'satellitePosition': widgetData['jet_tricks_widget_satellite_position'] || 'top-center',
1156				'satelliteText': widgetData['jet_tricks_widget_satellite_text'] || 'Lorem Ipsum',
1157				'satelliteIcon': widgetData['selected_jet_tricks_widget_satellite_icon'] || '',
1158				'satelliteImage': widgetData['jet_tricks_widget_satellite_image'] || '',
1159				'satelliteLink': widgetData['jet_tricks_widget_satellite_link'] || '',
1160				'tooltip': widgetData['jet_tricks_widget_tooltip'] || 'false',
1161				'tooltipDescription': widgetData['jet_tricks_widget_tooltip_description'] || 'Lorem Ipsum',
1162				'tooltipPlacement': widgetData['jet_tricks_widget_tooltip_placement'] || 'top',
1163				'tooltipArrow': 'true' === widgetData['jet_tricks_widget_tooltip_arrow'] ? true : false,
1164				'xOffset': widgetData['jet_tricks_widget_tooltip_x_offset'] || 0,
1165				'yOffset': widgetData['jet_tricks_widget_tooltip_y_offset'] || 0,
1166				'tooltipAnimation': widgetData['jet_tricks_widget_tooltip_animation'] || 'shift-toward',
1167				'tooltipTrigger': widgetData['jet_tricks_widget_tooltip_trigger'] || 'mouseenter',
1168				'customSelector': widgetData['jet_tricks_widget_tooltip_custom_selector'] || '',
1169				'zIndex': widgetData['jet_tricks_widget_tooltip_z_index'] || '999',
1170				'appendTo': widgetData['jet_tricks_widget_tooltip_append_to'] || 'widget',
1171				'delay': widgetData['jet_tricks_widget_tooltip_delay'] || '0',
1172				'followCursor': widgetData['jet_tricks_widget_tooltip_follow_cursor'] || 'false',
1173				'tooltipDevices': Array.isArray( widgetData['jet_tricks_widget_tooltip_devices'] )
1174					? widgetData['jet_tricks_widget_tooltip_devices']
1175					: [],
1176				'scrollReveal': widgetData['jet_tricks_widget_scroll_reveal'] || 'false',
1177				'scrollRevealEffect': widgetData['jet_tricks_widget_scroll_reveal_effect'] || 'fade-up',
1178				'scrollRevealMaskDirection': widgetData['jet_tricks_widget_scroll_reveal_mask_direction'] || 'up',
1179				'scrollRevealDuration': widgetData['jet_tricks_widget_scroll_reveal_duration'] || { 'size': 0.6, 'unit': 's' },
1180				'scrollRevealDelay': widgetData['jet_tricks_widget_scroll_reveal_delay'] || { 'size': 0, 'unit': 's' },
1181				'scrollRevealOnce': widgetData['jet_tricks_widget_scroll_reveal_once'] || 'true',
1182				'scrollRevealRootMargin': widgetData['jet_tricks_widget_scroll_reveal_root_margin'] !== undefined && widgetData['jet_tricks_widget_scroll_reveal_root_margin'] !== null ? parseInt( widgetData['jet_tricks_widget_scroll_reveal_root_margin'], 10 ) : 0,
1183				'scrollRevealOn': widgetData['jet_tricks_widget_scroll_reveal_on'] || [ 'desktop', 'tablet', 'mobile' ]
1184			}
1185		}
1186	}
1187
1188	/**
1189	 * Jet jetViewMore Class
1190	 *
1191	 * @return {void}
1192	 */
1193	window.jetViewMore = function( $selector, settings ) {
1194		var self            = this,
1195			$window         = $( window ),
1196			$button         = $( '.jet-view-more__button', $selector ),
1197			defaultSettings = {
1198				sections: {},
1199				effect: 'move-up',
1200				showall: false
1201			},
1202			settings        = $.extend( {}, defaultSettings, settings ),
1203			sections        = settings['sections'],
1204			sectionsData    = {},
1205			editMode        = Boolean( elementor && elementor.isEditMode() ),
1206			readLess      = settings['read_less'] || false,
1207			readMoreLabel   = settings['read_more_label'],
1208			readLessLabel   = settings['read_less_label'],
1209			readMoreIconHtml = settings['read_more_icon_html'] || '',
1210			readLessIconHtml = settings['read_less_icon_html'] || '',
1211			hideAll         = settings['hide_all'] || false,
1212			isOpened        = false;
1213
1214		/**
1215		 * Init
1216		 */
1217		self.init = function() {
1218			self.setSectionsData();
1219
1220			if ( editMode ) {
1221				return false;
1222			}			
1223
1224			function hideSection($section) {
1225				// Apply hide effect if available
1226				if (settings['hide_effect'] && settings['hide_effect'] !== 'none') {
1227					$section.addClass('view-more-hiding');
1228					$section.addClass('jet-tricks-' + settings['hide_effect'] + '-hide-effect');
1229					
1230					// Remove classes after animation completes
1231					(function($currentSection) {
1232						$currentSection.on('animationend', function animationEndHandler() {
1233							$currentSection.off('animationend', animationEndHandler);
1234							$currentSection.removeClass('view-more-hiding');
1235							$currentSection.removeClass('jet-tricks-' + settings['hide_effect'] + '-hide-effect');
1236							$currentSection.css('height', '');
1237							$currentSection.removeClass('view-more-visible');
1238							$currentSection.removeClass('jet-tricks-' + settings['effect'] + '-effect');
1239						});
1240					})($section);
1241				} else {
1242					$section.css('height', '');
1243					$section.removeClass('view-more-visible');
1244					$section.removeClass('jet-tricks-' + settings['effect'] + '-effect');
1245				}
1246			}
1247
1248			function showAllSections() {
1249				for ( var section in sectionsData ) {
1250					var $section = sectionsData[ section ]['selector'];
1251					sectionsData[ section ]['visible'] = true;
1252					$section.addClass( 'view-more-visible' );
1253					$section.addClass( 'jet-tricks-' + settings['effect'] + '-effect' );
1254				}
1255			}
1256
1257			function hideAllSections() {
1258				for ( var section in sectionsData ) {
1259					var $section = sectionsData[ section ]['selector'];
1260					sectionsData[ section ]['visible'] = false;
1261					hideSection($section);
1262				}
1263			}
1264
1265			function showNextSection() {
1266				for ( var section in sectionsData ) {
1267					var $section = sectionsData[ section ]['selector'];
1268					if ( !sectionsData[ section ]['visible'] ) {
1269						sectionsData[ section ]['visible'] = true;
1270						$section.addClass( 'view-more-visible' );
1271						$section.addClass( 'jet-tricks-' + settings['effect'] + '-effect' );
1272						break;
1273					}
1274				}
1275			}
1276
1277			function hideNextSection() {
1278				var sectionKeys = Object.keys(sectionsData).reverse();
1279				for (var i = 0; i < sectionKeys.length; i++) {
1280					var sectionKey = sectionKeys[i];
1281					var $section = sectionsData[sectionKey]['selector'];
1282					if (sectionsData[sectionKey]['visible']) {
1283						sectionsData[sectionKey]['visible'] = false;
1284						hideSection($section);
1285						break;
1286					}
1287				}
1288			}
1289
1290			$button.on('click', function() {
1291				if (readLess) {
1292					if (!isOpened) {
1293						if (!settings.showall) {
1294							showNextSection();
1295							var allVisible = true;
1296							for (var section in sectionsData) {
1297								if (!sectionsData[section]['visible']) {
1298									allVisible = false;
1299									break;
1300								}
1301							}
1302							if (allVisible) {
1303								$button.find('.jet-view-more__label').text(readLessLabel);
1304								var lessIconHtml = readLessIconHtml;
1305								if ( lessIconHtml ) {
1306									$button.find('.jet-view-more__icon').html( lessIconHtml );
1307								}
1308								$button.addClass('jet-view-more__button--read-less');
1309								isOpened = true;
1310							}
1311						} else {
1312						showAllSections();
1313						$button.find('.jet-view-more__label').text(readLessLabel);
1314							var lessIconHtml2 = readLessIconHtml;
1315							if ( lessIconHtml2 ) {
1316								$button.find('.jet-view-more__icon').html( lessIconHtml2 );
1317							}
1318							$button.addClass('jet-view-more__button--read-less');
1319							isOpened = true;
1320						}
1321					} else {
1322						if (hideAll) {
1323						hideAllSections();
1324						$button.find('.jet-view-more__label').text(readMoreLabel);
1325							var moreIconHtml = readMoreIconHtml;
1326							if ( moreIconHtml ) {
1327								$button.find('.jet-view-more__icon').html( moreIconHtml );
1328							}
1329							$button.removeClass('jet-view-more__button--read-less');
1330							isOpened = false;
1331						} else {
1332							hideNextSection();
1333							var allHidden = true;
1334							for (var section in sectionsData) {
1335								if (sectionsData[section]['visible']) {
1336									allHidden = false;
1337									break;
1338								}
1339							}
1340							if (allHidden) {
1341								$button.find('.jet-view-more__label').text(readMoreLabel);
1342								var moreIconHtml2 = readMoreIconHtml;
1343								if ( moreIconHtml2 ) {
1344									$button.find('.jet-view-more__icon').html( moreIconHtml2 );
1345								}
1346								$button.removeClass('jet-view-more__button--read-less');
1347								isOpened = false;
1348							}
1349						}
1350					}
1351				} else {
1352					if (!settings.showall) {
1353						showNextSection();
1354					} else {
1355						showAllSections();
1356					}
1357					var allVisible = true;
1358					for (var section in sectionsData) {
1359						if (!sectionsData[section]['visible']) {
1360							allVisible = false;
1361							break;
1362						}
1363					}
1364					if (allVisible) {
1365						$button.css({ 'display': 'none' });
1366					}
1367				}
1368			});
1369
1370			$button.keydown(function(e) {
1371				var $which = e.which || e.keyCode;
1372				if ($which == 13 || $which == 32) {
1373					e.preventDefault();
1374					if (readLess) {
1375						$button.trigger('click');
1376					} else {
1377						if (!settings.showall) {
1378							showNextSection();
1379						} else {
1380							showAllSections();
1381						}
1382						var allVisible = true;
1383						for (var section in sectionsData) {
1384							if (!sectionsData[section]['visible']) {
1385								allVisible = false;
1386								break;
1387							}
1388						}
1389						if (allVisible) {
1390							$button.css({ 'display': 'none' });
1391						}
1392					}
1393				}
1394			});
1395		};
1396
1397		self.setSectionsData = function() {
1398
1399			for ( var section in sections ) {
1400				var $selector = $( '#' + sections[ section ] );
1401
1402				if ( ! editMode ) {
1403					$selector.addClass( 'jet-view-more-section' );
1404				} else {
1405					$selector.addClass( 'jet-view-more-section-edit-mode' );
1406				}
1407
1408				sectionsData[ section ] = {
1409					'section_id': sections[ section ],
1410					'selector': $selector,
1411					'visible': false,
1412				}
1413			}
1414		};
1415	};
1416
1417	/**
1418	 * [jetWidgetParallax description]
1419	 * @param  {[type]} $scope [description]
1420	 * @return {[type]}        [description]
1421	 */
1422	window.jetWidgetParallax = function( $scope ) {
1423		var self         = this,
1424			$target      = $scope,
1425			$section     = $scope.closest( '.elementor-top-section' ),
1426			widgetId     = $scope.data('id'),
1427			settings     = {},
1428			editMode     = Boolean( elementor && elementor.isEditMode() ),
1429			$window      = $( window ),
1430			isSafari     = !!navigator.userAgent.match(/Version\/[\d\.]+.*Safari/),
1431			platform     = navigator.platform,
1432			safariClass  = isSafari ? 'is-safari' : '',
1433			macClass    = 'MacIntel' == platform ? ' is-mac' : '';
1434
1435		/**
1436		 * Init
1437		 */
1438		self.init = function() {
1439
1440			$scope.addClass( macClass );
1441
1442			if ( ! editMode ) {
1443				settings = $scope.data( 'jet-tricks-settings' );
1444			} else {
1445				settings = JetTricksTools.widgetEditorSettings( widgetId );
1446			}
1447
1448			if ( ! settings ) {
1449				return false;
1450			}
1451
1452			if ( 'undefined' === typeof settings ) {
1453				return false;
1454			}
1455
1456			if ( 'false' === settings['parallax'] || 'undefined' === typeof settings['parallax'] ) {
1457				return false;
1458			}
1459
1460			$window.on( 'scroll.jetWidgetParallax resize.jetWidgetParallax', self.scrollHandler ).trigger( 'resize.jetWidgetParallax' );
1461		};
1462
1463		self.scrollHandler = function( event ) {
1464			var speed             = +settings['speed']['size'] * 0.01,
1465				invert            = 'true' == settings['invert'] ? -1 : 1,
1466				winHeight         = $window.height(),
1467				winScrollTop      = $window.scrollTop(),
1468				offsetTop         = $scope.offset().top,
1469				thisHeight        = $scope.outerHeight(),
1470				sectionHeight     = $section.length ? $section.outerHeight() : 0,
1471				positionDelta     = winScrollTop - offsetTop + ( winHeight / 2 ),
1472				abs               = positionDelta > 0 ? 1 : -1,
1473				posY              = abs * Math.pow( Math.abs( positionDelta ), 0.85 ),
1474				availableDevices  = settings['stickyOn'] || [],
1475				currentDeviceMode = JetTricks.getDeviceMode();
1476
1477			posY = invert * Math.ceil( speed * posY );
1478
1479			if ( ! availableDevices.length || -1 !== availableDevices.indexOf( currentDeviceMode ) ) {
1480				$target.css( {
1481					'transform': 'translateY(' + posY + 'px)'
1482				} );
1483			} else {
1484				$target.css( {
1485					'transform': 'translateY(0)'
1486				} );
1487			}
1488		};
1489	};
1490
1491	/**
1492	 * Scroll reveal on viewport entry (Elementor widgets).
1493	 *
1494	 * @param {jQuery} $scope Widget root.
1495	 */
1496	window.jetWidgetScrollReveal = function( $scope ) {
1497		var self     = this,
1498			settings = {},
1499			io         = null,
1500			el         = $scope[ 0 ];
1501
1502		self.init = function() {
1503
1504			if ( ! el || $scope.data( 'jetScrollRevealInit' ) ) {
1505				return false;
1506			}
1507
1508			settings = $scope.data( 'jet-tricks-settings' );
1509
1510			if ( ! settings || typeof settings !== 'object' ) {
1511				return false;
1512			}
1513
1514			if ( settings.scrollReveal !== 'true' && settings.scrollReveal !== true ) {
1515				return false;
1516			}
1517
1518			var availableDevices  = settings.scrollRevealOn || [],
1519				currentDeviceMode = JetTricks.getDeviceMode(),
1520				deviceOk          = ! availableDevices.length || -1 !== availableDevices.indexOf( currentDeviceMode );
1521
1522			if ( ! deviceOk ) {
1523				$scope
1524					.addClass( 'jet-scroll-reveal--instant-exit jet-scroll-reveal--in-view' )
1525					.removeClass( 'jet-scroll-reveal--pending' );
1526				return false;
1527			}
1528
1529			if ( window.matchMedia && window.matchMedia( '(prefers-reduced-motion: reduce)' ).matches ) {
1530				$scope
1531					.addClass( 'jet-scroll-reveal--instant-exit jet-scroll-reveal--in-view' )
1532					.removeClass( 'jet-scroll-reveal--pending' );
1533				return false;
1534			}
1535
1536			if ( typeof IntersectionObserver === 'undefined' ) {
1537				$scope
1538					.addClass( 'jet-scroll-reveal--instant-exit jet-scroll-reveal--in-view' )
1539					.removeClass( 'jet-scroll-reveal--pending' );
1540				return false;
1541			}
1542
1543			$scope.data( 'jetScrollRevealInit', true );
1544
1545			var dur = settings.scrollRevealDuration && typeof settings.scrollRevealDuration.size !== 'undefined'
1546				? parseFloat( settings.scrollRevealDuration.size, 10 )
1547				: 0.6;
1548			var del = settings.scrollRevealDelay && typeof settings.scrollRevealDelay.size !== 'undefined'
1549				? parseFloat( settings.scrollRevealDelay.size, 10 )
1550				: 0;
1551			var rm  = typeof settings.scrollRevealRootMargin === 'number'
1552				? settings.scrollRevealRootMargin
1553				: parseInt( settings.scrollRevealRootMargin || 0, 10 );
1554			var once = settings.scrollRevealOnce === 'true' || settings.scrollRevealOnce === true;
1555
1556			el.style.setProperty( '--jet-sr-duration', dur + 's' );
1557			el.style.setProperty( '--jet-sr-delay', del + 's' );
1558
1559			var rootMargin = '0px 0px ' + rm + 'px 0px';
1560
1561			io = new IntersectionObserver( function( entries ) {
1562				entries.forEach( function( entry ) {
1563					if ( entry.isIntersecting ) {
1564						entry.target.classList.remove( 'jet-scroll-reveal--instant-exit' );
1565						entry.target.classList.add( 'jet-scroll-reveal--in-view' );
1566						entry.target.classList.remove( 'jet-scroll-reveal--pending' );
1567						if ( once && io ) {
1568							io.unobserve( entry.target );
1569						}
1570					} else if ( ! once ) {
1571						entry.target.classList.add( 'jet-scroll-reveal--instant-exit' );
1572						entry.target.classList.remove( 'jet-scroll-reveal--in-view' );
1573						entry.target.classList.add( 'jet-scroll-reveal--pending' );
1574					}
1575				} );
1576			}, {
1577				root: null,
1578				rootMargin: rootMargin,
1579				threshold: 0
1580			} );
1581
1582			io.observe( el );
1583		};
1584	};
1585
1586	/**
1587	 * [jetWidgetSatellite description]
1588	 * @param  {[type]} $scope [description]
1589	 * @return {[type]}        [description]
1590	 */
1591	window.jetWidgetSatellite = function( $scope ) {
1592		var self     = this,
1593			widgetId = $scope.data('id'),
1594			settings = {},
1595			editMode = Boolean( elementor && elementor.isEditMode() );
1596
1597		self.getClampedNumber = function( value, fallback, min, max ) {
1598			var parsed = parseFloat( value );
1599
1600			if ( isNaN( parsed ) ) {
1601				parsed = fallback;
1602			}
1603
1604			if ( parsed < min ) {
1605				parsed = min;
1606			}
1607
1608			if ( parsed > max ) {
1609				parsed = max;
1610			}
1611
1612			return parsed;
1613		};
1614
1615		self.getSatelliteLayoutStyleAttr = function() {
1616			var x = self.getClampedNumber( settings['satelliteOffsetX'], 0, -500, 500 );
1617			var y = self.getClampedNumber( settings['satelliteOffsetY'], 0, -500, 500 );
1618			var rotate = self.getClampedNumber( settings['satelliteRotate'], 0, -180, 180 );
1619			var zIndex = self.getClampedNumber( settings['satelliteZIndex'], 2, -10, 999 );
1620			var styleParts = [
1621				'--jet-satellite-offset-x:' + x + 'px',
1622				'--jet-satellite-offset-y:' + y + 'px',
1623				'--jet-satellite-rotate:' + rotate + 'deg',
1624				'--jet-satellite-z:' + zIndex
1625			];
1626
1627			return ' style="' + styleParts.join( ';' ) + '"';
1628		};
1629
1630		/**
1631		 * Init
1632		 */
1633		self.init = function() {
1634
1635			if ( ! editMode ) {
1636				settings = $scope.data( 'jet-tricks-settings' );
1637			} else {
1638				settings = JetTricksTools.widgetEditorSettings( widgetId );
1639			}
1640
1641			if ( ! settings || typeof settings !== 'object' ) {
1642				return false;
1643			}
1644
1645			if ( 'false' === settings['satellite'] || 'undefined' === typeof settings['satellite'] ) {
1646				return false;
1647			}
1648
1649			$scope.addClass( 'jet-satellite-widget' );
1650
1651			$( '.jet-tricks-satellite', $scope ).addClass( 'jet-tricks-satellite--' + settings['satellitePosition'] );
1652
1653			//satellite display in edit mode
1654			if ( editMode && $scope.find( '.jet-tricks-satellite' ).length === 0 ) {
1655				var html = '';
1656				var layoutStyle = self.getSatelliteLayoutStyleAttr();
1657				var pos = settings['satellitePosition'] || 'top-center';
1658				var rootTag = ( $scope[0] && $scope[0].tagName ) ? $scope[0].tagName.toLowerCase() : '';
1659				var wrapperTag = [ 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ].indexOf( rootTag ) !== -1 ? 'span' : 'div';
1660				var instanceTag = 'span' === wrapperTag ? 'span' : 'div';
1661
1662				var link = settings['satelliteLink'] || {};
1663				var linkStart = '', linkEnd = '';
1664				if ( link.url ) {
1665					linkStart = '<a class="jet-tricks-satellite__link">';
1666					linkEnd = '</a>';
1667				}
1668
1669				if ( settings['satelliteType'] === 'text' && settings['satelliteText'] ) {
1670					html = '<' + wrapperTag + ' class="jet-tricks-satellite jet-tricks-satellite--' + pos + '"' + layoutStyle + '><' + wrapperTag + ' class="jet-tricks-satellite__inner"><' + wrapperTag + ' class="jet-tricks-satellite__text">' + linkStart + '<span>' + settings['satelliteText'] + '</span>' + linkEnd + '</' + wrapperTag + '></' + wrapperTag + '></' + wrapperTag + '>';
1671				} else if ( settings['satelliteType'] === 'icon' && settings['satelliteIcon'] && settings['satelliteIcon'].value ) {
1672					html = '<' + wrapperTag + ' class="jet-tricks-satellite jet-tricks-satellite--' + pos + '"' + layoutStyle + '><' + wrapperTag + ' class="jet-tricks-satellite__inner"><' + wrapperTag + ' class="jet-tricks-satellite__icon">' + linkStart + '<' + instanceTag + ' class="jet-tricks-satellite__icon-instance jet-tricks-icon"><i class="' + settings['satelliteIcon'].value + '"></i></' + instanceTag + '>' + linkEnd + '</' + wrapperTag + '></' + wrapperTag + '></' + wrapperTag + '>';
1673				} else if ( settings['satelliteType'] === 'image' && settings['satelliteImage'] && settings['satelliteImage'].url ) {
1674					html = '<' + wrapperTag + ' class="jet-tricks-satellite jet-tricks-satellite--' + pos + '"' + layoutStyle + '><' + wrapperTag + ' class="jet-tricks-satellite__inner"><' + wrapperTag + ' class="jet-tricks-satellite__image">' + linkStart + '<img class="jet-tricks-satellite__image-instance" src="' + settings['satelliteImage'].url + '" alt="">' + linkEnd + '</' + wrapperTag + '></' + wrapperTag + '></' + wrapperTag + '>';
1675				}
1676
1677				if ( html ) {
1678					$scope.prepend(html);
1679				}
1680			}
1681		};
1682	};
1683
1684	/**
1685	 * [jetWidgetTooltip description]
1686	 * @param  {[type]} $scope [description]
1687	 * @return {[type]}        [description]
1688	 */
1689	window.jetWidgetTooltip = function( $scope ) {
1690		var self            = this,
1691			widgetId        = $scope.data('id'),
1692			widgetSelector  = $scope[0],
1693			tooltipSelector = widgetSelector,
1694			settings        = {},
1695			editMode        = Boolean( elementor && elementor.isEditMode() ),
1696			$window         = $( window ),
1697			resizeTimer;
1698
1699		self.removeTooltipContent = function() {
1700			$scope.find( '> .jet-tooltip-widget__content' ).remove();
1701		};
1702
1703		self.destroyTooltipInstance = function() {
1704			if ( tooltipSelector && tooltipSelector._tippy ) {
1705				tooltipSelector._tippy.destroy();
1706			}
1707			if ( widgetSelector && widgetSelector._tippy ) {
1708				widgetSelector._tippy.destroy();
1709			}
1710		};
1711
1712		self.isTooltipDeviceAllowed = function() {
1713			var devices = settings['tooltipDevices'];
1714			if ( typeof devices === 'undefined' || devices === null ) {
1715				return true;
1716			}
1717			if ( ! devices.length ) {
1718				return true;
1719			}
1720			return -1 !== devices.indexOf( JetTricks.getDeviceMode() );
1721		};
1722
1723		self.getTooltipDelayMs = function() {
1724			var d = settings['delay'];
1725			if ( d && typeof d === 'object' && d.hasOwnProperty( 'size' ) ) {
1726				return d.size ? d.size : 0;
1727			}
1728			if ( typeof d === 'number' ) {
1729				return d;
1730			}
1731			return 0;
1732		};
1733
1734		self.mountTippy = function() {
1735			if ( ! tooltipSelector ) {
1736				return;
1737			}
1738
1739			var contentEl = $scope.find( '.jet-tooltip-widget__content' )[0];
1740			if ( ! contentEl ) {
1741				return;
1742			}
1743
1744			var appendToBody = editMode || ( settings['appendTo'] === 'body' );
1745
1746			tippy(
1747				[ tooltipSelector ],
1748				{
1749					content: contentEl.innerHTML,
1750					allowHTML: true,
1751					appendTo: appendToBody ? document.body : widgetSelector,
1752					arrow: settings['tooltipArrow'] ? true : false,
1753					placement: settings['tooltipPlacement'],
1754					offset: [ settings['xOffset'], settings['yOffset'] ],
1755					animation: settings['tooltipAnimation'],
1756					trigger: settings['tooltipTrigger'],
1757					interactive: settings['followCursor'] === 'false' || settings['followCursor'] === '
1757initial',
1758					zIndex: settings['zIndex'],
1759					maxWidth: 'none',
1760					delay: self.getTooltipDelayMs(),
1761					followCursor: settings['followCursor'] === 'false' ? false : (settings['followCursor'] === 'true' ? true : settings['followCursor']),
1762					onCreate: function (instance) {
1763						if ( appendToBody ) {
1764							var tippyId = editMode ? ( tooltipSelector.getAttribute('data-id') || widgetId ) : widgetId;
1765							if ( tippyId ) {
1766								instance.popper.classList.add( 'tippy-' + tippyId );
1767							}
1768							if ( settings['wrapperClass'] ) {
1769								instance.popper.classList.add( settings['wrapperClass'] );
1770							}
1771						}
1772					},
1773					onShow: function (instance) {
1774						// JetFormBuilder Formless Actions Endpoints compatibility
1775						var addButtonListeners = window.crocoblock && window.crocoblock.frontComponents && window.crocoblock.frontComponents.addButtonListeners;
1776						if ( addButtonListeners && instance.popper ) {
1777							var buttons = instance.popper.querySelectorAll( '[data-jfb-submit-endpoint]' );
1778							buttons.forEach( function (el) { addButtonListeners( el ); } );
1779						}
1780					}
1781				}
1782			);
1783
1784			if ( editMode && tooltipSelector && tooltipSelector._tippy ) {
1785				tooltipSelector._tippy.show();
1786			}
1787		};
1788
1789		self.refreshTooltipForDevice = function() {
1790			self.destroyTooltipInstance();
1791
1792			if ( ! self.isTooltipDeviceAllowed() ) {
1793				return;
1794			}
1795
1796			self.mountTippy();
1797		};
1798
1799		/**
1800		 * Init
1801		 */
1802		self.init = function() {
1803
1804			if ( ! editMode ) {
1805				settings = $scope.data( 'jet-tricks-settings' );
1806			} else {
1807				settings = JetTricksTools.widgetEditorSettings( widgetId );
1808			}
1809
1810			if ( ! settings ) {
1811				return false;
1812			}
1813
1814			if ( 'undefined' === typeof settings ) {
1815				return false;
1816			}
1817
1818			if ( 'false' === settings['tooltip'] || 'undefined' === typeof settings['tooltip'] || '' === settings['tooltipDescription'] ) {
1819				self.destroyTooltipInstance();
1820				self.removeTooltipContent();
1821				return false;
1822			}
1823
1824			$scope.addClass( 'jet-tooltip-widget' );
1825
1826			tooltipSelector = widgetSelector;
1827			if ( settings['customSelector'] ) {
1828				var customEl = $( '.' + settings['customSelector'], $scope )[0];
1829				if ( customEl ) {
1830					tooltipSelector = customEl;
1831				}
1832			}
1833
1834			if ( editMode && ! $( '#jet-tricks-tooltip-content-' + widgetId )[0] ) {
1835				var rootTag = ( $scope[0] && $scope[0].tagName ) ? $scope[0].tagName.toLowerCase() : '';
1836				var wrapperTag = [ 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ].indexOf( rootTag ) !== -1 ? 'span' : 'div';
1837				var template = $( '<' + wrapperTag + '>', {
1838					id: 'jet-tricks-tooltip-content-' + widgetId,
1839					class: 'jet-tooltip-widget__content'
1840				} );
1841
1842				template.html( settings['tooltipDescription'] );
1843				$scope.append( template );
1844			}
1845
1846			$window.off( 'resize.jetTooltip' + widgetId );
1847			$window.on( 'resize.jetTooltip' + widgetId, function() {
1848				clearTimeout( resizeTimer );
1849				resizeTimer = setTimeout( function() {
1850					self.refreshTooltipForDevice();
1851				}, 200 );
1852			} );
1853
1854			if ( editMode && document.body ) {
1855				var editorBindingsCleanupKey = 'jetTooltipEditorBindingsCleanup';
1856				var prevEditorCleanup = $scope.data( editorBindingsCleanupKey );
1857				if ( typeof prevEditorCleanup === 'function' ) {
1858					prevEditorCleanup();
1859				}
1860				$scope.removeData( editorBindingsCleanupKey );
1861
1862				var onEditorDeviceModeChange = function() {
1863					clearTimeout( resizeTimer );
1864					resizeTimer = setTimeout( function() {
1865						self.refreshTooltipForDevice();
1866					}, 50 );
1867				};
1868				window.addEventListener( 'elementor/device-mode/change', onEditorDeviceModeChange );
1869				var deviceModeObserver = new MutationObserver( function( mutations ) {
1870					var i;
1871					for ( i = 0; i < mutations.length; i++ ) {
1872						if ( mutations[ i ].attributeName === 'data-elementor-device-mode' ) {
1873							onEditorDeviceModeChange();
1874							break;
1875						}
1876					}
1877				} );
1878				deviceModeObserver.observe( document.body, {
1879					attributes: true,
1880					attributeFilter: [ 'data-elementor-device-mode' ]
1881				} );
1882
1883				$scope.data( editorBindingsCleanupKey, function jetTooltipEditorBindingsCleanup() {
1884					window.removeEventListener( 'elementor/device-mode/change', onEditorDeviceModeChange );
1885					deviceModeObserver.disconnect();
1886				} );
1887			}
1888
1889			self.refreshTooltipForDevice();
1890
1891		};
1892	};
1893
1894	JetTricks.initBlocksExtensions = function() {
1895		var isBlockEditorContext = !! (
1896			document.body && (
1897				document.body.classList.contains( 'block-editor-page' ) ||
1898				document.body.classList.contains( 'block-editor-iframe__body' ) ||
1899				document.body.classList.contains( 'editor-styles-wrapper' )
1900			)
1901		) || !! document.querySelector( '.block-editor-block-list__layout, .edit-post-visual-editor' );
1902
1903		$( '[data-jet-tricks-settings]' ).each( function() {
1904			var $scope   = $( this ),
1905				settings = $scope.data( 'jet-tricks-settings' );
1906
1907			if ( ! settings ) {
1908				return;
1909			}
1910
1911			if ( settings['parallax'] === 'true' ) {
1912				new jetWidgetParallax( $scope ).init();
1913			}
1914
1915			if ( settings['satellite'] === 'true' && ! isBlockEditorContext ) {
1916				new jetWidgetSatellite( $scope ).init();
1917			}
1918
1919			if ( settings['tooltip'] === 'true' && typeof tippy !== 'undefined' && ! isBlockEditorContext ) {
1920				new jetWidgetTooltip( $scope ).init();
1921			}
1922
1923			if ( settings['scrollReveal'] === 'true' || settings['scrollReveal'] === true ) {
1924				new jetWidgetScrollReveal( $scope ).init();
1925			}
1926		} );
1927
1928		JetTricks.initBlocksParticles();
1929	};
1930
1931	JetTricks.initBlocksParticles = function() {
1932		$( '.jet-tricks-particles-section[data-jet-tricks-particles="true"]' ).each( function() {
1933			var $scope  = $( this ),
1934				blockId = $scope.attr( 'data-jet-tricks-particles-id' ),
1935				jsonStr = $scope.attr( 'data-jet-tricks-particles-json' );
1936
1937			if ( ! blockId || ! jsonStr ) {
1938				return;
1939			}
1940
1941			try {
1942				var particlesJson = JSON.parse( jsonStr );
1943			} catch ( e ) {
1944				return;
1945			}
1946
1947			JetTricks.loadParticles( $scope, 'jet-tricks-particles-instance-' + blockId, particlesJson );
1948		} );
1949	};
1950
1951	JetTricks.destroyBlockStickyColumn = function( $target ) {
1952		$target.css( {
1953			position: '',
1954			top: '',
1955			bottom: '',
1956			alignSelf: '',
1957			zIndex: '',
1958		} );
1959
1960	};
1961
1962	JetTricks.getBlockStickyAlign = function( settings ) {
1963		var align = settings && settings.stickyAlign ? String( settings.stickyAlign ) : 'top';
1964
1965		if ( -1 === [ 'top', 'center', 'bottom' ].indexOf( align ) ) {
1966			align = 'top';
1967		}
1968
1969		return align;
1970	};
1971
1972	JetTricks.applyBlockStickyColumn = function( $target, settings, topSpacing, bottomSpacing ) {
1973		var align = JetTricks.getBlockStickyAlign( settings );
1974		var alignSelf = 'flex-start';
1975
1976		if ( 'bottom' === align ) {
1977			alignSelf = 'flex-end';
1978		} else if ( 'center' === align ) {
1979			alignSelf = 'center';
1980		}
1981
1982		$target.css( {
1983			position: 'sticky',
1984			top: topSpacing,
1985			bottom: bottomSpacing,
1986			alignSelf: alignSelf,
1987			zIndex: settings.zIndex !== undefined && settings.zIndex !== null && settings.zIndex !== '' ? settings.zIndex : '',
1988		} );
1989	};
1990
1991	JetTricks.initBlockStickyColumn = function( $target ) {
1992		var raw = $target.attr( 'data-jet-settings' );
1993		var settings = raw;
1994		if ( typeof settings === 'string' ) {
1995			try {
1996				settings = JSON.parse( settings );
1997			} catch ( e ) {
1998				return;
1999			}
2000		}
2001		if ( ! settings || typeof settings !== 'object' || ! settings.stickyOn || ! settings.stickyOn.length ) {
2002			return;
2003		}
2004
2005		var topS = parseInt( settings.topSpacing, 10 );
2006		if ( settings.topSpacing === undefined || settings.topSpacing === null || settings.topSpacing === '' || window.isNaN( topS ) ) {
2007			topS = 50;
2008		}
2009		var bottomS = parseInt( settings.bottomSpacing, 10 );
2010		if ( settings.bottomSpacing === undefined || settings.bottomSpacing === null || settings.bottomSpacing === '' || window.isNaN( bottomS ) ) {
2011			bottomS = 50;
2012		}
2013
2014		var allowed = -1 !== settings.stickyOn.indexOf( JetTricks.getDeviceMode() );
2015
2016		if ( ! allowed ) {
2017			JetTricks.destroyBlockStickyColumn( $target );
2018			return;
2019		}
2020
2021		var $row = $target.closest( '.wp-block-columns' );
2022		if ( ! $row.length ) {
2023			JetTricks.destroyBlockStickyColumn( $target );
2024			return;
2025		}
2026
2027		JetTricks.applyBlockStickyColumn( $target, settings, topS, bottomS );
2028	};
2029
2030	JetTricks.initBlocksStickyColumns = function() {
2031		$( '.wp-block-column.jet-sticky-column' ).each( function() {
2032			JetTricks.initBlockStickyColumn( $( this ) );
2033		} );
2034
2035		if ( ! JetTricks._blockStickyResizeBound ) {
2036			JetTricks._blockStickyResizeBound = true;
2037			$( window ).on(
2038				'resize.jetTricksBlockSticky orientationchange.jetTricksBlockSticky',
2039				JetTricksTools.debounce( 150, function() {
2040					$( '.wp-block-column.jet-sticky-column' ).each( function() {
2041						JetTricks.initBlockStickyColumn( $( this ) );
2042					} );
2043				} )
2044			);
2045		}
2046	};
2047
2048	window.JetTricks = JetTricks;
2049
2050	if ( window.JetPlugins ) {
2051		JetTricks.initBlocks();
2052		$( function() { JetPlugins.init() } );
2053	}
2054
2055	$( function() {
2056		JetTricks.initBlocksExtensions();
2057		JetTricks.initBlocksStickyColumns();
2058	} );
2059
2060}( jQuery, window.elementorFrontend ) );

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.