PageSourceSearch

https://www.callan.com/wp-content/plugins/kurtosys-elements/assets/js/kurtosys-elements.js?ver=1.15.9

js callan.com collected 2026-10-02 04:33:37 UTC 84,032 bytes, 3,026 lines download raw bytes

1( function( $, elementor ) {
2
3	"use strict";
4
5	var KurtosysElements = {
6
7		init: function() {
8
9			var widgets = {
10				'kurtosys-carousel.default' : KurtosysElements.widgetCarousel,
11				'kurtosys-circle-progress.default' : KurtosysElements.widgetProgress,
12				'kurtosys-map.default' : KurtosysElements.widgetMap,
13				'kurtosys-countdown-timer.default' : KurtosysElements.widgetCountdown,
14				'kurtosys-posts.default' : KurtosysElements.widgetPosts,
15				'kurtosys-animated-text.default' : KurtosysElements.widgetAnimatedText,
16				'kurtosys-animated-box.default' : KurtosysElements.widgetAnimatedBox,
17				'kurtosys-images-layout.default' : KurtosysElements.widgetImagesLayout,
18				'kurtosys-slider.default' : KurtosysElements.widgetSlider,
19				'kurtosys-testimonials.default' : KurtosysElements.widgetTestimonials,
20				'kurtosys-image-comparison.default' : KurtosysElements.widgetImageComparison,
21				'kurtosys-instagram-gallery.default' : KurtosysElements.widgetInstagramGallery,
22				'kurtosys-scroll-navigation.default' : KurtosysElements.widgetScrollNavigation,
23				'kurtosys-subscribe-form.default' : KurtosysElements.widgetSubscribeForm,
24				'kurtosys-progress-bar.default' : KurtosysElements.widgetProgressBar,
25				'kurtosys-portfolio.default' : KurtosysElements.widgetPortfolio,
26				'kurtosys-timeline.default': KurtosysElements.widgetTimeLine,
27				'kurtosys-table.default': KurtosysElements.widgetTable,
28				'kurtosys-dropbar.default': KurtosysElements.widgetDropbar,
29				'kurtosys-video.default': KurtosysElements.widgetVideo,
30				'kurtosys-audio.default': KurtosysElements.widgetAudio,
31				'kurtosys-horizontal-timeline.default': KurtosysElements.widgetHorizontalTimeline,
32				'mp-timetable.default': KurtosysElements.widgetTimeTable,
33				'kurtosys-pie-chart.default': KurtosysElements.widgetPieChart
34			};
35
36			$.each( widgets, function( widget, callback ) {
37				elementor.hooks.addAction( 'frontend/element_ready/' + widget, callback );
38			});
39
40			elementor.hooks.addAction( 'frontend/element_ready/section', KurtosysElements.elementorSection );
41		},
42
43		widgetCountdown: function( $scope ) {
44
45			var timeInterval,
46				$coutdown = $scope.find( '[data-due-date]' ),
47				endTime = new Date( $coutdown.data( 'due-date' ) * 1000 ),
48				elements = {
49					days: $coutdown.find( '[data-value="days"]' ),
50					hours: $coutdown.find( '[data-value="hours"]' ),
51					minutes: $coutdown.find( '[data-value="minutes"]' ),
52					seconds: $coutdown.find( '[data-value="seconds"]' )
53				};
54
55			KurtosysElements.widgetCountdown.updateClock = function() {
56
57				var timeRemaining = KurtosysElements.widgetCountdown.getTimeRemaining( endTime );
58
59				$.each( timeRemaining.parts, function( timePart ) {
60
61					var $element = elements[ timePart ];
62
63					if ( $element.length ) {
64						$element.html( this );
65					}
66
67				} );
68
69				if ( timeRemaining.total <= 0 ) {
70					clearInterval( timeInterval );
71				}
72			};
73
74			KurtosysElements.widgetCountdown.initClock = function() {
75				KurtosysElements.widgetCountdown.updateClock();
76				timeInterval = setInterval( KurtosysElements.widgetCountdown.updateClock, 1000 );
77			};
78
79			KurtosysElements.widgetCountdown.splitNum = function( num ) {
80
81				var num   = num.toString(),
82					arr   = [],
83					reult = '';
84
85				if ( 1 === num.length ) {
86					num = 0 + num;
87				}
88
89				arr = num.match(/\d{1}/g);
90
91				$.each( arr, function( index, val ) {
92					reult += '<span class="kurtosys-countdown-timer__digit">' + val + '</span>';
93				});
94
95				return reult;
96			};
97
98			KurtosysElements.widgetCountdown.getTimeRemaining = function( endTime ) {
99
100				var timeRemaining = endTime - new Date(),
101					seconds = Math.floor( ( timeRemaining / 1000 ) % 60 ),
102					minutes = Math.floor( ( timeRemaining / 1000 / 60 ) % 60 ),
103					hours = Math.floor( ( timeRemaining / ( 1000 * 60 * 60 ) ) % 24 ),
104					days = Math.floor( timeRemaining / ( 1000 * 60 * 60 * 24 ) );
105
106				if ( days < 0 || hours < 0 || minutes < 0 ) {
107					seconds = minutes = hours = days = 0;
108				}
109
110				return {
111					total: timeRemaining,
112					parts: {
113						days: KurtosysElements.widgetCountdown.splitNum( days ),
114						hours: KurtosysElements.widgetCountdown.splitNum( hours ),
115						minutes: KurtosysElements.widgetCountdown.splitNum( minutes ),
116						seconds: KurtosysElements.widgetCountdown.splitNum( seconds )
117					}
118				};
119			};
120
121			KurtosysElements.widgetCountdown.initClock();
122
123		},
124
125		widgetMap: function( $scope ) {
126
127			var $container = $scope.find( '.kurtosys-map' ),
128				map,
129				init,
130				pins;
131
132			if ( ! window.google || ! $container.length ) {
133				return;
134			}
135
136			init = $container.data( 'init' );
137			pins = $container.data( 'pins' );
138			map  = new google.maps.Map( $container[0], init );
139
140			if ( pins ) {
141				$.each( pins, function( index, pin ) {
142
143					var marker,
144						infowindow,
145						pinData = {
146							position: pin.position,
147							map: map
148						};
149
150					if ( '' !== pin.image ) {
151						pinData.icon = pin.image;
152					}
153
154					marker = new google.maps.Marker( pinData );
155
156					if ( '' !== pin.desc ) {
157						infowindow = new google.maps.InfoWindow({
158							content: pin.desc,
159							disableAutoPan: true
160						});
161					}
162
163					marker.addListener( 'click', function() {
164						infowindow.setOptions({ disableAutoPan: false });
165						infowindow.open( map, marker );
166					});
167
168					if ( 'visible' === pin.state && '' !== pin.desc ) {
169						infowindow.open( map, marker );
170					}
171
172				});
173			}
174
175		},
176
177		widgetProgress: function( $scope ) {
178
179			var $progress = $scope.find( '.circle-progress' );
180
181			if ( ! $progress.length ) {
182				return;
183			}
184
185			var $value            = $progress.find( '.circle-progress__value' ),
186				$meter            = $progress.find( '.circle-progress__meter' ),
187				percent           = parseInt( $value.data( 'value' ) ),
188				progress          = percent / 100,
189				duration          = $scope.find( '.circle-progress-wrap' ).data( 'duration' ),
190				responsiveSizes   = $progress.data( 'responsive-sizes' ),
191				desktopSizes      = responsiveSizes.desktop,
192				tabletSizes       = responsiveSizes.tablet,
193				mobileSizes       = responsiveSizes.mobile,
194				currentDeviceMode = elementorFrontend.getCurrentDeviceMode(),
195				prevDeviceMode    = currentDeviceMode,
196				isAnimatedCircle  = false;
197
198			if ( 'tablet' === currentDeviceMode ) {
199				updateSvgSizes( tabletSizes.size, tabletSizes.viewBox, tabletSizes.center, tabletSizes.radius, tabletSizes.valStroke, tabletSizes.bgStroke, tabletSizes.circumference );
200			}
201
202			if ( 'mobile' === currentDeviceMode ) {
203				updateSvgSizes( mobileSizes.size, mobileSizes.viewBox, mobileSizes.center, mobileSizes.radius, mobileSizes.valStroke, mobileSizes.bgStroke, mobileSizes.circumference );
204			}
205
206			elementorFrontend.waypoint( $scope, function() {
207
208				// animate counter
209				var $number = $scope.find( '.circle-counter__number' ),
210					data = $number.data();
211
212				var decimalDigits = data.toValue.toString().match( /\.(.*)/ );
213
214				if ( decimalDigits ) {
215					data.rounding = decimalDigits[1].length;
216				}
217
218				data.duration = duration;
219
220				$number.numerator( data );
221
222				// animate progress
223				var circumference = parseInt( $progress.data( 'circumference' ) ),
224					dashoffset    = circumference * (1 - progress);
225
226				$value.css({
227					'transitionDuration': duration + 'ms',
228					'strokeDashoffset': dashoffset
229				});
230
231				isAnimatedCircle = true;
232
233			}, {
234				offset: 'bottom-in-view'
235			} );
236
237			$( window ).on( 'resize.kurtosysCircleProgress orientationchange.kurtosysCircleProgress', circleResizeHandler );
238
239			function circleResizeHandler( event ) {
240				currentDeviceMode = elementorFrontend.getCurrentDeviceMode();
241
242				if ( 'widescreen' === currentDeviceMode && 'widescreen' !== prevDeviceMode ) {
243					updateSvgSizes( desktopSizes.size, desktopSizes.viewBox, desktopSizes.center, desktopSizes.radius, desktopSizes.valStroke, desktopSizes.bgStroke, desktopSizes.circumference );
244					prevDeviceMode = 'widescreen';
245				}
246
247				if ( 'desktop' === currentDeviceMode && 'desktop' !== prevDeviceMode ) {
248					updateSvgSizes( desktopSizes.size, desktopSizes.viewBox, desktopSizes.center, desktopSizes.radius, desktopSizes.valStroke, desktopSizes.bgStroke, desktopSizes.circumference );
249					prevDeviceMode = 'desktop';
250				}
251
252				if ( 'tablet' === currentDeviceMode && 'tablet' !== prevDeviceMode ) {
253					updateSvgSizes( tabletSizes.size, tabletSizes.viewBox, tabletSizes.center, tabletSizes.radius, tabletSizes.valStroke, tabletSizes.bgStroke, tabletSizes.circumference );
254					prevDeviceMode = 'tablet';
255				}
256
257				if ( 'mobile' === currentDeviceMode && 'mobile' !== prevDeviceMode ) {
258					updateSvgSizes( mobileSizes.size, mobileSizes.viewBox, mobileSizes.center, mobileSizes.radius, mobileSizes.valStroke, mobileSizes.bgStroke, mobileSizes.circumference );
259					prevDeviceMode = 'mobile';
260				}
261			}
262
263			function updateSvgSizes( size, viewBox, center, radius, valStroke, bgStroke, 
263circumference ) {
264				var dashoffset = circumference * (1 - progress);
265
266				$progress.attr( {
267					'width': size,
268					'height': size,
269					'data-radius': radius,
270					'data-circumference': circumference
271				} );
272
273				$progress[0].setAttribute( 'viewBox', viewBox );
274
275				$meter.attr( {
276					'cx': center,
277					'cy': center,
278					'r': radius,
279					'stroke-width': bgStroke
280				} );
281
282				if ( isAnimatedCircle ) {
283					$value.css( {
284						'transitionDuration': ''
285					} );
286				}
287
288				$value.attr( {
289					'cx': center,
290					'cy': center,
291					'r': radius,
292					'stroke-width': valStroke
293				} );
294
295				$value.css( {
296					'strokeDasharray': circumference,
297					'strokeDashoffset': isAnimatedCircle ? dashoffset : circumference
298				} );
299			}
300		},
301
302		widgetCarousel: function( $scope ) {
303
304			var $carousel = $scope.find( '.kurtosys-carousel' );
305
306			if ( ! $carousel.length ) {
307				return;
308			}
309
310			KurtosysElements.initCarousel( $carousel, $carousel.data( 'slider_options' ) );
311
312		},
313
314		widgetPosts: function ( $scope ) {
315
316			var $target = $scope.find( '.kurtosys-carousel' );
317
318			if ( ! $target.length ) {
319				return;
320			}
321
322			KurtosysElements.initCarousel( $target.find( '.kurtosys-posts' ), $target.data( 'slider_options' ) );
323
324		},
325
326		widgetAnimatedText: function( $scope ) {
327			var $target = $scope.find( '.kurtosys-animated-text' ),
328				instance = null,
329				settings = {};
330
331			if ( ! $target.length ) {
332				return;
333			}
334
335			settings = $target.data( 'settings' );
336			instance = new kurtosysAnimatedText( $target, settings );
337			instance.init();
338		},
339
340		widgetAnimatedBox: function( $scope ) {
341
342			KurtosysElements.onAnimatedBoxSectionActivated( $scope );
343
344			var $target      = $scope.find( '.kurtosys-animated-box' ),
345				toogleEvents = 'mouseenter mouseleave',
346				scrollOffset = $( window ).scrollTop(),
347				firstMouseEvent = true;
348
349			if ( ! $target.length ) {
350				return;
351			}
352
353			if ( 'ontouchend' in window || 'ontouchstart' in window ) {
354				$target.on( 'touchstart', function( event ) {
355					scrollOffset = $( window ).scrollTop();
356				} );
357
358				$target.on( 'touchend', function( event ) {
359
360					if ( scrollOffset !== $( window ).scrollTop() ) {
361						return false;
362					}
363
364					if ( ! $( this ).hasClass( 'flipped-stop' ) ) {
365						$( this ).toggleClass( 'flipped' );
366					}
367				} );
368
369			} else {
370				$target.on( toogleEvents, function( event ) {
371
372					if ( firstMouseEvent && 'mouseleave' === event.type ) {
373						return;
374					}
375
376					if ( firstMouseEvent && 'mouseenter' === event.type ) {
377						firstMouseEvent = false;
378					}
379
380					if ( ! $( this ).hasClass( 'flipped-stop' ) ) {
381						$( this ).toggleClass( 'flipped' );
382					}
383				} );
384			}
385		},
386
387		onAnimatedBoxSectionActivated: function( $scope ) {
388			if ( ! window.elementor ) {
389				return;
390			}
391
392			if ( ! window.KurtosysElementsEditor ) {
393				return;
394			}
395
396			if ( ! window.KurtosysElementsEditor.activeSection ) {
397				return;
398			}
399
400			var section = window.KurtosysElementsEditor.activeSection;
401			var isBackSide = -1 !== [ 'section_back_content', 'section_action_button_style' ].indexOf( section );
402
403			if ( isBackSide ) {
404				$scope.find( '.kurtosys-animated-box' ).addClass( 'flipped' );
405				$scope.find( '.kurtosys-animated-box' ).addClass( 'flipped-stop' );
406			} else {
407				$scope.find( '.kurtosys-animated-box' ).removeClass( 'flipped' );
408				$scope.find( '.kurtosys-animated-box' ).removeClass( 'flipped-stop' );
409			}
410		},
411
412		widgetImagesLayout: function( $scope ) {
413			var $target = $scope.find( '.kurtosys-images-layout' ),
414				instance = null,
415				settings = {};
416
417			if ( ! $target.length ) {
418				return;
419			}
420
421			settings = $target.data( 'settings' );
422			instance = new kurtosysImagesLayout( $target, settings );
423			instance.init();
424		},
425
426		widgetPortfolio: function( $scope ) {
427			var $target = $scope.find( '.kurtosys-portfolio' ),
428				instance = null,
429				settings = {};
430
431			if ( ! $target.length ) {
432				return;
433			}
434
435			settings = $target.data( 'settings' );
436			instance = new kurtosysPortfolio( $target, settings );
437			instance.init();
438		},
439
440		widgetInstagramGallery: function( $scope ) {
441			var $target         = $scope.find( '.kurtosys-instagram-gallery__instance' ),
442				instance        = null,
443				defaultSettings = {},
444				settings        = {};
445
446			if ( ! $target.length ) {
447				return;
448			}
449
450			settings = $target.data( 'settings' ),
451
452			/*
453			 * Default Settings
454			 */
455			defaultSettings = {
456				layoutType: 'masonry',
457				columns: 3,
458				columnsTablet: 2,
459				columnsMobile: 1,
460			}
461
462			/**
463			 * Checking options, settings and options merging
464			 */
465			$.extend( defaultSettings, settings );
466
467			if ( 'masonry' === settings.layoutType ) {
468				salvattore.init();
469			}
470		},
471
472		widgetScrollNavigation: function( $scope ) {
473			var $target         = $scope.find( '.kurtosys-scroll-navigation' ),
474				instance        = null,
475				settings        = $target.data( 'settings' );
476
477			instance = new kurtosysScrollNavigation( $target, settings );
478			instance.init();
479		},
480
481		widgetSubscribeForm: function( $scope ) {
482			var $target               = $scope.find( '.kurtosys-subscribe-form' ),
483				scoreId               = $scope.data( 'id' ),
484				settings              = $target.data( 'settings' ),
485				kurtosysSubscribeFormAjax  = null,
486				subscribeFormAjax     = 'kurtosys_subscribe_form_ajax',
487				ajaxRequestSuccess    = false,
488				$subscribeForm        = $( '.kurtosys-subscribe-form__form', $target ),
489				$fields               = $( '.kurtosys-subscribe-form__fields', $target ),
490				$mailField            = $( '.kurtosys-subscribe-form__mail-field', $target ),
491				$inputData            = $mailField.data( 'instance-data' ),
492				$submitButton         = $( '.kurtosys-subscribe-form__submit', $target ),
493				$subscribeFormMessage = $( '.kurtosys-subscribe-form__message', $target ),
494				timeout               = null,
495				invalidMailMessage    = window.kurtosysElements.messages.invalidMail || 'Please specify a valid email';
496
497			$mailField.on( 'focus', function() {
498				$mailField.removeClass( 'mail-invalid' );
499			} );
500
501			$( document ).keydown( function( event ) {
502
503				if ( 13 === event.keyCode && $mailField.is( ':focus' ) ) {
504					subscribeHandle();
505
506					return false;
507				}
508			} );
509
510			$submitButton.on( 'click', function() {
511				subscribeHandle();
512
513				return false;
514			} );
515
516			function subscribeHandle() {
517				var inputValue     = $mailField.val(),
518					sendData       = {
519						'email': inputValue,
520						'use_target_list_id': settings['use_target_list_id'] || false,
521						'target_list_id': settings['target_list_id'] || '',
522						'data': $inputData
523					},
524					serializeArray = $subscribeForm.serializeArray(),
525					additionalFields = {};
526
527				if ( KurtosysElementsTools.validateEmail( inputValue ) ) {
528
529					$.each( serializeArray, function( key, fieldData ) {
530
531						if ( 'email' === fieldData.name ) {
532							sendData[ fieldData.name ] = fieldData.value;
533						} else {
534							additionalFields[ fieldData.name ] = fieldData.value;
535						}
536					} );
537
538					sendData['additional'] = additionalFields;
539
540					if ( ! ajaxRequestSuccess && kurtosysSubscribeFormAjax ) {
541						kurtosysSubscribeFormAjax.abort();
542					}
543
544					kurtosysSubscribeFormAjax = $.ajax( {
545						type: 'POST',
546						url: window.kurtosysElements.ajaxUrl,
547						data: {
548							action: subscribeFormAjax,
549							data: sendData
550						},
551						cache: false,
552						beforeSend: function() {
553							$submitButton.addClass( 'loading' );
554							ajaxRequestSuccess = false;
555						},
556						success: function( data ){
557							var successType   = data.type,
558								message       = data.message || '',
559								responceClass = 'kurtosys-subscribe-form--response-' + successType;
560
561							$submitButton.removeClass( 'loading' );
562							ajaxRequestSuccess = true;
563
564							$target.removeClass( 'kurtosys-subscribe-form--response-error' );
565							$target.addClass( responceClass );
566
567							$( 'span', $subscribeFormMessage ).html( message );
568							$subscribeFormMessage.css( { 'visibility': 'visible' } );
569
570							timeout = setTimeout( function() {
571								$subscribeFormMessage.css( { 'visibility': 'hidden' } );
572								$target.removeClass( responceClass );
573							}, 20000 );
574
575							if ( settings['redirect'] ) {
576								if( settings['open_redirect_in_new_tab']) {
577									var a = document.createElement('a');
578
579									Object.assign(a, {
580										target: '_blank',
581										href: settings['redirect_url']
582									});
583
584									document.body.append(a);
585
586									a.click();
587									a.remove();
588								} else {
589									window.location.href = settings['redirect_url'];
590								}
591							}
592
593							$( window ).trigger( {
594								type: 'kurtosys-elements/subscribe',
595								elementId: scoreId,
596								successType: successType,
597								inputData: $inputData
598							} );
599						}
600					});
601
602				} else {
603					$mailField.addClass( 'mail-invalid' );
604
605					$target.addClass( 'kurtosys-subscribe-form--response-error' );
606					$( 'span', $subscribeFormMessage ).html( invalidMailMessage );
607					$subscribeFormMessage.css( { 'visibility': 'visible' } );
608
609					timeout = setTimeout( function() {
610						$target.removeClass( 'kurtosys-subscribe-form--response-error' );
611						$subscribeFormMessage.css( { 'visibility': 'hidden' } );
612						$mailField.removeClass( 'mail-invalid' );
613					}, 20000 );
614				}
615			}
616		},
617
618		widgetProgressBar: function( $scope ) {
619			var $target      = $scope.find( '.kurtosys-progress-bar' ),
620				percent      = $target.data( 'percent' ),
621				type         = $target.data( 'type' ),
622				deltaPercent = percent * 0.01;
623
624			elementorFrontend.waypoint( $target, function( direction ) {
625				var $this       = $( this ),
626					animeObject = { charged: 0 },
627					$statusBar  = $( '.kurtosys-progress-bar__status-bar', $this ),
628					$percent    = $( '.kurtosys-progress-bar__percent-value', $this ),
629					animeProgress,
630					animePercent;
631
632				if ( 'type-7' == type ) {
633					$statusBar.css( {
634						'height': percent + '%'
635					} );
636				} else {
637					$statusBar.css( {
638						'width': percent + '%'
639					} );
640				}
641
642				animePercent = anime({
643					targets: animeObject,
644					charged: percent,
645					round: 1,
646					duration: 1000,
647					easing: 'easeInOutQuad',
648					update: function() {
649						$percent.html( animeObject.charged );
650					}
651				});
652
653			} );
654		},
655
656		widgetSlider: function( $scope ) {
657			var $target        = $scope.find( '.kurtosys-slider' ),
658				$imagesTagList = $( '.sp-image', $target ),
659				instance       = null,
660				defaultSettings = {
661					imageScaleMode: 'cover',
662					slideDistance: { size: 10, unit: 'px' },
663					slideDuration: 500,
664					sliderAutoplay: true,
665					sliderAutoplayDelay: 2000,
666					sliderAutoplayOnHover: 'pause',
667					sliderFadeMode: false,
668					sliderFullScreen: true,
669					sliderFullscreenIcon: 'fa fa-arrows-alt',
670					sliderHeight: { size: 600, unit: 'px' },
671					sliderHeightTablet: { size: 400, unit: 'px' },
672					sliderHeightMobile: { size: 300, unit: 'px' },
673					sliderLoop: true,
674					sliderNaviOnHover: false,
675					sliderNavigation: true,
676					sliderNavigationIcon: 'fa fa-angle-left',
677					sliderPagination: false,
678					sliderShuffle: false,
679					sliderWidth: { size: 100, unit: '%' },
680					thumbnailWidth: 120,
681					thumbnailHeight: 80,
682					thumbnails: true,
683					rightToLeft: false,
684				},
685				instanceSettings = $target.data( 'settings' ) || {},
686				settings        = $.extend( {}, defaultSettings, instanceSettings );
687
688			if ( ! $target.length ) {
689				return;
690			}
691
692			$target.imagesLoaded().progress( function( instance, image ) {
693				var loadedImages = null,
694					progressBarWidth = null;
695
696				if ( image.isLoaded ) {
697
698					if ( $( image.img ).hasClass( 'sp-image' ) ) {
699						$( image.img ).addClass( 'image-loaded' );
700					}
701
702					loadedImages = $( '.image-loaded', $target );
703					progressBarWidth = 100 * ( loadedImages.length / $imagesTagList.length ) + '%';
704
705					$( '.kurtosys-slider-loader', $target ).css( { width: progressBarWidth } );
706				}
707
708			} ).done( function( instance ) {
709
710				$( '.slider-pro', $target ).addClass( 'slider-loaded' );
711				$( '.kurtosys-slider-loader', $target ).css( { 'display': 'none' } );
712			} );
713
714			var tabletHeight = '' !== settings['sliderHeightTablet']['size'] ? settings['sliderHeightTablet']['size'] + settings['sliderHeightTablet']['unit'] : settings['sliderHeight']['size'] + settings['sliderHeight']['unit'];
715			var mobileHeight = '' !== settings['sliderHeightMobile']['size'] ? settings['sliderHeightMobile']['size'] + settings['sliderHeightMobile']['unit'] : tabletHeight;
716
717			// Breakpoint Settings Start
718			var tabletBreakpoint = ( undefined !== elementor.config.breakpoints.lg ) ? elementor.config.breakpoints.lg - 1 : 1023,
719				mobileBreakpoint = ( undefined !== elementor.config.breakpoints.md ) ? elementor.config.breakpoints.md - 1 : 767,
720				breakpointsSettings = {};
721
722			if ( elementor.isEditMode() ) {
723				mobileBreakpoint -= 17; // needed for fixed bug when the height of the slider does not work for the tablet in the editor mode
724			}
725
726			breakpointsSettings[tabletBreakpoint] = {
727				height: tabletHeight
728			};
729
730			breakpointsSettings[mobileBreakpoint] = {
731				height: mobileHeight
732			};
733			// Breakpoint Settings End
734
735			$( '.slider-pro', $target ).sliderPro( {
736				width: settings['sliderWidth']['size'] + settings['sliderWidth']['unit'],
737				height: settings['sliderHeight']['size'] + settings['sliderHeight']['unit'],
738				arrows: settings['sliderNavigation'],
739				fadeArrows: settings['sliderNaviOnHover'],
740				buttons: settings['sliderPagination'],
741				autoplay: settings['sliderAutoplay'],
742				autoplayDelay: settings['sliderAutoplayDelay'],
743				autoplayOnHover: settings['sliderAutoplayOnHover'],
744				fullScreen: settings['sliderFullScreen'],
745				shuffle: settings['sliderShuffle'],
746				loop: settings['sliderLoop'],
747				fade: settings['sliderFadeMode'],
748				slideDistance: ( 'string' !== typeof settings['slideDistance']['size'] ) ? settings['slideDistance']['size'] : 0,
749				slideAnimationDuration: +settings['slideDuration'],
750				//imageScaleMode: settings['imageScaleMode'],
751				imageScaleMode: 'exact',
752				waitForLayers: false,
753				grabCursor: false,
754				thumbnailWidth: settings['thumbnailWidth'],
755				thumbnailHeight: settings['thumbnailHeight'],
756				rightToLeft: settings['rightToLeft'],
757				init: function() {
758					this.resize();
759
760					$( '.sp-previous-arrow', $target ).append( '<i class="' + settings['sliderNavigationIcon'] + '"></i>' );
761					$( '.sp-next-arrow', $target ).append( '<i class="' + settings['sliderNavigationIcon'] + '"></i>' );
762
763					$( '.sp-full-screen-button', $target ).append( '<i class="' + settings['sliderFullscreenIcon'] + '"></i>' );
764
765				},
766				breakpoints: breakpointsSettings
767			} );
768		},
769
770		widgetTestimonials: function( $scope ) {
771			var $target        = $scope.find( '.kurtosys-testimonials__instance' ),
772				$imagesTagList = $( '.kurtosys-testimonials__figure', $target ),
773				instance       = null,
774				settings       = $target.data( 'settings' );
775
776			if ( ! $target.length ) {
777				return;
778			}
779
780			settings.adaptiveHeight = settings['adaptiveHeight'];
781
782			KurtosysElements.initCarousel( $target, settings );
783		},
784
785		widgetImageComparison: function( $scope ) {
786			var $target              = $scope.find( '.kurtosys-image-comparison__instance' ),
787				instance             = null,
788				imageComparisonItems = $( '.kurtosys-image-comparison__container', $target ),
789				settings             = $target.data( 'settings' ),
790				elementId            = $scope.data( 'id' );
791
792			if ( ! $target.length ) {
793				return;
794			}
795
796			window.juxtapose.scanPage( '.kurtosys-juxtapose' );
797
798			settings.draggable = false;
799			settings.infinite = false;
800			//settings.adaptiveHeight = true;
801			KurtosysElements.initCarousel( $target, settings );
802		},
803
804		widgetTimeTable: function( $scope ) {
805
806			var $mptt_shortcode_wrapper = $scope.find( '.mptt-shortcode-wrapper' );
807
808			if ( ( typeof typenow ) !== 'undefined' ) {
809				if ( pagenow === typenow ) {
810					switch ( typenow ) {
811
812						case 'mp-event':
813							Registry._get( 'Event' ).init();
814							break;
815
816						case 'mp-column':
817							Registry._get( 'Event' ).initDatePicker();
818							Registry._get( 'Event' ).columnRadioBox();
819							break;
820
821						default:
822							break;
823					}
824				}
825			}
826
827			if ( $mptt_shortcode_wrapper.length ) {
828
829				Registry._get( 'Event' ).initTableData();
830				Registry._get( 'Event' ).filterShortcodeEvents();
831				Registry._get( 'Event' ).getFilterByHash();
832
833				$mptt_shortcode_wrapper.show();
834			}
835
836			if ( $( '.upcoming-events-widget' ).length || $mptt_shortcode_wrapper.length ) {
837				Registry._get( 'Event' ).setColorSettings();
838			}
839		},
840
841		elementorSection: function( $scope ) {
842			var $target   = $scope,
843				instance  = null,
844				editMode  = Boolean( elementor.isEditMode() );
845
846			if ( window.kurtosysElements.hasOwnProperty( 'kurtosysParallaxSections' ) || editMode ) {
847				instance = new kurtosysSectionParallax( $target );
848				instance.init();
849			}
850		},
851
852		initCarousel: function( $target, options ) {
853
854			var tabletSlides, mobileSlides, defaultOptions, slickOptions;
855
856			if ( options.slidesToShow.tablet ) {
857				tabletSlides = options.slidesToShow.tablet;
858			} else {
859				tabletSlides = 1 === options.slidesToShow.desktop ? 1 : 2;
860			}
861
862			if ( options.slidesToShow.mobile ) {
863				mobileSlides = options.slidesToShow.mobile;
864			} else {
865				mobileSlides = 1;
866			}
867
868			options.slidesToShow = options.slidesToShow.desktop;
869
870			defaultOptions = {
871				customPaging: function(slider, i) {
872					return $( '<span />' ).text( i + 1 );
873				},
874				dotsClass: 'kurtosys-slick-dots',
875				responsive: [
876					{
877						breakpoint: 1025,
878						settings: {
879							slidesToShow: tabletSlides,
880						}
881					},
882					{
883						breakpoint: 768,
884						settings: {
885							slidesToShow: mobileSlides,
886							slidesToScroll: 1
887						}
888					}
889				]
890			};
891
892			slickOptions = $.extend( {}, defaultOptions, options );
893			$target.slick( slickOptions );
894
895			$(".kurtosys-arrow").keyup(function(event){
896				if(event.keyCode == 13 || event.keyCode == 32){
897					$(this).click();
898				}
899			});
900		},
901
902		widgetTimeLine : function ( $scope ){
903			var $target = $scope.find( '.kurtosys-timeline' ),
904				instance = null;
905
906			if ( ! $target.length ) {
907				return;
908			}
909
910			instance = new kurtosysTimeLine( $target );
911			instance.init();
912		},
913
914		widgetTable: function( $scope ) {
915			var $target = $scope.find( '.kurtosys-table' ),
916				options = {
917					cssHeader: 'kurtosys-table-header-sort',
918					cssAsc: 'kurtosys-table-header-sort--up',
919					cssDesc: 'kurtosys-table-header-sort--down',
920					initWidgets: false
921				};
922
923			if ( ! $target.length ) {
924				return;
925			}
926
927			if ( $target.hasClass( 'kurtosys-table--sorting' ) ) {
928				$target.tablesorter( options );
929			}
930		},
931
932		widgetDropbar: function( $scope ) {
933			var $dropbar       = $scope.find( '.kurtosys-dropbar' ),
934				$dropbar_inner = $dropbar.find( '.kurtosys-dropbar__inner' ),
935				$btn           = $dropbar.find( '.kurtosys-dropbar__button' ),
936				$content       = $dropbar.find( '.kurtosys-dropbar__content' ),
937				settings       = $dropbar.data( 'settings' ) || {},
938				mode           = settings['mode'] || 'hover',
939				hide_delay     = +settings['hide_delay'] || 0,
940				activeClass    = 'kurtosys-dropbar-open',
941				scrollOffset,
942				timer;
943
944			if ( 'click' === mode ) {
945				$btn.on( 'click.kurtosysDropbar', function( event ) {
946					$dropbar.toggleClass( activeClass );
947				} );
948			} else {
949				if ( 'ontouchstart' in window || 'ontouchend' in window ) {
950					$btn.on( 'touchend.kurtosysDropbar', function( event ) {
951						if ( $( window ).scrollTop() !== scrollOffset ) {
952							return;
953						}
954
955						$dropbar.toggleClass( activeClass );
956					} );
957				} else {
958					$dropbar_inner.on( 'mouseenter.kurtosysDropbar', function( event ) {
959						clearTimeout( timer );
960						$dropbar.addClass( activeClass );
961					} );
962
963					$dropbar_inner.on( 'mouseleave.kurtosysDropbar', function( event ) {
964						timer = setTimeout( function() {
965							$dropbar.removeClass( activeClass );
966						}, hide_delay );
967					} );
968				}
969			}
970
971			$( document ).on( 'touchstart.kurtosysDropbar', function( event ) {
972				scrollOffset = $( window ).scrollTop();
973			} );
974
975			$( document ).on( 'click.kurtosysDropbar touchend.kurtosysDropbar', function( event ) {
976
977				if ( 'touchend' === event.type && $( window ).scrollTop() !== scrollOffset ) {
978					return;
979				}
980
981				if ( $( event.target ).closest( $btn ).length || $( event.target ).closest( $content ).length ) {
982					return;
983				}
984
985				if ( ! $dropbar.hasClass( activeClass ) ) {
986					return;
987				}
988
989				$dropbar.removeClass( activeClass );
990			} );
991		},
992
993		widgetVideo: function( $scope ) {
994			var $video = $scope.find( '.kurtosys-video' ),
995				$iframe = $scope.find( '.kurtosys-video-iframe' ),
996				$videoPlaer = $scope.find( '.kurtosys-video-player' ),
997				$playButton = $scope.find ('.kurtosys-video__play-button' ),
998				$mejsPlaer = $scope.find( '.kurtosys-video-mejs-player' ),
999				mejsPlaerControls = $mejsPlaer.data( 'controls' ) || ['playpause', 'current', 'progress', 'duration', 'volume', 'fullscreen'],
1000				$overlay = $scope.find( '.kurtosys-video__overlay' ),
1001				hasOverlay = $overlay.length > 0,
1002				settings = $video.data( 'settings' ) || {},
1003				autoplay = settings.autoplay || false;
1004
1005			$playButton.keydown(function( event ) {
1006				// Enter = 13; Space = 32
1007				if (event.keyCode === 13 || event.keyCode === 32) {
1008					if ( $videoPlaer[0] ) {
1009						$videoPlaer[0].play();
1010						$overlay.remove();
1011						hasOverlay = false;
1012						return;
1013					}
1014					if ( $iframe[0] ) {
1015						iframeStartPlay();
1016					}
1017				}
1018			});
1019
1020			if ( $overlay[0] ) {
1021				$overlay.on( 'click.kurtosysVideo', function( event ) {
1022
1023					if ( $videoPlaer[0] ) {
1024						$videoPlaer[0].play();
1025
1026						$overlay.remove();
1027						hasOverlay = false;
1028
1029						return;
1030					}
1031
1032					if ( $iframe[0] ) {
1033						iframeStartPlay();
1034					}
1035				} );
1036			}
1037
1038			if ( autoplay && $iframe[0] && $overlay[0] ) {
1039				iframeStartPlay();
1040			}
1041
1042			function iframeStartPlay() {
1043				var lazyLoad = $iframe.data( 'lazy-load' );
1044
1045				if ( lazyLoad ) {
1046					$iframe.attr( 'src', lazyLoad );
1047				}
1048
1049				if ( ! autoplay ) {
1050					$iframe[0].src = $iframe[0].src.replace( '&autoplay=0', '&autoplay=1' );
1051				}
1052
1053				$overlay.remove();
1054				hasOverlay = false;
1055			}
1056
1057			if ( $videoPlaer[0] ) {
1058				$videoPlaer.on( 'play.kurtosysVideo', function( event ) {
1059					if ( hasOverlay ) {
1060						$overlay.remove();
1061						hasOverlay = false;
1062					}
1063				} );
1064			}
1065
1066			if ( $mejsPlaer[0] ) {
1067				$mejsPlaer.mediaelementplayer( {
1068					videoVolume: 'horizontal',
1069					hideVolumeOnTouchDevices: false,
1070					enableProgressTooltip: false,
1071					features: mejsPlaerControls,
1072					success: function( media ) {
1073						media.addEventListener( 'timeupdate', function( event ) {
1074							var $currentTime = $scope.find( '.mejs-time-current' ),
1075								inlineStyle  = $currentTime.attr( 'style' );
1076
1077							if ( inlineStyle ) {
1078								var scaleX = inlineStyle.match(/scaleX\([0-9.]*\)/gi)[0].replace( 'scaleX(', '' ).replace( ')', '' );
1079
1080								if ( scaleX ) {
1081									$currentTime.css( 'width', scaleX * 100 + '%' );
1082								}
1083							}
1084						}, false );
1085					}
1086				} );
1087			}
1088		},
1089
1090		widgetAudio: function( $scope ) {
1091			var $wrapper = $scope.find( '.kurtosys-audio' ),
1092				$player  = $scope.find( '.kurtosys-audio-player' ),
1093				settings = $wrapper.data( 'settings' );
1094
1095			if ( ! $player[0] ) {
1096				return;
1097			}
1098
1099			$player.mediaelementplayer( {
1100				features: settings['controls'] || ['playpause', 'current', 'progress', 'duration', 'volume'],
1101				audioVolume: settings['audioVolume'] || 'horizontal',
1102				startVolume: settings['startVolume'] || 0.8,
1103				hideVolumeOnTouchDevices: settings['hideVolumeOnTouchDevices'],
1104				enableProgressTooltip: false,
1105				success: function( media ) {
1106					media.addEventListener( 'timeupdate', function( event ) {
1107						var $currentTime = $scope.find( '.mejs-time-current' ),
1108							inlineStyle  = $currentTime.attr( 'style' );
1109
1110						if ( inlineStyle ) {
1111							var scaleX = inlineStyle.match(/scaleX\([0-9.]*\)/gi)[0].replace( 'scaleX(', '' ).replace( ')', '' );
1112
1113							if ( scaleX ) {
1114								$currentTime.css( 'width', scaleX * 100 + '%' );
1115							}
1116						}
1117					}, false );
1118				}
1119			} );
1120		},
1121
1122		widgetHorizontalTimeline: function( $scope ) {
1123			var $timeline         = $scope.find( '.kurtosys-hor-timeline' ),
1124				$timelineTrack    = $scope.find( '.kurtosys-hor-timeline-track' ),
1125				$items            = $scope.find( '.kurtosys-hor-timeline-item' ),
1126				$arrows           = $scope.find( '.kurtosys-arrow' ),
1127				$nextArrow        = $scope.find( '.kurtosys-next-arrow' ),
1128				$prevArrow        = $scope.find( '.kurtosys-prev-arrow' ),
1129				columns           = $timeline.data( 'columns' ) || {},
1130				desktopColumns    = columns.desktop || 3,
1131				tabletColumns     = columns.tablet || desktopColumns,
1132				mobileColumns     = columns.mobile || tabletColumns,
1133				firstMouseEvent   = true,
1134				currentDeviceMode = elementorFrontend.getCurrentDeviceMode(),
1135				prevDeviceMode    = currentDeviceMode,
1136				itemsCount        = $scope.find( '.kurtosys-hor-timeline-list--mi
1136ddle .kurtosys-hor-timeline-item' ).length,
1137				currentTransform  = 0,
1138				currentPosition   = 0,
1139				transform = {
1140					widescreen: 100 / desktopColumns,
1141					desktop: 100 / desktopColumns,
1142					tablet:  100 / tabletColumns,
1143					mobile:  100 / mobileColumns
1144				},
1145				maxPosition = {
1146					widescreen: Math.max( 0, (itemsCount - desktopColumns) ),
1147					desktop: Math.max( 0, (itemsCount - desktopColumns) ),
1148					tablet:  Math.max( 0, (itemsCount - tabletColumns) ),
1149					mobile:  Math.max( 0, (itemsCount - mobileColumns) )
1150				};
1151
1152			if ( 'ontouchstart' in window || 'ontouchend' in window ) {
1153				$items.on( 'touchend.kurtosysHorTimeline', function( event ) {
1154					var itemId = $( this ).data( 'item-id' );
1155
1156					$scope.find( '.elementor-repeater-item-' + itemId ).toggleClass( 'is-hover' );
1157				} );
1158			} else {
1159				$items.on( 'mouseenter.kurtosysHorTimeline mouseleave.kurtosysHorTimeline', function( event ) {
1160
1161					if ( firstMouseEvent && 'mouseleave' === event.type ) {
1162						return;
1163					}
1164
1165					if ( firstMouseEvent && 'mouseenter' === event.type ) {
1166						firstMouseEvent = false;
1167					}
1168
1169					var itemId = $( this ).data( 'item-id' );
1170
1171					$scope.find( '.elementor-repeater-item-' + itemId ).toggleClass( 'is-hover' );
1172				} );
1173			}
1174
1175			// Set Line Position
1176			setLinePosition();
1177			$( window ).on( 'resize.kurtosysHorTimeline orientationchange.kurtosysHorTimeline', setLinePosition );
1178
1179			function setLinePosition() {
1180				var $line             = $scope.find( '.kurtosys-hor-timeline__line' ),
1181					$firstPoint       = $scope.find( '.kurtosys-hor-timeline-item__point-content:first' ),
1182					$lastPoint        = $scope.find( '.kurtosys-hor-timeline-item__point-content:last' ),
1183					firstPointLeftPos = $firstPoint.position().left + parseInt( $firstPoint.css( 'marginLeft' ) ),
1184					lastPointLeftPos  = $lastPoint.position().left + parseInt( $lastPoint.css( 'marginLeft' ) ),
1185					pointWidth        = $firstPoint.outerWidth();
1186
1187				$line.css( {
1188					'left': firstPointLeftPos + pointWidth/2,
1189					'width': lastPointLeftPos - firstPointLeftPos
1190				} );
1191
1192				// var $progressLine   = $scope.find( '.kurtosys-hor-timeline__line-progress' ),
1193				// 	$lastActiveItem = $scope.find( '.kurtosys-hor-timeline-list--middle .kurtosys-hor-timeline-item.is-active:last' );
1194				//
1195				// if ( $lastActiveItem[0] ) {
1196				// 	var $lastActiveItemPointWrap = $lastActiveItem.find( '.kurtosys-hor-timeline-item__point' ),
1197				// 		progressLineWidth        = $lastActiveItemPointWrap.position().left + $lastActiveItemPointWrap.outerWidth() - firstPointLeftPos - pointWidth / 2;
1198				//
1199				// 	$progressLine.css( {
1200				// 		'width': progressLineWidth
1201				// 	} );
1202				// }
1203			}
1204
1205			// Arrows Navigation Type
1206			if ( $nextArrow[0] && maxPosition[ currentDeviceMode ] === 0 ) {
1207				$nextArrow.addClass( 'kurtosys-arrow-disabled' );
1208			}
1209
1210			if ( $arrows[0] ) {
1211				$arrows.on( 'click.kurtosysHorTimeline', function( event ){
1212					var $this = $( this ),
1213						direction = $this.hasClass( 'kurtosys-next-arrow' ) ? 'next' : 'prev',
1214						currentDeviceMode = elementorFrontend.getCurrentDeviceMode();
1215
1216					if ( 'next' === direction && currentPosition < maxPosition[ currentDeviceMode ] ) {
1217						currentTransform -= transform[ currentDeviceMode ];
1218						currentPosition += 1;
1219					}
1220
1221					if ( 'prev' === direction && currentPosition > 0 ) {
1222						currentTransform += transform[ currentDeviceMode ];
1223						currentPosition -= 1;
1224					}
1225
1226					if ( currentPosition > 0 ) {
1227						$prevArrow.removeClass( 'kurtosys-arrow-disabled' );
1228					} else {
1229						$prevArrow.addClass( 'kurtosys-arrow-disabled' );
1230					}
1231
1232					if ( currentPosition === maxPosition[ currentDeviceMode ] ) {
1233						$nextArrow.addClass( 'kurtosys-arrow-disabled' );
1234					} else {
1235						$nextArrow.removeClass( 'kurtosys-arrow-disabled' );
1236					}
1237
1238					if ( currentPosition === 0 ) {
1239						currentTransform = 0;
1240					}
1241
1242					$timelineTrack.css({
1243						'transform': 'translateX(' + currentTransform + '%)'
1244					});
1245
1246				} );
1247			}
1248
1249			setArrowPosition();
1250			$( window ).on( 'resize.kurtosysHorTimeline orientationchange.kurtosysHorTimeline', setArrowPosition );
1251			$( window ).on( 'resize.kurtosysHorTimeline orientationchange.kurtosysHorTimeline', timelineSliderResizeHandler );
1252
1253			function setArrowPosition() {
1254				if ( ! $arrows[0] ) {
1255					return;
1256				}
1257
1258				var $middleList = $scope.find( '.kurtosys-hor-timeline-list--mi
1258ddle' ),
1259					middleListTopPosition = $middleList.position().top,
1260					middleListHeight = $middleList.outerHeight();
1261
1262				$arrows.css({
1263					'top': middleListTopPosition + middleListHeight/2
1264				});
1265			}
1266
1267			function timelineSliderResizeHandler( event ) {
1268				if ( ! $timeline.hasClass( 'kurtosys-hor-timeline--arrows-nav' ) ) {
1269					return;
1270				}
1271
1272				var currentDeviceMode = elementorFrontend.getCurrentDeviceMode(),
1273					resetSlider = function() {
1274						$prevArrow.addClass( 'kurtosys-arrow-disabled' );
1275
1276						if ( $nextArrow.hasClass( 'kurtosys-arrow-disabled' ) ) {
1277							$nextArrow.removeClass( 'kurtosys-arrow-disabled' );
1278						}
1279
1280						if ( maxPosition[ currentDeviceMode ] === 0 ) {
1281							$nextArrow.addClass( 'kurtosys-arrow-disabled' );
1282						}
1283
1284						currentTransform = 0;
1285						currentPosition = 0;
1286
1287						$timelineTrack.css({
1288							'transform': 'translateX(0%)'
1289						});
1290					};
1291
1292				switch ( currentDeviceMode ) {
1293					case 'widescreen':
1294						if ( 'widescreen' !== prevDeviceMode ) {
1295							resetSlider();
1296							prevDeviceMode = 'widescreen';
1297						}
1298						break;
1299
1300					case 'desktop':
1301						if ( 'desktop' !== prevDeviceMode ) {
1302							resetSlider();
1303							prevDeviceMode = 'desktop';
1304						}
1305						break;
1306
1307					case 'tablet':
1308						if ( 'tablet' !== prevDeviceMode ) {
1309							resetSlider();
1310							prevDeviceMode = 'tablet';
1311						}
1312						break;
1313
1314					case 'mobile':
1315						if ( 'mobile' !== prevDeviceMode ) {
1316							resetSlider();
1317							prevDeviceMode = 'mobile';
1318						}
1319						break;
1320				}
1321			}
1322		},
1323
1324		widgetPieChart: function( $scope ) {
1325			var $container     = $scope.find( '.kurtosys-pie-chart-container' ),
1326				$canvas        = $scope.find( '.kurtosys-pie-chart' )[0],
1327				data           = $container.data( 'chart' ) || {},
1328				options        = $container.data( 'options' ) || {},
1329				defaultOptions = {
1330					maintainAspectRatio: false
1331				};
1332
1333			options = $.extend( {}, defaultOptions, options );
1334
1335			elementorFrontend.waypoint( $scope, function() {
1336				var chartInstance = new Chart( $canvas, {
1337					type:    'pie',
1338					data:    data,
1339					options: options
1340				} );
1341			}, {
1342				offset: 'bottom-in-view'
1343			} );
1344		}
1345	};
1346
1347	$( window ).on( 'elementor/frontend/init', KurtosysElements.init );
1348
1349	var KurtosysElementsTools = {
1350		debounce: function( threshold, callback ) {
1351			var timeout;
1352
1353			return function debounced( $event ) {
1354				function delayed() {
1355					callback.call( this, $event );
1356					timeout = null;
1357				}
1358
1359				if ( timeout ) {
1360					clearTimeout( timeout );
1361				}
1362
1363				timeout = setTimeout( delayed, threshold );
1364			};
1365		},
1366
1367		getObjectNextKey: function( object, key ) {
1368			var keys      = Object.keys( object ),
1369				idIndex   = keys.indexOf( key ),
1370				nextIndex = idIndex += 1;
1371
1372			if( nextIndex >= keys.length ) {
1373				//we're at the end, there is no next
1374				return false;
1375			}
1376
1377			var nextKey = keys[ nextIndex ];
1378
1379			return nextKey;
1380		},
1381
1382		getObjectPrevKey: function( object, key ) {
1383			var keys      = Object.keys( object ),
1384				idIndex   = keys.indexOf( key ),
1385				prevIndex = idIndex -= 1;
1386
1387			if ( 0 > idIndex ) {
1388				//we're at the end, there is no next
1389				return false;
1390			}
1391
1392			var prevKey = keys[ prevIndex ];
1393
1394			return prevKey;
1395		},
1396
1397		getObjectFirstKey: function( object ) {
1398			return Object.keys( object )[0];
1399		},
1400
1401		getObjectLastKey: function( object ) {
1402			return Object.keys( object )[ Object.keys( object ).length - 1 ];
1403		},
1404
1405		getObjectValues: function( object ) {
1406			var values;
1407
1408			if ( !Object.values ) {
1409				values = Object.keys( object ).map( function( e ) {
1410					return object[e]
1411				} );
1412
1413				return values;
1414			}
1415
1416			return Object.values( object );
1417		},
1418
1419		validateEmail: function( email ) {
1420			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,}))$/;
1421
1422			return re.test( email );
1423		}
1424	}
1425
1426	/**
1427	 * Kurtosys animated text Class
1428	 *
1429	 * @return {void}
1430	 */
1431	window.kurtosysAnimatedText = function( $selector, settings ) {
1432		var self                   = this,
1433			$instance              = $selector,
1434			$animatedTextContainer = $( '.kurtosys-animated-text__animated-text', $instance ),
1435			$animatedTextList      = $( '.kurtosys-animated-text__animated-text-item', $animatedTextContainer ),
1436			timeOut                = null,
1437			defaultSettings        = {
1438				effect: 'fx1',
1439				delay: 3000
1440			},
1441			settings               =  $.extend( defaultSettings, settings || {} ),
1442			currentIndex           = 0,
1443			animationDelay         = settings.delay;
1444
1445		/**
1446		 * Avaliable Effects
1447		 */
1448		self.avaliableEffects = {
1449			'fx1' : {
1450				in: {
1451					duration: 1000,
1452					delay: function( el, index ) { return 75 + index * 100; },
1453					easing: 'easeOutElastic',
1454					elasticity: 650,
1455					opacity: {
1456						value: [ 0, 1 ],
1457						easing: 'easeOutExpo',
1458					},
1459					translateY: ['100%','0%']
1460				},
1461				out: {
1462					duration: 300,
1463					delay: function(el, index) { return index*40; },
1464					easing: 'easeInOutExpo',
1465					opacity: 0,
1466					translateY: '-100%'
1467				}
1468			},
1469			'fx2' : {
1470				in: {
1471					duration: 800,
1472					delay: function( el, index) { return index * 50; },
1473					easing: 'easeOutElastic',
1474					opacity: {
1475						value: [ 0, 1 ],
1476						easing: 'easeOutExpo',
1477					},
1478					translateY: function(el, index) {
1479						return index%2 === 0 ? ['-80%', '0%'] : ['80%', '0%'];
1480					}
1481				},
1482				out: {
1483					duration: 300,
1484					delay: function( el, index ) { return index * 20; },
1485					easing: 'easeOutExpo',
1486					opacity: 0,
1487					translateY: function( el, index ) {
1488						return index%2 === 0 ? '80%' : '-80%';
1489					}
1490				}
1491			},
1492			'fx3' : {
1493				in: {
1494					duration: 700,
1495					delay: function(el, index) {
1496						return ( el.parentNode.children.length - index - 1 ) * 80;
1497					},
1498					easing: 'easeOutElastic',
1499					opacity: {
1500						value: [ 0, 1 ],
1501						easing: 'easeOutExpo',
1502					},
1503					translateY: function(el, index) {
1504						return index%2 === 0 ? [ '-80%', '0%' ] : [ '80%', '0%' ];
1505					},
1506					rotateZ: [90,0]
1507				},
1508				out: {
1509					duration: 300,
1510					delay: function(el, index) { return (el.parentNode.children.length-index-1) * 50; },
1511					easing: 'easeOutExpo',
1512					opacity: 0,
1513					translateY: function(el, index) {
1514						return index%2 === 0 ? '80%' : '-80%';
1515					},
1516					rotateZ: function(el, index) {
1517						return index%2 === 0 ? -25 : 25;
1518					}
1519				}
1520			},
1521			'fx4' : {
1522				in: {
1523					duration: 700,
1524					delay: function( el, index ) { return 550 + index * 50; },
1525					easing: 'easeOutQuint',
1526					opacity: {
1527						value: [ 0, 1 ],
1528						easing: 'easeOutExpo',
1529					},
1530					translateY: [ '-150%','0%' ],
1531					rotateY: [ 180, 0 ]
1532				},
1533				out: {
1534					duration: 200,
1535					delay: function( el, index ) { return index * 30; },
1536					easing: 'easeInQuint',
1537					opacity: {
1538						value: 0,
1539						easing: 'linear',
1540					},
1541					translateY: '100%',
1542					rotateY: -180
1543				}
1544			},
1545			'fx5' : {
1546				in: {
1547					duration: 250,
1548					delay: function( el, index ) { return 200 + index * 25; },
1549					easing: 'easeOutCubic',
1550					opacity: {
1551						value: [ 0, 1 ],
1552						easing: 'easeOutExpo',
1553					},
1554					translateY: ['-50%','0%']
1555				},
1556				out: {
1557					duration: 250,
1558					delay: function( el, index ) { return index * 25; },
1559					easing: 'easeOutCubic',
1560					opacity: 0,
1561					translateY: '50%'
1562				}
1563			},
1564			'fx6' : {
1565				in: {
1566					duration: 400,
1567					delay: function( el, index ) { return index * 50; },
1568					easing: 'easeOutSine',
1569					opacity: {
1570						value: [ 0, 1 ],
1571						easing: 'easeOutExpo',
1572					},
1573					rotateY: [ -90, 0 ]
1574				},
1575				out: {
1576					duration: 200,
1577					delay: function( el, index ) { return index * 50; },
1578					easing: 'easeOutSine',
1579					opacity: 0,
1580					rotateY: 45
1581				}
1582			},
1583			'fx7' : {
1584				in: {
1585					duration: 1000,
1586					delay: function( el, index ) { return 100 + index * 30; },
1587					easing: 'easeOutElastic',
1588					opacity: {
1589						value: [ 0, 1 ],
1590						easing: 'easeOutExpo',
1591					},
1592					rotateZ: function( el, index ) {
1593						return [ anime.random( 20, 40 ), 0 ];
1594					}
1595				},
1596				out: {
1597					duration: 300,
1598					opacity: {
1599						value: [ 1, 0 ],
1600						easing: 'easeOutExpo',
1601					}
1602				}
1603			},
1604			'fx8' : {
1605				in: {
1606					duration: 400,
1607					delay: function( el, index ) { return 200 + index * 20; },
1608					easing: 'easeOutExpo',
1609					opacity: 1,
1610					rotateY: [ -90, 0 ],
1611					translateY: [ '50%','0%' ]
1612				},
1613				out: {
1614					duration: 250,
1615					delay: function( el, index ) { return index * 20; },
1616					easing: 'easeOutExpo',
1617					opacity: 0,
1618					rotateY: 90
1619				}
1620			},
1621			'fx9' : {
1622				in: {
1623					duration: 400,
1624					delay: function(el, index) { return 200+index*30; },
1625					easing: 'easeOutExpo',
1626					opacity: 1,
1627					rotateX: [90,0]
1628				},
1629				out: {
1630					duration: 250,
1631					delay: function(el, index) { return index*30; },
1632					easing: 'easeOutExpo',
1633					opacity: 0,
1634					rotateX: -90
1635				}
1636			},
1637			'fx10' : {
1638				in: {
1639					duration: 400,
1640					delay: function( el, index ) { return 100 + index * 50; },
1641					easing: 'easeOutExpo',
1642					opacity: {
1643						value: [ 0, 1 ],
1644						easing: 'easeOutExpo',
1645					},
1646					rotateX: [ 110, 0 ]
1647				},
1648				out: {
1649					duration: 250,
1650					delay: function( el, index ) { return index * 50; },
1651					easing: 'easeOutExpo',
1652					opacity: 0,
1653					rotateX: -110
1654				}
1655			},
1656			'fx11' : {
1657				in: {
1658					duration: function( el, index ) { return anime.random( 800, 1000 ); },
1659					delay: function( el, index ) { return anime.random( 100, 300 ); },
1660					easing: 'easeOutExpo',
1661					opacity: {
1662						value: [ 0, 1 ],
1663						easing: 'easeOutExpo',
1664					},
1665					translateY: [ '-150%','0%' ],
1666					rotateZ: function( el, index ) { return [ anime.random( -50, 50 ), 0 ]; }
1667				},
1668				out: {
1669					duration: function( el, index ) { return anime.random( 200, 300 ); },
1670					delay: function( el, index ) { return anime.random( 0, 80 ); },
1671					easing: 'easeInQuart',
1672					opacity: 0,
1673					translateY: '50%',
1674					rotateZ: function( el, index ) { return anime.random( -50, 50 ); }
1675				}
1676			},
1677			'fx12' : {
1678				in: {
1679					elasticity: false,
1680					duration: 1,
1681					delay: function( el, index ) {
1682						var delay = index * 100 + anime.random( 50, 100 );
1683
1684						return delay;
1685					},
1686					width: [ 0, function( el, i ) { return $( el ).width(); } ]
1687				},
1688				out: {
1689					duration: 1,
1690					delay: function( el, index ) { return ( el.parentNode.children.length - index - 1 ) * 20; },
1691					easing: 'linear',
1692					width: {
1693						value: 0
1694					}
1695				}
1696			}
1697		};
1698
1699		self.textChange = function() {
1700			var currentDelay = animationDelay,
1701				$prevText    = $animatedTextList.eq( currentIndex ),
1702				$nextText;
1703
1704			if ( currentIndex < $animatedTextList.length - 1 ) {
1705				currentIndex++;
1706			} else {
1707				currentIndex = 0;
1708			}
1709
1710			$nextText = $animatedTextList.eq( currentIndex );
1711
1712			self.hideText( $prevText, settings.effect, null, function( anime ) {
1713				$prevText.toggleClass( 'visible' );
1714
1715				var currentDelay = animationDelay;
1716
1717				if ( timeOut ) {
1718					clearTimeout( timeOut );
1719				}
1720
1721				self.showText(
1722					$nextText,
1723					settings.effect,
1724					function() {
1725						$nextText.toggleClass( 'active' );
1726						$prevText.toggleClass( 'active' );
1727
1728						$nextText.toggleClass( 'visible' );
1729					},
1730					function() {
1731						timeOut = setTimeout( function() {
1732							self.textChange();
1733						}, currentDelay );
1734					}
1735				);
1736
1737			} );
1738		};
1739
1740		self.showText = function( $selector, effect, beginCallback, completeCallback ) {
1741			var targets = [];
1742
1743			$( 'span', $selector ).each( function() {
1744				$( this ).css( {
1745					'width': 'auto',
1746					'opacity': 1,
1747					'WebkitTransform': '',
1748					'transform': ''
1749				});
1750				targets.push( this );
1751			});
1752
1753			self.animateText( targets, 'in', effect, beginCallback, completeCallback );
1754		};
1755
1756		self.hideText = function( $selector, effect, beginCallback, completeCallback ) {
1757			var targets = [];
1758
1759			$( 'span', $selector ).each( function() {
1760				targets.push(this);
1761			});
1762
1763			self.animateText( targets, 'out', effect, beginCallback, completeCallback );
1764		};
1765
1766		self.animateText = function( targets, direction, effect, beginCallback, completeCallback ) {
1767			var effectSettings   = self.avaliableEffects[ effect ] || {},
1768				animationOptions = effectSettings[ direction ],
1769				animeInstance = null;
1770
1771			animationOptions.targets = targets;
1772
1773			animationOptions.begin = beginCallback;
1774			animationOptions.complete = completeCallback;
1775
1776			animeInstance = anime( animationOptions );
1777		};
1778
1779		self.init = function() {
1780			var $text = $animatedTextList.eq( currentIndex );
1781
1782			self.showText(
1783				$text,
1784				settings.effect,
1785				null,
1786				function() {
1787					var currentDelay = animationDelay;
1788
1789					if ( timeOut ) {
1790						clearTimeout( timeOut );
1791					}
1792
1793					timeOut = setTimeout( function() {
1794						self.textChange();
1795					}, currentDelay );
1796
1797				}
1798			);
1799		};
1800	}
1801
1802	/**
1803	 * Kurtosys Images Layout Class
1804	 *
1805	 * @return {void}
1806	 */
1807	window.kurtosysImagesLayout = function( $selector, settings ) {
1808		var self            = this,
1809			$instance       = $selector,
1810			$instanceList   = $( '.kurtosys-images-layout__list', $instance ),
1811			$itemsList      = $( '.kurtosys-images-layout__item', $instance ),
1812			defaultSettings = {},
1813			settings        = settings || {};
1814
1815		/*
1816		 * Default Settings
1817		 */
1818		defaultSettings = {
1819			layoutType: 'masonry',
1820			columns: 3,
1821			columnsTablet: 2,
1822			columnsMobile: 1,
1823			justifyHeight: 300
1824		}
1825
1826		/**
1827		 * Checking options, settings and options merging
1828		 */
1829		$.extend( defaultSettings, settings );
1830
1831		/**
1832		 * Layout build
1833		 */
1834		self.layoutBuild = function() {
1835			switch ( settings['layoutType'] ) {
1836				case 'masonry':
1837					salvattore.init();
1838				break;
1839				case 'justify':
1840					$itemsList.each( function() {
1841						var $this          = $( this ),
1842							$imageInstance = $( '.kurtosys-images-layout__image-instance', $this),
1843							imageWidth     = $imageInstance.data( 'width' ),
1844							imageHeight    = $imageInstance.data( 'height' ),
1845							imageRatio     = +imageWidth / +imageHeight,
1846							flexValue      = imageRatio * 100,
1847							newWidth       = +settings['justifyHeight'] * imageRatio,
1848							newHeight      = 'auto';
1849
1850						$this.css( {
1851							'flex-grow': flexValue,
1852							'flex-basis': newWidth
1853						} );
1854					} );
1855				break;
1856			}
1857
1858			if ( $.isFunction( $.fn.imagesLoaded ) ) {
1859
1860				$( '.kurtosys-images-layout__image', $itemsList ).imagesLoaded().progress( function( instance, image ) {
1861					var $image      = $( image.img ),
1862						$parentItem = $image.closest( '.kurtosys-images-layout__item' ),
1863						$loader     = $( '.kurtosys-images-layout__image-loader', $parentItem );
1864
1865					$parentItem.addClass( 'image-loaded' );
1866
1867					$loader.fadeTo( 500, 0, function() {
1868						$( this ).remove();
1869					} );
1870
1871				});
1872
1873			} else {
1874				var $loader = $( '.kurtosys-images-layout__image-loader', $itemsList );
1875
1876				$itemsList.addClass( 'image-loaded' );
1877
1878				$loader.fadeTo( 500, 0, function() {
1879					$( this ).remove();
1880				} );
1881			}
1882		}
1883
1884		/**
1885		 * Init
1886		 */
1887		self.init = function() {
1888			self.layoutBuild();
1889		}
1890	}
1891
1892	/**
1893	 * Kurtosys Scroll Navigation Class
1894	 *
1895	 * @return {void}
1896	 */
1897	window.kurtosysScrollNavigation = function( $selector, settings ) {
1898		var self            = this,
1899			$window         = $( window ),
1900			$document       = $( document ),
1901			$body           = $( 'body' ),
1902			$instance       = $selector,
1903			$htmlBody       = $( 'html, body' ),
1904			$itemsList      = $( '.kurtosys-scroll-navigation__item', $instance ),
1905			sectionList     = [],
1906			defaultSettings = {
1907				speed: 500,
1908				blockSpeed: 500,
1909				offset: 200,
1910				sectionSwitch: false
1911			},
1912			settings        = $.extend( {}, defaultSettings, settings ),
1913			sections        = {},
1914			currentSection  = null,
1915			isScrolling     = false,
1916			isSwipe         = false,
1917			hash            = window.location.hash.slice(1),
1918			timeout         = null,
1919			timeStamp       = 0,
1920			platform        = navigator.platform;
1921
1922		jQuery.extend( jQuery.easing, {
1923			easeInOutCirc: function (x, t, b, c, d) {
1924				if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
1925				return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
1926			}
1927		});
1928
1929		/**
1930		 * [init description]
1931		 * @return {[type]} [description]
1932		 */
1933		self.init = function() {
1934			self.setSectionsData();
1935
1936			if ( hash && sections.hasOwnProperty( hash ) ) {
1937				$itemsList.addClass( 'invert' );
1938			}
1939
1940			// Add Events
1941			$itemsList.on( 'click.kurtosysScrollNavigation', self.onAnchorChange );
1942			$window.on( 'resize.kurtosysScrollNavigation orientationchange.kurtosysScrollNavigation', KurtosysElementsTools.debounce( 50, self.onResize ) );
1943			$window.on( 'load', function() { self.setSectionsData(); } );
1944
1945			$document.keydown( function( event ) {
1946
1947				if ( 38 == event.keyCode ) {
1948					self.directionSwitch( event, 'up' );
1949				}
1950
1951				if ( 40 == event.keyCode ) {
1952					self.directionSwitch( event, 'down' );
1953				}
1954			} );
1955
1956			// waypoint section detection
1957			self.waypointHandler();
1958
1959			// hijaking handler
1960			self.hijakingHandler();
1961		};
1962
1963		/**
1964		 * [waypointHandler description]
1965		 * @return {[type]} [description]
1966		 */
1967		self.waypointHandler = function() {
1968
1969			for ( var section in sections ) {
1970				var $section = sections[section].selector;
1971
1972				elementorFrontend.waypoint( $section, function( direction ) {
1973					var $this = $( this ),
1974						sectionId = $this.attr( 'id' );
1975
1976						if ( 'down' === direction && ! isScrolling ) {
1977							window.history.pushState( null, null, '#' + sectionId );
1978							currentSection = sectionId;
1979							$itemsList.removeClass( 'active' );
1980							$( '[data-anchor=' + sectionId + ']', $instance ).addClass( 'active' );
1981
1982							$itemsList.removeClass( 'invert' );
1983
1984							if ( sections[sectionId].invert ) {
1985								$itemsList.addClass( 'invert' );
1986							}
1987						}
1988				}, {
1989					offset: '70%',
1990					triggerOnce: false
1991				} );
1992
1993				elementorFrontend.waypoint( $section, function( direction ) {
1994					var $this = $( this ),
1995						sectionId = $this.attr( 'id' );
1996
1997						if ( 'up' === direction && ! isScrolling ) {
1998							window.history.pushState( null, null, '#' + sectionId );
1999							currentSection = sectionId;
2000							$itemsList.removeClass( 'active' );
2001							$( '[data-anchor=' + sectionId + ']', $instance ).addClass( 'active' );
2002
2003							$itemsList.removeClass( 'invert' );
2004
2005							if ( sections[sectionId].invert ) {
2006								$itemsList.addClass( 'invert' );
2007							}
2008						}
2009				}, {
2010					offset: '0%',
2011					triggerOnce: false
2012				} );
2013			}
2014		};
2015
2016		/**
2017		 * [scrollifyHandler description]
2018		 * @return {[type]} [description]
2019		 */
2020		self.hijakingHandler = function() {
2021
2022			if ( settings.sectionSwitch ) {
2023
2024				//$document.on( 'mousewheel.kurtosysScrollNavigation DOMMouseScroll.kurtosysScrollNavigation', self.onWheel );
2025				$document.on( 'wheel.kurtosysScrollNavigation', self.onWheel );
2026			}
2027		}
2028
2029		/**
2030		 * [onAnchorChange description]
2031		 * @param  {[type]} event [description]
2032		 * @return {[type]}       [description]
2033		 */
2034		self.onAnchorChange = function( event ) {
2035			event.preventDefault();
2036
2037			var $this     = $( this ),
2038				sectionId = $this.data('anchor'),
2039				offset    = null;
2040
2041			if ( ! sections.hasOwnProperty( sectionId ) ) {
2042				return false;
2043			}
2044
2045			offset = sections[sectionId].offset - settings.offset;
2046
2047			if ( ! isScrolling ) {
2048				isScrolling = true;
2049
2050				window.history.pushState( null, null, '#' + sectionId );
2051				currentSection = sectionId;
2052
2053				$itemsList.removeClass( 'active' );
2054				$this.addClass( 'active' );
2055
2056				$itemsList.removeClass( 'invert' );
2057
2058				if ( sections[sectionId].invert ) {
2059					$itemsList.addClass( 'invert' );
2060				}
2061
2062				$htmlBody.stop().clearQueue().animate( { 'scrollTop': offset }, settings.speed, 'easeInOutCirc', function() {
2063					isScrolling = false;
2064				} );
2065
2066				return false;
2067			}
2068		};
2069
2070		/**
2071		 * [directionSwitch description]
2072		 * @param  {[type]} event     [description]
2073		 * @param  {[type]} direction [description]
2074		 * @return {[type]}           [description]
2075		 */
2076		self.directionSwitch = function( event, direction ) {
2077			var direction = direction || 'up',
2078				sectionId,
2079				nextItem = $( '[data-anchor=' + currentSection + ']', $instance ).next(),
2080				prevItem = $( '[data-anchor=' + currentSection + ']', $instance ).prev();
2081
2082			if ( isScrolling ) {
2083				return false;
2084			}
2085
2086			if ( 'up' === direction ) {
2087				if ( prevItem[0] ) {
2088					prevItem.trigger( 'click.kurtosysScrollNavigation' );
2089				}
2090			}
2091
2092			if ( 'down' === direction ) {
2093				if ( nextItem[0] ) {
2094					nextItem.trigger( 'click.kurtosysScrollNavigation' );
2095				}
2096			}
2097		};
2098
2099		/**
2100		 * [onScroll description]
2101		 * @param  {[type]} event [description]
2102		 * @return {[type]}       [description]
2103		 */
2104		self.onScroll = function( event ) {
2105
2106			/* On Scroll Event */
2107			if ( isScrolling ) {
2108				event.preventDefault();
2109			}
2110		};
2111
2112		/**
2113		 * [onWheel description]
2114		 * @param  {[type]} event [description]
2115		 * @return {[type]}       [description]
2116		 */
2117		self.onWheel = function( event ) {
2118
2119			event.preventDefault();
2120
2121			if ( isScrolling ) {
2122
2123				return false;
2124			}
2125
2126			var $target         = $( event.target ),
2127				$section        = $target.closest( '.elementor-top-section' ),
2128				sectionId       = $section.attr( 'id' ),
2129				offset          = 0,
2130				newSectionId    = false,
2131				prevSectionId   = false,
2132				nextSectionId   = false,
2133				delta           = event.originalEvent.deltaY,
2134				direction       = ( 0 > delta ) ? 'up' : 'down',
2135				windowScrollTop = $window.scrollTop();
2136
2137			if ( self.beforeCheck() ) {
2138				sectionId = KurtosysElementsTools.getObjectFirstKey( sections );
2139			}
2140
2141			if ( self.afterCheck() ) {
2142				sectionId = KurtosysElementsTools.getObjectLastKey( sections );
2143			}
2144
2145			if ( sectionId && sections.hasOwnProperty( sectionId ) ) {
2146
2147				prevSectionId = KurtosysElementsTools.getObjectPrevKey( sections, sectionId );
2148				nextSectionId = KurtosysElementsTools.getObjectNextKey( sections, sectionId );
2149
2150				if ( 'up' === direction ) {
2151					if ( ! nextSectionId && sections[sectionId].offset < windowScrollTop ) {
2152						newSectionId = sectionId;
2153					} else {
2154						newSectionId = prevSectionId;
2155					}
2156				}
2157
2158				if ( 'down' === direction ) {
2159					if ( ! prevSectionId && sections[sectionId].offset > windowScrollTop + 5 ) {
2160						newSectionId = sectionId;
2161					} else {
2162						newSectionId = nextSectionId;
2163					}
2164				}
2165
2166				if ( newSectionId ) {
2167
2168					if ( event.timeStamp - timeStamp > 10 && 'MacIntel' == platform ) {
2169						timeStamp = event.timeStamp;
2170						event.preventDefault();
2171						return false;
2172					}
2173
2174					offset = sections[newSectionId].offset - settings.offset;
2175					window.history.pushState( null, null, '#' + newSectionId );
2176					currentSection = newSectionId;
2177
2178					$itemsList.removeClass( 'active' );
2179					$( '[data-anchor=' + newSectionId + ']', $instance ).addClass( 'active' );
2180
2181					$itemsList.removeClass( 'invert' );
2182
2183					if ( sections[newSectionId].invert ) {
2184						$itemsList.addClass( 'invert' );
2185					}
2186
2187					isScrolling = true;
2188					self.scrollStop();
2189					$htmlBody.animate( { 'scrollTop': offset }, settings.blockSpeed, 'easeInOutCirc', function() {
2190						isScrolling = false;
2191					} );
2192				}
2193			}
2194
2195		};
2196
2197		/**
2198		 * [setSectionsData description]
2199		 */
2200		self.setSectionsData = function() {
2201			$itemsList.each( function() {
2202				var $this         = $( this ),
2203					sectionId     = $this.data('anchor'),
2204					sectionInvert = 'yes' === $this.data('invert') ? true : false,
2205					$section      = $( '#' + sectionId );
2206
2207				$section.addClass( 'kurtosys-scroll-navigation-section' );
2208				$section[0].dataset.sectionName = sectionId;
2209
2210				if ( $section[0] ) {
2211					sections[ sectionId ] = {
2212						selector: $section,
2213						offset: Math.round( $section.offset().top ),
2214						height: $section.outerHeight(),
2215						invert: sectionInvert
2216					};
2217				}
2218			} );
2219		};
2220
2221
2222		/**
2223		 * [beforeCheck description]
2224		 * @param  {[type]} event [description]
2225		 * @return {[type]}       [description]
2226		 */
2227		self.beforeCheck = function( event ) {
2228			var windowScrollTop = $window.scrollTop(),
2229				firstSectionId = KurtosysElementsTools.getObjectFirstKey( sections ),
2230				offset = sections[ firstSectionId ].offset,
2231				topBorder = windowScrollTop + $window.outerHeight();
2232
2233			if ( topBorder > offset ) {
2234				return false;
2235			}
2236
2237			return true;
2238		};
2239
2240		/**
2241		 * [afterCheck description]
2242		 * @param  {[type]} event [description]
2243		 * @return {[type]}       [description]
2244		 */
2245		self.afterCheck = function( event ) {
2246			var windowScrollTop = $window.scrollTop(),
2247				lastSectionId = KurtosysElementsTools.getObjectLastKey( sections ),
2248				offset = sections[ lastSectionId ].offset,
2249				bottomBorder = sections[ lastSectionId ].offset + sections[ lastSectionId ].height;
2250
2251			if ( windowScrollTop < bottomBorder ) {
2252				return false;
2253			}
2254
2255			return true;
2256		};
2257
2258		/**
2259		 * [onResize description]
2260		 * @param  {[type]} event [description]
2261		 * @return {[type]}       [description]
2262		 */
2263		self.onResize = function( event ) {
2264			self.setSectionsData();
2265		};
2266
2267		/**
2268		 * [scrollStop description]
2269		 * @return {[type]} [description]
2270		 */
2271		self.scrollStop = function() {
2272			$htmlBody.stop( true );
2273		};
2274
2275		/**
2276		 * Mobile and tablet check funcion.
2277		 *
2278		 * @return {boolean} Mobile Status
2279		 */
2280		self.mobileAndTabletcheck = function() {
2281			var check = false;
2282
2283			(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);
2284
2285			return check;
2286		};
2287
2288	}
2289
2290	/**
2291	 * kurtosysSectionParallax Class
2292	 *
2293	 * @return {void}
2294	 */
2295	window.kurtosysSectionParallax = function( $target ) {
2296		var self             = this,
2297			sectionId        = $target.data('id'),
2298			settings         = false,
2299			editMode         = Boolean( elementor.isEditMode() ),
2300			$window          = $( window ),
2301			$body            = $( 'body' ),
2302			scrollLayoutList = [],
2303			mouseLayoutList  = [],
2304			winScrollTop     = $window.scrollTop(),
2305			winHeight        = $window.height(),
2306			requesScroll     = null,
2307			requestMouse     = null,
2308			tiltx            = 0,
2309			tilty            = 0,
2310			isSafari         = !!navigator.userAgent.match(/Version\/[\d\.]+.*Safari/),
2311			platform         = navigator.platform;
2312
2313		/**
2314		 * Init
2315		 */
2316		self.init = function() {
2317
2318			if ( ! editMode ) {
2319				settings = kurtosysElements[ 'kurtosysParallaxSections' ][ sectionId ] || false;
2320			} else {
2321				settings = self.generateEditorSettings( sectionId );
2322			}
2323
2324			if ( ! settings ) {
2325				return false;
2326			}
2327
2328			self.generateLayouts();
2329
2330			//$window.on( 'scroll.kurtosysSectionParallax resize.kurtosysSectionParallax', KurtosysElementsTools.debounce( 5, self.scrollHandler ) );
2331
2332			if ( 0 !== scrollLayoutList.length ) {
2333				$window.on( 'scroll.kurtosysSectionParallax resize.kurtosysSectionParallax', self.scrollHandler );
2334			}
2335
2336			if ( 0 !== mouseLayoutList.length ) {
2337				$target.on( 'mousemove.kurtosysSectionParallax resize.kurtosysSectionParallax', self.mouseMoveHandler );
2338				$target.on( 'mouseleave.kurtosysSectionParallax', self.mouseLeaveHandler );
2339			}
2340
2341			self.scrollUpdate();
2342		};
2343
2344		self.generateEditorSettings = function( sectionId ) {
2345			var editorElements      = null,
2346				sectionsData        = {},
2347				sectionData         = {},
2348				sectionParallaxData = {},
2349				settings            = [];
2350
2351			if ( ! window.elementor.hasOwnProperty( 'elements' ) ) {
2352				return false;
2353			}
2354
2355			editorElements = window.elementor.elements;
2356
2357			if ( ! editorElements.models ) {
2358				return false;
2359			}
2360
2361			$.each( editorElements.models, function( index, obj ) {
2362				if ( sectionId == obj.id ) {
2363					sectionData = obj.attributes.settings.attributes;
2364				}
2365			} );
2366
2367			if ( ! sectionData.hasOwnProperty( 'kurtosys_parallax_layout_list' ) || 0 === Object.keys( sectionData ).length ) {
2368				return false;
2369			}
2370
2371			sectionParallaxData = sectionData[ 'kurtosys_parallax_layout_list' ].models;
2372
2373			$.each( sectionParallaxData, function( index, obj ) {
2374				settings.push( obj.attributes );
2375			} );
2376
2377			if ( 0 !== settings.length ) {
2378				return settings;
2379			}
2380
2381			return false;
2382		};
2383
2384		self.generateLayouts = function() {
2385
2386			$( '.kurtosys-parallax-section__layout', $target ).remove();
2387
2388			$.each( settings, function( index, layout ) {
2389
2390				var imageData      = layout['kurtosys_parallax_layout_image'],
2391					speed          = layout['kurtosys_parallax_layout_speed']['size'] || 50,
2392					zIndex         = layout['kurtosys_parallax_layout_z_index'],
2393					bgSize         = layout['kurtosys_parallax_layout_bg_size'] || 'auto',
2394					animProp       = layout['kurtosys_parallax_layout_animation_prop'] || 'bgposition',
2395					bgX            = layout['kurtosys_parallax_layout_bg_x'],
2396					bgY            = layout['kurtosys_parallax_layout_bg_y'],
2397					type           = layout['kurtosys_parallax_layout_type'] || 'none',
2398					device         = layout['kurtosys_parallax_layout_on'] || ['desktop', 'tablet'],
2399					_id            = layout['_id'],
2400					isDynamicImage = layout.hasOwnProperty( '__dynamic__' ) && layout.__dynamic__.hasOwnProperty( 'kurtosys_parallax_layout_image' ),
2401					$layout        = null,
2402					layoutData     = {},
2403					safariClass    = isSafari ? ' is-safari' : '',
2404					macClass       = 'MacIntel' == platform ? ' is-mac' : '';
2405
2406				if ( '' === imageData['url'] && ! isDynamicImage ) {
2407					return false;
2408				}
2409
2410				if ( ! $target.hasClass( 'kurtosys-parallax-section' ) ) {
2411					$target.addClass( 'kurtosys-parallax-section' );
2412				}
2413
2414				$layout = $( '<div class="kurtosys-parallax-section__layout elementor-repeater-item-' + _id + ' kurtosys-parallax-section__' + type +'-layout' + macClass + '"><div class="kurtosys-parallax-section__image"></div></div>' )
2415					.prependTo( $target )
2416					.css({
2417						'z-index': zIndex
2418					});
2419
2420				var imageCSS = {
2421					'background-size': bgSize,
2422					'background-position-x': bgX + '%',
2423					'background-position-y': bgY + '%'
2424				};
2425
2426				if ( '' !== imageData['url'] ) {
2427					imageCSS['background-image'] = 'url(' + imageData['url'] + ')';
2428				}
2429
2430				$( '> .kurtosys-parallax-section__image', $layout ).css( imageCSS );
2431
2432				layoutData = {
2433					selector: $layout,
2434					image: imageData['url'],
2435					size: bgSize,
2436					prop: animProp,
2437					type: type,
2438					device: device,
2439					xPos: bgX,
2440					yPos: bgY,
2441					speed: 2 * ( speed / 100 )
2442				};
2443
2444				if ( 'none' !== type ) {
2445					if ( 'scroll' === type || 'zoom' === type ) {
2446						scrollLayoutList.push( layoutData );
2447					}
2448
2449					if ( 'mouse' === type ) {
2450						mouseLayoutList.push( layoutData );
2451					}
2452				}
2453
2454			});
2455
2456		};
2457
2458		self.scrollHandler = function( event ) {
2459			winScrollTop = $window.scrollTop();
2460			winHeight    = $window.height();
2461
2462			self.scrollUpdate();
2463		};
2464
2465		self.scrollUpdate = function() {
2466			$.each( scrollLayoutList, function( index, layout ) {
2467
2468				var $this      = layout.selector,
2469					$image     = $( '.kurtosys-parallax-section__image', $this ),
2470					speed      = layout.speed,
2471					offsetTop  = $this.offset().top,
2472					thisHeight = $this.outerHeight(),
2473					prop       = layout.prop,
2474					type       = layout.type,
2475					posY       = ( winScrollTop - offsetTop + winHeight ) / thisHeight * 100,
2476					device     = elementorFrontend.getCurrentDeviceMode();
2477
2478				if ( -1 == layout.device.indexOf( device ) ) {
2479					$image.css( {
2480						'transform': 'translateY(0)',
2481						'background-position-y': layout.yPos
2482					} );
2483
2484					return false;
2485				}
2486
2487				if ( winScrollTop < offsetTop - winHeight ) posY = 0;
2488				if ( winScrollTop > offsetTop + thisHeight) posY = 200;
2489
2490				posY = parseFloat( speed * posY ).toFixed(1);
2491
2492				switch( type ) {
2493					case 'scroll':
2494						if ( 'bgposition' === layout.prop ) {
2495							$image.css( {
2496								'background-position-y': 'calc(' + layout.yPos + '% + ' + posY + 'px)'
2497							} );
2498						} else {
2499							$image.css( {
2500								'transform': 'translateY(' + posY + 'px)'
2501							} );
2502						}
2503						break;
2504					case 'zoom':
2505						var deltaScale = ( winScrollTop - offsetTop + winHeight ) / winHeight,
2506							scale      = deltaScale * speed;
2507
2508						scale = scale + 1;
2509
2510						$image.css( {
2511							'transform': 'scale(' + scale + ')'
2512						} );
2513						break;
2514				}
2515
2516			} );
2517
2518			//requesScroll = requestAnimationFrame( self.scrollUpdate );
2519			//requestAnimationFrame( self.scrollUpdate );
2520		};
2521
2522		self.mouseMoveHandler = function( event ) {
2523			var windowWidth  = $window.width(),
2524				windowHeight = $window.height(),
2525				cx           = Math.ceil( windowWidth / 2 ),
2526				cy           = Math.ceil( windowHeight / 2 ),
2527				dx           = event.clientX - cx,
2528				dy           = event.clientY - cy;
2529
2530			tiltx = -1 * ( dx / cx );
2531			tilty = -1 * ( dy / cy);
2532
2533			self.mouseMoveUpdate();
2534		};
2535
2536		self.mouseLeaveHandler = function( event ) {
2537
2538			$.each( mouseLayoutList, function( index, layout ) {
2539				var $this  = layout.selector,
2540					$image = $( '.kurtosys-parallax-section__image', $this );
2541
2542				switch( layout.prop ) {
2543					case 'transform3d':
2544						TweenMax.to(
2545							$image[0],
2546							1.2, {
2547								x: 0,
2548								y: 0,
2549								z: 0,
2550								rotationX: 0,
2551								rotationY: 0,
2552								ease:Power2.easeOut
2553							}
2554						);
2555					break;
2556				}
2557
2558			} );
2559		};
2560
2561		self.mouseMoveUpdate = function() {
2562			$.each( mouseLayoutList, function( index, layout ) {
2563				var $this   = layout.selector,
2564					$image  = $( '.kurtosys-parallax-section__image', $this ),
2565					speed   = layout.speed,
2566					prop    = layout.prop,
2567					posX    = parseFloat( tiltx * 125 * speed ).toFixed(1),
2568					posY    = parseFloat( tilty * 125 * speed ).toFixed(1),
2569					posZ    = layout.zIndex * 50,
2570					rotateX = parseFloat( tiltx * 25 * speed ).toFixed(1),
2571					rotateY = parseFloat( tilty * 25 * speed ).toFixed(1),
2572					device  = elementorFrontend.getCurrentDeviceMode();
2573
2574				if ( -1 == layout.device.indexOf( device ) ) {
2575					$image.css( {
2576						'transform': 'translateX(0) translateY(0)',
2577						'background-position-x': layout.xPos,
2578						'background-position-y': layout.yPos
2579					} );
2580
2581					return false;
2582				}
2583
2584				switch( prop ) {
2585					case 'bgposition':
2586						TweenMax.to(
2587							$image[0],
2588							1, {
2589								backgroundPositionX: 'calc(' + layout.xPos + '% + ' + posX + 'px)',
2590								backgroundPositionY: 'calc(' + layout.yPos + '% + ' + posY + 'px)',
2591								ease:Power2.easeOut
2592							}
2593						);
2594					break;
2595
2596					case 'transform':
2597						TweenMax.to(
2598							$image[0],
2599							1, {
2600								x: posX,
2601								y: posY,
2602								ease:Power2.easeOut
2603							}
2604						);
2605					break;
2606
2607					case 'transform3d':
2608						TweenMax.to(
2609							$image[0],
2610							2, {
2611								x: posX,
2612								y: posY,
2613								z: posZ,
2614								rotationX: rotateY,
2615								rotationY: -rotateX,
2616								ease:Power2.easeOut
2617							}
2618						);
2619					break;
2620				}
2621
2622			} );
2623		};
2624
2625	}
2626
2627	/**
2628	 * Kurtosys Portfolio Class
2629	 *
2630	 * @return {void}
2631	 */
2632	window.kurtosysPortfolio = function( $selector, settings ) {
2633		var self            = this,
2634			$instance       = $selector,
2635			$instanceList   = $( '.kurtosys-portfolio__list', $instance ),
2636			$itemsList      = $( '.kurtosys-portfolio__item', $instance ),
2637			$filterList     = $( '.kurtosys-portfolio__filter-item', $instance ),
2638			$moreWrapper    = $( '.kurtosys-portfolio__view-more', $instance ),
2639			$moreButton     = $( '.kurtosys-portfolio__view-more-button', $instance ),
2640			isViewMore      = $moreButton[0],
2641			itemsData       = {},
2642			filterData      = {},
2643			activeSlug      = [],
2644			defaultSettings = {
2645				layoutType: 'masonry',
2646				columns: 3,
2647				columnsTablet: 2,
2648				columnsMobile: 1,
2649				perPage: 6
2650			},
2651			masonryOptions = {
2652				itemSelector: '.kurtosys-portfolio__item',
2653				percentPosition: true,
2654				//isAnimated: true
2655			},
2656			settings        = $.extend( defaultSettings, settings ),
2657			$masonryInstance,
2658			page            = 1;
2659
2660		/**
2661		 * Init
2662		 */
2663		self.init = function() {
2664			self.layoutBuild();
2665		}
2666
2667		/**
2668		 * Layout build
2669		 */
2670		self.layoutBuild = function() {
2671
2672			self.generateData();
2673
2674			$filterList.data( 'showItems', isViewMore ? settings.perPage : 'all' );
2675
2676			if ( 'justify' == settings['layoutType'] ) {
2677				masonryOptions['columnWidth'] = '.grid-sizer';
2678			}
2679
2680			$masonryInstance = $instanceList.masonry( masonryOptions );
2681
2682			if ( $.isFunction( $.fn.imagesLoaded ) ) {
2683
2684				$( '.kurtosys-portfolio__image', $itemsList ).imagesLoaded().progress( function( instance, image ) {
2685					var $image      = $( image.img ),
2686						$parentItem = $image.closest( '.kurtosys-portfolio__item' ),
2687						$loader     = $( '.kurtosys-portfolio__image-loader', $parentItem );
2688
2689					$loader.remove();
2690
2691					$parentItem.addClass( 'item-loaded' );
2692
2693					$masonryInstance.masonry( 'layout' );
2694				} );
2695
2696			} else {
2697				var $loader = $( '.kurtosys-portfolio__image-loader', $itemsList );
2698
2699				$itemsList.addClass( 'item-loaded' );
2700
2701				$loader.remove();
2702			}
2703
2704			$filterList.on( 'click.kurtosysPortfolio', self.filterHandler );
2705			$moreButton.on( 'click.kurtosysPortfolio', self.moreButtonHandler );
2706
2707			self.render();
2708			self.checkMoreButton();
2709		};
2710
2711		self.generateData = function() {
2712			if ( $filterList[0] ) {
2713				$filterList.each( function( index ) {
2714					var $this = $( this ),
2715						slug  = $this.data('slug');
2716
2717					filterData[ slug ] = false;
2718
2719					if ( 'all' == slug ) {
2720						filterData[ slug ] = true;
2721					}
2722				} );
2723			} else {
2724				filterData['all'] = true;
2725			}
2726
2727			$itemsList.each( function( index ) {
2728				var $this = $( this ),
2729					slug  = $this.data('slug');
2730
2731				itemsData[ index ] = {
2732					selector: $this,
2733					slug: slug,
2734					visible: $this.hasClass( 'visible-status' ) ? true : false,
2735					more: $this.hasClass( 'hidden-status' ) ? true : false
2736				};
2737			} );
2738		};
2739
2740		self.filterHandler = function( event ) {
2741			var $this = $( this ),
2742				counter = 1,
2743				slug  = $this.data( 'slug' ),
2744				showItems = $this.data( 'showItems' );
2745
2746			$filterList.removeClass( 'active' );
2747			$this.addClass( 'active' );
2748
2749			for ( var slugName in filterData ) {
2750				filterData[ slugName ] = false;
2751
2752				if ( slugName == slug ) {
2753					filterData[ slugName ] = true;
2754				}
2755			}
2756
2757			$.each( itemsData, function( index, obj ) {
2758				var visible = false;
2759
2760				if ( 'all' === showItems ) {
2761
2762					if ( self.isItemVisible( obj.slug ) && ! obj['more'] ) {
2763						visible = true;
2764					}
2765
2766				} else if ( self.isItemVisible( obj.slug ) ) {
2767
2768					if ( counter <= showItems ) {
2769						visible = true;
2770						obj.more = false;
2771					} else {
2772						obj.more = true;
2773					}
2774
2775					counter++
2776				}
2777
2778				obj.visible = visible;
2779
2780			} );
2781
2782			self.render();
2783			self.checkMoreButton();
2784		}
2785
2786		/**
2787		 * [moreButtonHandler description]
2788		 * @param  {[type]} event [description]
2789		 * @return {[type]}       [description]
2790		 */
2791		self.moreButtonHandler = function( event ) {
2792			var $this   = $( this ),
2793				counter = 1,
2794				activeFilter = $( '.kurtosys-portfolio__filter-item.active', $instance ),
2795				showItems;
2796
2797			$.each( itemsData, function( index, obj ) {
2798
2799				if ( self.isItemVisible( obj.slug ) && obj.more && counter <= settings.perPage ) {
2800					obj.more = false;
2801					obj.visible = true;
2802
2803					counter++;
2804				}
2805			} );
2806
2807			if ( activeFilter[0] ) {
2808				showItems = activeFilter.data( 'showItems' );
2809				activeFilter.data( 'showItems', showItems + counter - 1 );
2810			}
2811
2812			self.render();
2813			self.checkMoreButton();
2814		}
2815
2816		/**
2817		 * [checkmoreButton description]
2818		 * @return {[type]} [description]
2819		 */
2820		self.checkMoreButton = function() {
2821			var check = false;
2822
2823			$.each( itemsData, function( index, obj ) {
2824
2825				if ( self.isItemVisible( obj.slug ) && obj.more ) {
2826					check = true;
2827				}
2828			} );
2829
2830			if ( check ) {
2831				$moreWrapper.removeClass( 'hidden-status' );
2832			} else {
2833				$moreWrapper.addClass( 'hidden-status' );
2834			}
2835		}
2836
2837		/**
2838		 * [anyFilterEnabled description]
2839		 * @return {Boolean} [description]
2840		 */
2841		self.isItemVisible = function( slugs ) {
2842			var slugList = KurtosysElementsTools.getObjectValues( slugs );
2843
2844			for ( var slug in filterData ) {
2845				var checked = filterData[ slug ];
2846
2847				if ( checked && -1 !== slugList.indexOf( slug ) ) {
2848					return true;
2849				}
2850			}
2851
2852			return false;
2853		}
2854
2855		/**
2856		 * [anyFilterEnabled description]
2857		 * @return {Boolean} [description]
2858		 */
2859		self.anyFilterEnabled = function() {
2860
2861			for ( var slug in filterData ) {
2862				if ( filterData[ slug ] ) {
2863					return true;
2864				}
2865			}
2866
2867			return false;
2868		}
2869
2870		/**
2871		 * Render
2872		 *
2873		 * @return void
2874		 */
2875		self.render = function() {
2876			var hideAnimation,
2877				showAnimation;
2878
2879			$itemsList.removeClass( 'visible-status' ).removeClass( 'hidden-status' );
2880
2881			$.each( itemsData, function( index, itemData ) {
2882				var selector = $( '.kurtosys-portfolio__inner', itemData.selector );
2883
2884				if ( itemData.visible ) {
2885					itemData.selector.addClass( 'visible-status' );
2886
2887					showAnimation = anime( {
2888						targets: selector[0],
2889						opacity: {
2890							value: 1,
2891							duration: 400,
2892						},
2893						scale: {
2894							value: 1,
2895							duration: 500,
2896							easing: 'easeOutExpo'
2897						},
2898						delay: 50,
2899						elasticity: false
2900					} );
2901				} else {
2902					itemData.selector.addClass( 'hidden-status' );
2903
2904					hideAnimation = anime( {
2905						targets: selector[0],
2906						opacity: 0,
2907						scale: 0,
2908						duration: 500,
2909						elasticity: false
2910					} );
2911				}
2912			} );
2913
2914			$masonryInstance.masonry( 'layout' );
2915		}
2916	}
2917
2918	/**
2919	 * Kurtosys Timeline Class
2920	 *
2921	 * @return {void}
2922	 */
2923	window.kurtosysTimeLine = function ( $element ){
2924		var $viewport		= $(window),
2925			self			= this,
2926			$line 			= $element.find( '.kurtosys-timeline__line' ),
2927			$progress		= $line.find( '.kurtosys-timeline__line-progress' ),
2928			$cards			= $element.find( '.kurtosys-timeline-item' ),
2929			$points 		= $element.find('.timeline-item__point'),
2930
2931			currentScrollTop 		= $viewport.scrollTop(),
2932			lastScrollTop 			= -1,
2933			currentWindowHeight 	= $(window).height(),
2934			currentViewportHeight 	= $viewport.outerHeight(),
2935			lastWindowHeight 		= -1,
2936			requestAnimationId 		= null,
2937			flag 					= false;
2938
2939		self.onScroll = function (){
2940			currentScrollTop = $viewport.scrollTop();
2941
2942			self.updateFrame();
2943			self.animateCards();
2944		};
2945
2946		self.onResize = function() {
2947			currentScrollTop = $viewport.scrollTop();
2948			currentWindowHeight = $viewport.height();
2949
2950			self.updateFrame();
2951		};
2952
2953		self.updateWindow = function() {
2954			flag = false;
2955
2956			$line.css({
2957				'top' 		: $cards.first().find( $points ).offset().top - $cards.first().offset().top,
2958				'bottom'	: ( $element.offset().top + $element.outerHeight() ) - $cards.last().find( $points ).offset().top
2959			});
2960
2961			if ( ( lastScrollTop !== currentScrollTop ) ) {
2962				lastScrollTop 		= currentScrollTop;
2963				lastWindowHeight = currentWindowHeight;
2964
2965				self.updateProgress();
2966			}
2967		};
2968
2969		self.updateProgress = function() {
2970			var progressFinishPosition = $cards.last().find( $points ).offset().top,
2971				progressHeight = ( currentScrollTop - $progress.offset().top ) + ( currentViewportHe
2971ight / 2 );
2972
2973			if ( progressFinishPosition <= ( currentScrollTop + currentViewportHeight / 2 ) ) {
2974				progressHeight = progressFinishPosition - $progress.offset().top;
2975			}
2976
2977			$progress.css({
2978				'height' : progressHeight + 'px'
2979			});
2980
2981			$cards.each( function() {
2982				if ( $(this).find( $points ).offset().top < ( currentScrollTop + currentViewportHeight * 0.5 ) ) {
2983					$(this).addClass('is--active');
2984				} else {
2985					$(this).removeClass('is--active');
2986				}
2987			});
2988		};
2989
2990		self.updateFrame = function() {
2991			if ( ! flag ) {
2992				requestAnimationId = requestAnimationFrame( self.updateWindow );
2993			}
2994			flag = true;
2995		};
2996
2997		self.animateCards = function() {
2998			$cards.each( function() {
2999				if( $(this).offset().top <= currentScrollTop + currentViewportHeight * 0.9 && $(this).hasClass('kurtosys-timeline-item--animated') ) {
3000					$(this).addClass('is--show');
3001				}
3002			});
3003		};
3004
3005		self.init = function(){
3006			$(document).ready(self.onScroll);
3007			$(window).on('scroll.kurtosysTimeline', self.onScroll);
3008			$(window).on('resize.kurtosysTimeline orientationchange.kurtosysTimeline', KurtosysElementsTools.debounce( 50, self.onResize ));
3009		};
3010	}
3011
3012	$('.kurtosys-next-arrow').keypress(function (e) {
3013		var key = e.which;
3014		if (key === 13 || key === 32) {
3015			$(this).click();
3016		}
3017	});
3018
3019	$('.kurtosys-prev-arrow').keypress(function (e) {
3020		var key = e.which;
3021		if (key === 13 || key === 32) {
3022			$(this).click();
3023		}
3024	});
3025
3026}( jQuery, window.elementorFrontend ) );

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.