PageSourceSearch

https://motorhomespuravida.com/wp-content/plugins/jet-elements/assets/js/jet-elements.js?ver=2.6.8

js motorhomespuravida.com collected 2026-10-08 23:02:29 UTC 146,723 bytes, 4,836 lines download raw bytes

1( function( $, elementor ) {
2
3	"use strict";
4
5	var JetElements = {
6
7		init: function() {
8
9			var widgets = {
10				'jet-carousel.default' : JetElements.widgetCarousel,
11				'jet-circle-progress.default' : JetElements.widgetProgress,
12				'jet-map.default' : JetElements.widgetMap,
13				'jet-countdown-timer.default' : JetElements.widgetCountdown,
14				'jet-posts.default' : JetElements.widgetPosts,
15				'jet-animated-text.default' : JetElements.widgetAnimatedText,
16				'jet-animated-box.default' : JetElements.widgetAnimatedBox,
17				'jet-images-layout.default' : JetElements.widgetImagesLayout,
18				'jet-slider.default' : JetElements.widgetSlider,
19				'jet-testimonials.default' : JetElements.widgetTestimonials,
20				'jet-image-comparison.default' : JetElements.widgetImageComparison,
21				'jet-instagram-gallery.default' : JetElements.widgetInstagramGallery,
22				'jet-scroll-navigation.default' : JetElements.widgetScrollNavigation,
23				'jet-subscribe-form.default' : JetElements.widgetSubscribeForm,
24				'jet-progress-bar.default' : JetElements.widgetProgressBar,
25				'jet-portfolio.default' : JetElements.widgetPortfolio,
26				'jet-timeline.default': JetElements.widgetTimeLine,
27				'jet-table.default': JetElements.widgetTable,
28				'jet-dropbar.default': JetElements.widgetDropbar,
29				'jet-video.default': JetElements.widgetVideo,
30				'jet-audio.default': JetElements.widgetAudio,
31				'jet-horizontal-timeline.default': JetElements.widgetHorizontalTimeline,
32				'mp-timetable.default': JetElements.widgetTimeTable,
33				'jet-pie-chart.default': JetElements.widgetPieChart,
34				'jet-bar-chart.default': JetElements.widgetBarChart,
35				'jet-line-chart.default': JetElements.widgetLineChart,
36				'jet-lottie.default': JetElements.widgetLottie,
37				'jet-pricing-table.default': JetElements.widgetPricingTable
38			};
39
40			$.each( widgets, function( widget, callback ) {
41				elementor.hooks.addAction( 'frontend/element_ready/' + widget, callback );
42			});
43
44			elementor.hooks.addAction( 'frontend/element_ready/section', JetElements.elementorSection );
45		},
46
47		initElementsHandlers: function( $selector ) {
48			$selector.find( '[data-element_type]' ).each( function() {
49				var $this       = $( this ),
50					elementType = $this.data( 'element_type' );
51
52				if ( !elementType ) {
53					return;
54				}
55
56				if ( 'widget' === elementType ) {
57					elementType = $this.data( 'widget_type' );
58					window.elementorFrontend.hooks.doAction( 'frontend/element_ready/widget', $this, $ );
59				}
60
61				window.elementorFrontend.hooks.doAction( 'frontend/element_ready/global', $this, $ );
62				window.elementorFrontend.hooks.doAction( 'frontend/element_ready/' + elementType, $this, $ );
63
64			} );
65		},
66
67		widgetCountdown: function( $scope ) {
68
69			var timeInterval,
70				$countdown = $scope.find( '.jet-countdown-timer' ),
71				type = $countdown.data( 'type' ),
72				endTime = null,
73				dueDate = $countdown.data( 'due-date' ),
74				startDate = $countdown.data( 'start-date' ),
75				actions = $countdown.data( 'expire-actions' ),
76				evergreenInterval = $countdown.data( 'evergreen-interval' ),
77				restartInterval = $countdown.data( 'restart-interval' ),
78				elements = {
79					days: $countdown.find( '[data-value="days"]' ),
80					hours: $countdown.find( '[data-value="hours"]' ),
81					minutes: $countdown.find( '[data-value="minutes"]' ),
82					seconds: $countdown.find( '[data-value="seconds"]' )
83				};
84
85			var initClock = function() {
86
87				switch( type ) {
88					case 'due_date':
89						endTime = new Date( dueDate * 1000 );
90						break;
91
92					case 'evergreen':
93						if ( evergreenInterval > 0 ) {
94							endTime = getEvergreenDate();
95						}
96						break;
97
98					case 'endless':
99						var currentTime = new Date(),
100							startTime = new Date( startDate * 1000 );
101
102						if ( currentTime > startTime ) {
103							endTime = new Date( (startDate + restartInterval) * 1000 );
104						}
105
106						if ( endTime && ( currentTime > endTime ) ) {
107							endTime = endTime.setSeconds( endTime.getSeconds() + (Math.floor( (currentTime - endTime) / (restartInterval * 1000) ) + 1) * restartInterval );
108						}
109
110						break;
111				}
112
113				updateClock();
114				timeInterval = setInterval( updateClock, 1000 );
115			};
116
117			var updateClock = function() {
118
119				if ( ! endTime ) {
120					return;
121				}
122
123				var timeRemaining = getTimeRemaining(
124					endTime,
125					{
126						days:    elements.days.length,
127						hours:   elements.hours.length,
128						minutes: elements.minutes.length
129					}
130				);
131
132				$.each( timeRemaining.parts, function( timePart ) {
133
134					var $element = elements[ timePart ];
135
136					if ( $element.length ) {
137						$element.html( this );
138					}
139
140				} );
141
142				if ( timeRemaining.total <= 0 ) {
143					clearInterval( timeInterval );
144					runActions();
145				}
146			};
147
148			var splitNum = function( num ) {
149
150				var num    = num.toString(),
151					arr    = [],
152					result = '';
153
154				if ( 1 === num.length ) {
155					num = 0 + num;
156				}
157
158				arr = num.match(/\d{1}/g);
159
160				$.each( arr, function( index, val ) {
161					result += '<span class="jet-countdown-timer__digit">' + val + '</span>';
162				});
163
164				return result;
165			};
166
167			var getTimeRemaining = function( endTime, visible ) {
168
169				var timeRemaining = endTime - new Date(),
170					seconds = Math.floor( ( timeRemaining / 1000 ) % 60 ),
171					minutes = Math.floor( ( timeRemaining / 1000 / 60 ) % 60 ),
172					hours = Math.floor( ( timeRemaining / ( 1000 * 60 * 60 ) ) % 24 ),
173					days = Math.floor( timeRemaining / ( 1000 * 60 * 60 * 24 ) );
174
175				if ( days < 0 || hours < 0 || minutes < 0 ) {
176					seconds = minutes = hours = days = 0;
177				}
178
179				if ( ! visible.days ) {
180					hours += days * 24;
181					days = 0;
182				}
183
184				if ( ! visible.hours ) {
185					minutes += hours * 60;
186					hours = 0;
187				}
188
189				if ( ! visible.minutes ) {
190					seconds += minutes * 60;
191					minutes = 0;
192				}
193
194				return {
195					total: timeRemaining,
196					parts: {
197						days: splitNum( days ),
198						hours: splitNum( hours ),
199						minutes: splitNum( minutes ),
200						seconds: splitNum( seconds )
201					}
202				};
203			};
204
205			var runActions = function() {
206
207				$scope.trigger( 'jetCountdownTimerExpire', $scope );
208
209				if ( ! actions ) {
210					return;
211				}
212
213				$.each( actions, function( index, action ) {
214					switch ( action ) {
215						case 'redirect':
216							var redirect_url = $countdown.data( 'expire-redirect-url' );
217
218							if ( redirect_url ) {
219								window.location.href = redirect_url;
220							}
221
222							break;
223
224						case 'message':
225							$scope.find( '.jet-countdown-timer-message' ).show();
226							break;
227
228						case 'hide':
229							$countdown.hide();
230							break;
231
232						case 'restart':
233
234							endTime = new Date();
235							endTime = endTime.setSeconds( endTime.getSeconds() + restartInterval );
236
237							updateClock();
238							timeInterval = setInterval( updateClock, 1000 );
239							break;
240					}
241				} );
242			};
243
244			var getEvergreenDate = function() {
245				var id = $scope.data( 'id' ),
246					dueDateKey = 'jet_evergreen_countdown_due_date_' + id,
247					intervalKey = 'jet_evergreen_countdown_interval_' + id,
248					localDueDate = localStorage.getItem( dueDateKey ),
249					localInterval = localStorage.getItem( intervalKey ),
250
251					initEvergreenTimer = function(){
252						var dueDate = new Date(),
253							_endTime = dueDate.setSeconds( dueDate.getSeconds() + evergreenInterval );
254
255						localStorage.setItem( dueDateKey, _endTime );
256						localStorage.setItem( intervalKey, evergreenInterval );
257
258						return _endTime;
259					};
260
261				if ( null === localDueDate && null === localInterval ) {
262					return initEvergreenTimer();
263				}
264
265				if ( null !== localDueDate && evergreenInterval !== parseInt( localInterval, 10 ) ) {
266					return initEvergreenTimer();
267				}
268
269				if ( localDueDate > 0 && parseInt( localInterval, 10 ) === evergreenInterval ) {
270					return localDueDate;
271				}
272			};
273
274			initClock();
275
276		},
277
278		widgetMap: function( $scope ) {
279
280			var $container = $scope.find( '.jet-map' ),
281				map,
282				init,
283				pins;
284
285			if ( ! window.google || ! $container.length ) {
286				return;
287			}
288
289			init = $container.data( 'init' );
290			pins = $container.data( 'pins' );
291			map  = new google.maps.Map( $container[0], init );
292
293			if ( pins ) {
294				$.each( pins, function( index, pin ) {
295
296					var marker,
297						infowindow,
298						pinData = {
299							position: pin.position,
300							map: map
301						};
302
303					if ( '' !== pin.image ) {
304
305						if ( undefined !== pin.image_width && undefined !== pin.image_height ) {
306							var icon = {
307								url:        pin.image,
308								scaledSize: new google.maps.Size( pin.image_width, pin.image_height ),
309								origin:     new google.maps.Point( 0, 0 ),
310								anchor:     new google.maps.Point( pin.image_width/2, pin.image_height/2 )
311							}
312
313							pinData.icon = icon;
314						} else {
315							pinData.icon = pin.image;
316						}
317					}
318
319					marker = new google.maps.Marker( pinData );
320
321					if ( '' !== pin.desc || undefined !== pin.link_title ) {
322
323						if ( undefined !== pin.link_title ) {
324							var link_url               = pin.link.url,
325								link_is_external       = 'on' === pin.link.is_external ? 'target="_blank"': '',
326								link_nofollow          = 'on' === pin.link.nofollow ? 'rel="nofollow"': '',
327								link_custom_attributes = undefined !== parse_custom_attributes( pin.link.custom_attributes ) ? parse_custom_attributes( pin.link.custom_attributes ) : '',
328								link_layout;
329
330							link_layout = '<div class="jet-map-pin__wrapper">
330<a class="jet-map-pin__link" href="' + link_url + '" ' + link_is_external + link_nofollow + link_custom_attributes + '>' + pin.link_title + '</a></div>';
331							pin.desc += link_layout;
332						}
333
334						infowindow = new google.maps.InfoWindow({
335							content: pin.desc,
336							disableAutoPan: true
337						});
338					}
339
340					marker.addListener( 'click', function() {
341						infowindow.setOptions({ disableAutoPan: false });
342						infowindow.open( map, marker );
343					});
344
345					if ( 'visible' === pin.state && '' !== pin.desc ) {
346						infowindow.open( map, marker );
347					}
348
349				});
350			}
351
352			function parse_custom_attributes( attributes_string, delimiter = ',' ) {
353				var attributes = attributes_string.split( delimiter ),
354					result;
355
356				result = attributes.reduce(function( res, attribute ) {
357					var attr_key_value = attribute.split( '|' ),
358						attr_key       = attr_key_value[0].toLowerCase(),
359						attr_value     = '',
360						regex          = new RegExp(/[-_a-z0-9]+/);
361
362					if( !regex.test( attr_key ) ) {
363						return;
364					}
365
366					// Avoid Javascript events and unescaped href.
367					if ( 'href' === attr_key || 'on' === attr_key.substring( 0, 2 ) ) {
368						return;
369					}
370
371					if ( undefined !== attr_key_value[1] ) {
372						attr_value = attr_key_value[1].trim();
373					} else {
374						attr_value = '';
375					}
376					return res + attr_key + '="' + attr_value + '" ';
377				}, '');
378
379				return result;
380			}
381		},
382
383		prepareWaypointOptions: function( $scope, waypointOptions ) {
384			var options = waypointOptions || {},
385				$parentPopup = $scope.closest( '.jet-popup__container-inner, .elementor-popup-modal .dialog-message' );
386
387			if ( $parentPopup[0] ) {
388				options.context = $parentPopup[0];
389			}
390
391			return options;
392		},
393
394		widgetProgress: function( $scope ) {
395
396			var $progress = $scope.find( '.circle-progress' );
397
398			if ( ! $progress.length ) {
399				return;
400			}
401
402			var $value              = $progress.find( '.circle-progress__value' ),
403				$meter              = $progress.find( '.circle-progress__meter' ),
404				percent             = parseInt( $value.data( 'value' ) ),
405				progress            = percent / 100,
406				duration            = $scope.find( '.circle-progress-wrap' ).data( 'duration' ),
407				currentDeviceMode   = elementorFrontend.getCurrentDeviceMode(),
408				isAnimatedCircle    = false,
409				breakpoints         = JetElementsTools.getElementorElementSettings( $scope ),
410				breakpointsSettings = [],
411				activeBreakpoints   = elementor.config.responsive.activeBreakpoints;
412
413			breakpointsSettings['desktop'] = [];
414
415			var breakpointSize        = breakpoints['circle_size']['size'] ? breakpoints['circle_size']['size'] : $progress[0].getAttribute( 'width' ),
416
417				breakpointStrokeValue = breakpoints['value_stroke']['size'] ? breakpoints['value_stroke']['size'] : $progress[0].getElementsByClassName( 'circle-progress__value' )[0].getAttribute( 'stroke-width' ),
418
419				breakpointStrokeBg    = breakpoints['bg_stroke']['size'] ? breakpoints['bg_stroke']['size'] : $progress[0].getElementsByClassName( 'circle-progress__meter' )[0].getAttribute( 'stroke-width' );
420
421			breakpointSizes( 'desktop', breakpointSize, breakpointStrokeValue, breakpointStrokeBg );
422
423			Object.keys( activeBreakpoints ).reverse().forEach( function( breakpointName, index ) {
424
425				if ( 'widescreen' === breakpointName ){
426					var breakpointSize        = breakpoints['circle_size_' + breakpointName]['size'] ? breakpoints['circle_size_' + breakpointName]['size'] : breakpoints['circle_size']['size'],
427
428						breakpointStrokeValue = breakpoints['value_stroke_' + breakpointName]['size'] ? breakpoints['value_stroke_' + breakpointName]['size'] : breakpoints['value_stroke']['size'],
429
430						breakpointStrokeBg    = breakpoints['bg_stroke_' + breakpointName]['size'] ? breakpoints['bg_stroke_' + breakpointName]['size'] : breakpoints['bg_stroke']['size'];
431
432					breakpointsSettings[breakpointName] = [];
433
434					breakpointSizes( breakpointName, breakpointSize, breakpointStrokeValue, breakpointStrokeBg );
435				} else {
436					var breakpointSize        = breakpoints['circle_size_' + breakpointName]['size'] ? breakpoints['circle_size_' + breakpointName]['size'] : $progress[0].getAttribute( 'width' ),
437
438						breakpointStrokeValue = breakpoints['value_stroke_' + breakpointName]['size'] ? breakpoints['value_stroke_' + breakpointName]['size'] : $progress[0].getElementsByClassName( 'circle-progress__value' )[0].getAttribute( 'stroke-width' ),
439
440						breakpointStrokeBg    = breakpoints['bg_stroke_' + breakpointName]['size'] ? breakpoints['bg_stroke_' + breakpointName]['size'] : $progress[0].getElementsByClassName( 'circle-progress__meter' )[0].getAttribute( 'stroke-width' );
441
442					breakpointsSettings[breakpointName] = [];
443
444					breakpointSizes( breakpointName, breakpointSize, breakpointStrokeValue, breakpointStrokeBg );
445				}
446			} );
447
448			updateSvgSizes( breakpointsSettings[currentDeviceMode]['size'],
449								breakpointsSettings[currentDeviceMode]['viewBox'],
450								breakpointsSettings[currentDeviceMode]['center'],
451								breakpointsSettings[currentDeviceMode]['radius'],
452								breakpointsSettings[currentDeviceMode]['valStroke'],
453								breakpointsSettings[currentDeviceMode]['bgStroke'],
454								breakpointsSettings[currentDeviceMode]['circumference']
455			);
456
457			elementorFrontend.waypoint( $scope, function() {
458
459				// animate counter
460				var $number = $scope.find( '.circle-counter__number' ),
461					data = $number.data();
462
463				var decimalDigits = data.toValue.toString().match( /\.(.*)/ );
464
465				if ( decimalDigits ) {
466					data.rounding = decimalDigits[1].length;
467				}
468
469				data.duration = duration;
470
471				$number.numerator( data );
472
473				// animate progress
474				var circumference = parseInt( $progress.data( 'circumference' ) ),
475					dashoffset    = circumference * (1 - progress);
476
477				$value.css({
478					'transitionDuration': duration + 'ms',
479					'strokeDashoffset': dashoffset
480				});
481
482				isAnimatedCircle = true;
483
484			}, JetElements.prepareWaypointOptions( $scope, {
485					offset: 'bottom-in-view'
486			} ) );
487
488			$( window ).on( 'resize.jetCircleProgress orientationchange.jetCircleProgress', JetElementsTools.debounce( 50, function() {
489				currentDeviceMode = elementorFrontend.getCurrentDeviceMode();
490
491				if ( breakpointsSettings[currentDeviceMode] ) {
492					updateSvgSizes( breakpointsSettings[currentDeviceMode]['size'],
493										breakpointsSettings[currentDeviceMode]['viewBox'],
494										breakpointsSettings[currentDeviceMode]['center'],
495										breakpointsSettings[currentDeviceMode]['radius'],
496										breakpointsSettings[currentDeviceMode]['valStroke'],
497										breakpointsSettings[currentDeviceMode]['bgStroke'],
498										breakpointsSettings[currentDeviceMode]['circumference']
499					);
500				}
501			} ) );
502
503			function breakpointSizes( breakpointName, breakpointSize, breakpointStrokeValue, breakpointStrokeBg) {
504				var max,
505					radius;
506
507				breakpointsSettings[breakpointName]['size']          = breakpointSize;
508				breakpointsSettings[breakpointName]['viewBox']       = `0 0 ${breakpointSize} ${breakpointSize}`;
509				breakpointsSettings[breakpointName]['center']        = breakpointSize / 2;
510				radius                                               = breakpointSize / 2;
511				max                                                  = ( breakpointStrokeValue >= breakpointStrokeBg ) ? breakpointStrokeValue : breakpointStrokeBg;
512				breakpointsSettings[breakpointName]['radius']        = radius - ( max / 2 );
513				breakpointsSettings[breakpointName]['circumference'] = 2 * Math.PI * breakpointsSettings[breakpointName]['radius'];
514				breakpointsSettings[breakpointName]['valStroke']     = breakpointStrokeValue;
515				breakpointsSettings[breakpointName]['bgStroke']      = breakpointStrokeBg;
516			}
517
518			function updateSvgSizes( size, viewBox, center, radius, valStroke, bgStroke, circumference ) {
519				var dashoffset = circumference * (1 - progress);
520
521				$progress.attr( {
522					'width': size,
523					'height': size,
524					'data-radius': radius,
525					'data-circumference': circumference
526				} );
527
528				$progress[0].setAttribute( 'viewBox', viewBox );
529
530				$meter.attr( {
531					'cx': center,
532					'cy': center,
533					'r': radius,
534					'stroke-width': bgStroke
535				} );
536
537				if ( isAnimatedCircle ) {
538					$value.css( {
539						'transitionDuration': ''
540					} );
541				}
542
543				$value.attr( {
544					'cx': center,
545					'cy': center,
546					'r': radius,
547					'stroke-width': valStroke
548				} );
549
550				$value.css( {
551					'strokeDasharray': circumference,
552					'strokeDashoffset': isAnimatedCircle ? dashoffset : circumference
553				} );
554			}
555		},
556
557		widgetCarousel: function( $scope ) {
558
559			var $carousel    = $scope.find( '.jet-carousel' ),
560				fraction_nav = $carousel.find('.jet-carousel__fraction-navigation');
561
562			if ( ! $carousel.length ) {
563				return;
564			}
565
566			if ( true === $carousel.data( 'slider_options' ).fractionNav ) {
567				$carousel.find( '.elementor-slick-slider' ).on( 'init reInit afterChange', function ( event, slick, currentSlide, nextSlide ) {
568					//currentSlide is undefined on init -- set it to 0 in this case (currentSlide is 0 based)
569					var i = ( currentSlide ? currentSlide : 0 ) + 1;
570					fraction_nav.html( '<span class="current">' + i + '</span>' + '<span class="separator">/</span>' + '<span class="total">
570' + slick.slideCount + '</span>');
571				} );
572			}
573
574			JetElements.initCarousel( $carousel.find( '.elementor-slick-slider' ), $carousel.data( 'slider_options' ) );
575
576		},
577
578		widgetPosts: function ( $scope ) {
579
580			var $target  = $scope.find( '.jet-carousel' ),
581				settings = $target.data( 'slider_options' );
582
583			if ( ! $target.length ) {
584				return;
585			}
586
587			settings['slide'] = '.jet-posts__item';
588
589			JetElements.initCarousel( $target.find( '.jet-posts' ), settings );
590
591		},
592
593		widgetAnimatedText: function( $scope ) {
594			var $target = $scope.find( '.jet-animated-text' ),
595				instance = null,
596				settings = {};
597
598			if ( ! $target.length ) {
599				return;
600			}
601
602			settings = $target.data( 'settings' );
603			instance = new jetAnimatedText( $target, settings );
604			instance.init();
605		},
606
607		widgetAnimatedBox: function( $scope ) {
608
609			JetElements.onAnimatedBoxSectionActivated( $scope );
610
611			var $target         = $scope.find( '.jet-animated-box' ),
612				defaultSettings = {
613					widgetId: null,
614					switchEventType: 'hover',
615					paperFoldDirection: 'left',
616					slideOutDirection: 'left'
617				},
618				settings        = $target.data( 'settings' ),
619				settings        = $.extend( {}, defaultSettings, settings ),
620				scrollOffset    = $( window ).scrollTop(),
621				firstMouseEvent = true,
622				editMode        = Boolean( elementor.isEditMode() );
623
624			if ( ! $target.length ) {
625				return;
626			}
627
628			switch( settings['switchEventType'] ) {
629				case 'hover':
630					if ( ! editMode ) {
631						hoverSwitchType();
632					} else {
633						clickSwitchType();
634					}
635
636					break;
637
638				case 'click':
639					clickSwitchType();
640					break;
641
642				case 'toggle':
643					toggleSwitchType();
644					break;
645
646				case 'scratch':
647					scratchSwitchType();
648					break;
649
650				case 'fold':
651					foldSwitchType();
652					break;
653
654				case 'peel':
655					peelSwitchType();
656					break;
657
658				case 'slide-out':
659					slideOutSwitchType();
660					break;
661			}
662
663			function hoverSwitchType() {
664
665				if ( 'ontouchend' in window || 'ontouchstart' in window ) {
666					$target.on( 'touchstart', function( event ) {
667						scrollOffset = $( window ).scrollTop();
668					} );
669
670					$target.on( 'touchend', function( event ) {
671
672						if ( scrollOffset !== $( window ).scrollTop() ) {
673							return false;
674						}
675
676						var $this = $( this );
677
678						if ( $this.hasClass( 'flipped-stop' ) ) {
679							return;
680						}
681
682						setTimeout( function() {
683							$this.toggleClass( 'flipped' );
684						}, 10 );
685					} );
686
687					$( document ).on( 'touchend', function( event ) {
688
689						if ( $( event.target ).closest( $target ).length ) {
690							return;
691						}
692
693						if ( $target.hasClass( 'flipped-stop' ) ) {
694							return;
695						}
696
697						if ( ! $target.hasClass( 'flipped' ) ) {
698							return;
699						}
700
701						$target.removeClass( 'flipped' );
702					} );
703				} else {
704
705					$target.on( 'mouseenter mouseleave', function( event ) {
706
707						if ( firstMouseEvent && 'mouseleave' === event.type ) {
708							return;
709						}
710
711						if ( firstMouseEvent && 'mouseenter' === event.type ) {
712							firstMouseEvent = false;
713						}
714
715						if ( ! $( this ).hasClass( 'flipped-stop' ) ) {
716							$( this ).toggleClass( 'flipped' );
717						}
718					} );
719				}
720			}
721
722			function clickSwitchType() {
723				if ( 'ontouchend' in window || 'ontouchstart' in window ) {
724					$target.on( 'touchstart', function( event ) {
725						scrollOffset = $( window ).scrollTop();
726					} );
727
728					$target.on( 'touchend', function( event ) {
729
730						if ( scrollOffset !== $( window ).scrollTop() ) {
731							return false;
732						}
733
734						var $this = $( this );
735
736						if ( $this.hasClass( 'flipped-stop' ) ) {
737							return;
738						}
739
740						setTimeout( function() {
741							$this.toggleClass( 'flipped' );
742						}, 10 );
743					} );
744
745					$( document ).on( 'touchend', function( event ) {
746
747						if ( $( event.target ).closest( $target ).length ) {
748							return;
749						}
750
751						if ( $target.hasClass( 'flipped-stop' ) ) {
752							return;
753						}
754
755						if ( ! $target.hasClass( 'flipped' ) ) {
756							return;
757						}
758
759						$target.removeClass( 'flipped' );
760					} );
761				} else {
762					$target.on( 'click', function( event ) {
763
764						if ( ! $target.hasClass( 'flipped-stop' ) ) {
765							$target.toggleClass( 'flipped' );
766						}
767					} );
768				}
769			}
770
771			function toggleSwitchType() {
772				if ( 'ontouchend' in window || 'ontouchstart' in window ) {
773					$target.on( 'touchstart', '.jet-animated-box__toggle', function( event ) {
774
775					if ( ! $target.hasClass( 'flipped-stop' ) ) {
776						$target.toggleClass( 'flipped' );
777					}
778				} );
779				} else {
780					$target.on( 'click', '.jet-animated-box__toggle', function( event ) {
781
782						if ( ! $target.hasClass( 'flipped-stop' ) ) {
783							$target.toggleClass( 'flipped' );
784						}
785					} );
786				}
787			}
788
789			function scratchSwitchType() {
790
791				if ( editMode ) {
792					return false;
793				}
794
795				var windowWidth = $( window ).width();
796
797				$( 'html, body' ).scrollTop(0);
798
799				html2canvas( document.querySelector( '#jet-animated-box__front-' + settings['widgetId'] ), {
800					allowTaint: true,
801					backgroundColor: null,
802					windowWidth: $( window ).width(),
803					windowHeight: $( window ).height(),
804					scrollX: 0,
805					scrollY: -window.scrollY,
806				} ).then( function( canvas ) {
807					canvas.setAttribute( 'id', 'jet-animated-box-canvas-' + settings['widgetId'] );
808					$target.prepend( canvas );
809
810					$( '.jet-animated-box__front', $target ).fadeOut( 300, function() {
811						$( this ).remove();
812					});
813
814					$( window ).one( 'resize.jetScratch', function( e ) {
815
816						if ( $( window ).width() !== windowWidth ) {
817							windowWidth = $( window ).width();
818
819							$( canvas ).fadeOut( 250, function() {
820								$( this ).remove();
821							});
822						}
823
824					} );
825
826					var jetScratch = new jetScratchEffect(
827						'#jet-animated-box-' + settings['widgetId'],
828						'#jet-animated-box-canvas-' + settings['widgetId'],
829						function() {
830							$( canvas ).fadeOut( 300, function() {
831								$( this ).remove();
832								$target.removeClass( 'back-events-inactive' );
833							} );
834						},
835						settings['scratchFillPercent']
836					);
837				} );
838			}
839
840			function foldSwitchType() {
841
842				if ( editMode ) {
843					$target.addClass( 'fold-init' );
844
845					return false;
846				}
847
848				var folded        = null,
849					frontSelector = '#jet-animated-box__front-' + settings['widgetId'];
850
851				folded = new OriDomi( document.querySelector( frontSelector ), {
852					vPanels:          5,
853					hPanels:          5,
854					speed:            500,
855					ripple:           true,
856					shadingIntensity: .9,
857					perspective:      1000,
858					//maxAngle:         90,
859					shading:          false,
860					gapNudge:          0,
861					touchSensitivity: .25,
862					touchMoveCallback: function( moveCoordinate, event ) {
863
864						if ( 89.5 < moveCoordinate ) {
865							$( frontSelector ).remove();
866						}
867					}
868				}).accordion( 0, settings['paperFoldDirection'] );
869
870				$target.addClass( 'fold-init' );
871			}
872
873			function peelSwitchType() {
874
875				if ( editMode ) {
876					$target.addClass( 'peel-ready' );
877
878					return false;
879				}
880
881				var $front = $( '.jet-animated-box__front', $target ),
882					$frontClone = $front.clone();
883
884				$( '.jet-animated-box__front', $target ).addClass( 'peel-top' );
885
886				$frontClone.removeAttr('id');
887				$frontClone.addClass('peel-back');
888				$frontClone.insertAfter( '#jet-animated-box__front-' + settings['widgetId'] );
889
890				$( '.jet-animated-box__back', $target ).addClass( 'peel-bottom' );
891
892				var peel = new Peel( '#jet-animated-box-' + settings['widgetId'], {
893					corner: Peel.Corners.TOP_RIGHT
894				} );
895
896				var targetWidth = $target.width(),
897					targetHeight = $target.height();
898
899				peel.setPeelPosition( targetWidth - 30, 40 );
900
901				peel.setFadeThreshold(.8);
902
903				peel.handleDrag( function( evt, x, y ) {
904					var targetOffset = $target.offset(),
905						offsetX      = targetOffset.left,
906						offsetY      = targetOffset.top,
907						deltaX       = x - offsetX,
908						deltaY       = y - offsetY;
909
910					deltaX = deltaX < 0 ? deltaX*=3 : deltaX;
911					deltaY = deltaY < 0 ? deltaY*=3 : deltaY;
912
913					if ( 0.98 < this.getAmountClipped() ) {
914						this.removeEvents();
915
916						$( '.peel-top, .peel-back, .peel-bottom-shadow', $target ).remove();
917					}
918
919					peel.setPeelPosition( Math.round( deltaX ), Math.round( deltaY ) );
920
921				});
922			}
923
924			function slideOutSwitchType() {
925
926				var $frontSide    = $( '.jet-animated-box__front', $target ),
927					$backSide     = $( '.jet-animated-box__back', $target ),
928					$targetWidth  = $target.width(),
929					$targetHeight = $target.height(),
930					axis          = ( 'left' === settings.slideOutDirection || 'right' === settings.slideOutDirection ) ? 'x' : 'y';
931
932				$frontSide.draggable( {
933					axis: axis,
934					drag: function( event, ui ) {
935						var dragData = ui.position;
936						switch( settings.slideOutDirection ) {
937							case 'left':
938								if ( dragData.left >= 0 ) {
939									ui.position.left = 0;
940								}
941								break;
942							case 'right':
943								if ( dragData.left <= 0 ) {
944									ui.position.left = 0;
945								}
946								break;
947							case 'top':
948								if ( dragData.top >= 0 ) {
949									ui.position.top = 0;
950								}
951								break;
952							case 'bottom':
953								if ( dragData.top <= 0 ) {
954									ui.position.top = 0;
955								}
956								break;
957						}
958
959					},
960				} );
961
962			}
963		},
964
965		onAnimatedBoxSectionActivated: function( $scope ) {
966			if ( ! window.elementor ) {
967				return;
968			}
969
970			if ( ! window.JetElementsEditor ) {
971				return;
972			}
973
974			if ( ! window.JetElementsEditor.activeSection ) {
975				return;
976			}
977
978			var section = window.JetElementsEditor.activeSection;
979			var isBackSide = -1 !== [ 'section_back_content', 'section_action_button_style' ].indexOf( section );
980
981			if ( isBackSide ) {
982				$scope.find( '.jet-animated-box' ).addClass( 'flipped' );
983				$scope.find( '.jet-animated-box' ).addClass( 'flipped-stop' );
984			} else {
985				$scope.find( '.jet-animated-box' ).removeClass( 'flipped' );
986				$scope.find( '.jet-animated-box' ).removeClass( 'flipped-stop' );
987			}
988		},
989
990		widgetImagesLayout: function( $scope ) {
991			var $target = $scope.find( '.jet-images-layout' ),
992				instance = null,
993				settings = {};
994
995			if ( ! $target.length ) {
996				return;
997			}
998
999			settings = $target.data( 'settings' );
1000			instance = new jetImagesLayout( $target, settings );
1001			instance.init();
1002		},
1003
1004		widgetPortfolio: function( $scope ) {
1005			var $target   = $scope.find( '.jet-portfolio' ),
1006				instance  = null,
1007				eSettings = JetElementsTools.getElementorElementSettings( $scope ),
1008				settings  = {
1009					id: $scope.data( 'id' )
1010				};
1011
1012			if ( ! $target.length ) {
1013				return;
1014			}
1015
1016			settings = $.extend( {}, settings, $target.data( 'settings' ), eSettings );
1017			instance = new jetPortfolio( $target, settings );
1018			instance.init();
1019		},
1020
1021		widgetInstagramGallery: function( $scope ) {
1022			var $target         = $scope.find( '.jet-instagram-gallery__instance' ),
1023				instance        = null,
1024				defaultSettings = {},
1025				settings        = {};
1026
1027			if ( ! $target.length ) {
1028				return;
1029			}
1030
1031			settings = $target.data( 'settings' ),
1032
1033			/*
1034			 * Default Settings
1035			 */
1036			defaultSettings = {
1037				layoutType: 'masonry',
1038			}
1039			/**
1040			 * Checking options, settings and options merging
1041			 */
1042			$.extend( defaultSettings, settings );
1043
1044			if ( 'masonry' === settings.layoutType ) {
1045				salvattore.init();
1046
1047				$( window ).on( 'resize orientationchange', function() {
1048					salvattore.rescanMediaQueries();
1049				} )
1050			}
1051		},
1052
1053		widgetScrollNavigation: function( $scope ) {
1054			var $target         = $scope.find( '.jet-scroll-navigation' ),
1055				instance        = null,
1056				settings        = $target.data( 'settings' );
1057
1058			instance = new jetScrollNavigation( $scope, $target, settings );
1059			instance.init();
1060		},
1061
1062		widgetSubscribeForm: function( $scope ) {
1063			var $target               = $scope.find( '.jet-subscribe-form' ),
1064				scoreId               = $scope.data( 'id' ),
1065				settings              = $target.data( 'settings' ),
1066				jetSubscribeFormAjax  = null,
1067				subscribeFormAjax     = 'jet_subscribe_form_ajax',
1068				ajaxRequestSuccess    = false,
1069				$subscribeForm        = $( '.jet-subscribe-form__form', $target ),
1070				$fields               = $( '.jet-subscribe-form__fields', $target ),
1071				$mailField            = $( '.jet-subscribe-form__mail-field', $target ),
1072				$inputData            = $mailField.data( 'instance-data' ),
1073				$submitButton         = $( '.jet-subscribe-form__submit', $target ),
1074				$subscribeFormMessage = $( '.jet-subscribe-form__message', $target ),
1075				timeout               = null,
1076				invalidMailMessage    = window.jetElements.messages.invalidMail || 'Please specify a valid email';
1077
1078			$mailField.on( 'focus', function() {
1079				$mailField.removeClass( 'mail-invalid' );
1080			} );
1081
1082			$( document ).keydown( function( event ) {
1083
1084				if ( 13 === event.keyCode && $mailField.is( ':focus' ) ) {
1085					subscribeHandle();
1086
1087					return false;
1088				}
1089			} );
1090
1091			$submitButton.on( 'click', function() {
1092				subscribeHandle();
1093
1094				return false;
1095			} );
1096
1097			function subscribeHandle() {
1098				var inputValue     = $mailField.val(),
1099					sendData       = {
1100						'email': inputValue,
1101						'use_target_list_id': settings['use_target_list_id'] || false,
1102						'target_list_id': settings['target_list_id'] || '',
1103						'data': $inputData
1104					},
1105					serializeArray = $subscribeForm.serializeArray(),
1106					additionalFields = {};
1107
1108				if ( JetElementsTools.validateEmail( inputValue ) ) {
1109
1110					$.each( serializeArray, function( key, fieldData ) {
1111
1112						if ( 'email' === fieldData.name ) {
1113							sendData[ fieldData.name ] = fieldData.value;
1114						} else {
1115							additionalFields[ fieldData.name ] = fieldData.value;
1116						}
1117					} );
1118
1119					sendData['additional'] = additionalFields;
1120
1121					if ( ! ajaxRequestSuccess && jetSubscribeFormAjax ) {
1122						jetSubscribeFormAjax.abort();
1123					}
1124
1125					jetSubscribeFormAjax = $.ajax( {
1126						type: 'POST',
1127						url: window.jetElements.ajaxUrl,
1128						data: {
1129							action: subscribeFormAjax,
1130							data: sendData
1131						},
1132						cache: false,
1133						beforeSend: function() {
1134							$submitButton.addClass( 'loading' );
1135							ajaxRequestSuccess = false;
1136						},
1137						success: function( data ){
1138							var successType   = data.type,
1139								message       = data.message || '',
1140								responceClass = 'jet-subscribe-form--response-' + successType;
1141
1142							$submitButton.removeClass( 'loading' );
1143							ajaxRequestSuccess = true;
1144
1145							$target.removeClass( 'jet-subscribe-form--response-error' );
1146							$target.addClass( responceClass );
1147
1148							$( 'span', $subscribeFormMessage ).html( message );
1149							$subscribeFormMessage.css( { 'visibility': 'visible' } );
1150
1151							timeout = setTimeout( function() {
1152								$subscribeFormMessage.css( { 'visibility': 'hidden' } );
1153								$target.removeClass( responceClass );
1154							}, 20000 );
1155
1156							if ( settings['redirect'] ) {
1157								window.location.href = settings['redirect_url'];
1158							}
1159
1160							$( window ).trigger( {
1161								type: 'jet-elements/subscribe',
1162								elementId: scoreId,
1163								successType: successType,
1164								inputData: $inputData
1165							} );
1166						}
1167					});
1168
1169				} else {
1170					$mailField.addClass( 'mail-invalid' );
1171
1172					$target.addClass( 'jet-subscribe-form--response-error' );
1173					$( 'span', $subscribeFormMessage ).html( invalidMailMessage );
1174					$subscribeFormMessage.css( { 'visibility': 'visible' } );
1175
1176					timeout = setTimeout( function() {
1177						$target.removeClass( 'jet-subscribe-form--response-error' );
1178						$subscribeFormMessage.css( { 'visibility': 'hidden' } );
1179						$mailField.removeClass( 'mail-invalid' );
1180					}, 20000 );
1181				}
1182			}
1183		},
1184
1185		widgetProgressBar: function( $scope ) {
1186			var $target      = $scope.find( '.jet-progress-bar' ),
1187				percent      = $target.data( 'percent' ),
1188				type         = $target.data( 'type' ),
1189				deltaPercent = percent * 0.01;
1190
1191			elementorFrontend.waypoint( $target, function( direction ) {
1192				var $this       = $( this ),
1193					animeObject = { charged: 0 },
1194					$statusBar  = $( '.jet-progress-bar__status-bar', $this ),
1195					$percent    = $( '.jet-progress-bar__percent-value', $this ),
1196					animeProgress,
1197					animePercent;
1198
1199				if ( 'type-7' == type ) {
1200					$statusBar.css( {
1201						'height': percent + '%'
1202					} );
1203				} else {
1204					$statusBar.css( {
1205						'width': percent + '%'
1206					} );
1207				}
1208
1209				animePercent = anime({
1210					targets: animeObject,
1211					charged: percent,
1212					round: 1,
1213					duration: 1000,
1214					easing: 'easeInOutQuad',
1215					update: function() {
1216						$percent.html( animeObject.charged );
1217					}
1218				} );
1219
1220			}, JetElements.prepareWaypointOptions( $scope ) );
1221		},
1222
1223		widgetSlider: function( $scope ) {
1224			var $target         = $scope.find( '.jet-slider' ),
1225				$imagesTagList  = $( '.sp-image', $target ),
1226				item            = $( '.jet-slider__item', $target ),
1227				instance        = null,
1228				item_url        = '',
1229				item_url_target = '',
1230				defaultSettings = {
1231					imageScaleMode: 'cover',
1232					slideDistance: { size: 10, unit: 'px' },
1233					slideDuration: 500,
1234					sliderAutoplay: true,
1235					sliderAutoplayDelay: 2000,
1236					sliderAutoplayOnHover: 'pause',
1237					sliderFadeMode: false,
1238					sliderFullScreen: true,
1239					sliderFullscreenIcon: '',
1240					sliderHeight: { size: 600, unit: 'px' },
1241					sliderLoop: true,
1242					sliderNaviOnHover: false,
1243					sliderNavigation: true,
1244					sliderNavigationIcon: '',
1245					sliderPagination: false,
1246					sliderShuffle: false,
1247					sliderWidth: { size: 100, unit: '%' },
1248					thumbnailWidth: 120,
1249					thumbnailHeight: 80,
1250					thumbnails: true,
1251					rightToLeft: false,
1252				},
1253				instanceSettings    = $target.data( 'settings' ) || {},
1254				breakpoints         = JetElementsTools.getElementorElementSettings( $scope ),
1255				breakpointsSettings = {},
1256				defaultHeight,
1257				defaultThumbHeight,
1258				defaultThumbWidth,
1259				activeBreakpoints   = elementor.config.responsive.activeBreakpoints,
1260				settings            = $.extend( {}, defaultSettings, instanceSettings ),
1261				fraction_nav        = $target.find( '.jet-slider__fraction-pagination' );
1262
1263			if ( ! $target.length ) {
1264				return;
1265			}
1266
1267			item.each( function() {
1268				var _this = $( this ).find( '.jet-slider__content' );
1269
1270				if ( _this.data( 'slide-url' ) && !elementor.isEditMode() ) {
1271					let clickXPos,
1272						clickYPos;
1273
1274					_this.on( 'mousedown touchstart', function( e ) {
1275						window.XPos = e.pageX || e.originalEvent.changedTouches[0].pageX;
1276						window.YPos = e.pageY || e.originalEvent.changedTouches[0].pageY;
1277					} )
1278
1279					_this.on( 'mouseup touchend', function( e ) {
1280						item_url        = _this.data( 'slide-url' );
1281						item_url_target = _this.data( 'slide-url-target' );
1282						clickXPos       = e.pageX || e.originalEvent.changedTouches[0].pageX;
1283						clickYPos       = e.pageY || e.originalEvent.changedTouches[0].pageY;
1284
1285						if ( window.XPos === clickXPos && window.YPos === clickYPos ) {
1286							if ( '_blank' === item_url_target ) {
1287								window.open( item_url );
1288								return;
1289							} else {
1290								window.location = item_url;
1291							}
1292						}
1293					} );
1294				}
1295			} );
1296
1297			defaultHeight = ( breakpoints['slider_height'] && '' != breakpoints['slider_height']['size'] ) ? breakpoints['slider_height']['size'] + breakpoints['slider_height']['unit'] : '600px';
1298
1299			defaultThumbHeight = ( breakpoints['thumbnail_height'] && '' != breakpoints['thumbnail_height']['size'] ) ? breakpoints['thumbnail_height']['size'] : 80;
1300
1301			defaultThumbWidth  = ( breakpoints['thumbnail_width'] && '' != breakpoints['thumbnail_width']['size'] ) ? breakpoints['thumbnail_width']['size'] : 120;
1302
1303			Object.keys( activeBreakpoints ).forEach( function( breakpointName ) {
1304
1305				if ( 'widescreen' === breakpointName ) {
1306					var breakpoint = activeBreakpoints[breakpointName].value - 1,
1307
1308						breakpointHeight = '' != breakpoints['slider_height_' + breakpointName]['size'] ? breakpoints['slider_height_' + breakpointName]['size'] + breakpoints['slider_height_' + breakpointName]['unit'] : defaultHeight,
1309
1310						breakpointThumbHeight = '' != breakpoints['thumbnail_height_' + breakpointName] ? breakpoints['thumbnail_height_' + breakpointName] : defaultThumbHeight,
1311
1312						breakpointThumbWidth  = '' != breakpoints['thumbnail_width_' + breakpointName] ? breakpoints['thumbnail_width_' + breakpointName] : defaultThumbWidth,
1313
1314						desktopHeight      = '' != breakpoints['slider_height']['size'] ? breakpoints['slider_height']['size'] + breakpoints['slider_height']['unit'] : settings['sliderHeight']['size'] + settings['sliderHeight']['unit'],
1315
1316						desktopThumbHeight = '' != breakpoints['thumbnail_height'] ? breakpoints['thumbnail_height'] : settings['thumbnailHeight'],
1317
1318						desktopThumbWidth  = '' != breakpoints['thumbnail_width'] ? breakpoints['thumbnail_width'] : settings['thumbnailWidth'];
1319
1320					if ( breakpointHeight || breakpointThumbHeight || breakpointThumbWidth ) {
1321						breakpointsSettings[breakpoint] = {};
1322					} else {
1323						return;
1324					}
1325
1326					if ( breakpointHeight ) {
1327						defaultHeight = breakpointHeight;
1328
1329						breakpointsSettings[breakpoint]['height'] = desktopHeight;
1330					}
1331
1332					if ( breakpointThumbHeight ) {
1333						defaultThumbHeight = breakpointThumbHeight;
1334
1335						breakpointsSettings[breakpoint]['thumbnailHeight'] = desktopThumbHe
1335ight;
1336					}
1337
1338					if ( breakpointThumbWidth ) {
1339						defaultThumbWidth = breakpointThumbWidth;
1340
1341						breakpointsSettings[breakpoint]['thumbnailWidth'] = desktopThumbWidth;
1342					}
1343
1344				} else {
1345					var breakpoint = activeBreakpoints[breakpointName].value - 1,
1346
1347						breakpointThumbHeight = breakpoints['thumbnail_height_' + breakpointName] ? breakpoints['thumbnail_height_' + breakpointName] : false,
1348						breakpointThumbWidth  = breakpoints['thumbnail_width_' + breakpointName] ? breakpoints['thumbnail_width_' + breakpointName] : false;
1349
1350						breakpointHeight = breakpoints['slider_height_' + breakpointName]['size'] ? breakpoints['slider_height_' + breakpointName]['size'] + breakpoints['slider_height_' + breakpointName]['unit'] : false;
1351
1352					if ( breakpointHeight || breakpointThumbHeight || breakpointThumbWidth ) {
1353						breakpointsSettings[breakpoint] = {};
1354					} else {
1355						return;
1356					}
1357
1358					if ( breakpointHeight ) {
1359						breakpointsSettings[breakpoint]['height'] = breakpointHeight;
1360					}
1361
1362					if ( breakpointThumbHeight ) {
1363						breakpointsSettings[breakpoint]['thumbnailHeight'] = breakpointThumbHeight;
1364					}
1365
1366					if ( breakpointThumbWidth ) {
1367						breakpointsSettings[breakpoint]['thumbnailWidth'] = breakpointThumbWidth;
1368					}
1369				}
1370			} );
1371
1372			$( '.slider-pro', $target ).sliderPro( {
1373				width: settings['sliderWidth']['size'] + settings['sliderWidth']['unit'],
1374				height: defaultHeight,
1375				arrows: settings['sliderNavigation'],
1376				fadeArrows: settings['sliderNaviOnHover'],
1377				buttons: settings['sliderPagination'],
1378				autoplay: settings['sliderAutoplay'],
1379				autoplayDelay: settings['sliderAutoplayDelay'],
1380				autoplayOnHover: settings['sliderAutoplayOnHover'],
1381				fullScreen: settings['sliderFullScreen'],
1382				shuffle: settings['sliderShuffle'],
1383				loop: settings['sliderLoop'],
1384				fade: settings['sliderFadeMode'],
1385				slideDistance: ( 'string' !== typeof settings['slideDistance']['size'] ) ? settings['slideDistance']['size'] : 0,
1386				slideAnimationDuration: +settings['slideDuration'],
1387				imageScaleMode: 'exact',
1388				waitForLayers: false,
1389				grabCursor: false,
1390				thumbnailWidth: defaultThumbWidth,
1391				thumbnailHeight: defaultThumbHeight,
1392				rightToLeft: settings['rightToLeft'],
1393				touchSwipe: settings['touchswipe'],
1394				init: function() {
1395					var fullscreenIconHtml = $( '.' + settings['sliderFullscreenIcon'] ).html(),
1396						arrowIconHtml      = $( '.' + settings['sliderNavigationIcon'] ).html();
1397
1398					$( '.sp-full-screen-button', $target ).html( fullscreenIconHtml );
1399					$( '.sp-previous-arrow', $target ).html( arrowIconHtml );
1400					$( '.sp-next-arrow', $target ).html( arrowIconHtml );
1401					$( '.slider-pro', $target ).addClass( 'slider-loaded' );
1402
1403					this.resize();
1404				},
1405				gotoSlideComplete: function() {
1406					if ( true === settings['fractionPag'] ) {
1407						var i = ( this.getSelectedSlide() ? this.getSelectedSlide() : 0 ) + 1;
1408
1409						fraction_nav.html( '<span class="current">' + i + '</span>' + '<span class="separator">/</span>' + '<span class="total">' + this.getTotalSlides() + '</span>');
1410					}
1411				},
1412				update: function() {
1413					if ( true === settings['fractionPag'] ) {
1414						var i = ( this.getSelectedSlide() ? this.getSelectedSlide() : 0 ) + 1;
1415
1416						fraction_nav.html( '<span class="current">' + i + '</span>' + '<span class="separator">/</span>' + '<span class="total">' + this.getTotalSlides() + '</span>');
1417					}
1418				},
1419				breakpoints: breakpointsSettings
1420			} );
1421
1422			$( '.slider-pro', $target ).on( 'gotoSlide', function() {
1423				$target.find( '[data-element_type]' ).each( function() {
1424					window.elementorFrontend.hooks.doAction( 'frontend/element_ready/global', $( this ), $ );
1425				} );
1426			} );
1427
1428		},
1429
1430		widgetTestimonials: function( $scope ) {
1431			var $target        = $scope.find( '.jet-testimonials__instance' ),
1432				$imagesTagList = $( '.jet-testimonials__figure', $target ),
1433				targetContent  = $( '.jet-testimonials__content', $target ),
1434				instance       = null,
1435				settings       = $target.data( 'settings' ),
1436				ratingSettings = $target.data( 'rating-settings' );
1437
1438			if ( ! $target.length ) {
1439				return;
1440			}
1441
1442			targetContent.each( function() {
1443				var ratingList = $( '.jet-testimonials__rating', this );
1444
1445				if ( ratingList ) {
1446					var rating = ratingList.data('rating');
1447
1448					ratingList.each( function() {
1449
1450						$( 'i', this ).each( function( index ) {
1451							if ( index <= rating - 1 ) {
1452								var itemClass = $( this ).data( 'active-star' );
1453								$( this ).addClass( itemClass );
1454							} else {
1455								var itemClass = $( this ).data( 'star' );
1456								$( this ).addClass( itemClass );
1457							}
1458						} )
1459					} )
1460				}
1461			} )
1462
1463			settings.adaptiveHeight = settings['adaptiveHeight'];
1464
1465			settings['slide'] = '.jet-testimonials__item';
1466
1467			JetElements.initCarousel( $target, settings );
1468		},
1469
1470		widgetImageComparison: function( $scope ) {
1471			var $target              = $scope.find( '.jet-image-comparison__instance' ),
1472				instance             = null,
1473				imageComparisonItems = $( '.jet-image-comparison__container', $target ),
1474				settings             = $target.data( 'settings' ),
1475				elementId            = $scope.data( 'id' );
1476
1477			if ( ! $target.length ) {
1478				return;
1479			}
1480
1481			window.juxtapose.scanPage( '.jet-juxtapose' );
1482
1483			settings.draggable = false;
1484			settings.infinite = false;
1485			//settings.adaptiveHeight = true;
1486			JetElements.initCarousel( $target, settings );
1487		},
1488
1489		widgetTimeTable: function( $scope ) {
1490
1491			var $mptt_shortcode_wrapper = $scope.find( '.mptt-shortcode-wrapper' );
1492
1493			if ( ( typeof typenow ) !== 'undefined' ) {
1494				if ( pagenow === typenow ) {
1495					switch ( typenow ) {
1496
1497						case 'mp-event':
1498							Registry._get( 'Event' ).init();
1499							break;
1500
1501						case 'mp-column':
1502							Registry._get( 'Event' ).initDatePicker();
1503							Registry._get( 'Event' ).columnRadioBox();
1504							break;
1505
1506						default:
1507							break;
1508					}
1509				}
1510			}
1511
1512			if ( $mptt_shortcode_wrapper.length ) {
1513
1514				Registry._get( 'Event' ).initTableData();
1515				Registry._get( 'Event' ).filterShortcodeEvents();
1516				Registry._get( 'Event' ).getFilterByHash();
1517
1518				$mptt_shortcode_wrapper.show();
1519			}
1520
1521			if ( $( '.upcoming-events-widget' ).length || $mptt_shortcode_wrapper.length ) {
1522				Registry._get( 'Event' ).setColorSettings();
1523			}
1524		},
1525
1526		elementorSection: function( $scope ) {
1527			var $target   = $scope,
1528				instance  = null,
1529				editMode  = Boolean( elementor.isEditMode() );
1530
1531				instance = new jetSectionParallax( $target );
1532				instance.init();
1533		},
1534
1535		initCarousel: function( $target, options ) {
1536
1537			var	defaultOptions,
1538				slickOptions,
1539				responsive        = [],
1540				eTarget           = $target.closest( '.elementor-widget' ),
1541				breakpoints       = JetElementsTools.getElementorElementSettings( eTarget ),
1542				activeBreakpoints = elementor.config.responsive.activeBreakpoints,
1543				prevDeviceToShowValue,
1544				prevDeviceToScrollValue,
1545				slidesCount,
1546				dotsEnable = options.dots;
1547
1548			if ( $target.hasClass( 'jet-posts' ) && $target.parent().hasClass( 'jet-carousel' ) ) {
1549				function renameKeys( obj, newKeys ) {
1550					const keyValues = Object.keys( obj ).map( key => {
1551						const newKey = newKeys[key] || key;
1552						return { [newKey]: obj[key] };
1553					} );
1554					return Object.assign( {}, ...keyValues );
1555				}
1556
1557				var newBreakpointsKeys = {
1558					columns: "slides_to_show",
1559					columns_widescreen: "slides_to_show_widescreen",
1560					columns_laptop: "slides_to_show_laptop",
1561					columns_tablet_extra: "slides_to_show_tablet_extra",
1562					columns_tablet: "slides_to_show_tablet",
1563					columns_mobile_extra: "slides_to_show_mobile_extra",
1564					columns_mobile: "slides_to_show_mobile"
1565				};
1566
1567				breakpoints = renameKeys( breakpoints, newBreakpointsKeys );
1568				slidesCount = $( '> div.jet-posts__item', $target ).length;
1569			} else {
1570				slidesCount = $( '> div', $target ).length;
1571			}
1572
1573			options.slidesToShow = +breakpoints.slides_to_show;
1574
1575			Object.keys( activeBreakpoints ).forEach( function( breakpointName ) {
1576				if ( 'widescreen' === breakpointName ) {
1577					options.slidesToShow = breakpoints.slides_to_show_widescreen ? +breakpoints.slides_to_show_widescreen : +breakpoints.slides_to_show;
1578
1579					if ( breakpoints.slides_to_scroll_widescreen ) {
1580						options.slidesToScroll = '' != breakpoints.slides_to_scroll_widescreen ? +breakpoints.slides_to_scroll_widescreen : +breakpoints.slides_to_scroll;
1581					} else {
1582						options.slidesToScroll = 1;
1583					}
1584				}
1585			} );
1586
1587			if ( options.slidesToShow >= slidesCount ) {
1588				options.dots = false;
1589			}
1590
1591			prevDeviceToShowValue   = options.slidesToShow;
1592			prevDeviceToScrollValue = options.slidesToScroll;
1593
1594			$target.on( 'init reInit', function() {
1595				if ( options.infinite ) {
1596					var $items        = $( this ),
1597						$clonedSlides = $( '> .slick-list > .slick-track > .slick-cloned.jet-carousel__item', $items );
1598
1599					if ( !$clonedSlides.length ) {
1600						return;
1601					}
1602
1603					JetElements.initElementsHandlers( $clonedSlides );
1604
1605				}
1606			} );
1607
1608			if ( $target.hasClass( 'slick-initialized' ) ) {
1609				$target.slick( 'refresh', true );
1610				return;
1611			}
1612
1613			Object.keys( activeBreakpoints ).reverse().forEach( function( breakpointName ) {
1614
1615				if ( breakpoints['slides_to_show_' + breakpointName] || breakpoints['slides_to_scroll_' + breakpointName] ) {
1616
1617					var breakpointSetting = {
1618						breakpoint: null,
1619						settings: {}
1620					}
1621
1622					breakpointSetting.breakpoint = 'widescreen' != breakpointName ? activeBreakpoints[breakpointName].value : activeBreakpoints[breakpointName].value - 1;
1623
1624					if ( 'widescreen' === breakpointName ) {
1625						breakpointSetting.settings.slidesToShow   = +breakpoints['slides_to_show'];
1626						breakpointSetting.settings.slidesToScroll = +breakpoints['slides_to_scroll'];
1627					} else {
1628						breakpointSetting.settings.slidesToShow = breakpoints['slides_to_show_' + breakpointName] ? +breakpoints['slides_to_show_' + breakpointName] : prevDeviceToShowValue;
1629
1630						breakpointSetting.settings.slidesToScroll = breakpoints['slides_to_scroll_' + breakpointName] ? +breakpoints['slides_to_scroll_' + breakpointName] : prevDeviceToScrollValue;
1631					}
1632
1633					$target.on( 'init reInit', function( event, slick, currentSlide, nextSlide ) {
1634						if ( breakpointSetting.settings.slidesToShow >= slick.slideCount ) {
1635							breakpointSetting.settings.dots = false;
1636						} else {
1637							if ( dotsEnable ) {
1638								breakpointSetting.settings.dots = true;
1639							}
1640						}
1641					} );
1642
1643					prevDeviceToShowValue   = breakpointSetting.settings.slidesToShow;
1644					prevDeviceToScrollValue = breakpointSetting.settings.slidesToScroll
1645
1646					responsive.push( breakpointSetting );
1647				}
1648			} );
1649
1650			options.responsive = responsive;
1651
1652			if ( options.slidesToShow >= slidesCount ) {
1653				options.dots = false;
1654			}
1655
1656			defaultOptions = {
1657				customPaging: function(slider, i) {
1658					return $( '<span />' ).text( i + 1 );
1659				},
1660				dotsClass: 'jet-slick-dots'
1661			};
1662
1663			slickOptions = $.extend( {}, defaultOptions, options );
1664
1665			$target.slick( slickOptions );
1666		},
1667
1668		widgetTimeLine : function ( $scope ){
1669			var $target = $scope.find( '.jet-timeline' ),
1670				instance = null;
1671
1672			if ( ! $target.length ) {
1673				return;
1674			}
1675
1676			instance = new jetTimeLine( $target );
1677			instance.init();
1678		},
1679
1680		widgetTable: function( $scope ) {
1681			var $target = $scope.find( '.jet-table' ),
1682				options = {
1683					cssHeader: 'jet-table-header-sort',
1684					cssAsc: 'jet-table-header-sort--up',
1685					cssDesc: 'jet-table-header-sort--down',
1686					initWidgets: false
1687				};
1688
1689			if ( ! $target.length ) {
1690				return;
1691			}
1692
1693			if ( $target.hasClass( 'jet-table--sorting' ) ) {
1694				$target.tablesorter( options );
1695			}
1696
1697			$( '.jet-table__body-row', $target ).each( function() {
1698				var _this         = $( this ),
1699					itemsCounter  = 0,
1700					emptyContents = 0;
1701
1702				$( '.jet-table__cell', _this ).each( function() {
1703					var image      = $( 'img', $( this ) ),
1704						svg        = $( 'svg', $( this ) ),
1705						icon       = $( 'i', $( this ) ),
1706						itemImages = 0;
1707
1708					if ( 0 === svg.length && 0 === icon.length ) {
1709						image.each( function() {
1710							if ( '' != $( this ).attr( 'src' ) ) {
1711								itemImages++;
1712							}
1713						} )
1714
1715						if ( 0 === $( this ).text().length && 0 === itemImages ) {
1716							emptyContents++;
1717						}
1718					}
1719
1720					itemsCounter++;
1721				} )
1722
1723				if( emptyContents === itemsCounter ) {
1724					_this.remove();
1725				}
1726			} )
1727		},
1728
1729		widgetDropbar: function( $scope ) {
1730			var $dropbar       = $scope.find( '.jet-dropbar' ),
1731				$dropbar_inner = $dropbar.find( '.jet-dropbar__inner' ),
1732				$btn           = $dropbar.find( '.jet-dropbar__button' ),
1733				$content       = $dropbar.find( '.jet-dropbar__content' ),
1734				settings       = $dropbar.data( 'settings' ) || {},
1735				mode           = settings['mode'] || 'hover',
1736				hide_delay     = +settings['hide_delay'] || 0,
1737				activeClass    = 'jet-dropbar-open',
1738				scrollOffset,
1739				timer;
1740
1741			if ( 'click' === mode ) {
1742				$btn.on( 'click.jetDropbar', function( event ) {
1743					$dropbar.toggleClass( activeClass );
1744				} );
1745			} else {
1746				if ( 'ontouchstart' in window || 'ontouchend' in window ) {
1747					$btn.on( 'touchend.jetDropbar', function( event ) {
1748						if ( $( window ).scrollTop() !== scrollOffset ) {
1749							return;
1750						}
1751
1752						$dropbar.toggleClass( activeClass );
1753					} );
1754				} else {
1755					$dropbar_inner.on( 'mouseenter.jetDropbar', function( event ) {
1756						clearTimeout( timer );
1757						$dropbar.addClass( activeClass );
1758					} );
1759
1760					$dropbar_inner.on( 'mouseleave.jetDropbar', function( event ) {
1761						timer = setTimeout( function() {
1762							$dropbar.removeClass( activeClass );
1763						}, hide_delay );
1764					} );
1765				}
1766			}
1767
1768			$( document ).on( 'touchstart.jetDropbar', function( event ) {
1769				scrollOffset = $( window ).scrollTop();
1770			} );
1771
1772			$( document ).on( 'click.jetDropbar touchend.jetDropbar', function( event ) {
1773
1774				if ( 'touchend' === event.type && $( window ).scrollTop() !== scrollOffset ) {
1775					return;
1776				}
1777
1778				if ( $( event.target ).closest( $btn ).length || $( event.target ).closest( $content ).length ) {
1779					return;
1780				}
1781
1782				if ( ! $dropbar.hasClass( activeClass ) ) {
1783					return;
1784				}
1785
1786				$dropbar.removeClass( activeClass );
1787			} );
1788		},
1789
1790		widgetVideo: function( $scope ) {
1791			var $video = $scope.find( '.jet-video' ),
1792				$iframe = $scope.find( '.jet-video-iframe' ),
1793				$videoPlaer = $scope.find( '.jet-video-player' ),
1794				$mejsPlaer = $scope.find( '.jet-video-mejs-player' ),
1795				mejsPlaerControls = $mejsPlaer.data( 'controls' ) || ['playpause', 'current', 'progress', 'duration', 'volume', 'fullscreen'],
1796				$overlay = $scope.find( '.jet-video__overlay' ),
1797				hasOverlay = $overlay.length > 0,
1798				settings = $video.data( 'settings' ) || {},
1799				lightbox = settings.lightbox || false,
1800				autoplay = settings.autoplay || false;
1801
1802			if ( $overlay[0] ) {
1803				$overlay.on( 'click.jetVideo', function( event ) {
1804
1805					if ( $videoPlaer[0] ) {
1806						$videoPlaer[0].play();
1807
1808						$overlay.remove();
1809						hasOverlay = false;
1810
1811						return;
1812					}
1813
1814					if ( $iframe[0] ) {
1815						iframeStartPlay();
1816					}
1817				} );
1818			}
1819
1820			if ( autoplay && $iframe[0] && $overlay[0] ) {
1821				iframeStartPlay();
1822			}
1823
1824			function iframeStartPlay() {
1825				var lazyLoad = $iframe.data( 'lazy-load' );
1826
1827				if ( lazyLoad ) {
1828					$iframe.attr( 'src', lazyLoad );
1829				}
1830
1831				if ( ! autoplay ) {
1832					$iframe[0].src = $iframe[0].src.replace( '&autoplay=0', '&autoplay=1' );
1833				}
1834
1835				$overlay.remove();
1836				hasOverlay = false;
1837			}
1838
1839			if ( $videoPlaer[0] ) {
1840				$videoPlaer.on( 'play.jetVideo', function( event ) {
1841					if ( hasOverlay ) {
1842						$overlay.remove();
1843						hasOverlay = false;
1844					}
1845				} );
1846
1847				if ( autoplay ) {
1848					$overlay.remove();
1849				}
1850			}
1851
1852			if ( $mejsPlaer[0] ) {
1853				$mejsPlaer.mediaelementplayer( {
1854					videoVolume: 'horizontal',
1855					hideVolumeOnTouchDevices: false,
1856					enableProgressTooltip: false,
1857					features: mejsPlaerControls,
1858					success: function( media ) {
1859						media.addEventListener( 'timeupdate', function( event ) {
1860							var $currentTime = $scope.find( '.mejs-time-current' ),
1861								inlineStyle  = $currentTime.attr( 'style' );
1862
1863							if ( inlineStyle ) {
1864								var scaleX = inlineStyle.match(/scaleX\([0-9.]*\)/gi)[0].replace( 'scaleX(', '' ).replace( ')', '' );
1865
1866								if ( scaleX ) {
1867									$currentTime.css( 'width', scaleX * 100 + '%' );
1868								}
1869							}
1870						}, false );
1871					}
1872				} );
1873			}
1874		},
1875
1876		widgetAudio: function( $scope ) {
1877			var $wrapper    = $scope.find( '.jet-audio' ),
1878				$player     = $scope.find( '.jet-audio-player' ),
1879				settings    = $wrapper.data( 'audio-settings' ),
1880				unmuted     = 0,
1881				hasVolume   = false,
1882				startVolume;
1883
1884			if ( ! $player[0] ) {
1885				return;
1886			}
1887
1888			startVolume = settings['startVolume'] || 0.8;
1889
1890			settings['controls'].map( function( control ) {
1891				if ( 'volume' === control ) {
1892					hasVolume = true;
1893				}
1894			} );
1895
1896			$player.mediaelementplayer( {
1897				features: settings['controls'] || ['playpause', 'current', 'progress', 'duration', 'volume'],
1898				audioVolume: settings['audioVolume'] || 'horizontal',
1899				startVolume: startVolume,
1900				hideVolumeOnTouchDevices: settings['hideVolumeOnTouchDevices'],
1901				enableProgressTooltip: false,
1902				success: function( media ) {
1903					var muteBtn = $scope.find( '.mejs-button button' );
1904
1905					media.addEventListener( 'timeupdate', function( event ) {
1906						var $currentTime = $scope.find( '.mejs-time-current' ),
1907							inlineStyle  = $currentTime.attr( 'style' );
1908
1909						if ( inlineStyle ) {
1910							var scaleX = inlineStyle.match(/scaleX\([0-9.]*\)/gi)[0].replace( 'scaleX(', '' ).replace( ')', '' );
1911
1912							if ( scaleX ) {
1913								$currentTime.css( 'width', scaleX * 100 + '%' );
1914							}
1915						}
1916					}, false );
1917
1918					if ( hasVolume && 'yes' === settings['hasVolumeBar'] && !settings['hideVolumeOnTouchDevices']) {
1919						media.setVolume( startVolume );
1920						media.addEventListener( 'volumechange', function() {
1921							var volumeBar          = 'horizontal' === settings['audioVolume'] ? $scope.find( '.mejs-horizontal-volume-current' ) : $scope.find( '.mejs-volume-current' ),
1922								volumeValue        = 'horizontal' === settings['audioVolume'] ? parseInt( volumeBar[0].style.width, 10 ) / 100 : parseInt( volumeBar[0].style.height, 10 ) / 100,
1923								volumeBarTotal     = 'horizontal' === settings['audioVolume'] ? $scope.find( '.mejs-horizontal-volume-total' ) : $scope.find( '.mejs-volume-slider .mejs-volume-total' ),
1924								playBrn            = $scope.find( '.mejs-playpause-button' ),
1925								volumeCurrentValue = '';
1926
1927							volumeBarTotal.on( 'click', function() {
1928								if ( 'horizontal' === settings['audioVolume'] ) {
1929									volumeCurrentValue = parseInt( $scope.find( '.mejs-horizontal-volume-total .mejs-horizontal-volume-current' )[0].style.width, 10 ) / 100;
1930								} else {
1931									volumeCurrentValue = parseInt( $scope.find( '.mejs-volume-slider .mejs-volume-total .mejs-volume-current' )[0].style.height, 10 ) / 100;
1932								}
1933							} )
1934
1935							playBrn.on( 'click', function() {
1936								if ( '' !== volumeCurrentValue ) {
1937									media.setVolume( volumeCurrentValue );
1938								}
1939							} )
1940
1941							muteBtn.on( 'click', function() {
1942								if ( ! media.muted ) {
1943									if ( 'yes' === settings['muted'] && 0 === unmuted && 0 === volumeValue ) {
1944										media.setVolume( startVolume );
1945										unmuted = 1;
1946									}
1947								}
1948							} )
1949						}, false );
1950					} else if ( hasVolume && !settings['hideVolumeOnTouchDevices'] ) {
1951						muteBtn.on( 'click', function() {
1952							media.setVolume( startVolume );
1953						} )
1954					}
1955				}
1956			} );
1957		},
1958
1959		widgetHorizontalTimeline: function( $scope ) {
1960			var $timeline         = $scope.find( '.jet-hor-timeline' ),
1961				$timelineTrack    = $scope.find( '.jet-hor-timeline-track' ),
1962				$items            = $scope.find( '.jet-hor-timeline-item' ),
1963				$arrows           = $scope.find( '.jet-arrow' ),
1964				$nextArrow        = $scope.find( '.jet-next-arrow' ),
1965				$prevArrow        = $scope.find( '.jet-prev-arrow' ),
1966				settings          = $timeline.data( 'timeline-settings' ) || {},
1967				columns           = settings.column || {},
1968				slidesToScroll    = settings.slidesToScroll || {},
1969				firstMouseEvent   = true,
1970				currentDeviceMode = elementorFrontend.getCurrentDeviceMode(),
1971				prevDeviceMode    = currentDeviceMode,
1972				itemsCount        = $scope.find( '.jet-hor-timeline-list--middle .jet-hor-timeline-item' ).length,
1973				isRTL             = JetElementsTools.isRTL(),
1974				currentTransform  = 0,
1975				currentPosition   = 0,
1976				transform = {
1977					desktop: 100 / columns.desktop,
1978					tablet:  100 / columns.tablet,
1979					mobile:  100 / columns.mobile
1980				},
1981				maxPosition = {
1982					desktop: Math.max( 0, (itemsCount - columns.desktop) ),
1983					tablet:  Math.max( 0, (itemsCount - columns.tablet) ),
1984					mobile:  Math.max( 0, (itemsCount - columns.mobile) )
1985				};
1986
1987			if ( 'ontouchstart' in window || 'ontouchend' in window ) {
1988				$items.on( 'touchend.jetHorTimeline', function( event ) {
1989					var itemId = $( this ).data( 'item-id' );
1990
1991					$scope.find( '.elementor-repeater-item-' + itemId ).toggleClass( 'is-hover' );
1992				} );
1993			} else {
1994				$items.on( 'mouseenter.jetHorTimeline mouseleave.jetHorTimeline', function( event ) {
1995
1996					if ( firstMouseEvent && 'mouseleave' === event.type ) {
1997						return;
1998					}
1999
2000					if ( firstMouseEvent && 'mouseenter' === event.type ) {
2001						firstMouseEvent = false;
2002					}
2003
2004					var itemId = $( this ).data( 'item-id' );
2005
2006					$scope.find( '.elementor-repeater-item-' + itemId ).toggleClass( 'is-hover' );
2007				} );
2008			}
2009
2010			// Set Line Position
2011			setLinePosition();
2012			$( window ).on( 'resize.jetHorTimeline orientationchange.jetHorTimeline', JetElementsTools.debounce( 50, setLinePosition ) );
2013
2014			function setLinePosition() {
2015				var $line             = $scope.find( '.jet-hor-timeline__line' ),
2016					$firstPoint       = $scope.find( '.jet-hor-timeline-item__point-content:first' ),
2017					$lastPoint        = $scope.find( '.jet-hor-timeline-item__point-content:last' ),
2018					firstPointLeftPos = $firstPoint.position().left + parseInt( $firstPoint.css( 'marginLeft' ) ),
2019					lastPointLeftPos  = $lastPoint.position().left + parseInt( $lastPoint.css( 'marginLeft' ) ),
2020					pointWidth        = $firstPoint.outerWidth();
2021
2022				$line.css( {
2023					'left': !isRTL ? ( firstPointLeftPos + pointWidth/2 ) : ( lastPointLeftPos + pointWidth/2 ),
2024					'width': Math.abs( lastPointLeftPos - firstPointLeftPos )
2025				} );
2026			}
2027
2028			// Arrows Navigation Type
2029			if ( $nextArrow[0] && maxPosition[ currentDeviceMode ] === 0 ) {
2030				$nextArrow.addClass( 'jet-arrow-disabled' );
2031			}
2032
2033			if ( $arrows[0] ) {
2034				var slidesScroll      = slidesToScroll[ currentDeviceMode ],
2035					xPos              = 0,
2036					yPos              = 0,
2037					diffpos;
2038
2039				$arrows.on( 'click.jetHorTimeline', function( event ){
2040					var $this             = $( this ),
2041						currentDeviceMode = elementorFrontend.getCurrentDeviceMode(),
2042						direction         = $this.hasClass( 'jet-next-arrow' ) ? 'next' : 'prev',
2043						dirMultiplier     = !isRTL ? -1 : 1;
2044
2045					if ( slidesScroll > columns[ currentDeviceMode ] ) {
2046						slidesScroll = columns[ currentDeviceMode ];
2047					}
2048
2049					if ( 'next' === direction && currentPosition < maxPosition[ currentDeviceMode ] ) {
2050						currentPosition += slidesScroll;
2051
2052						if ( currentPosition > maxPosition[ currentDeviceMode ] ) {
2053							currentPosition = maxPosition[ currentDeviceMode ];
2054						}
2055					}
2056
2057					if ( 'prev' === direction && currentPosition > 0 ) {
2058						currentPosition -= slidesScroll;
2059
2060						if ( currentPosition < 0 ) {
2061							currentPosition = 0;
2062						}
2063					}
2064
2065					if ( currentPosition > 0 ) {
2066						$prevArrow.removeClass( 'jet-arrow-disabled' );
2067					} else {
2068						$prevArrow.addClass( 'jet-arrow-disabled' );
2069					}
2070
2071					if ( currentPosition === maxPosition[ currentDeviceMode ] ) {
2072						$nextArrow.addClass( 'jet-arrow-disabled' );
2073					} else {
2074						$nextArrow.removeClass( 'jet-arrow-disabled' );
2075					}
2076
2077					if ( currentPosition === 0 ) {
2078						currentTransform = 0;
2079					} else {
2080						currentTransform = currentPosition * transform[ currentDeviceMode ];
2081					}
2082
2083					$timelineTrack.css({
2084						'transform': 'translateX(' + dirMultiplier * currentTransform + '%)'
2085					});
2086
2087				} );
2088
2089				$( $items ).on( 'touchstart', function( e ) {
2090					var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
2091
2092					xPos = touch.pageX;
2093				} );
2094
2095				$( $items ).on( 'touchend', function( e ) {
2096					var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
2097
2098					yPos    = touch.pageX;
2099					diffpos = yPos - xPos;
2100
2101					if ( diffpos < -50 ) {
2102						var dirMultiplier     = !isRTL ? -1 : 1;
2103
2104						if ( slidesScroll > columns[ currentDeviceMode ] ) {
2105							slidesScroll = columns[ currentDeviceMode ];
2106						}
2107
2108						if ( currentPosition < maxPosition[ currentDeviceMode ] ) {
2109							currentPosition += slidesScroll;
2110
2111							if ( currentPosition > maxPosition[ currentDeviceMode ] ) {
2112								currentPosition = maxPosition[ currentDeviceMode ];
2113							}
2114						}
2115
2116						if ( currentPosition > 0 ) {
2117							$prevArrow.removeClass( 'jet-arrow-disabled' );
2118						} else {
2119							$prevArrow.addClass( 'jet-arrow-disabled' );
2120						}
2121
2122						if ( currentPosition === maxPosition[ currentDeviceMode ] ) {
2123							$nextArrow.addClass( 'jet-arrow-disabled' );
2124						} else {
2125							$nextArrow.removeClass( 'jet-arrow-disabled' );
2126						}
2127
2128						if ( currentPosition === 0 ) {
2129							currentTransform = 0;
2130						} else {
2131							currentTransform = currentPosition * transform[ currentDeviceMode ];
2132						}
2133
2134						$timelineTrack.css( {
2135							'transform': 'translateX(' + dirMultiplier * currentTransform + '%)'
2136						} );
2137
2138					} else if ( diffpos > 50 ) {
2139						var dirMultiplier     = !isRTL ? -1 : 1;
2140
2141						if ( slidesScroll > columns[ currentDeviceMode ] ) {
2142							slidesScroll = columns[ currentDeviceMode ];
2143						}
2144
2145						if ( currentPosition > 0 ) {
2146							currentPosition -= slidesScroll;
2147
2148							if ( currentPosition < 0 ) {
2149								currentPosition = 0;
2150							}
2151						}
2152
2153						if ( currentPosition > 0 ) {
2154							$prevArrow.removeClass( 'jet-arrow-disabled' );
2155						} else {
2156							$prevArrow.addClass( 'jet-arrow-disabled' );
2157						}
2158
2159						if ( currentPosition === maxPosition[ currentDeviceMode ] ) {
2160							$nextArrow.addClass( 'jet-arrow-disabled' );
2161						} else {
2162							$nextArrow.removeClass( 'jet-arrow-disabled' );
2163						}
2164
2165						if ( currentPosition === 0 ) {
2166							currentTransform = 0;
2167						} else {
2168							currentTransform = currentPosition * transform[ currentDeviceMode ];
2169						}
2170
2171						$timelineTrack.css( {
2172							'transform': 'translateX(' + dirMultiplier * currentTransform + '%)'
2173						} );
2174					}
2175				} );
2176			}
2177
2178			setArrowPosition();
2179			$( window ).on( 'resize.jetHorTimeline orientationchange.jetHorTimeline', setArrowPosition );
2180			$( window ).on( 'resize.jetHorTimeline orientationchange.jetHorTimeline', timelineSliderResizeHandler );
2181
2182			function setArrowPosition() {
2183				if ( ! $arrows[0] ) {
2184					return;
2185				}
2186
2187				var $middleList = $scope.find( '.jet-hor-timeline-list--middle' ),
2188					middleListTopPosition = $middleList.position().top,
2189					middleListHeight = $middleList.outerHeight();
2190
2191				$arrows.css({
2192					'top': middleListTopPosition + middleListHeight/2
2193				});
2194			}
2195
2196			function timelineSliderResizeHandler( event ) {
2197				if ( ! $timeline.hasClass( 'jet-hor-timeline--arrows-nav' ) ) {
2198					return;
2199				}
2200
2201				var currentDeviceMode = elementorFrontend.getCurrentDeviceMode(),
2202					resetSlider = function() {
2203						$prevArrow.addClass( 'jet-arrow-disabled' );
2204
2205						if ( $nextArrow.hasClass( 'jet-arrow-disabled' ) ) {
2206							$nextArrow.removeClass( 'jet-arrow-disabled' );
2207						}
2208
2209						if ( maxPosition[ currentDeviceMode ] === 0 ) {
2210							$nextArrow.addClass( 'jet-arrow-disabled' );
2211						}
2212
2213						currentTransform = 0;
2214						currentPosition = 0;
2215
2216						$timelineTrack.css({
2217							'transform': 'translateX(0%)'
2218						});
2219					};
2220
2221				switch ( currentDeviceMode ) {
2222					case 'desktop':
2223						if ( 'desktop' !== prevDeviceMode ) {
2224							resetSlider();
2225							prevDeviceMode = 'desktop';
2226						}
2227						break;
2228
2229					case 'tablet':
2230						if ( 'tablet' !== prevDeviceMode ) {
2231							resetSlider();
2232							prevDeviceMode = 'tablet';
2233						}
2234						break;
2235
2236					case 'mobile':
2237						if ( 'mobile' !== prevDeviceMode ) {
2238							resetSlider();
2239							prevDeviceMode = 'mobile';
2240						}
2241						break;
2242				}
2243			}
2244		},
2245
2246		widgetPieChart: function( $scope ) {
2247			var $container     = $scope.find( '.jet-pie-chart-container' ),
2248				$canvas        = $scope.find( '.jet-pie-chart' )[0],
2249				data           = $container.data( 'chart' ) || {},
2250				options        = $container.data( 'options' ) || {},
2251				tooltip        = $container.data( 'tooltip' ) || '',
2252				defaultOptions = {
2253					maintainAspectRatio: false
2254				};
2255
2256			options = $.extend( {}, defaultOptions, options );
2257
2258			if ( true === options.tooltips.enabled ) {
2259				options.tooltips.callbacks = {
2260					label: function( tooltipItem, data ) {
2261						return ' ' + data.labels[tooltipItem.index] + ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index] + tooltip;
2262					}
2263				};
2264			}
2265
2266			elementorFrontend.waypoint( $scope, function() {
2267				var chartInstance = new Chart( $canvas, {
2268					type:    'pie',
2269					data:    data,
2270					options: options
2271				} );
2272			}, JetElements.prepareWaypointOptions( $scope, {
2273				offset: 'bottom-in-view'
2274			} ) );
2275		},
2276
2277		widgetBarChart: function( $scope ) {
2278
2279			var $chart        = $scope.find( '.jet-bar-chart-container' ),
2280				$chart_canvas = $chart.find( '.jet-bar-chart' ),
2281				settings      = $chart.data( 'settings' ),
2282				tooltip_prefix    = $chart.data( 'tooltip-prefix' ) || '',
2283				tooltip_suffix    = $chart.data( 'tooltip-suffix' ) || '',
2284				tooltip_separator = $chart.data( 'tooltip-separator' ) || '';
2285
2286				if ( true === settings.options.tooltips.enabled ) {
2287					settings.options.tooltips.callbacks = {
2288						label: function(tooltipItem, data) {
2289							return ' ' + data.labels[tooltipItem.index] + ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
2290						}
2291					}
2292				}
2293
2294			if ( ! $chart.length ) {
2295				return;
2296			}
2297
2298			if ( true === settings.options.tooltips.enabled ) {
2299				settings.options.tooltips.callbacks = {
2300					label: function( tooltipItem, data ) {
2301						var value = '' != tooltip_separator ? JetElementsTools.addThousandCommaSeparator( data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index], tooltip_separator) : data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
2302						return ' ' + data.labels[tooltipItem.index] + ': ' + tooltip_prefix + value + tooltip_suffix;
2303					}
2304				};
2305			}
2306
2307			elementorFrontend.waypoint( $chart_canvas, function() {
2308				var $this   = $( this ),
2309					ctx     = $this[0].getContext( '2d' ),
2310					myChart = new Chart( ctx, settings );
2311			}, JetElements.prepareWaypointOptions( $scope, {
2312				offset: 'bottom-in-view'
2313
2314			} ) );
2315		},
2316		widgetLineChart: function( $scope ) {
2317			var id                  = $scope.data( 'id' ),
2318				$line_chart         = $scope.find( '.jet-line-chart-container' ),
2319				$line_chart_canvas  = $line_chart.find( '.jet-line-chart' ),
2320				$compare            = $line_chart.data( 'compare' ),
2321				previous_label      = $line_chart.data( 'previous-label' ),
2322				current_label       = $line_chart.data( 'current-label' ),
2323				settings            = $line_chart.data( 'settings' ),
2324				compare_labels_type = $line_chart.data( 'compare-labels-type' ),
2325				tooltip_prefix      = $line_chart.data( 'tooltip-prefix' ) || '',
2326				tooltip_suffix      = $line_chart.data( 'tooltip-suffix' ) || '',
2327				tooltip_separator   = $line_chart.data( 'tooltip-separator' ) || '';
2328
2329			if ( ! $line_chart.length ) {
2330				return;
2331			}
2332
2333			elementorFrontend.waypoint( $line_chart_canvas, function() {
2334
2335				var $this   = $( this ),
2336					ctx     = $this[0].getContext( '2d' ),
2337					myLineChart = new Chart( ctx, settings );
2338
2339					myLineChart.options.tooltips = {
2340						enabled:   false,
2341						mode:      'x-axis',
2342						intersect: false,
2343						callbacks: {
2344							label: function( tooltipItem, data ) {
2345								var colorBox = data.datasets[tooltipItem.datasetIndex].borderColor;
2346								colorBox = colorBox.replace( /"/g, '"' );
2347
2348								if ( true === $compare ) {
2349									var currentLabel    = 'custom' === compare_labels_type ? current_label : data.labels[tooltipItem.index],
2350										title           = data.datasets[tooltipItem.datasetIndex].label,
2351										currentVal      = '' != tooltip_separator ? JetElementsTools.addThousandCommaSeparator( data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index], tooltip_separator ) : data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index],
2352										current         = '<div class="jet-line-chart-tooltip-compare-current">' + currentLabel + ' : ' + tooltip_prefix + currentVal + tooltip_suffix + '</div>',
2353										previous        = '',
2354										compareColorBox = data.datasets[tooltipItem.datasetIndex].borderColor,
2355										compareColorBox = compareColorBox.replace( /"/g, '"' );
2356
2357									if ( typeof (data.labels[tooltipItem.index - 1]) != "undefined" && data.labels[tooltipItem.index - 1] !== null ) {
2358										var previousLabel = 'custom' === compare_labels_type ? previous_label : data.labels[tooltipItem.index - 1],
2359											previousVal   = '' != tooltip_separator ? JetElementsTools.addThousandCommaSeparator( data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index - 1], tooltip_separator ) : data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index - 1],
2360											previous      = '<div class="jet-line-chart-tooltip-compare-previous">' + previousLabel + ' : ' + tooltip_prefix + previousVal + tooltip_suffix + '</div>';
2361									}
2362
2363									return '<div class="jet-line-chart-tooltip-title"><span class="jet-line-chart-tooltip-color-box" style="background:' + compareColorBox + '"></span>' + title + '</div><div class="jet-line-chart-tooltip-body">' + current + previous + '</div>';
2364								} else {
2365									var label = data.datasets[tooltipItem.datasetIndex].label,
2366										val   = '' != tooltip_separator ? JetElementsTools.addThousandCommaSeparator( data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index], tooltip_separator ) : data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
2367									return '<div class="jet-line-chart-tooltip-body"><span class="jet-line-chart-tooltip-color-box" style="background:' + colorBox + '"></span>' + label + ' : ' + tooltip_prefix + val + tooltip_suffix + '</div>';
2368								}
2369							},
2370						},
2371						custom: function( tooltipModel ) {
2372							// Tooltip Element
2373							var tooltipEl = document.getElementById( 'chartjs-tooltip_' + id );
2374
2375							// Create element on first render
2376							if ( !tooltipEl ) {
2377								tooltipEl = document.createElement( 'div' );
2378								tooltipEl.id = 'chartjs-tooltip_' + id;
2379								tooltipEl.innerHTML = '<div class="jet-line-chart-tooltip"></div>';
2380								document.body.appendChild( tooltipEl );
2381							}
2382
2383							// Hide if no tooltip
2384							if ( tooltipModel.opacity === 0 ) {
2385								tooltipEl.style.opacity = 0;
2386								return;
2387							}
2388							// Set caret Position
2389							tooltipEl.classList.remove( 'above', 'below', 'no-transform' );
2390							if ( tooltipModel.yAlign ) {
2391								tooltipEl.classList.add( tooltipModel.yAlign );
2392							} else {
2393								tooltipEl.classList.add( 'no-transform' );
2394							}
2395
2396							function getBody( bodyItem ) {
2397								return bodyItem.lines;
2398							}
2399
2400							// Set Text
2401							if ( tooltipModel.body ) {
2402								var titleLines = tooltipModel.title || [];
2403								var bodyLines = tooltipModel.body.map( getBody );
2404								var innerHtml = '';
2405
2406								innerHtml += '<div class="jet-line-chart-tooltip-wrapper">';
2407								bodyLines.forEach( function( body, i ) {
2408									innerHtml += body;
2409								} );
2410								innerHtml += '</div>';
2411
2412								var tableRoot = tooltipEl.querySelector( 'div' );
2413								tableRoot.innerHTML = innerHtml;
2414							}
2415
2416							// `this` will be the overall tooltip
2417
2418							var _this         = this,
2419								position      = this._chart.canvas.getBoundingClientRect(),
2420								tooltipWidth  = tooltipEl.offsetWidth,
2421								tooltipHeight = tooltipEl.offsetHeight,
2422								offsetX       = 0,
2423								offsetY       = 0;
2424
2425							setTimeout( function(){
2426								tooltipWidth = tooltipEl.offsetWidth;
2427								tooltipHeight = tooltipEl.offsetHeight;
2428
2429								if ( _this._chart.width / 2 > _this._chart.tooltip._eventPosition.x ) {
2430									offsetX = 0;
2431								} else {
2432									offsetX = -tooltipWidth;
2433								}
2434
2435								if ( _this._chart.height / 2 > _this._chart.tooltip._eventPosition.y ) {
2436									offsetY = 0;
2437								} else {
2438									offsetY = -tooltipHeight;
2439								}
2440								tooltipEl.style.left = position.left + window.pageXOffset + tooltipModel.caretX + offsetX + 'px';
2441								tooltipEl.style.top = position.top + window.pageYOffset + tooltipModel.caretY + offsetY + 'px';
2442								tooltipEl.style.opacity = 1;
2443							}, 10 );
2444
2445							// Display, position, and set styles for font
2446							tooltipEl.style.position = 'absolute';
2447							tooltipEl.style.fontFamily = tooltipModel._bodyFontFamily;
2448							tooltipEl.style.fontSize = tooltipModel.bodyFontSize + 'px';
2449							tooltipEl.style.fontStyle = tooltipModel._bodyFontStyle;
2450							tooltipEl.style.padding = tooltipModel.yPadding + 'px ' + tooltipModel.xPadding + 'px';
2451							tooltipEl.style.pointerEvents = 'none';
2452						},
2453					};
2454					myLineChart.update();
2455			}, JetElements.prepareWaypointOptions( $scope, {
2456				offset: 'bottom-in-view'
2457			} ) );
2458		},
2459
2460		widgetLottie: function ( $scope ) {
2461			var $lottie     = $scope.find( '.jet-lottie' ),
2462				$lottieElem = $lottie.find( '.jet-lottie__elem' ),
2463				settings    = $lottie.data( 'settings' ),
2464				options,
2465				instance;
2466
2467			if ( ! $lottie[0] ) {
2468				return;
2469			}
2470
2471			options = {
2472				container: $lottieElem[0],
2473				renderer:  settings.renderer,
2474				loop:      '' === settings.loop_times ? settings.loop : settings.loop_times,
2475				autoplay:  false,
2476				path:      settings.path,
2477				name:      'jet-lottie'
2478			};
2479
2480			instance = lottie.loadAnimation( options );
2481
2482			if ( settings.play_speed ) {
2483				instance.setSpeed( settings.play_speed );
2484			}
2485
2486			if ( settings.reversed ) {
2487				instance.setDirection( -1 );
2488			}
2489
2490			var start = 0,
2491				end = 0;
2492
2493			if ( settings.viewport ) {
2494				start = -settings.viewport.start || 0;
2495				end = -(100 - settings.viewport.end) || 0;
2496			}
2497
2498			switch( settings.action_start ) {
2499				case 'on_hover':
2500
2501					var startFlag = false,
2502
2503						onHoverHandler = function() {
2504							if ( startFlag && 'reverse' === settings.on_hover_out ) {
2505								var reverseValue = settings.reversed ? -1 : 1;
2506								instance.setDirection( reverseValue );
2507							}
2508
2509							instance.play();
2510							startFlag = true;
2511						},
2512
2513						onHoverOutHandler = function() {
2514							switch ( settings.on_hover_out ) {
2515								case 'pause':
2516									instance.pause();
2517									break;
2518
2519								case 'stop':
2520									instance.stop();
2521									break;
2522
2523								case 'reverse':
2524									var reverseValue = settings.reversed ? 1 : -1;
2525									instance.setDirection( reverseValue );
2526									instance.play();
2527							}
2528						};
2529
2530					$lottie
2531						.off( 'mouseenter.JetLottie', onHoverHandler )
2532						.on( 'mouseenter.JetLottie', onHoverHandler );
2533
2534					$lottie
2535						.off( 'mouseleave.JetLottie', onHoverOutHandler )
2536						.on( 'mouseleave.JetLottie', onHoverOutHandler );
2537
2538					break;
2539
2540				case 'on_click':
2541
2542					var $link = $lottie.find( '.jet-lottie__link' ),
2543						redirectTimeout = +settings.redirect_timeout,
2544
2545						onClickHandler = function() {
2546							instance.play();
2547						},
2548
2549						onLinkClickHandler = function( event ) {
2550
2551							event.preventDefault();
2552
2553							instance.play();
2554
2555							var url = $( this ).attr( 'href' ),
2556								target = '_blank' === $( this ).attr( 'target' ) ? '_blank' : '_self';
2557
2558							setTimeout( function() {
2559								window.open( url, target );
2560							}, redirectTimeout );
2561						};
2562
2563					if ( $link[0] && redirectTimeout > 0 ) {
2564
2565						$link
2566							.off( 'click.JetLottie', onLinkClickHandler )
2567							.on( 'click.JetLottie', onLinkClickHandler );
2568
2569					} else {
2570						$lottie
2571							.off( 'click.JetLottie', onClickHandler )
2572							.on( 'click.JetLottie', onClickHandler );
2573					}
2574
2575					break;
2576
2577				case 'on_viewport':
2578
2579					if ( undefined !== window.IntersectionObserver ) {
2580						var observer = new IntersectionObserver(
2581							function( entries, observer ) {
2582								if ( entries[0].isIntersecting ) {
2583									instance.play();
2584								} else {
2585									instance.pause();
2586								}
2587							},
2588							{
2589								rootMargin: end +'% 0% ' + start + '%'
2590							}
2591						);
2592
2593						observer.observe( $lottie[0] );
2594					} else {
2595						instance.play();
2596					}
2597
2598					break;
2599
2600				case 'on_scroll':
2601
2602					if ( undefined !== window.IntersectionObserver ) {
2603						var scrollY = 0,
2604							requestId,
2605							scrollObserver = new IntersectionObserver(
2606								function( entries, observer ) {
2607									if ( entries[0].isIntersecting ) {
2608
2609										requestId = requestAnimationFrame( function scrollAnimation() {
2610											if ( window.scrollY !== scrollY ) {
2611												var viewportPercentage = JetElementsTools.getElementPercentageSeen( $lottieElem, { start: start, end: end } ),
2612													nextFrame = (instance.totalFrames - instance.firstFrame) * viewportPercentage / 100;
2613
2614												instance.goToAndStop( nextFrame, true );
2615												scrollY = window.scrollY;
2616											}
2617
2618											requestId = requestAnimationFrame( scrollAnimation );
2619										} );
2620									} else {
2621										cancelAnimationFrame(requestId);
2622									}
2623								},
2624								{
2625									rootMargin: end +'% 0% ' + start + '%'
2626								}
2627							);
2628
2629						scrollObserver.observe( $lottie[0] );
2630					}
2631
2632					break;
2633
2634				default:
2635					var delay = +settings.delay;
2636
2637					if ( delay > 0 ) {
2638
2639						setTimeout( function() {
2640							instance.play();
2641						}, delay );
2642
2643					} else {
2644						instance.play();
2645					}
2646			}
2647
2648		},
2649
2650		widgetPricingTable: function( $scope ) {
2651			var $target         = $scope.find( '.pricing-table' ),
2652				$tooltips       = $( '.pricing-feature .pricing-feature__inner[data-tippy-content]', $target ),
2653				settings        = $target.data( 'tooltips-settings' ),
2654				$fold_target    = $scope.find( '.pricing-table__fold-mask' ),
2655				$fold_button    = $scope.find( '.pricing-table__fold-button' ),
2656				$fold_mask      = $fold_target,
2657				$fold_content   = $( '.pricing-table__features', $fold_target ),
2658				fold_settings   = $fold_target.data( 'fold-settings' ) || {},
2659				fold_enabled    = fold_settings['fold_enabled'] || false,
2660				fold_maskHeight = 0,
2661				contentHeight   = 0,
2662				unfoldDuration  = fold_settings['unfoldDuration'],
2663				foldDuration    = fold_settings['unfoldDuration'],
2664				unfoldEasing    = fold_settings['unfoldEasing'],
2665				foldEasing      = fold_settings['foldEasing'];
2666
2667			if ( $tooltips[0] ) {
2668				$tooltips.each( function() {
2669					var $this        = $( this ),
2670						itemSelector = $this[0];
2671
2672					if ( itemSelector._tippy ) {
2673						itemSelector._tippy.destroy();
2674					}
2675
2676					tippy( [ itemSelector ], {
2677						arrow: settings['tooltipArrow'] ? true : false,
2678						duration: [ settings['tooltipShowDuration']['size'], settings['tooltipHideDuration']['size'] ],
2679						delay: settings['tooltipDelay']['size'],
2680						placement: settings['tooltipPlacement'],
2681						trigger: settings['tooltipTrigger'],
2682						animation: settings['tooltipAnimation'],
2683						appendTo: itemSelector,
2684						offset: [ 0, settings['tooltipDistance']['size'] ],
2685						allowHTML: true,
2686						popperOptions: {
2687							strategy: 'fixed',
2688						},
2689					} );
2690
2691				} );
2692			}
2693
2694			function maskHeight(){
2695				$scope.find( '.pricing-table__fold-mask .fold_visible' ).each( function() {
2696					fold_maskHeight = fold_maskHeight + $( this ).outerHeight( true );
2697				} );
2698			}
2699
2700			function fold_content_height(){
2701				contentHeight = 0;
2702				$scope.find( '.pricing-table__fold-mask .pricing-feature' ).each( function() {
2703					contentHeight = contentHeight + $( this ).outerHeight( true );
2704				} )
2705			}
2706
2707			if ( fold_enabled ) {
2708
2709				maskHeight();
2710				fold_content_height();
2711
2712				if ( !$fold_target.hasClass( 'pricing-table-unfold-state' ) ) {
2713					$fold_mask.css( {
2714						'height': fold_maskHeight
2715					} );
2716				}
2717
2718				$scope.find( '.pricing-table__fold-mask' ).css('max-height', 'none');
2719
2720				$fold_button.on( 'click.jetPricingTable', function() {
2721					var $this         = $( this ),
2722						$buttonText   = $( '.pricing-table__fold-button-text', $this ),
2723						$buttonIcon   = $( '.pricing-table__fold-button-icon', $this ),
2724						unfoldText    = $this.data( 'unfold-text' ),
2725						foldText      = $this.data( 'fold-text' ),
2726						unfoldIcon    = $this.data( 'unfold-icon' ),
2727						foldIcon      = $this.data( 'fold-icon' );
2728
2729					if ( ! $fold_target.hasClass( 'pricing-table-unfold-state' ) ) {
2730						$fold_target.addClass( 'pricing-table-unfold-state' );
2731
2732						fold_content_height();
2733
2734						$buttonIcon.html( foldIcon );
2735						$buttonText.html( foldText );
2736
2737						anime( {
2738							targets:  $fold_mask[0],
2739							height:   contentHeight,
2740							duration: unfoldDuration['size'] || unfoldDuration,
2741							easing:   unfoldEasing
2742						} );
2743					} else {
2744						$fold_target.removeClass( 'pricing-table-unfold-state' );
2745
2746						$buttonIcon.html( unfoldIcon );
2747						$buttonText.html( unfoldText );
2748
2749						anime( {
2750							targets:  $fold_mask[0],
2751							height:   fold_maskHeight,
2752							duration: foldDuration['size'] || foldDuration,
2753							easing:   foldEasing
2754						} );
2755					}
2756				} );
2757			}
2758		}
2759	};
2760
2761	$( window ).on( 'elementor/frontend/init', JetElements.init );
2762
2763	var JetElementsTools = {
2764
2765		getElementPercentageSeen: function( $element, offset ) {
2766			var offsetSettings      = offset || {},
2767				startOffset         = offsetSettings.start || 0,
2768				endOffset           = offsetSettings.end || 0,
2769				viewportHeight      = $( window ).height(),
2770				viewportStartOffset = viewportHeight * startOffset / 100,
2771				viewportEndOffset   = viewportHeight * endOffset / 100,
2772				scrollTop           = $( window ).scrollTop(),
2773				elementOffsetTop    = $element.offset().top,
2774				elementHeight       = $element.height(),
2775				percentage;
2776
2777			percentage = (scrollTop + viewportHeight + viewportStartOffset - elementOffsetTop) / (viewportHeight + viewportStartOffset + viewportEndOffset + elementHeight);
2778			percentage = Math.min( 100, Math.max( 0, percentage * 100 ) );
2779
2780			return parseFloat( percentage.toFixed( 2 ) );
2781		},
2782
2783		isRTL: function() {
2784			return $( 'body' ).hasClass( 'rtl' );
2785		},
2786
2787		inArray: function( needle, haystack ) {
2788			return -1 < haystack.indexOf( needle );
2789		},
2790
2791		debounce: function( threshold, callback ) {
2792			var timeout;
2793
2794			return function debounced( $event ) {
2795				function delayed() {
2796					callback.call( this, $event );
2797					timeout = null;
2798				}
2799
2800				if ( timeout ) {
2801					clearTimeout( timeout );
2802				}
2803
2804				timeout = setTimeout( delayed, threshold );
2805			};
2806		},
2807
2808		getObjectNextKey: function( object, key ) {
2809			var keys      = Object.keys( object ),
2810				idIndex   = keys.indexOf( key ),
2811				nextIndex = idIndex += 1;
2812
2813			if( nextIndex >= keys.length ) {
2814				//we're at the end, there is no next
2815				return false;
2816			}
2817
2818			var nextKey = keys[ nextIndex ];
2819
2820			return nextKey;
2821		},
2822
2823		getObjectPrevKey: function( object, key ) {
2824			var keys      = Object.keys( object ),
2825				idIndex   = keys.indexOf( key ),
2826				prevIndex = idIndex -= 1;
2827
2828			if ( 0 > idIndex ) {
2829				//we're at the end, there is no next
2830				return false;
2831			}
2832
2833			var prevKey = keys[ prevIndex ];
2834
2835			return prevKey;
2836		},
2837
2838		getObjectFirstKey: function( object ) {
2839			return Object.keys( object )[0];
2840		},
2841
2842		getObjectLastKey: function( object ) {
2843			return Object.keys( object )[ Object.keys( object ).length - 1 ];
2844		},
2845
2846		getObjectValues: function( object ) {
2847			var values;
2848
2849			if ( !Object.values ) {
2850				values = Object.keys( object ).map( function( e ) {
2851					return object[e]
2852				} );
2853
2854				return values;
2855			}
2856
2857			return Object.values( object );
2858		},
2859
2860		validateEmail: function( email ) {
2861			var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
2862
2863			return re.test( email );
2864		},
2865
2866		mobileAndTabletcheck: function() {
2867			var check = false;
2868
2869			(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|
2869sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
2870
2871			return check;
2872		},
2873
2874		addThousandCommaSeparator: function ( nStr, separator ) {
2875			var nStr = nStr + '',
2876				x    = nStr.split('.'),
2877				x1   = x[0],
2878				x2   = x.length > 1 ? '.' + x[1] : '',
2879				rgx  = /(\d+)(\d{3})/;
2880
2881			while ( rgx.test(x1) ) {
2882				x1 = x1.replace(rgx, '$1' + separator + '$2');
2883			}
2884
2885			return x1 + x2;
2886		},
2887
2888		getElementorElementSettings: function( $scope ) {
2889
2890			if ( window.elementorFrontend && window.elementorFrontend.isEditMode() && $scope.hasClass( 'elementor-element-edit-mode' ) ) {
2891				return JetElementsTools.getEditorElementSettings( $scope );
2892			}
2893
2894			return $scope.data( 'settings' ) || {};
2895		},
2896
2897		getEditorElementSettings: function( $scope ) {
2898			var modelCID = $scope.data( 'model-cid' ),
2899				elementData;
2900
2901			if ( ! modelCID ) {
2902				return {};
2903			}
2904
2905			if ( ! elementor.hasOwnProperty( 'config' ) ) {
2906				return {};
2907			}
2908
2909			if ( ! elementor.config.hasOwnProperty( 'elements' ) ) {
2910				return {};
2911			}
2912
2913			if ( ! elementor.config.elements.hasOwnProperty( 'data' ) ) {
2914				return {};
2915			}
2916
2917			elementData = elementor.config.elements.data[ modelCID ];
2918
2919			if ( ! elementData ) {
2920				return {};
2921			}
2922
2923			return elementData.toJSON();
2924		}
2925	}
2926
2927	/**
2928	 * Jet animated text Class
2929	 *
2930	 * @return {void}
2931	 */
2932	window.jetAnimatedText = function( $selector, settings ) {
2933		var self                   = this,
2934			$instance              = $selector,
2935			$animatedTextContainer = $( '.jet-animated-text__animated-text', $instance ),
2936			$animatedTextList      = $( '.jet-animated-text__animated-text-item', $animatedTextContainer ),
2937			timeOut                = null,
2938			defaultSettings        = {
2939				effect: 'fx1',
2940				delay: 3000
2941			},
2942			settings               =  $.extend( defaultSettings, settings || {} ),
2943			currentIndex           = 0,
2944			animationDelay         = settings.delay;
2945
2946		/**
2947		 * Avaliable Effects
2948		 */
2949		self.avaliableEffects = {
2950			'fx1' : {
2951				in: {
2952					duration: 1000,
2953					delay: function( el, index ) { return 75 + index * 100; },
2954					easing: 'easeOutElastic',
2955					elasticity: 650,
2956					opacity: {
2957						value: [ 0, 1 ],
2958						easing: 'easeOutExpo',
2959					},
2960					translateY: ['100%','0%']
2961				},
2962				out: {
2963					duration: 300,
2964					delay: function(el, index) { return index*40; },
2965					easing: 'easeInOutExpo',
2966					opacity: 0,
2967					translateY: '-100%'
2968				}
2969			},
2970			'fx2' : {
2971				in: {
2972					duration: 800,
2973					delay: function( el, index) { return index * 50; },
2974					easing: 'easeOutElastic',
2975					opacity: {
2976						value: [ 0, 1 ],
2977						easing: 'easeOutExpo',
2978					},
2979					translateY: function(el, index) {
2980						return index%2 === 0 ? ['-80%', '0%'] : ['80%', '0%'];
2981					}
2982				},
2983				out: {
2984					duration: 300,
2985					delay: function( el, index ) { return index * 20; },
2986					easing: 'easeOutExpo',
2987					opacity: 0,
2988					translateY: function( el, index ) {
2989						return index%2 === 0 ? '80%' : '-80%';
2990					}
2991				}
2992			},
2993			'fx3' : {
2994				in: {
2995					duration: 700,
2996					delay: function(el, index) {
2997						return ( el.parentNode.children.length - index - 1 ) * 80;
2998					},
2999					easing: 'easeOutElastic',
3000					opacity: {
3001						value: [ 0, 1 ],
3002						easing: 'easeOutExpo',
3003					},
3004					translateY: function(el, index) {
3005						return index%2 === 0 ? [ '-80%', '0%' ] : [ '80%', '0%' ];
3006					},
3007					rotateZ: [90,0]
3008				},
3009				out: {
3010					duration: 300,
3011					delay: function(el, index) { return (el.parentNode.children.length-index-1) * 50; },
3012					easing: 'easeOutExpo',
3013					opacity: 0,
3014					translateY: function(el, index) {
3015						return index%2 === 0 ? '80%' : '-80%';
3016					},
3017					rotateZ: function(el, index) {
3018						return index%2 === 0 ? -25 : 25;
3019					}
3020				}
3021			},
3022			'fx4' : {
3023				in: {
3024					duration: 700,
3025					delay: function( el, index ) { return 550 + index * 50; },
3026					easing: 'easeOutQuint',
3027					opacity: {
3028						value: [ 0, 1 ],
3029						easing: 'easeOutExpo',
3030					},
3031					translateY: [ '-150%','0%' ],
3032					rotateY: [ 180, 0 ]
3033				},
3034				out: {
3035					duration: 200,
3036					delay: function( el, index ) { return index * 30; },
3037					easing: 'easeInQuint',
3038					opacity: {
3039						value: 0,
3040						easing: 'linear',
3041					},
3042					translateY: '100%',
3043					rotateY: -180
3044				}
3045			},
3046			'fx5' : {
3047				in: {
3048					duration: 250,
3049					delay: function( el, index ) { return 200 + index * 25; },
3050					easing: 'easeOutCubic',
3051					opacity: {
3052						value: [ 0, 1 ],
3053						easing: 'easeOutExpo',
3054					},
3055					translateY: ['-50%','0%']
3056				},
3057				out: {
3058					duration: 250,
3059					delay: function( el, index ) { return index * 25; },
3060					easing: 'easeOutCubic',
3061					opacity: 0,
3062					translateY: '50%'
3063				}
3064			},
3065			'fx6' : {
3066				in: {
3067					duration: 400,
3068					delay: function( el, index ) { return index * 50; },
3069					easing: 'easeOutSine',
3070					opacity: {
3071						value: [ 0, 1 ],
3072						easing: 'easeOutExpo',
3073					},
3074					rotateY: [ -90, 0 ]
3075				},
3076				out: {
3077					duration: 200,
3078					delay: function( el, index ) { return index * 50; },
3079					easing: 'easeOutSine',
3080					opacity: 0,
3081					rotateY: 45
3082				}
3083			},
3084			'fx7' : {
3085				in: {
3086					duration: 1000,
3087					delay: function( el, index ) { return 100 + index * 30; },
3088					easing: 'easeOutElastic',
3089					opacity: {
3090						value: [ 0, 1 ],
3091						easing: 'easeOutExpo',
3092					},
3093					rotateZ: function( el, index ) {
3094						return [ anime.random( 20, 40 ), 0 ];
3095					}
3096				},
3097				out: {
3098					duration: 300,
3099					opacity: {
3100						value: [ 1, 0 ],
3101						easing: 'easeOutExpo',
3102					}
3103				}
3104			},
3105			'fx8' : {
3106				in: {
3107					duration: 400,
3108					delay: function( el, index ) { return 200 + index * 20; },
3109					easing: 'easeOutExpo',
3110					opacity: 1,
3111					rotateY: [ -90, 0 ],
3112					translateY: [ '50%','0%' ]
3113				},
3114				out: {
3115					duration: 250,
3116					delay: function( el, index ) { return index * 20; },
3117					easing: 'easeOutExpo',
3118					opacity: 0,
3119					rotateY: 90
3120				}
3121			},
3122			'fx9' : {
3123				in: {
3124					duration: 400,
3125					delay: function(el, index) { return 200+index*30; },
3126					easing: 'easeOutExpo',
3127					opacity: 1,
3128					rotateX: [90,0]
3129				},
3130				out: {
3131					duration: 250,
3132					delay: function(el, index) { return index*30; },
3133					easing: 'easeOutExpo',
3134					opacity: 0,
3135					rotateX: -90
3136				}
3137			},
3138			'fx10' : {
3139				in: {
3140					duration: 400,
3141					delay: function( el, index ) { return 100 + index * 50; },
3142					easing: 'easeOutExpo',
3143					opacity: {
3144						value: [ 0, 1 ],
3145						easing: 'easeOutExpo',
3146					},
3147					rotateX: [ 110, 0 ]
3148				},
3149				out: {
3150					duration: 250,
3151					delay: function( el, index ) { return index * 50; },
3152					easing: 'easeOutExpo',
3153					opacity: 0,
3154					rotateX: -110
3155				}
3156			},
3157			'fx11' : {
3158				in: {
3159					duration: function( el, index ) { return anime.random( 800, 1000 ); },
3160					delay: function( el, index ) { return anime.random( 100, 300 ); },
3161					easing: 'easeOutExpo',
3162					opacity: {
3163						value: [ 0, 1 ],
3164						easing: 'easeOutExpo',
3165					},
3166					translateY: [ '-150%','0%' ],
3167					rotateZ: function( el, index ) { return [ anime.random( -50, 50 ), 0 ]; }
3168				},
3169				out: {
3170					duration: function( el, index ) { return anime.random( 200, 300 ); },
3171					delay: function( el, index ) { return anime.random( 0, 80 ); },
3172					easing: 'easeInQuart',
3173					opacity: 0,
3174					translateY: '50%',
3175					rotateZ: function( el, index ) { return anime.random( -50, 50 ); }
3176				}
3177			},
3178			'fx12' : {
3179				in: {
3180					elasticity: false,
3181					duration: 1,
3182					delay: function( el, index ) {
3183						var delay = index * 100 + anime.random( 50, 100 );
3184
3185						return delay;
3186					},
3187					width: [ 0, function( el, i ) { return $( el ).width(); } ]
3188				},
3189				out: {
3190					duration: 1,
3191					delay: function( el, index ) { return ( el.parentNode.children.length - index - 1 ) * 20; },
3192					easing: 'linear',
3193					width: {
3194						value: 0
3195					}
3196				}
3197			}
3198		};
3199
3200		self.textChange = function() {
3201			var currentDelay = animationDelay,
3202				$prevText    = $animatedTextList.eq( currentIndex ),
3203				$nextText;
3204
3205			if ( currentIndex < $animatedTextList.length - 1 ) {
3206				currentIndex++;
3207			} else {
3208				currentIndex = 0;
3209			}
3210
3211			$nextText = $animatedTextList.eq( currentIndex );
3212
3213			self.hideText( $prevText, settings.effect, null, function( anime ) {
3214				$prevText.toggleClass( 'visible' );
3215
3216				var currentDelay = animationDelay;
3217
3218				if ( timeOut ) {
3219					clearTimeout( timeOut );
3220				}
3221
3222				self.showText(
3223					$nextText,
3224					settings.effect,
3225					function() {
3226						$nextText.toggleClass( 'active' );
3227						$prevText.toggleClass( 'active' );
3228
3229						$nextText.toggleClass( 'visible' );
3230					},
3231					function() {
3232						timeOut = setTimeout( function() {
3233							self.textChange();
3234						}, currentDelay );
3235					}
3236				);
3237
3238			} );
3239		};
3240
3241		self.showText = function( $selector, effect, beginCallback, completeCallback ) {
3242			var targets = [];
3243
3244			$( 'span', $selector ).each( function() {
3245				$( this ).css( {
3246					'width': 'auto',
3247					'opacity': 1,
3248					'WebkitTransform': '',
3249					'transform': ''
3250				});
3251				targets.push( this );
3252			});
3253
3254			self.animateText( targets, 'in', effect, beginCallback, completeCallback );
3255		};
3256
3257		self.hideText = function( $selector, effect, beginCallback, completeCallback ) {
3258			var targets = [];
3259
3260			$( 'span', $selector ).each( function() {
3261				targets.push(this);
3262			});
3263
3264			self.animateText( targets, 'out', effect, beginCallback, completeCallback );
3265		};
3266
3267		self.animateText = function( targets, direction, effect, beginCallback, completeCallback ) {
3268			var effectSettings   = self.avaliableEffects[ effect ] || {},
3269				animationOptions = effectSettings[ direction ],
3270				animeInstance = null;
3271
3272			animationOptions.targets = targets;
3273
3274			animationOptions.begin = beginCallback;
3275			animationOptions.complete = completeCallback;
3276
3277			animeInstance = anime( animationOptions );
3278		};
3279
3280		self.init = function() {
3281			var $text = $animatedTextList.eq( currentIndex );
3282
3283			self.showText(
3284				$text,
3285				settings.effect,
3286				null,
3287				function() {
3288					var currentDelay = animationDelay;
3289
3290					if ( timeOut ) {
3291						clearTimeout( timeOut );
3292					}
3293
3294					timeOut = setTimeout( function() {
3295						self.textChange();
3296					}, currentDelay );
3297
3298				}
3299			);
3300		};
3301	}
3302
3303	/**
3304	 * Jet Images Layout Class
3305	 *
3306	 * @return {void}
3307	 */
3308	window.jetImagesLayout = function( $selector, settings ) {
3309		var self            = this,
3310			$instance       = $selector,
3311			$instanceList   = $( '.jet-images-layout__list', $instance ),
3312			$itemsList      = $( '.jet-images-layout__item', $instance ),
3313			defaultSettings = {},
3314			editMode        = Boolean( elementor.isEditMode() ),
3315			settings        = settings || {};
3316
3317		/*
3318		 * Default Settings
3319		 */
3320		defaultSettings = {
3321			layoutType: 'masonry',
3322			justifyHeight: 300
3323		}
3324
3325		/**
3326		 * Checking options, settings and options merging
3327		 */
3328		$.extend( defaultSettings, settings );
3329
3330		/**
3331		 * Layout build
3332		 */
3333		self.layoutBuild = function() {
3334			switch ( settings['layoutType'] ) {
3335				case 'masonry':
3336					salvattore.init();
3337				break;
3338				case 'justify':
3339					$itemsList.each( function() {
3340						var $this          = $( this ),
3341							$imageInstance = $( '.jet-images-layout__image-instance', $this),
3342							imageWidth     = $imageInstance.data( 'width' ),
3343							imageHeight    = $imageInstance.data( 'height' ),
3344							imageRatio     = +imageWidth / +imageHeight,
3345							flexValue      = imageRatio * 100,
3346							newWidth       = +settings['justifyHeight'] * imageRatio,
3347							newHeight      = 'auto';
3348
3349						$this.css( {
3350							'flex-grow': flexValue,
3351							'flex-basis': newWidth
3352						} );
3353					} );
3354				break;
3355			}
3356
3357			if ( $.isFunction( $.fn.imagesLoaded ) ) {
3358
3359				$( '.jet-images-layout__image', $itemsList ).imagesLoaded().progress( function( instance, image ) {
3360					var $image      = $( image.img ),
3361						$parentItem = $image.closest( '.jet-images-layout__item' ),
3362						$loader     = $( '.jet-images-layout__image-loader', $parentItem );
3363
3364					$parentItem.addClass( 'image-loaded' );
3365
3366					$loader.fadeTo( 500, 0, function() {
3367						$( this ).remove();
3368					} );
3369
3370				});
3371
3372			} else {
3373				var $loader = $( '.jet-images-layout__image-loader', $itemsList );
3374
3375				$itemsList.addClass( 'image-loaded' );
3376
3377				$loader.fadeTo( 500, 0, function() {
3378					$( this ).remove();
3379				} );
3380			}
3381		}
3382
3383		/**
3384		 * Init
3385		 */
3386		self.init = function() {
3387			self.layoutBuild();
3388		}
3389	}
3390
3391	/**
3392	 * Jet Scroll Navigation Class
3393	 *
3394	 * @return {void}
3395	 */
3396	window.jetScrollNavigation = function( $scope, $selector, settings ) {
3397		var self            = this,
3398			$window         = $( window ),
3399			$document       = $( document ),
3400			$body           = $( 'body' ),
3401			$instance       = $selector,
3402			$htmlBody       = $( 'html, body' ),
3403			$itemsList      = $( '.jet-scroll-navigation__item', $instance ),
3404			sectionList     = [],
3405			defaultSettings = {
3406				speed: 500,
3407				blockSpeed: 500,
3408				offset: 0,
3409				sectionSwitch: false,
3410				sectionSwitchOnMobile: true,
3411			},
3412			settings        = $.extend( {}, defaultSettings, settings ),
3413			sections        = {},
3414			currentSection  = null,
3415			isScrolling     = false,
3416			isSwipe         = false,
3417			hash            = window.location.hash.slice(1),
3418			timeout         = null,
3419			timeStamp       = 0,
3420			platform        = navigator.platform;
3421
3422		jQuery.extend( jQuery.easing, {
3423			easeInOutCirc: function (x, t, b, c, d) {
3424				if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
3425				return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
3426			}
3427		});
3428
3429		/**
3430		 * [init description]
3431		 * @return {[type]} [description]
3432		 */
3433		self.init = function() {
3434			self.setSectionsData();
3435
3436			if ( hash && sections.hasOwnProperty( hash ) ) {
3437				$itemsList.addClass( 'invert' );
3438			}
3439
3440			// Add Events
3441			$itemsList.on( 'click.jetScrollNavigation', function( event ) {
3442				var $this     = $( this ),
3443					sectionId = $this.data( 'anchor' );
3444
3445				self.onAnchorChange( sectionId );
3446			} );
3447
3448			$window.on( 'resize.jetScrollNavigation orientationchange.jetScrollNavigation', JetElementsTools.debounce( 50, self.onResize ) );
3449			$window.on( 'load', function() { self.setSectionsData(); } );
3450
3451			$document.keydown( function( event ) {
3452				if ( !self.isEnabled() ) {
3453					return;
3454				}
3455
3456				if ( 38 == event.keyCode ) {
3457					self.directionSwitch( event, 'up' );
3458				}
3459
3460				if ( 40 == event.keyCode ) {
3461					self.directionSwitch( event, 'down' );
3462				}
3463			} );
3464
3465			// waypoint section detection
3466			self.waypointHandler();
3467
3468			// hijaking handler
3469			self.hijakingHandler();
3470
3471			// init resizeSensor.js
3472			if ( 'undefined' !== typeof ResizeSensor ) {
3473				new ResizeSensor( $( '.jet-scroll-navigation-section' ), JetElementsTools.debounce( 50, function() {
3474					self.setSectionsData();
3475					self.waypointHandler();
3476				} ) );
3477			}
3478		};
3479
3480		/**
3481		 * [setSectionsData description]
3482		 */
3483		self.setSectionsData = function() {
3484			$itemsList.each( function() {
3485				var $this         = $( this ),
3486					sectionId     = $this.data('anchor'),
3487					sectionInvert = 'yes' === $this.data('invert') ? true : false,
3488					$section      = $( '#' + sectionId );
3489
3490				if ( $section[0] ) {
3491					$section.addClass( 'jet-scroll-navigation-section' );
3492					//$section.attr( 'touch-action', 'none' );
3493					$section[0].dataset.sectionName = sectionId;
3494					sections[ sectionId ] = {
3495						selector: $section,
3496						offset: Math.round( $section.offset().top ),
3497						height: $section.outerHeight(),
3498						invert: sectionInvert
3499					};
3500				}
3501			} );
3502		};
3503
3504		/**
3505		 * [waypointHandler description]
3506		 * @return {[type]} [description]
3507		 */
3508		self.waypointHandler = function() {
3509
3510			for ( var section in sections ) {
3511				var $section = sections[section].selector;
3512
3513				elementorFrontend.waypoint( $section, function( direction ) {
3514					var $this = $( this ),
3515						sectionId = $this.attr( 'id' );
3516
3517						if ( 'down' === direction && ! isScrolling ) {
3518							window.history.pushState( null, null, '#' + sectionId );
3519							currentSection = sectionId;
3520							$itemsList.removeClass( 'active' );
3521							$( '[data-anchor=' + sectionId + ']', $instance ).addClass( 'active' );
3522
3523							$itemsList.removeClass( 'invert' );
3524
3525							if ( sections[sectionId].invert ) {
3526								$itemsList.addClass( 'invert' );
3527							}
3528						}
3529				}, {
3530					offset: '70%',
3531					triggerOnce: false
3532				} );
3533
3534				elementorFrontend.waypoint( $section, function( direction ) {
3535					var $this = $( this ),
3536						sectionId = $this.attr( 'id' );
3537
3538						if ( 'up' === direction && ! isScrolling ) {
3539							window.history.pushState( null, null, '#' + sectionId );
3540							currentSection = sectionId;
3541							$itemsList.removeClass( 'active' );
3542							$( '[data-anchor=' + sectionId + ']', $instance ).addClass( 'active' );
3543
3544							$itemsList.removeClass( 'invert' );
3545
3546							if ( sections[sectionId].invert ) {
3547								$itemsList.addClass( 'invert' );
3548							}
3549						}
3550				}, {
3551					offset: '0%',
3552					triggerOnce: false
3553				} );
3554			}
3555		};
3556
3557		/**
3558		 * [onAnchorChange description]
3559		 * @param  {[type]} event [description]
3560		 * @return {[type]}       [description]
3561		 */
3562		self.onAnchorChange = function( sectionId ) {
3563			var $this     = $( '[data-anchor=' + sectionId + ']', $instance ),
3564				offset    = null;
3565
3566			if ( ! sections.hasOwnProperty( sectionId ) ) {
3567				return false;
3568			}
3569
3570			offset = sections[sectionId].offset - settings.offset;
3571
3572			if ( ! isScrolling ) {
3573				isScrolling = true;
3574
3575				window.history.pushState( null, null, '#' + sectionId );
3576				currentSection = sectionId;
3577
3578				$itemsList.removeClass( 'active' );
3579				$this.addClass( 'active' );
3580
3581				$itemsList.removeClass( 'invert' );
3582
3583				if ( sections[sectionId].invert ) {
3584					$itemsList.addClass( 'invert' );
3585				}
3586
3587				$htmlBody.animate( { 'scrollTop': offset }, settings.speed, 'easeInOutCirc', function() {
3588					isScrolling = false;
3589				} );
3590			}
3591		};
3592
3593		/**
3594		 * [directionSwitch description]
3595		 * @param  {[type]} event     [description]
3596		 * @param  {[type]} direction [description]
3597		 * @return {[type]}           [description]
3598		 */
3599		self.directionSwitch = function( event, direction ) {
3600			var direction = direction || 'up',
3601				nextItem = $( '[data-anchor=' + currentSection + ']', $instance ).next(),
3602				prevItem = $( '[data-anchor=' + currentSection + ']', $instance ).prev();
3603
3604			if ( isScrolling ) {
3605				return false;
3606			}
3607
3608			if ( 'up' === direction ) {
3609				if ( prevItem[0] ) {
3610					prevItem.trigger( 'click.jetScrollNavigation' );
3611				}
3612			}
3613
3614			if ( 'down' === direction ) {
3615				if ( nextItem[0] ) {
3616					nextItem.trigger( 'click.jetScrollNavigation' );
3617				}
3618			}
3619		};
3620
3621		/**
3622		 * [scrollifyHandler description]
3623		 * @return {[type]} [description]
3624		 */
3625		self.hijakingHandler = function() {
3626			var isMobile    = JetElementsTools.mobileAndTabletcheck(),
3627				touchStartY = 0,
3628				touchEndY   = 0;
3629
3630			if ( settings.sectionSwitch ) {
3631
3632				if ( ! isMobile ) {
3633					document.addEventListener( 'wheel', self.onWheel, { passive: false } );
3634				}
3635
3636				if ( isMobile && settings['sectionSwitchOnMobile'] ) {
3637
3638					document.addEventListener( 'touchstart', function( event ) {
3639						if ( !self.isEnabled() ) {
3640							return;
3641						}
3642
3643						var $target   = $( event.target ),
3644							$section  = $target.closest( '.elementor-top-section' ),
3645							sectionId = $section.attr( 'id' ) || false;
3646
3647						touchStartY = event.changedTouches[0].clientY; // clientY instead of screenY, screenY is implemented differently in iOS, making it useless for thresholding
3648
3649						if ( sectionId && isScrolling ) {
3650							event.preventDefault();
3651						}
3652
3653					}, { passive: false } );
3654
3655					document.addEventListener( 'touchend', function( event ) {
3656						if ( !self.isEnabled() ) {
3657							return;
3658						}
3659
3660						var $target         = $( event.target ),
3661							$navigation     = $target.closest( '.jet-scroll-navigation' ) || false,
3662							$section        = $target.closest( '.elementor-top-section' ) || false,
3663							sectionId       = $section.attr( 'id' ) || false,
3664							endScrollTop    = $window.scrollTop(),
3665							touchEndY       = event.changedTouches[0].clientY,
3666							direction       = touchEndY > touchStartY ? 'up' : 'down',
3667							sectionOffset   = false,
3668							newSectionId    = false,
3669							prevSectionId   = false,
3670							nextSectionId   = false,
3671							swipeYthreshold = (window.screen.availHeight / 8); // defining pageswitch threshold at 1/8 of screenheight
3672
3673						if ( Math.abs( touchEndY - touchStartY ) < 20 ) {
3674							return false;
3675						}
3676
3677						if ( $navigation[0] ) {
3678							return false;
3679						}
3680
3681						if ( sectionId && sections.hasOwnProperty( sectionId ) ) {
3682
3683							prevSectionId = JetElementsTools.getObjectPrevKey( sections, sectionId );
3684							nextSectionId = JetElementsTools.getObjectNextKey( sections, sectionId );
3685
3686							sectionOffset = sections[ sectionId ].offset;
3687
3688							if ( 'up' === direction ) {
3689
3690								if ( sectionOffset - swipeYthreshold < endScrollTop ) { //threshold used here
3691									prevSectionId = sectionId;
3692								}
3693
3694								if ( prevSectionId ) {
3695									newSectionId = prevSectionId;
3696								}
3697							}
3698
3699							if ( 'down' === direction ) {
3700
3701								if ( sectionOffset + swipeYthreshold > endScrollTop ) { //threshold used here
3702									nextSectionId = sectionId;
3703								}
3704
3705								if ( nextSectionId ) {
3706									newSectionId = nextSectionId;
3707								}
3708							}
3709
3710							if ( newSectionId ) {
3711
3712								self.onAnchorChange( newSectionId );
3713							}
3714						}
3715
3716					}, { passive: false } );
3717				}
3718			}
3719		}
3720
3721		/**
3722		 * [onScroll description]
3723		 * @param  {[type]} event [description]
3724		 * @return {[type]}       [description]
3725		 */
3726		self.onScroll = function( event ) {
3727			event.preventDefault();
3728		};
3729
3730		self.onWheel = function( event ) {
3731
3732			if ( !self.isEnabled() ) {
3733				return;
3734			}
3735
3736			if ( isScrolling ) {
3737				event.preventDefault();
3738			}
3739
3740			var $target         = $( event.target ),
3741				$section        = $target.closest( '.elementor-top-section[id]' ),
3742				sectionId       = $section.attr( 'id' ) || false,
3743				delta           = event.deltaY,
3744				direction       = ( 0 > delta ) ? 'up' : 'down',
3745				sectionOffset   = false,
3746				newSectionId    = false,
3747				prevSectionId   = false,
3748				nextSectionId   = false,
3749				windowScrollTop = $window.scrollTop();
3750
3751			if ( sectionId && sections.hasOwnProperty( sectionId ) ) {
3752
3753				prevSectionId = JetElementsTools.getObjectPrevKey( sections, sectionId );
3754				nextSectionId = JetElementsTools.getObjectNextKey( sections, sectionId );
3755
3756				sectionOffset = sections[ sectionId ].offset;
3757
3758				if ( 'up' === direction ) {
3759
3760					if ( sectionOffset < windowScrollTop + settings.offset - 10 ) {
3761						prevSectionId = sectionId;
3762					}
3763
3764					if ( prevSectionId ) {
3765						newSectionId = prevSectionId;
3766					}
3767				}
3768
3769				if ( 'down' === direction ) {
3770
3771					if ( sectionOffset > windowScrollTop + settings.offset + 10 ) {
3772						nextSectionId = sectionId;
3773					}
3774
3775					if ( nextSectionId ) {
3776						newSectionId = nextSectionId;
3777					}
3778				}
3779
3780				if ( newSectionId ) {
3781					event.preventDefault();
3782
3783					if ( event.timeStamp - timeStamp > 15 && 'MacIntel' == platform ) {
3784						timeStamp = event.timeStamp;
3785
3786						return false;
3787					}
3788
3789					self.onAnchorChange( newSectionId );
3790				}
3791			}
3792
3793			return false;
3794		};
3795
3796		/**
3797		 * [onResize description]
3798		 * @param  {[type]} event [description]
3799		 * @return {[type]}       [description]
3800		 */
3801		self.onResize = function( event ) {
3802			self.setSectionsData();
3803		};
3804
3805		/**
3806		 * [scrollStop description]
3807		 * @return {[type]} [description]
3808		 */
3809		self.scrollStop = function() {
3810			$htmlBody.stop( true );
3811		};
3812
3813		/**
3814		 * Is the responsive breakpoint enabled
3815		 *
3816		 * @return {boolean} Enabled
3817		 */
3818		self.isEnabled = function() {
3819			return $scope.is(":visible");
3820		};
3821
3822		/**
3823		 * Mobile and tablet check funcion.
3824		 *
3825		 * @return {boolean} Mobile Status
3826		 */
3827		self.mobileAndTabletcheck = function() {
3828			var check = false;
3829
3830			(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
3831
3832			return check;
3833		};
3834
3835	}
3836
3837	/**
3838	 * jetSectionParallax Class
3839	 *
3840	 * @return {void}
3841	 */
3842	window.jetSectionParallax = function( $target ) {
3843		var self             = this,
3844			sectionId        = $target.data('id'),
3845			settings         = false,
3846			editMode         = Boolean( elementor.isEditMode() ),
3847			$window          = $( window ),
3848			$body            = $( 'body' ),
3849			scrollLayoutList = [],
3850			mouseLayoutList  = [],
3851			winScrollTop     = $window.scrollTop(),
3852			winHeight        = $window.height(),
3853			requesScroll     = null,
3854			requestMouse     = null,
3855			tiltx            = 0,
3856			tilty            = 0,
3857			isSafari         = !!navigator.userAgent.match(/Version\/[\d\.]+.*Safari/),
3858			platform         = navigator.platform;
3859
3860		/**
3861		 * Init
3862		 */
3863		self.init = function() {
3864
3865			if ( ! editMode ) {
3866				settings = $target.data('settings') || false;
3867				settings = false != settings ? settings['jet_parallax_layout_list'] : false;
3868			} else {
3869				settings = self.generateEditorSettings( sectionId );
3870			}
3871
3872			if ( ! settings ) {
3873				return false;
3874			}
3875
3876			self.generateLayouts();
3877
3878			$window.on( 'resize.jetSectionParallax orientationchange.jetSectionParallax', JetElementsTools.debounce( 30, self.generateLayouts ) );
3879
3880			if ( 0 !== scrollLayoutList.length ) {
3881				$window.on( 'scroll.jetSectionParallax resize.jetSectionParallax', self.scrollHandler );
3882			}
3883
3884			if ( 0 !== mouseLayoutList.length ) {
3885				$target.on( 'mousemove.jetSectionParallax resize.jetSectionParallax', self.mouseMoveHandler );
3886				$target.on( 'mouseleave.jetSectionParallax', self.mouseLeaveHandler );
3887			}
3888
3889			self.scrollUpdate();
3890		};
3891
3892		self.generateEditorSettings = function( sectionId ) {
3893			var editorElements      = null,
3894				sectionsData        = {},
3895				sectionData         = {},
3896				sectionParallaxData = {},
3897				settings            = [];
3898
3899			if ( ! window.elementor.hasOwnProperty( 'elements' ) ) {
3900				return false;
3901			}
3902
3903			editorElements = window.elementor.elements;
3904
3905			if ( ! editorElements.models ) {
3906				return false;
3907			}
3908
3909			$.each( editorElements.models, function( index, obj ) {
3910				if ( sectionId == obj.id ) {
3911					sectionData = obj.attributes.settings.attributes;
3912				}
3913			} );
3914
3915			if ( ! sectionData.hasOwnProperty( 'jet_parallax_layout_list' ) || 0 === Object.keys( sectionData ).length ) {
3916				return false;
3917			}
3918
3919			sectionParallaxData = sectionData[ 'jet_parallax_layout_list' ].models;
3920
3921			$.each( sectionParallaxData, function( index, obj ) {
3922				settings.push( obj.attributes );
3923			} );
3924
3925			if ( 0 !== settings.length ) {
3926				return settings;
3927			}
3928
3929			return false;
3930		};
3931
3932		self.generateLayouts = function() {
3933
3934			$( '.jet-parallax-section__layout', $target ).remove();
3935
3936			$.each( settings, function( index, layout ) {
3937				var imageData      = layout['jet_parallax_layout_image'],
3938					speed          = layout['jet_parallax_layout_speed']['size'] || 50,
3939					zIndex         = layout['jet_parallax_layout_z_index'],
3940					animProp       = layout['jet_parallax_layout_animation_prop'] || 'bgposition',
3941					deviceMode     = elementorFrontend.getCurrentDeviceMode(),
3942					activeBreakpoints = elementor.config.responsive.activeBreakpoints,
3943					activeBreakpointsArray = [],
3944					bgX            = layout['jet_parallax_layout_bg_x'],
3945					bgY            = layout['jet_parallax_layout_bg_y'],
3946					type           = layout['jet_parallax_layout_type'] || 'none',
3947					direction      = layout['jet_parallax_layout_direction'] || '1',
3948					fxDirection    = layout['jet_parallax_layout_fx_direction'] || 'fade-in',
3949					device         = layout['jet_parallax_layout_on'] || ['desktop', 'tablet'],
3950					_id            = layout['_id'],
3951					$layout        = null,
3952					layoutData     = {},
3953					safariClass    = isSafari ? ' is-safari' : '',
3954					macClass       = 'MacIntel' == platform ? ' is-mac' : '';
3955
3956				if ( -1 === device.indexOf( deviceMode ) ) {
3957					return false;
3958				}
3959			
3960				
3961				for ( var [key, value] of Object.entries( activeBreakpoints ) ) {
3962					if ( 'widescreen' === key ) {
3963						activeBreakpointsArray.push( 'desktop' );
3964						activeBreakpointsArray.push( key );
3965					} else {
3966						activeBreakpointsArray.push( key );
3967					}
3968					
3969				}
3970
3971				if ( -1 === activeBreakpointsArray.indexOf( 'widescreen' ) ) {
3972					activeBreakpointsArray.push( 'desktop' );
3973				}
3974
3975				activeBreakpointsArray = activeBreakpointsArray.reverse();
3976
3977				var breakpoints = [ 'widescreen', 'desktop', 'laptop', 'tablet_extra', 'tablet', 'mobile_extra', 'mobile'],
3978					i = 0,
3979					prevDevice,
3980					layoutBreakpoinntsSettings = [];
3981
3982				breakpoints.forEach( function( item ) {
3983
3984					if ( -1 != activeBreakpointsArray.indexOf( item ) ) {
3985
3986						layoutBreakpoinntsSettings[i] = [];
3987
3988						if ( 'widescreen' === item ) {
3989							layoutBreakpoinntsSettings[i][item] = {
3990								'bgX' : '' != layout['jet_parallax_layout_bg_x_' + item] ? layout['jet_parallax_layout_bg_x'] : 0,
3991
3992								'bgY' : '' != layout['jet_parallax_layout_bg_y_' + item] ? layout['jet_parallax_layout_bg_y'] : 0,
3993
3994								'layoutImageData' : '' != layout['jet_parallax_layout_image_' + item] ? layout['jet_parallax_layout_image_' + item] : ''
3995							};
3996						} else if ( 'desktop' === item ) {
3997							layoutBreakpoinntsSettings[i][item] = {
3998								'bgX' : '' != layout['jet_parallax_layout_bg_x'] ? layout['jet_parallax_layout_bg_x'] : 0,
3999
4000								'bgY' : '' != layout['jet_parallax_layout_bg_y'] ? layout['jet_parallax_layout_bg_y'] : 0,
4001
4002								'layoutImageData' : imageData['url'] || layout['jet_parallax_layout_image']['url']
4003							};
4004						} else {
4005							layoutBreakpoinntsSettings[i][item] = {
4006								'bgX': ( layout['jet_parallax_layout_bg_x_' + item] && '' != layout['jet_parallax_layout_bg_x_' + item] ) ? layout['jet_parallax_layout_bg_x_' + item] : layoutBreakpoinntsSettings[i-1][prevDevice].bgX,
4007
4008								'bgY' : ( layout['jet_parallax_layout_bg_y_' + item] && '' != layout['jet_parallax_layout_bg_y_' + item] ) ? layout['jet_parallax_layout_bg_y_' + item] : layoutBreakpoinntsSettings[i-1][prevDevice].bgY,
4009
4010								'layoutImageData' : ( layout['jet_parallax_layout_image_' + item] && '' != layout['jet_parallax_layout_image_' + item]['url'] ) ? layout['jet_parallax_layout_image_' + item]['url'] : layoutBreakpoinntsSettings[i-1][prevDevice].layoutImageData
4011							};
4012						}
4013
4014						if ( deviceMode === item ) {
4015							bgX    = layoutBreakpoinntsSettings[i][item].bgX;
4016							bgY    = layoutBreakpoinntsSettings[i][item].bgY;
4017							imageData = layoutBreakpoinntsSettings[i][item].layoutImageData;
4018						}
4019
4020						prevDevice = item;
4021
4022						i++;
4023					}
4024
4025				} );
4026
4027				if ( ! $target.hasClass( 'jet-parallax-section' ) ) {
4028					$target.addClass( 'jet-parallax-section' );
4029				}
4030
4031				$layout = $( '<div class="jet-parallax-section__layout elementor-repeater-item-' + _id + ' jet-parallax-section__' + type +'-layout' + macClass + '"><div class="jet-parallax-section__image"></div></div>' )
4032					.prependTo( $target )
4033					.css( {
4034						'z-index': zIndex
4035					} );
4036
4037				var imageCSS = {
4038					'background-position-x': bgX + '%',
4039					'background-position-y': bgY + '%',
4040					'background-image': 'url(' + imageData + ')'
4041				};
4042
4043				$( '> .jet-parallax-section__image', $layout ).css( imageCSS );
4044
4045				layoutData = {
4046					selector: $layout,
4047					prop: animProp,
4048					type: type,
4049					device: device,
4050					xPos: bgX,
4051					yPos: bgY,
4052					direction: +direction,
4053					fxDirection: fxDirection,
4054					speed: 2 * ( speed / 100 )
4055				};
4056
4057				if ( 'none' !== type ) {
4058					if ( JetElementsTools.inArray( type, ['scroll', 'h-scroll', 'zoom', 'rotate', 'blur', 'opacity'] ) ) {
4059						scrollLayoutList.push( layoutData );
4060					}
4061
4062					if ( 'mouse' === type ) {
4063						mouseLayoutList.push( layoutData );
4064					}
4065				}
4066
4067			} );
4068
4069		};
4070
4071		self.scrollHandler = function( event ) {
4072			winScrollTop = $window.scrollTop();
4073			winHeight    = $window.height();
4074
4075			self.scrollUpdate();
4076		};
4077
4078		self.scrollUpdate = function() {
4079			$.each( scrollLayoutList, function( index, layout ) {
4080
4081				var $this      = layout.selector,
4082					$image     = $( '.jet-parallax-section__image', $this ),
4083					speed      = layout.speed,
4084					offsetTop  = $this.offset().top,
4085					thisHeight = $this.outerHeight(),
4086					prop       = layout.prop,
4087					type       = layout.type,
4088					dir        = layout.direction,
4089					fxDir      = layout.fxDirection,
4090					posY       = ( winScrollTop - offsetTop + winHeight ) / thisHeight * 100,
4091					device     = elementorFrontend.getCurrentDeviceMode();
4092
4093				if ( -1 === layout.device.indexOf( device ) ) {
4094					$image.css( {
4095						'transform': 'translateX(0) translateY(0)',
4096						'background-position-y': layout.yPos,
4097						'background-position-x': layout.xPos,
4098						'filter': 'none',
4099						'opacity': '1'
4100					} );
4101
4102					return false;
4103				}
4104
4105				if ( winScrollTop < offsetTop - winHeight ) posY = 0;
4106				if ( winScrollTop > offsetTop + thisHeight) posY = 200;
4107
4108				posY = parseFloat( speed * posY ).toFixed(1);
4109
4110				switch( type ) {
4111					case 'scroll':
4112						if ( 'bgposition' === prop ) {
4113							$image.css( {
4114								'background-position-y': 'calc(' + layout.yPos + '% + ' + posY + 'px)'
4115							} );
4116						} else {
4117							$image.css( {
4118								'transform': 'translateY(' + posY + 'px)'
4119							} );
4120						}
4121						break;
4122					case 'h-scroll':
4123						if ( 'bgposition' === prop ) {
4124							$image.css( {
4125								'background-position-x': 'calc(' + layout.xPos + '% + ' + (posY * dir) + 'px)'
4126							} );
4127						} else {
4128							$image.css( {
4129								'transform': 'translateX(' + (posY * dir) + 'px)'
4130							} );
4131						}
4132						break;
4133					case 'zoom':
4134						var deltaScale = ( winScrollTop - offsetTop + winHeight ) / winHeight,
4135							scale      = deltaScale * speed;
4136
4137						scale = scale + 1;
4138
4139						$image.css( {
4140							'transform': 'scale(' + scale + ')'
4141						} );
4142						break;
4143					case 'rotate':
4144						var rotate = posY;
4145
4146						$image.css( {
4147							'transform': 'rotateZ(' + (rotate * dir) + 'deg)'
4148						} );
4149						break;
4150					case 'blur':
4151						var blur = 0;
4152
4153						switch ( fxDir ) {
4154							case 'fade-in':
4155								blur = posY / 40;
4156								break;
4157
4158							case 'fade-out':
4159								blur = (5 * speed) - (posY / 40);
4160								break
4161						}
4162
4163						$image.css( {
4164							'filter': 'blur(' + blur + 'px)'
4165						} );
4166						break;
4167					case 'opacity':
4168						var opacity = 1;
4169
4170						switch ( fxDir ) {
4171							case 'fade-in':
4172								opacity = 1 - (posY / 400);
4173								break;
4174
4175							case 'fade-out':
4176								opacity = (1 - (0.5 * speed)) + (posY / 400);
4177								break
4178						}
4179
4180						$image.css( {
4181							'opacity': opacity
4182						} );
4183						break;
4184				}
4185
4186			} );
4187		};
4188
4189		self.mouseMoveHandler = function( event ) {
4190			var windowWidth  = $window.width(),
4191				windowHeight = $window.height(),
4192				cx           = Math.ceil( windowWidth / 2 ),
4193				cy           = Math.ceil( windowHeight / 2 ),
4194				dx           = event.clientX - cx,
4195				dy           = event.clientY - cy;
4196
4197			tiltx = -1 * ( dx / cx );
4198			tilty = -1 * ( dy / cy );
4199
4200			self.mouseMoveUpdate();
4201		};
4202
4203		self.mouseLeaveHandler = function( event ) {
4204
4205			$.each( mouseLayoutList, function( index, layout ) {
4206				var $this  = layout.selector,
4207					$image = $( '.jet-parallax-section__image', $this );
4208
4209				switch( layout.prop ) {
4210					case 'transform3d':
4211						TweenMax.to(
4212							$image[0],
4213							1.2, {
4214								x: 0,
4215								y: 0,
4216								z: 0,
4217								rotationX: 0,
4218								rotationY: 0,
4219								ease:Power2.easeOut
4220							}
4221						);
4222					break;
4223				}
4224
4225			} );
4226		};
4227
4228		self.mouseMoveUpdate = function() {
4229			$.each( mouseLayoutList, function( index, layout ) {
4230				var $this   = layout.selector,
4231					$image  = $( '.jet-parallax-section__image', $this ),
4232					speed   = layout.speed,
4233					prop    = layout.prop,
4234					posX    = parseFloat( tiltx * 125 * speed ).toFixed(1),
4235					posY    = parseFloat( tilty * 125 * speed ).toFixed(1),
4236					posZ    = layout.zIndex * 50,
4237					rotateX = parseFloat( tiltx * 25 * speed ).toFixed(1),
4238					rotateY = parseFloat( tilty * 25 * speed ).toFixed(1),
4239					device  = elementorFrontend.getCurrentDeviceMode();
4240
4241				if ( -1 == layout.device.indexOf( device ) ) {
4242					$image.css( {
4243						'transform': 'translateX(0) translateY(0)',
4244						'background-position-x': layout.xPos,
4245						'background-position-y': layout.yPos
4246					} );
4247
4248					return false;
4249				}
4250
4251				switch( prop ) {
4252					case 'bgposition':
4253
4254						var bgPosX = layout.xPos + ( posX / $image[0].offsetWidth ) * 100,
4255							bgPosY = layout.yPos + ( posY / $image[0].offsetHeight ) * 100;
4256
4257						TweenMax.to(
4258							$image[0],
4259							1, {
4260								backgroundPositionX: bgPosX,
4261								backgroundPositionY: bgPosY,
4262								ease:Power2.easeOut
4263							}
4264						);
4265					break;
4266
4267					case 'transform':
4268						TweenMax.to(
4269							$image[0],
4270							1, {
4271								x: posX,
4272								y: posY,
4273								ease:Power2.easeOut
4274							}
4275						);
4276					break;
4277
4278					case 'transform3d':
4279						TweenMax.to(
4280							$image[0],
4281							2, {
4282								x: posX,
4283								y: posY,
4284								z: posZ,
4285								rotationX: rotateY,
4286								rotationY: -rotateX,
4287								ease:Power2.easeOut
4288							}
4289						);
4290					break;
4291				}
4292
4293			} );
4294		};
4295
4296	}
4297
4298	/**
4299	 * Jet Portfolio Class
4300	 *
4301	 * @return {void}
4302	 */
4303	window.jetPortfolio = function( $selector, settings ) {
4304		var self            = this,
4305			$instance       = $selector,
4306			$instanceList   = $( '.jet-portfolio__list', $instance ),
4307			$itemsList      = $( '.jet-portfolio__item', $instance ),
4308			$filterList     = $( '.jet-portfolio__filter-item', $instance ),
4309			$moreWrapper    = $( '.jet-portfolio__view-more', $instance ),
4310			$moreButton     = $( '.jet-portfolio__view-more-button', $instance ),
4311			isViewMore      = $moreButton[0],
4312			itemsData       = {},
4313			filterData      = {},
4314			currentFilter   = 'all',
4315			activeSlug      = [],
4316			isRTL           = JetElementsTools.isRTL(),
4317			editMode        = Boolean( elementor.isEditMode() ),
4318			defaultSettings = {
4319				layoutType: 'masonry',
4320				columns: 3,
4321				perPage: 6
4322			},
4323			masonryOptions = {
4324				itemSelector: '.jet-portfolio__item',
4325				percentPosition: true,
4326				isOriginLeft : true === isRTL ? false : true
4327			},
4328			settings        = $.extend( defaultSettings, settings ),
4329			$masonryInstance,
4330			page            = 1;
4331
4332		/**
4333		 * Init
4334		 */
4335		self.init = function() {
4336			self.layoutBuild();
4337
4338			if ( editMode && $masonryInstance.get(0) ) {
4339
4340				$(window).on( 'resize', JetElementsTools.debounce( 50, function() {
4341					$masonryInstance.masonry('layout');
4342				}));
4343			}
4344		}
4345
4346		/**
4347		 * Layout build
4348		 */
4349		self.layoutBuild = function() {
4350
4351			self.generateData();
4352
4353			$filterList.data( 'showItems', isViewMore ? settings.perPage : 'all' );
4354
4355			if ( 'justify' == settings['layoutType'] ) {
4356				masonryOptions['columnWidth'] = '.grid-sizer';
4357			}
4358
4359			if ( 'masonry' == settings['layoutType'] || 'justify' == settings['layoutType'] ) {
4360				$masonryInstance = $instanceList.masonry( masonryOptions );
4361			}
4362
4363			if ( $.isFunction( $.fn.imagesLoaded ) ) {
4364
4365				$( '.jet-portfolio__image', $itemsList ).imagesLoaded().progress( function( instance, image ) {
4366					var $image      = $( image.img ),
4367						$parentItem = $image.closest( '.jet-portfolio__item' ),
4368						$loader     = $( '.jet-portfolio__image-loader', $parentItem );
4369
4370					$loader.remove();
4371
4372					$parentItem.addClass( 'item-loaded' );
4373
4374					if ( $masonryInstance ) {
4375						$masonryInstance.masonry( 'layout' );
4376					}
4377				} );
4378
4379			} else {
4380				var $loader = $( '.jet-portfolio__image-loader', $itemsList );
4381
4382				$itemsList.addClass( 'item-loaded' );
4383
4384				$loader.remove();
4385			}
4386
4387			$filterList.on( 'click.jetPortfolio', self.filterHandler );
4388			$moreButton.on( 'click.jetPortfolio', self.moreButtonHandler );
4389
4390			self.render();
4391			self.checkMoreButton();
4392		};
4393
4394		self.generateData = function() {
4395			if ( $filterList[0] ) {
4396				$filterList.each( function( index ) {
4397					var $this = $( this ),
4398						slug  = $this.data('slug');
4399
4400					filterData[ slug ] = false;
4401
4402					if ( 'all' == slug ) {
4403						filterData[ slug ] = true;
4404					}
4405				} );
4406			} else {
4407				filterData['all'] = true;
4408			}
4409
4410			$itemsList.each( function( index ) {
4411				var $this = $( this ),
4412					slug  = $this.data('slug');
4413
4414				itemsData[ index ] = {
4415					selector: $this,
4416					slug: slug,
4417					visible: $this.hasClass( 'visible-status' ) ? true : false,
4418					more: $this.hasClass( 'hidden-status' ) ? true : false,
4419					lightboxEnabled: 'yes' === $this.find('.jet-portfolio__link').data( 'elementor-open-lightbox' ) ? true : false
4420				};
4421			} );
4422		};
4423
4424		self.filterHandler = function( event ) {
4425			var $this = $( this ),
4426				counter = 1,
4427				slug  = $this.data( 'slug' ),
4428				showItems = $this.data( 'showItems' );
4429
4430			$filterList.removeClass( 'active' );
4431			$this.addClass( 'active' );
4432
4433			for ( var slugName in filterData ) {
4434				filterData[ slugName ] = false;
4435
4436				if ( slugName == slug ) {
4437					filterData[ slugName ] = true;
4438					currentFilter = slugName;
4439				}
4440			}
4441
4442			$.each( itemsData, function( index, obj ) {
4443				var visible = false;
4444
4445				if ( 'all' === showItems ) {
4446
4447					if ( self.isItemVisible( obj.slug ) && ! obj['more'] ) {
4448						visible = true;
4449					}
4450
4451				} else if ( self.isItemVisible( obj.slug ) ) {
4452
4453					if ( counter <= showItems ) {
4454						visible = true;
4455						obj.more = false;
4456					} else {
4457						obj.more = true;
4458					}
4459
4460					counter++
4461				}
4462
4463				obj.visible = visible;
4464
4465			} );
4466
4467			self.render();
4468			self.checkMoreButton();
4469		}
4470
4471		/**
4472		 * [moreButtonHandler description]
4473		 * @param  {[type]} event [description]
4474		 * @return {[type]}       [description]
4475		 */
4476		self.moreButtonHandler = function( event ) {
4477			var $this   = $( this ),
4478				counter = 1,
4479				activeFilter = $( '.jet-portfolio__filter-item.active', $instance ),
4480				showItems;
4481
4482			$.each( itemsData, function( index, obj ) {
4483
4484				if ( self.isItemVisible( obj.slug ) && obj.more && counter <= settings.perPage ) {
4485					obj.more = false;
4486					obj.visible = true;
4487
4488					counter++;
4489				}
4490			} );
4491
4492			if ( activeFilter[0] ) {
4493				showItems = activeFilter.data( 'showItems' );
4494				activeFilter.data( 'showItems', showItems + counter - 1 );
4495			}
4496
4497			self.render();
4498			self.checkMoreButton();
4499		}
4500
4501		/**
4502		 * [checkmoreButton description]
4503		 * @return {[type]} [description]
4504		 */
4505		self.checkMoreButton = function() {
4506			var check = false;
4507
4508			$.each( itemsData, function( index, obj ) {
4509
4510				if ( self.isItemVisible( obj.slug ) && obj.more ) {
4511					check = true;
4512				}
4513			} );
4514
4515			if ( check ) {
4516				$moreWrapper.removeClass( 'hidden-status' );
4517			} else {
4518				$moreWrapper.addClass( 'hidden-status' );
4519			}
4520		}
4521
4522		/**
4523		 * [anyFilterEnabled description]
4524		 * @return {Boolean} [description]
4525		 */
4526		self.isItemVisible = function( slugs ) {
4527			var slugList = JetElementsTools.getObjectValues( slugs );
4528
4529			for ( var slug in filterData ) {
4530				var checked = filterData[ slug ];
4531
4532				if ( checked && -1 !== slugList.indexOf( slug ) ) {
4533					return true;
4534				}
4535			}
4536
4537			return false;
4538		}
4539
4540		/**
4541		 * [anyFilterEnabled description]
4542		 * @return {Boolean} [description]
4543		 */
4544		self.anyFilterEnabled = function() {
4545
4546			for ( var slug in filterData ) {
4547				if ( filterData[ slug ] ) {
4548					return true;
4549				}
4550			}
4551
4552			return false;
4553		}
4554
4555		/**
4556		 * Render
4557		 *
4558		 * @return void
4559		 */
4560		self.render = function() {
4561			var hideAnimation,
4562				showAnimation;
4563
4564			$itemsList.removeClass( 'visible-status' ).removeClass( 'hidden-status' );
4565
4566			$.each( itemsData, function( index, itemData ) {
4567				var selector = $( '.jet-portfolio__inner', itemData.selector ),
4568					$itemLink = $( '.jet-portfolio__link', itemData.selector ),
4569					slideshowID = settings.id + '-' + currentFilter;
4570
4571				if ( itemData.visible ) {
4572					itemData.selector.addClass( 'visible-status' );
4573
4574					if ( itemData.lightboxEnabled ) {
4575						$itemLink[0].setAttribute( 'data-elementor-lightbox-slideshow', slideshowID );
4576					}
4577
4578					showAnimation = anime( {
4579						targets: selector[0],
4580						opacity: {
4581							value: 1,
4582							duration: 400,
4583						},
4584						scale: {
4585							value: 1,
4586							duration: 500,
4587							easing: 'easeOutExpo'
4588						},
4589						delay: 50,
4590						elasticity: false
4591					} );
4592				} else {
4593					itemData.selector.addClass( 'hidden-status' );
4594					$itemLink[0].removeAttribute( 'data-elementor-lightbox-slideshow' );
4595
4596					hideAnimation = anime( {
4597						targets: selector[0],
4598						opacity: 0,
4599						scale: 0,
4600						duration: 500,
4601						elasticity: false
4602					} );
4603				}
4604			} );
4605
4606			if ( $masonryInstance ) {
4607				$masonryInstance.masonry( 'layout' );
4608			}
4609		}
4610	}
4611
4612	/**
4613	 * Jet Timeline Class
4614	 *
4615	 * @return {void}
4616	 */
4617	window.jetTimeLine = function ( $element ) {
4618		var $parentPopup	= $element.closest( '.jet-popup__container-inner, .elementor-popup-modal .dialog-message' ),
4619			inPopup			= !!$parentPopup[0],
4620			$viewport		= inPopup ? $parentPopup : $(window),
4621			viewportOffset  = inPopup ? $viewport.offset().top - $(window).scrollTop() : 0,
4622			self			= this,
4623			$line 			= $element.find( '.jet-timeline__line' ),
4624			$progress		= $line.find( '.jet-timeline__line-progress' ),
4625			$cards			= $element.find( '.jet-timeline-item' ),
4626			$points 		= $element.find('.timeline-item__point'),
4627
4628			currentScrollTop 		= $viewport.scrollTop(),
4629			lastScrollTop 			= -1,
4630			currentWindowHeight 	= $viewport.height(),
4631			currentViewportHeight 	= inPopup ? $viewport.outerHeight() : window.innerHeight,
4632			lastWindowHeight 		= -1,
4633			requestAnimationId 		= null,
4634			flag 					= false;
4635
4636		self.onScroll = function (){
4637			currentScrollTop = $viewport.scrollTop();
4638			viewportOffset   = inPopup ? $viewport.offset().top - $(window).scrollTop() : 0;
4639
4640			self.updateFrame();
4641			self.animateCards();
4642		};
4643
4644		self.onResize = function() {
4645			currentScrollTop = $viewport.scrollTop();
4646			currentWindowHeight = $viewport.height();
4647			viewportOffset = inPopup ? $viewport.offset().top - $(window).scrollTop() : 0;
4648
4649			self.updateFrame();
4650		};
4651
4652		self.updateWindow = function() {
4653			flag = false;
4654
4655			$line.css({
4656				'top' 		: $cards.first().find( $points ).offset().top - $cards.first().offset().top,
4657				'bottom'	: ( $element.offset().top + $element.outerHeight() ) - $cards.last().find( $points ).offset().top
4658			});
4659
4660			if ( ( lastScrollTop !== currentScrollTop ) ) {
4661				lastScrollTop 	 = currentScrollTop;
4662				lastWindowHeight = currentWindowHeight;
4663
4664				self.updateProgress();
4665			}
4666		};
4667
4668		self.updateProgress = function() {
4669			var lastCartOffset = $cards.last().find( $points ).offset().top,
4670				progressFinishPosition = ! inPopup ? lastCartOffset : lastCartOffset + currentScrollTop - viewportOffset - $(window).scrollTop(),
4671				progressOffsetTop = ! inPopup ? $progress.offset().top : $progress.offset().top + currentScrollTop - viewportOffset - $(window).scrollTop(),
4672				progressHeight = ( currentScrollTop - progressOffsetTop ) + ( currentViewportHe
4672ight / 2 );
4673
4674			if ( progressFinishPosition <= ( currentScrollTop + currentViewportHeight / 2 ) ) {
4675				progressHeight = progressFinishPosition - progressOffsetTop;
4676			}
4677
4678			$progress.css({
4679				'height' : progressHeight + 'px'
4680			});
4681
4682			$cards.each( function() {
4683				var itemOffset = $(this).find( $points ).offset().top;
4684				itemOffset = ! inPopup ? itemOffset : itemOffset + currentScrollTop - viewportOffset - $(window).scrollTop();
4685
4686				if ( itemOffset < ( currentScrollTop + currentViewportHeight * 0.5 ) ) {
4687					$(this).addClass('is--active');
4688				} else {
4689					$(this).removeClass('is--active');
4690				}
4691			});
4692		};
4693
4694		self.updateFrame = function() {
4695			if ( ! flag ) {
4696				requestAnimationId = requestAnimationFrame( self.updateWindow );
4697			}
4698			flag = true;
4699		};
4700
4701		self.animateCards = function() {
4702			$cards.each( function() {
4703				var itemOffset = $(this).offset().top;
4704				itemOffset = ! inPopup ? itemOffset : itemOffset + currentScrollTop - viewportOffset - $(window).scrollTop();
4705
4706				if( itemOffset <= currentScrollTop + currentViewportHe
4706ight * 0.9 && $(this).hasClass('jet-timeline-item--animated') ) {
4707					$(this).addClass('is--show');
4708				}
4709			});
4710		};
4711
4712		self.init = function(){
4713			$(document).ready(self.onScroll);
4714			$viewport.on('scroll.jetTimeline', self.onScroll);
4715			$(window).on('resize.jetTimeline orientationchange.jetTimeline', JetElementsTools.debounce( 50, self.onResize ));
4716		};
4717	}
4718
4719	/**
4720	 * [jetScratchEffect description]
4721	 * @param  {[type]} elementId        [description]
4722	 * @param  {[type]} canvasId         [description]
4723	 * @param  {[type]} completeCallback [description]
4724	 * @return {[type]}                  [description]
4725	 */
4726	window.jetScratchEffect = function ( elementId, canvasId, completeCallback, fillpercent = 75 ) {
4727		var container    = document.querySelector( elementId ),
4728			canvas       = document.querySelector( canvasId ),
4729			canvasWidth  = canvas.width,
4730			canvasHeight = canvas.height,
4731			ctx          = canvas.getContext('2d'),
4732			brush        = new Image(),
4733			isDrawing = false,
4734			lastPoint;
4735
4736			brush.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAAxCAYAAABNuS5SAAAKFklEQVR42u2aCXCcdRnG997NJtlkk83VJE3apEma9CQlNAR60UqrGSqW4PQSO9iiTkE8BxWtlGMqYCtYrLRQtfVGMoJaGRFliijaViwiWgQpyCEdraI1QLXG52V+n/5nzd3ENnX/M8/sJvvt933/533e81ufL7MyK7NOzuXPUDD0FQCZlVn/+xUUQhkXHny8M2TxGsq48MBjXdAhL9/7YN26dd5nI5aVRrvEc0GFEBNKhbDjwsHh3qP/FJK1EdYIedOFlFAOgREhPlICifZDYoBjTna3LYe4xcI4oSpNcf6RvHjuAJRoVszD0qFBGmgMChipZGFxbqzQkJWVZUSOF7JRX3S4LtLTeyMtkkqljMBkPzHRs2aYY5PcZH/qLY1EIo18byQ6hBytIr3WCAXcV4tQHYvFxg3w3N6+Bh3OQolEoqCoqCinlw16JzTFJSE6PYuZKqvztbC2ex7bzGxhKu+rerjJrEEq+r9ieElJSXFDQ0Mh9zYzOzu7FBUWcO4Q9xbD6HYvhXhGLccVD5ZAPyfMqaioyOrBUgEv8FZXV8caGxtz8vLykhCWTnZIKmsKhUJnEYeKcKk2YYERH41G7UYnck1/WvAPOxsdLJm2+bEY0Ay0RNeqkytXQkoBZM4U5oOaoYSUkBGRtvnesrBZK4e4F6ypqSkuLy+v4KI99ZQxkfc6vZ4jNAl1wkbhG8LrhfNBCdkxmhYacvj/GOce+3K9MHHbDHUmicOufREELRIWch/DljzMsglutr+VIJO5KjGrVfZAnpF8mnCd8G5hrnC60Cl8T/iw8C1hKd9P9eDCMcgo5HwBx8BB/g7xeRPkrBbeJ3xTeAxjvRGVV3NcshfPG1JX4tVDQae47GuVOknCi23xHr5nyrxe2C1sFlYJ7xe+Jlwm7BRulItP0ms957RzTMK1ws41jMS8eDxehopaOCYfxc3AIHcIX+K6nxW+ImyVF1i8PQ8DTuwtdC1atCja3NwcHkq5EuXmo85G+jq+yMm28V4q/zcIPxV+K9zPxnbgTi0ocybu6wX66fx/vfAB4T1gHt8xI1wlXMF5zEXnQKC56ruEjwhvEa4WrrXvK/Yt5Pt5I1UveeVKyKmT+lpG2gQ2npMmez8ZzFT3e+HXwj
47367hKXNf6rFZbDpJUjESLdFsFX4mfFv4Fd/7qPBm4UPCJ4RNwncwym4UfYVUtiAcDk/T+3NRmylwWzAY7BCBCwYYogZPnrJoRNm2IDc3tw4FVKXFm95UmGLzkTTFpog524WnhQPCQeGvwiPCCuFCYmk5GbEJt3tOeF54HPVeLLyXxHOv8BPhYaFLeFU4gsI7OWeZk3g+hpJNvVMGIIqhdRvy+biVISouq2TBqWxoIL1wgBhU5AR1SzJvFR4UnhX+Bl4RfsFGP0npUkTymIQ7fh8Cf4l6F0LgXkj6o3O+buGfwj+ElzGQETaNeJqPhxiahckYq8KJ9V6mP+4pTIATjsGCA8lCQVy9VbhB2CM8itu9IBxlkx6O4nbmmpcSi0KUExa3Psfn23DZC4lhlhRuIWs/R1Y9BrpR4WHcfiOq34bLl5DJm1B7BANPGO4+2OJfDcVwX+RZkL5d+DRqeRJ360IJx1CFp4w/8/lhVGXxay1xKp8asQ31rSbgz2az1aBBWCZsgKTfEFe7uM4xYus9KHWXcBv3eolwJe67hJLIN6yubMVpW1tbbllZWVxtzjRquvQe9981IG3RZHUQttH7hB8IP0cdLwp/YnNHcdsjEP1xsEruO56i2Fy3UWXMskAgYAH/EjOiCD6NDc/XZ4v12RqSy3WQ9rJD3jPClwkZz2Aoy8JnUEjPcwYWfgfHvcIW84h308mABQP4Xp02OY44M4tSZSfx7UXIewU3NpXuxw0vJzauYDP1XM8y8Ttx67fhylYrdlAMW1x7h/BF3NWI+4PwFwjbSha26/xQuBmib6HDqeI+m4m5wzrj9A/xO+O5qbm4yizcbDOKfAjVWeC/WzAFLSeI+4hN9WzQ65EvED7D8Tt4vwE33O64rIfD1JW3k6xeQoX3UN6chyG8In4tcbHuRAyKw2ktVIIM2U5XcA7t2FKy5vWQeBexbbrTpvmZiJwN6e3EwKspW/ajqBuAKfKQk8m7KIce5bgnMNQDkLWPUmkj511DSVV5HJOd417FzrDAK7RjZLMZiURigmLVFCYs5tI2PFhpcUj/n6z6sp72LwJKiU2rUdp62rA7IX4XytpJ3Weh4XfE1/0kk/uoFX8kbCHudZLld5E8vJIs2+mbT8iznaR60DHMBt0EE1DySVlSsOBvyrL6zkZG5qI2T/QSBYTHMYAlq2tw1+0MFO4kVj5GSbSbgvkA8fQQr1uIdfdD5mZ1GhZbP0XfuwlPmOp0SNkYbkQV2JdlEsq69VJS+rTER+NtZVC+TX+NRFq1XGeiHXbG
4736UHMg6lk2/DiZ+mHU8wTueoTXLtS3F5e9l2PNZW9lyrOB5LGSmJokzMQ6OjqCA3wsMXLLhqrWoZgKe3lyZ5YtLiwsLLfMLhJL0ibW3rKa7oMQ+Ajq6gKHcMeHeP8qZcpRMvyt1J97SRabcNP1ZGsbKhSb6lF+5GR6shUnlqTSyPM7LZxV/PUqjOfTH6cvqx+XyN3aCfBPUWh3UZIcxC2/jgu/BJ7Eve/G1R/EXS9gaLCc0dgySqIm7jV4MhEYdAaN4R4eRHkBusJp3GNp56iSOscyYN0DaUch8Ai13X6yrg0PvotCO8nme0geKymBaulc1qO+NbxOOpHZtrcHR+nT6+wePvcnk8k8qv6iNBdyH4/OoGR5gXbv75D4NIX3NoruLSjtKmLlbTwCKER1NmV+QIqfS13aai0izUHsRKksAQE5g0w4fuehj9f+xb25Ym1tbcIhuw2COmkBn2cAcQAFbsclV1BTns49JZio3EQWPkgCySJpFIu8aor0UfeLigDTlUTa/8eimhRGuUiKOZPYtYNabh9EGik3Mkk+A9I8JTWoAiik/LEpzY8tY4uwWc4AJMjxQd8oXRHU8JqbW32orNyAiubZo0WR5wX9KyHrLpLD52nrxhFHa1CVV5w3081cRu/7BYichpEqfafA7/sCzhT7tVkhLZvhTeB8Gv1r6U+ty/gqtWHQCSNTcPOl9NmXM1S4hgRjBjjL1MdUJ8cx3uhe3d3dfh5Meb8qyKWsuJRidwtN/h20XEtxvTwya7tKncU8ACqmXVwLict5fy6TnFhra2uW7xT8dWk2BHptVBOx8GLKjo3g7bhrBQq1sdVsCvEkhLZIac1y/zmUSO0oO8fX/0P2Ub3cwaWpZSITnLnOpDlBWTIfMleJqFb10jXCBJUlMyORSIP14LhqNef6v/05bpZTdHulUyXKsufDNdRxZ4vIhSKwhQFG5vfLfcwZsx2X92Jhje8/P8OI+TK/oO+zeA84WTzkvI/6RuB3y6f68qf11xnyMiuzMms4178AwArmZmkkdGcAAAAASUVORK5CYII=';
4737
4738			canvas.addEventListener( 'mousedown', handleMouseDown, false );
4739			canvas.addEventListener( 'mousemove', JetElementsTools.debounce( 5, handleMouseMove ), false );
4740			canvas.addEventListener( 'mouseup', handleMouseUp, false );
4741
4742			canvas.addEventListener( 'touchstart', handleMouseDown, false );
4743			canvas.addEventListener( 'touchmove', handleMouseMove, false );
4744			canvas.addEventListener( 'touchend', handleMouseUp, false );
4745
4746		function distanceBetween( point1, point2 ) {
4747			return Math.sqrt( Math.pow( point2.x - point1.x, 2 ) + Math.pow( point2.y - point1.y, 2 ) );
4748		}
4749
4750		function angleBetween( point1, point2 ) {
4751			return Math.atan2( point2.x - point1.x, point2.y - point1.y );
4752		}
4753
4754		function getFilledInPixels( stride ) {
4755
4756			if ( ! stride || stride < 1 ) {
4757				stride = 1;
4758			}
4759
4760			var pixels   = ctx.getImageData(0, 0, canvasWidth, canvasHeight),
4761				pdata    = pixels.data,
4762				l        = pdata.length,
4763				total    = ( l / stride ),
4764				count    = 0;
4765
4766			for( var i = count = 0; i < l; i += stride ) {
4767				if ( parseInt( pdata[i] ) === 0 ) {
4768					count++;
4769				}
4770			}
4771
4772			return Math.round( ( count / total ) * 100 );
4773		}
4774
4775		function getMouse( e, canvas ) {
4776			var offsetX = 0,
4777				offsetY = 0,
4778				mx,
4779				my;
4780
4781			mx = ( e.pageX || e.touches[0].clientX ) - offsetX;
4782			my = ( e.pageY || e.touches[0].clientY ) - offsetY;
4783
4784			return { x: mx, y: my };
4785		}
4786
4787		function handlePercentage( filledInPixels ) {
4788			filledInPixels = filledInPixels || 0;
4789
4790			if ( filledInPixels > fillpercent && completeCallback ) {
4791				completeCallback.call( canvas );
4792			}
4793		}
4794
4795		function handleMouseDown( e ) {
4796			isDrawing = true;
4797			lastPoint = getMouse( e, canvas );
4798		}
4799
4800		function handleMouseMove( e ) {
4801
4802			if ( ! isDrawing ) {
4803				return;
4804			}
4805
4806			e.preventDefault();
4807
4808			var currentPoint      = getMouse( e, canvas ),
4809				dist              = distanceBetween( lastPoint, currentPoint ),
4810				angle             = angleBetween( lastPoint, currentPoint ),
4811				x                 = 0,
4812				y                 = 0,
4813				userAgent         = navigator.userAgent || navigator.vendor || window.opera,
4814				isIos             = /iPad|iPhone|iPod/.test(userAgent) && !window.MSStream,
4815				isMobileDevice    = JetElementsTools.mobileAndTabletcheck(),
4816				yScroll           = ( isMobileDevice && !isIos ) ? window.scrollY : 0;
4817
4818			for ( var i = 0; i < dist; i++ ) {
4819				x = lastPoint.x + ( Math.sin( angle ) * i ) - 40;
4820				y = lastPoint.y + ( Math.cos( angle ) * i ) - 40 + yScroll;
4821				ctx.globalCompositeOperation = 'destination-out';
4822				ctx.drawImage( brush, x, y, 80, 80 );
4823			}
4824
4825			lastPoint = currentPoint;
4826
4827			handlePercentage( getFilledInPixels( 32 ) );
4828		}
4829
4830		function handleMouseUp( e ) {
4831			isDrawing = false;
4832		}
4833	}
4834
4835}( jQuery, window.elementorFrontend ) );
4836

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.