PageSourceSearch

https://mairie-gungwiller.fr/js/script.js

js mairie-gungwiller.fr collected 2026-10-03 02:46:39 UTC 57,582 bytes, 1,840 lines download raw bytes

1"use strict";
2(function () {
3	// Global variables
4	var userAgent = navigator.userAgent.toLowerCase(),
5			initialDate = new Date(),
6
7			$document = $(document),
8			$window = $(window),
9			$html = $("html"),
10			$body = $("body"),
11
12			isDesktop = $html.hasClass("desktop"),
13			isRtl = $html.attr("dir") === "rtl",
14			isIE = userAgent.indexOf("msie") != -1 ? parseInt(userAgent.split("msie")[1], 10) : userAgent.indexOf("trident") != -1 ? 11 : userAgent.indexOf("edge") != -1 ? 12 : false,
15			isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),
16			isTouch = "ontouchstart" in window,
17			onloadCaptchaCallback,
18			windowReady = false,
19			isNoviBuilder = false,
20			livedemo = true,
21
22			plugins = {
23				pointerEvents: isIE < 11 ? "js/pointer-events.min.js" : false,
24				bootstrapTooltip:        $("[data-toggle='tooltip']"),
25				bootstrapModalDialog:    $('.modal'),
26				bootstrapTabs:           $(".tabs-custom"),
27				rdNavbar:                $(".rd-navbar"),
28				rdMailForm:              $(".rd-mailform"),
29				rdInputLabel:            $(".form-label"),
30				regula:                  $("[data-constraints]"),
31				owl:                     $(".owl-carousel"),
32				swiper:                  $(".swiper-slider"),
33				search:                  $(".rd-search"),
34				searchResults:           $('.rd-search-results'),
35				statefulButton:          $('.btn-stateful'),
36				isotope:                 $(".isotope"),
37				popover:                 $('[data-toggle="popover"]'),
38				viewAnimate:             $('.view-animate'),
39				radio:                   $("input[type='radio']"),
40				checkbox:                $("input[type='checkbox']"),
41				customToggle:            $("[data-custom-toggle]"),
42				facebookWidget:          $('#fb-root'),
43				flickrfeed:              $(".flickr"),
44				twitterfeed:             $(".twitter"),
45				counter:                 $(".counter"),
46				progressLinear:          $(".progress-linear"),
47				progressCircle:          $(".progress-circle"),
48				dateCountdown:           $('.DateCountdown'),
49				preloader:               $(".page-loader"),
50				captcha:                 $('.recaptcha'),
51				scroller:                $(".scroll-wrap"),
52				lightGallery:            $( '[data-lightgallery="group"]' ),
53				lightGalleryItem:        $( '[data-lightgallery="item"]' ),
54				lightDynamicGalleryItem: $( '[data-lightgallery="dynamic"]' ),
55				mailchimp:               $('.mailchimp-mailform'),
56				campaignMonitor:         $('.campaign-mailform'),
57				copyrightYear:           $(".copyright-year"),
58				maps:                    $( '.google-map-container' ),
59			};
60
61	/**
62	 * @desc Check the element was been scrolled into the view
63	 * @param {object} elem - jQuery object
64	 * @return {boolean}
65	 */
66	function isScrolledIntoView ( elem ) {
67		if ( isNoviBuilder ) return true;
68		return elem.offset().top + elem.outerHeight() >= $window.scrollTop() && elem.offset().top <= $window.scrollTop() + $window.height();
69	}
70
71	/**
72	 * @desc Calls a function when element has been scrolled into the view
73	 * @param {object} element - jQuery object
74	 * @param {function} func - init function
75	 */
76	function lazyInit( element, func ) {
77		var scrollHandler = function () {
78			if ( ( !element.hasClass( 'lazy-loaded' ) && ( isScrolledIntoView( element ) ) ) ) {
79				func.call();
80				element.addClass( 'lazy-loaded' );
81			}
82		};
83
84		scrollHandler();
85		$window.on( 'scroll', scrollHandler );
86	}
87
88	// Initialize scripts that require a loaded window
89	$window.on('load', function () {
90		// Page loader & Page transition
91		if (plugins.preloader.length && !isNoviBuilder) {
92			setTimeout(function () {
93				plugins.preloader.addClass("loaded");
94				$window.trigger("resize");
95			}, 1000);
96		}
97	});
98
99// Initialize scripts that require a finished document
100	$(function () {
101		isNoviBuilder = window.xMode;
102
103		/**
104		 * @desc Google map function for getting latitude and longitude
105		 */
106		function getLatLngObject(str, marker, map, callback) {
107			var coordinates = {};
108			try {
109				coordinates = JSON.parse(str);
110				callback(new google.maps.LatLng(
111						coordinates.lat,
112						coordinates.lng
113				), marker, map)
114			} catch (e) {
115				map.geocoder.geocode({'address': str}, function (results, status) {
116					if (status === google.maps.GeocoderStatus.OK) {
117						var latitude = results[0].geometry.location.lat();
118						var longitude = results[0].geometry.location.lng();
119
120						callback(new google.maps.LatLng(
121								parseFloat(latitude),
122								parseFloat(longitude)
123						), marker, map)
124					}
125				})
126			}
127		}
128
129		/**
130		 * @desc Initialize Google maps
131		 */
132		function initMaps() {
133			var key;
134
135			for ( var i = 0; i < plugins.maps.length; i++ ) {
136				if ( plugins.maps[i].hasAttribute( "data-key" ) ) {
137					key = plugins.maps[i].getAttribute( "data-key" );
138					break;
139				}
140			}
141
142			$.getScript('//maps.google.com/maps/api/js?'+ ( key ? 'key='+ key + '&' : '' ) +'sensor=false&libraries=geometry,places&v=quarterly', function () {
143				var head = document.getElementsByTagName('head')[0],
144						insertBefore = head.insertBefore;
145
146				head.insertBefore = function (newElement, referenceElement) {
147					if (newElement.href && newElement.href.indexOf('//fonts.googleapis.com/css?family=Roboto') !== -1 || newElement.innerHTML.indexOf('gm-style') !== -1) {
148						return;
149					}
150					insertBefore.call(head, newElement, referenceElement);
151				};
152				var geocoder = new google.maps.Geocoder;
153				for (var i = 0; i < plugins.maps.length; i++) {
154					var zoom = parseInt(plugins.maps[i].getAttribute("data-zoom"), 10) || 11;
155					var styles = plugins.maps[i].hasAttribute('data-styles') ? JSON.parse(plugins.maps[i].getAttribute("data-styles")) : [];
156					var center = plugins.maps[i].getAttribute("data-center") || "New York";
157
158					// Initialize map
159					var map = new google.maps.Map(plugins.maps[i].querySelectorAll(".google-map")[0], {
160						zoom: zoom,
161						styles: styles,
162						scrollwheel: false,
163						center: {lat: 0, lng: 0}
164					});
165
166					// Add map object to map node
167					plugins.maps[i].map = map;
168					plugins.maps[i].geocoder = geocoder;
169					plugins.maps[i].keySupported = true;
170					plugins.maps[i].google = google;
171
172					// Get Center coordinates from attribute
173					getLatLngObject(center, null, plugins.maps[i], function (location, markerElement, mapElement) {
174						mapElement.map.setCenter(location);
175					});
176
177					// Add markers from google-map-markers array
178					var markerItems = plugins.maps[i].querySelectorAll(".google-map-markers li");
179
180					if (markerItems.length){
181						var markers = [];
182						for (var j = 0; j < markerItems.length; j++){
183							var markerElement = markerItems[j];
184							getLatLngObject(markerElement.getAttribute("data-location"), markerElement, plugins.maps[i], function(location, markerElement, mapElement){
185								var icon = markerElement.getAttribute("data-icon") || mapElement.getAttribute("data-icon");
186								var activeIcon = markerElement.getAttribute("data-icon-active") || mapElement.getAttribute("data-icon-active");
187								var info = markerElement.getAttribute("data-description") || "";
188								var infoWindow = new google.maps.InfoWindow({
189									content: info
190								});
191								markerElement.infoWindow = infoWindow;
192								var markerData = {
193									position: location,
194									map: mapElement.map
195								}
196								if (icon){
197									markerData.icon = icon;
198								}
199								var marker = new google.maps.Marker(markerData);
200								markerElement.gmarker = marker;
201								markers.push({markerElement: markerElement, infoWindow: infoWindow});
202								marker.isActive = false;
203								// Handle infoWindow close click
204								google.maps.event.addListener(infoWindow,'closeclick',(function(markerElement, mapElement){
205									var markerIcon = null;
206									markerElement.gmarker.isActive = false;
207									markerIcon = markerElement.getAttribute("data-icon") || mapElement.getAttribute("data-icon");
208									markerElement.gmarker.setIcon(markerIcon);
209								}).bind(this, markerElement, mapElement));
210
211
212								// Set marker active on Click and open infoWindow
213								google.maps.event.addListener(marker, 'click', (function(markerElement, mapElement) {
214									if (markerElement.infoWindow.getContent().length === 0) return;
215									var gMarker, currentMarker = markerElement.gmarker, currentInfoWindow;
216									for (var k =0; k < markers.length; k++){
217										var markerIcon;
218										if (markers[k].markerElement === markerElement){
219											currentInfoWindow = markers[k].infoWindow;
220										}
221										gMarker = markers[k].markerElement.gmarker;
222										if (gMarker.isActive && markers[k].markerElement !== markerElement){
223											gMarker.isActive = false;
224											markerIcon = markers[k].markerElement.getAttribute("data-icon") || mapElement.getAttribute("data-icon")
225											gMarker.setIcon(markerIcon);
226											markers[k].infoWindow.close();
227										}
228									}
229
230									currentMarker.isActive = !currentMarker.isActive;
231									if (currentMarker.isActive) {
232										if (markerIcon = markerElement.getAttribute("data-icon-active") || mapElement.getAttribute("data-icon-active")){
233											currentMarker.setIcon(markerIcon);
234										}
235
236										currentInfoWindow.open(map, marker);
237									}else{
238										if (markerIcon = markerElement.getAttribute("data-icon") || mapElement.getAttribute("data-icon")){
239											currentMarker.setIcon(markerIcon);
240										}
241										currentInfoWindow.close();
242									}
243								}).bind(this, markerElement, mapElement))
244							})
245						}
246					}
247				}
248			});
249		}
250
251		/**
252		 * getSwiperHeight
253		 * @description  calculate the height of swiper slider basing on data attr
254		 */
255		function getSwiperHeight(object, attr) {
256			var val = object.attr("data-" + attr),
257					dim;
258
259			if (!val) {
260				return undefined;
261			}
262
263			dim = val.match(/(px)|(%)|(vh)$/i);
264
265			if (dim.length) {
266				switch (dim[0]) {
267					case "px":
268						return parseFloat(val);
269					case "vh":
270						return $window.height() * (parseFloat(val) / 100);
271					case "%":
272						return object.width() * (parseFloat(val) / 100);
273				}
274			} else {
275				return undefined;
276			}
277		}
278
279		/**
280		 * toggleSwiperInnerVideos
281		 * @description  toggle swiper videos on active slides
282		 */
283		function toggleSwiperInnerVideos(swiper) {
284			var prevSlide = $(swiper.slides[swiper.previousIndex]),
285					nextSlide = $(swiper.slides[swiper.activeIndex]),
286					videos,
287					videoItems = prevSlide.find("video");
288
289			for (i = 0; i < videoItems.length; i++) {
290				videoItems[i].pause();
291			}
292
293			videos = nextSlide.find("video");
294			if (videos.length) {
295				videos.get(0).play();
296			}
297		}
298
299		/**
300		 * toggleSwiperCaptionAnimation
301		 * @description  toggle swiper animations on active slides
302		 */
303		function toggleSwiperCaptionAnimation(swiper) {
304			var prevSlide = $(swiper.container).find("[data-caption-animate]"),
305					nextSlide = $(swiper.slides[swiper.activeIndex]).find("[data-caption-animate]"),
306					delay,
307					duration,
308					nextSlideItem,
309					prevSlideItem;
310
311			for (i = 0; i < prevSlide.length; i++) {
312				prevSlideItem = $(prevSlide[i]);
313
314				prevSlideItem.removeClass("animated")
315				.removeClass(prevSlideItem.attr("data-caption-animate"))
316				.addClass("not-animated");
317			}
318
319			for (i = 0; i < nextSlide.length; i++) {
320				nextSlideItem = $(nextSlide[i]);
321				delay = nextSlideItem.attr("data-caption-delay");
322				duration = nextSlideItem.attr('data-caption-duration');
323
324				var tempFunction = function (nextSlideItem, duration) {
325					return function () {
326						nextSlideItem
327						.removeClass("not-animated")
328						.addClass(nextSlideItem.attr("data-caption-animate"))
329						.addClass("animated");
330
331						if (duration) {
332							nextSlideItem.css('animation-duration', duration + 'ms');
333						}
334					};
335				};
336
337				setTimeout(tempFunction(nextSlideItem, duration), delay ? parseInt(delay, 10) : 0);
338			}
339		}
340
341		/**
342		 * @desc Initialize owl carousel plugin
343		 * @param {object} carousel - carousel jQuery object
344		 */
345		function initOwlCarousel ( carousel ) {
346			var
347					aliaces = [ '-', '-sm-', '-md-', '-lg-', '-xl-', '-xxl-' ],
348					values = [ 0, 576, 768, 992, 1200, 1600 ],
349					responsive = {};
350
351			for ( var j = 0; j < values.length; j++ ) {
352				responsive[ values[ j ] ] = {};
353				for ( var k = j; k >= -1; k-- ) {
354					if ( !responsive[ values[ j ] ][ 'items' ] && carousel.attr( 'data' + aliaces[ k ] + 'items' ) ) {
355						responsive[ values[ j ] ][ 'items' ] = k < 0 ? 1 : parseInt( carousel.attr( 'data' + aliaces[ k ] + 'items' ), 10 );
356					}
357					if ( !responsive[ values[ j ] ][ 'stagePadding' ] && responsive[ values[ j ] ][ 'stagePadding' ] !== 0 && carousel.attr( 'data' + aliaces[ k ] + 'stage-padding' ) ) {
358						responsive[ values[ j ] ][ 'stagePadding' ] = k < 0 ? 0 : parseInt( carousel.attr( 'data' + aliaces[ k ] + 'stage-padding' ), 10 );
359					}
360					if ( !responsive[ values[ j ] ][ 'margin' ] && responsive[ values[ j ] ][ 'margin' ] !== 0 && carousel.attr( 'data' + aliaces[ k ] + 'margin' ) ) {
361						responsive[ values[ j ] ][ 'margin' ] = k < 0 ? 30 : parseInt( carousel.attr( 'data' + aliaces[ k ] + 'margin' ), 10 );
362					}
363				}
364			}
365
366			// Enable custom pagination
367			if ( carousel.attr( 'data-dots-custom' ) ) {
368				carousel.on( 'initialized.owl.carousel', function ( event ) {
369					var
370							carousel = $( event.currentTarget ),
371							customPag = $( carousel.attr( 'data-dots-custom' ) ),
372							active = 0;
373
374					if ( carousel.attr( 'data-active' ) ) {
375						active = parseInt( carousel.attr( 'data-active' ), 10 );
376					}
377
378					carousel.trigger( 'to.owl.carousel', [ active, 300, true ] );
379					customPag.find( '[data-owl-item="' + active + '"]' ).addClass( 'active' );
380
381					customPag.find( '[data-owl-item]' ).on( 'click', function ( event ) {
382						event.preventDefault();
383						carousel.trigger( 'to.owl.carousel', [ parseInt( this.getAttribute( 'data-owl-item' ), 10 ), 300, true ] );
384					} );
385
386					carousel.on( 'translate.owl.carousel', function ( event ) {
387						customPag.find( '.active' ).removeClass( 'active' );
388						customPag.find( '[data-owl-item="' + event.item.index + '"]' ).addClass( 'active' )
389					} );
390				} );
391			}
392
393			// Initialize lightgallery items in cloned owl items
394			carousel.on( 'initialized.owl.carousel', function () {
395				initLightGalleryItem( carousel.find( '[data-lightgallery="item"]' ), 'lightGallery-in-carousel' );
396			} );
397
398			carousel.owlCarousel( {
399				autoplay:           isNoviBuilder ? false : carousel.attr( 'data-autoplay' ) !== 'false',
400				autoplayTimeout:    carousel.attr( "data-autoplay" ) ? Number( carousel.attr( "data-autoplay" ) ) : 3000,
401				autoplayHoverPause: true,
402				loop:               isNoviBuilder ? false : carousel.attr( 'data-loop' ) !== 'false',
403				items:              1,
404				center:             carousel.attr( 'data-center' ) === 'true',
405				dotsContainer:      carousel.attr( 'data-pagination-class' ) || false,
406				navContainer:       carousel.attr( 'data-navigation-class' ) || false,
407				mouseDrag:          isNoviBuilder ? false : carousel.attr( 'data-mouse-drag' ) !== 'false',
408				nav:                carousel.attr( 'data-nav' ) === 'true',
409				dots:               carousel.attr( 'data-dots' ) === 'true',
410				dotsEach:           carousel.attr( 'data-dots-each' ) ? parseInt( carousel.attr( 'data-dots-each' ), 10 ) : false,
411				animateIn:          carousel.attr( 'data-animation-in' ) ? carousel.attr( 'data-animation-in' ) : false,
412				animateOut:         carousel.attr( 'data-animation-out' ) ? carousel.attr( 'data-animation-out' ) : false,
413				responsive:         responsive,
414				navText:            carousel.attr( 'data-nav-text' ) ? $.parseJSON( carousel.attr( 'data-nav-text' ) ) : [],
415				navClass:           carousel.attr( 'data-nav-class' ) ? $.parseJSON( carousel.attr( 'data-nav-class' ) ) : [ 'owl-prev', 'owl-next' ]
416			} );
417		}
418
419		/**
420		 * isScrolledIntoView
421		 * @description  check the element whas been scrolled into the view
422		 */
423		function isScrolledIntoView(elem) {
424			if (!isNoviBuilder) {
425				return elem.offset().top + elem.outerHeight() >= $window.scrollTop() && elem.offset().top <= $window.scrollTop() + $window.height();
426			} else {
427				return true;
428			}
429		}
430
431		/**
432		 * initOnView
433		 * @description  calls a function when element has been scrolled into the view
434		 */
435		function lazyInit(element, func) {
436			var $win = jQuery(window);
437			$win.on('load scroll', function () {
438				if ((!element.hasClass('lazy-loaded') && (isScrolledIntoView(element)))) {
439					func.call();
440					element.addClass('lazy-loaded');
441				}
442			});
443		}
444
445		/**
446		 * @desc Create live search results
447		 * @param {object} options
448		 */
449		function liveSearch(options) {
450			$('#' + options.live).removeClass('cleared').html();
451			options.current++;
452			options.spin.addClass('loading');
453			$.get(handler, {
454				s: decodeURI(options.term),
455				liveSearch: options.live,
456				dataType: "html",
457				liveCount: options.liveCount,
458				filter: options.filter,
459				template: options.template
460			}, function (data) {
461				options.processed++;
462				var live = $('#' + options.live);
463				if ((options.processed === options.current) && !live.hasClass('cleared')) {
464					live.find('> #search-results').removeClass('active');
465					live.html(data);
466					setTimeout(function () {
467						live.find('> #search-results').addClass('active');
468					}, 50);
469				}
470				options.spin.parents('.rd-search').find('.input-group-addon').removeClass('loading');
471			})
472		}
473
474		/**
475		 * @desc Initialize Bootstrap tooltip with required placement
476		 * @param {string} tooltipPlacement
477		 */
478		function initBootstrapTooltip(tooltipPlacement) {
479			plugins.bootstrapTooltip.tooltip('dispose');
480
481			if (window.innerWidth < 576) {
482				plugins.bootstrapTooltip.tooltip({placement: 'bottom'});
483			} else {
484				plugins.bootstrapTooltip.tooltip({placement: tooltipPlacement});
485			}
486		}
487
488		/**
489		 * @desc Initialize the gallery with set of images
490		 * @param {object} itemsToInit - jQuery object
491		 * @param {string} [addClass] - additional gallery class
492		 */
493		function initLightGallery ( itemsToInit, addClass ) {
494			if ( !isNoviBuilder ) {
495				$( itemsToInit ).lightGallery( {
496					thumbnail: $( itemsToInit ).attr( "data-lg-thumbnail" ) !== "false",
497					selector: "[data-lightgallery='item']",
498					autoplay: $( itemsToInit ).attr( "data-lg-autoplay" ) === "true",
499					pause: parseInt( $( itemsToInit ).attr( "data-lg-autoplay-delay" ) ) || 5000,
500					addClass: addClass,
501					mode: $( itemsToInit ).attr( "data-lg-animation" ) || "lg-slide",
502					loop: $( itemsToInit ).attr( "data-lg-loop" ) !== "false"
503				} );
504			}
505		}
506
507		/**
508		 * @desc Initialize the gallery with dynamic addition of images
509		 * @param {object} itemsToInit - jQuery object
510		 * @param {string} [addClass] - additional gallery class
511		 */
512		function initDynamicLightGallery ( itemsToInit, addClass ) {
513			if ( !isNoviBuilder ) {
514				$( itemsToInit ).on( "click", function () {
515					$( itemsToInit ).lightGallery( {
516						thumbnail: $( itemsToInit ).attr( "data-lg-thumbnail" ) !== "false",
517						selector: "[data-lightgallery='item']",
518						autoplay: $( itemsToInit ).attr( "data-lg-autoplay" ) === "true",
519						pause: parseInt( $( itemsToInit ).attr( "data-lg-autoplay-delay" ) ) || 5000,
520						addClass: addClass,
521						mode: $( itemsToInit ).attr( "data-lg-animation" ) || "lg-slide",
522						loop: $( itemsToInit ).attr( "data-lg-loop" ) !== "false",
523						dynamic: true,
524						dynamicEl: JSON.parse( $( itemsToInit ).attr( "data-lg-dynamic-elements" ) ) || []
525					} );
526				} );
527			}
528		}
529
530		/**
531		 * @desc Initialize the gallery with one image
532		 * @param {object} itemToInit - jQuery object
533		 * @param {string} [addClass] - additional gallery class
534		 */
535		function initLightGalleryItem ( itemToInit, addClass ) {
536			if ( !isNoviBuilder ) {
537				$( itemToInit ).lightGallery( {
538					selector: "this",
539					addClass: addClass,
540					counter: false,
541					youtubePlayerParams: {
542						modestbranding: 1,
543						showinfo: 0,
544						rel: 0,
545						controls: 0
546					},
547					vimeoPlayerParams: {
548						byline: 0,
549						portrait: 0
550					}
551				} );
552			}
553		}
554
555		/**
556		 * @desc Attach form validation to elements
557		 * @param {object} elements - jQuery object
558		 */
559		function attachFormValidator(elements) {
560			// Custom validator - phone number
561			regula.custom({
562				name: 'PhoneNumber',
563				defaultMessage: 'Invalid phone number format',
564				validator: function() {
565					if ( this.value === '' ) return true;
566					else return /^(\+\d)?[0-9\-\(\) ]{5,}$/i.test( this.value );
567				}
568			});
569
570			for (var i = 0; i < elements.length; i++) {
571				var o = $(elements[i]), v;
572				o.addClass("form-control-has-validation").after("<span class='form-validation'></span>");
573				v = o.parent().find(".form-validation");
574				if (v.is(":last-child")) o.addClass("form-control-last-child");
575			}
576
577			elements.on('input change propertychange blur', function (e) {
578				var $this = $(this), results;
579
580				if (e.type !== "blur") if (!$this.parent().hasClass("has-error")) return;
581				if ($this.parents('.rd-mailform').hasClass('success')) return;
582
583				if (( results = $this.regula('validate') ).length) {
584					for (i = 0; i < results.length; i++) {
585						$this.siblings(".form-validation").text(results[i].message).parent().addClass("has-error");
586					}
587				} else {
588					$this.siblings(".form-validation").text("").parent().removeClass("has-error")
589				}
590			}).regula('bind');
591
592			var regularConstraintsMessages = [
593				{
594					type: regula.Constraint.Required,
595					newMessage: "The text field is required."
596				},
597				{
598					type: regula.Constraint.Email,
599					newMessage: "The email is not a valid email."
600				},
601				{
602					type: regula.Constraint.Numeric,
603					newMessage: "Only numbers are required"
604				},
605				{
606					type: regula.Constraint.Selected,
607					newMessage: "Please choose an option."
608				}
609			];
610
611
612			for (var i = 0; i < regularConstraintsMessages.length; i++) {
613				var regularConstraint = regularConstraintsMessages[i];
614
615				regula.override({
616					constraintType: regularConstraint.type,
617					defaultMessage: regularConstraint.newMessage
618				});
619			}
620		}
621
622		/**
623		 * @desc Check if all elements pass validation
624		 * @param {object} elements - object of items for validation
625		 * @param {object} captcha - captcha object for validation
626		 * @return {boolean}
627		 */
628		function isValidated(elements, captcha) {
629			var results, errors = 0;
630
631			if (elements.length) {
632				for (var j = 0; j < elements.length; j++) {
633
634					var $input = $(elements[j]);
635					if ((results = $input.regula('validate')).length) {
636						for (k = 0; k < results.length; k++) {
637							errors++;
638							$input.siblings(".form-validation").text(results[k].message).parent().addClass("has-error");
639						}
640					} else {
641						$input.siblings(".form-validation").text("").parent().removeClass("has-error")
642					}
643				}
644
645				if (captcha) {
646					if (captcha.length) {
647						return validateReCaptcha(captcha) && errors === 0
648					}
649				}
650
651				return errors === 0;
652			}
653			return true;
654		}
655
656		/**
657		 * @desc Validate google reCaptcha
658		 * @param {object} captcha - captcha object for validation
659		 * @return {boolean}
660		 */
661		function validateReCaptcha(captcha) {
662			var captchaToken = captcha.find('.g-recaptcha-response').val();
663
664			if (captchaToken.length === 0) {
665				captcha
666				.siblings('.form-validation')
667				.html('Please, prove that you are not robot.')
668				.addClass('active');
669				captcha
670				.closest('.form-wrap')
671				.addClass('has-error');
672
673				captcha.on('propertychange', function () {
674					var $this = $(this),
675							captchaToken = $this.find('.g-recaptcha-response').val();
676
677					if (captchaToken.length > 0) {
678						$this
679						.closest('.form-wrap')
680						.removeClass('has-error');
681						$this
682						.siblings('.form-validation')
683						.removeClass('active')
684						.html('');
685						$this.off('propertychange');
686					}
687				});
688
689				return false;
690			}
691
692			return true;
693		}
694
695		/**
696		 * @desc Initialize Google reCaptcha
697		 */
698		window.onloadCaptchaCallback = function () {
699			for (var i = 0; i < plugins.captcha.length; i++) {
700				var
701						$captcha = $(plugins.captcha[i]),
702						resizeHandler = (function() {
703							var
704									frame = this.querySelector( 'iframe' ),
705									inner = this.firstElementChild,
706									inner2 = inner.firstElementChild,
707									containerRect = null,
708									frameRect = null,
709									scale = null;
710
711							inner2.style.transform = '';
712							inner.style.height = 'auto';
713							inner.style.width = 'auto';
714
715							containerRect = this.getBoundingClientRect();
716							frameRect = frame.getBoundingClientRect();
717							scale = containerRect.width/frameRect.width;
718
719							if ( scale < 1 ) {
720								inner2.style.transform = 'scale('+ scale +')';
721								inner.style.height = ( frameRect.height * scale ) + 'px';
722								inner.style.width = ( frameRect.width * scale ) + 'px';
723							}
724						}).bind( plugins.captcha[i] );
725
726				grecaptcha.render(
727						$captcha.attr('id'),
728						{
729							sitekey: $captcha.attr('data-sitekey'),
730							size: $captcha.attr('data-size') ? $captcha.attr('data-size') : 'normal',
731							theme: $captcha.attr('data-theme') ? $captcha.attr('data-theme') : 'light',
732							callback: function () {
733								$('.recaptcha').trigger('propertychange');
734							}
735						}
736				);
737
738				$captcha.after("<span class='form-validation'></span>");
739
740				if ( plugins.captcha[i].hasAttribute( 'data-auto-size' ) ) {
741					resizeHandler();
742					window.addEventListener( 'resize', resizeHandler );
743				}
744			}
745		};
746
747		/**
748		 * Copyright Year
749		 * @description  Evaluates correct copyright year
750		 */
751		if (plugins.copyrightYear.length) {
752			plugins.copyrightYear.text(initialDate.getFullYear());
753		}
754
755		/**
756		 * Google ReCaptcha
757		 * @description Enables Google ReCaptcha
758		 */
759		if (plugins.captcha.length) {
760			$.getScript("//www.google.com/recaptcha/api.js?onload=onloadCaptchaCallback&render=explicit&hl=en");
761		}
762
763		/**
764		 * Is Mac os
765		 * @description  add additional class on html if mac os.
766		 */
767		if (navigator.platform.match(/(Mac)/i)) $html.addClass("mac-os");
768
769		/**
770		 * IE Polyfills
771		 * @description  Adds some loosing functionality to IE browsers
772		 */
773		if (isIE) {
774			if (isIE < 10) {
775				$html.addClass("lt-ie-10");
776			}
777
778			if (isIE < 11) {
779				if (plugins.pointerEvents) {
780					$.getScript(plugins.pointerEvents)
781					.done(function () {
782						$html.addClass("ie-10");
783						PointerEventsPolyfill.initialize({});
784					});
785				}
786			}
787
788			if (isIE === 11) {
789				$html.addClass("ie-11");
790			}
791
792			if (isIE === 12) {
793				$html.addClass("ie-edge");
794			}
795		}
796
797		// Bootstrap Tooltips
798		if (plugins.bootstrapTooltip.length) {
799			var tooltipPlacement = plugins.bootstrapTooltip.attr('data-placement');
800			initBootstrapTooltip(tooltipPlacement);
801
802			$window.on('resize orientationchange', function () {
803				initBootstrapTooltip(tooltipPlacement);
804			})
805		}
806
807		/**
808		 * bootstrapModalDialog
809		 * @description Stap vioeo in bootstrapModalDialog
810		 */
811		if (plugins.bootstrapModalDialog.length > 0) {
812			var i = 0;
813
814			for (i = 0; i < plugins.bootstrapModalDialog.length; i++) {
815				var modalItem = $(plugins.bootstrapModalDialog[i]);
816
817				modalItem.on('hidden.bs.modal', $.proxy(function () {
818					var activeModal = $(this),
819							rdVideoInside = activeModal.find('video'),
820							youTubeVideoInside = activeModal.find('iframe');
821
822					if (rdVideoInside.length) {
823						rdVideoInside[0].pause();
824					}
825
826					if (youTubeVideoInside.length) {
827						var videoUrl = youTubeVideoInside.attr('src');
828
829						youTubeVideoInside
830						.attr('src', '')
831						.attr('src', videoUrl);
832					}
833				}, modalItem))
834			}
835		}
836
837		/**
838		 * JQuery mousewheel plugin
839		 * @description  Enables jquery mousewheel plugin
840		 */
841		if (plugins.scroller.length) {
842			var i;
843			for (i = 0; i < plugins.scroller.length; i++) {
844				var scrollerItem = $(plugins.scroller[i]);
845
846				scrollerItem.mCustomScrollbar({
847					theme: scrollerItem.attr('data-theme') ? scrollerItem.attr('data-theme') : 'minimal',
848					scrollInertia: 100,
849					scrollButtons: {enable: false}
850				});
851			}
852		}
853
854		/**
855		 * Facebook widget
856		 * @description  Enables official Facebook widget
857		 */
858		if (plugins.facebookWidget.length) {
859			lazyInit(plugins.facebookWidget, function () {
860				(function (d, s, id) {
861					var js, fjs = d.getElementsByTagName(s)[0];
862					if (d.getElementById(id)) return;
863					js = d.createElement(s);
864					js.id = id;
865					js.src = "//connect.facebook.net/en_EN/sdk.js#xfbml=1&version=v2.5";
866					fjs.parentNode.insertBefore(js, fjs);
867				}(document, 'script', 'facebook-jssdk'));
868			});
869		}
870
871		/**
872		 * Radio
873		 * @description Add custom styling options for input[type="radio"]
874		 */
875		if (plugins.radio.length) {
876			var i;
877			for (i = 0; i < plugins.radio.length; i++) {
878				var $this = $(plugins.radio[i]);
879				$this.addClass("radio-custom").after("<span class='radio-custom-dummy'></span>")
880			}
881		}
882
883		/**
884		 * Checkbox
885		 * @description Add custom styling options for input[type="checkbox"]
886		 */
887		if (plugins.checkbox.length) {
888			var i;
889			for (i = 0; i < plugins.checkbox.length; i++) {
890				var $this = $(plugins.checkbox[i]);
891				$this.addClass("checkbox-custom").after("<span class='checkbox-custom-dummy'></span>")
892			}
893		}
894
895		/**
896		 * Popovers
897		 * @description Enables Popovers plugin
898		 */
899		if (plugins.popover.length) {
900			if (window.innerWidth < 767) {
901				plugins.popover.attr('data-placement', 'bottom');
902				plugins.popover.popover();
903			} else {
904				plugins.popover.popover();
905			}
906		}
907
908		/**
909		 * Bootstrap Buttons
910		 * @description  Enable Bootstrap Buttons plugin
911		 */
912		if (plugins.statefulButton.length) {
913			$(plugins.statefulButton).on('click', function () {
914				var statefulButtonLoading = $(this).button('loading');
915
916				setTimeout(function () {
917					statefulButtonLoading.button('reset')
918				}, 2000);
919			})
920		}
921
922		/**
923		 * UI To Top
924		 * @description Enables ToTop Button
925		 */
926		if (isDesktop && !isNoviBuilder) {
927			$().UItoTop({
928				easingType: 'easeOutQuart',
929				containerClass: 'ui-to-top fa fa-arrow-up'
930			});
931		}
932
933		// RD Navbar
934		if ( plugins.rdNavbar.length ) {
935			var
936					navbar = plugins.rdNavbar,
937					aliases = { '-': 0, '-sm-': 576, '-md-': 768, '-lg-': 992, '-xl-': 1200, '-xxl-': 1600 },
938					responsive = {};
939
940			for ( var alias in aliases ) {
941				var link = responsive[ aliases[ alias ] ] = {};
942				if ( navbar.attr( 'data'+ alias +'layout' ) )          link.layout        = navbar.attr( 'data'+ alias +'layout' );
943				if ( navbar.attr( 'data'+ alias +'device-layout' ) )   link.deviceLayout  = navbar.attr( 'data'+ alias +'device-layout' );
944				if ( navbar.attr( 'data'+ alias +'hover-on' ) )        link.focusOnHover  = navbar.attr( 'data'+ alias +'hover-on' ) === 'true';
945				if ( navbar.attr( 'data'+ alias +'auto-height' ) )     link.autoHeight    = navbar.attr( 'data'+ alias +'auto-height' ) === 'true';
946				if ( navbar.attr( 'data'+ alias +'stick-up-offset' ) ) link.stickUpOffset = navbar.attr( 'data'+ alias +'stick-up-offset' );
947				if ( navbar.attr( 'data'+ alias +'stick-up' ) )        link.stickUp       = navbar.attr( 'data'+ alias +'stick-up' ) === 'true';
948				if ( isNoviBuilder ) link.stickUp = false;
949				else if ( navbar.attr( 'data'+ alias +'stick-up' ) )   link.stickUp       = navbar.attr( 'data'+ alias +'stick-up' ) === 'true';
950			}
951
952			plugins.rdNavbar.RDNavbar({
953				anchorNav: !isNoviBuilder,
954				stickUpClone: (plugins.rdNavbar.attr("data-stick-up-clone") && !isNoviBuilder) ? plugins.rdNavbar.attr("data-stick-up-clone") === 'true' : false,
955				responsive: responsive,
956				callbacks: {
957					onStuck: function () {
958						var navbarSearch = this.$element.find('.rd-search input');
959
960						if (navbarSearch) {
961							navbarSearch.val('').trigger('propertychange');
962						}
963					},
964					onDropdownOver: function () {
965						return !isNoviBuilder;
966					},
967					onUnstuck: function () {
968						if (this.$clone === null)
969							return;
970
971						var navbarSearch = this.$clone.find('.rd-search input');
972
973						if (navbarSearch) {
974							navbarSearch.val('').trigger('propertychange');
975							navbarSearch.trigger('blur');
976						}
977
978					}
979				}
980			});
981		}
982
983		// RD Search
984		if (plugins.search.length || plugins.searchResults) {
985			var handler = "bat/rd-search.php";
986			var defaultTemplate = '<h5 class="search-title"><a target="_top" href="#{href}" class="search-link">#{title}</a></h5>' +
987					'<p>...#{token}...</p>' +
988					'<p class="match"><em>Terms matched: #{count} - URL: #{href}</em></p>';
989			var defaultFilter = '*.html';
990
991			if (plugins.search.length) {
992				for (var i = 0; i < plugins.search.length; i++) {
993					var searchItem = $(plugins.search[i]),
994							options = {
995								element: searchItem,
996								filter: (searchItem.attr('data-search-filter')) ? searchItem.attr('data-search-filter') : defaultFilter,
997								template: (searchItem.attr('data-search-template')) ? searchItem.attr('data-search-template') : defaultTemplate,
998								live: (searchItem.attr('data-search-live')) ? searchItem.attr('data-search-live') : false,
999								liveCount: (searchItem.attr('data-search-live-count')) ? parseInt(searchItem.attr('data-search-live'), 10) : 4,
1000								current: 0, processed: 0, timer: {}
1001							};
1002
1003					var $toggle = $('.rd-navbar-search-toggle');
1004					if ($toggle.length) {
1005						$toggle.on('click', (function (searchItem) {
1006							return function () {
1007								if (!($(this).hasClass('active'))) {
1008									searchItem.find('input').val('').trigger('propertychange');
1009								}
1010							}
1011						})(searchItem));
1012					}
1013
1014					if (options.live) {
1015						var clearHandler = false;
1016
1017						searchItem.find('input').on("input propertychange", $.proxy(function () {
1018							this.term = this.element.find('input').val().trim();
1019							this.spin = this.element.find('.input-group-addon');
1020
1021							clearTimeout(this.timer);
1022
1023							if (this.term.length > 2) {
1024								this.timer = setTimeout(liveSearch(this), 200);
1025
1026								if (clearHandler === false) {
1027									clearHandler = true;
1028
1029									$body.on("click", function (e) {
1030										if ($(e.toElement).parents('.rd-search').length === 0) {
1031											$('#rd-search-results-live').addClass('cleared').html('');
1032										}
1033									})
1034								}
1035
1036							} else if (this.term.length === 0) {
1037								$('#' + this.live).addClass('cleared').html('');
1038							}
1039						}, options, this));
1040					}
1041
1042					searchItem.submit($.proxy(function () {
1043						$('<input />').attr('type', 'hidden')
1044						.attr('name', "filter")
1045						.attr('value', this.filter)
1046						.appendTo(this.element);
1047						return true;
1048					}, options, this))
1049				}
1050			}
1051
1052			if (plugins.searchResults.length) {
1053				var regExp = /\?.*s=([^&]+)\&filter=([^&]+)/g;
1054				var match = regExp.exec(location.search);
1055
1056				if (match !== null) {
1057					$.get(handler, {
1058						s: decodeURI(match[1]),
1059						dataType: "html",
1060						filter: match[2],
1061						template: defaultTemplate,
1062						live: ''
1063					}, function (data) {
1064						plugins.searchResults.html(data);
1065					})
1066				}
1067			}
1068		}
1069
1070		/**
1071		 * ViewPort Universal
1072		 * @description Add class in viewport
1073		 */
1074		if (plugins.viewAnimate.length) {
1075			var i;
1076			for (i = 0; i < plugins.viewAnimate.length; i++) {
1077				var $view = $(plugins.viewAnimate[i]).not('.active');
1078				$document.on("scroll", $.proxy(function () {
1079					if (isScrolledIntoView(this)) {
1080						this.addClass("active");
1081					}
1082				}, $view))
1083				.trigger("scroll");
1084			}
1085		}
1086
1087		/**
1088		 * Swiper 3.1.7
1089		 * @description  Enable Swiper Slider
1090		 */
1091		if (plugins.swiper.length) {
1092			var i;
1093			for (i = 0; i < plugins.swiper.length; i++) {
1094				var s = $(plugins.swiper[i]);
1095				var pag = s.find(".swiper-pagination"),
1096						next = s.find(".swiper-button-next"),
1097						prev = s.find(".swiper-button-prev"),
1098						bar = s.find(".swiper-scrollbar"),
1099						swiperSlide = s.find(".swiper-slide"),
1100						autoplay = false;
1101
1102				for (j = 0; j < swiperSlide.length; j++) {
1103					var $this = $(swiperSlide[j]),
1104							url;
1105
1106					if (url = $this.attr("data-slide-bg")) {
1107						$this.css({
1108							"background-image": "url(" + url + ")",
1109							"background-size": "cover"
1110						})
1111					}
1112				}
1113
1114
1115				swiperSlide.end()
1116				.find("[data-caption-animate]")
1117				.addClass("not-animated")
1118				.end()
1119				.swiper({
1120					autoplay: isNoviBuilder ? null : s.attr('data-autoplay') ? s.attr('data-autoplay') === "false" ? undefined : s.attr('data-autoplay') : 5000,
1121					direction: s.attr('data-direction') ? s.attr('data-direction') : "horizontal",
1122					effect: s.attr('data-slide-effect') ? s.attr('data-slide-effect') : "slide",
1123					speed: s.attr('data-slide-speed') ? s.attr('data-slide-speed') : 600,
1124					keyboardControl: s.attr('data-keyboard') === "true",
1125					mousewheelControl: s.attr('data-mousewheel') === "true",
1126					mousewheelReleaseOnEdges: s.attr('data-mousewheel-release') === "true",
1127					nextButton: next.length ? next.get(0) : null,
1128					prevButton: prev.length ? prev.get(0) : null,
1129					pagination: pag.length ? pag.get(0) : null,
1130					paginationClickable: pag.length ? pag.attr("data-clickable") !== "false" : false,
1131					paginationBulletRender: pag.length ? pag.attr("data-index-bullet") === "true" ? function (index, className) {
1132						return '<span class="' + className + '">' + (index + 1) + '</span>';
1133					} : null : null,
1134					scrollbar: bar.length ? bar.get(0) : null,
1135					scrollbarDraggable: bar.length ? bar.attr("data-draggable") !== "false" : true,
1136					scrollbarHide: bar.length ? bar.attr("data-draggable") === "false" : false,
1137					loop: isNoviBuilder ? false : s.attr('data-loop') !== "false",
1138					simulateTouch: s.attr('data-simulate-touch') && !isNoviBuilder ? s.attr('data-simulate-touch') === "true" : false,
1139					onTransitionStart: function (swiper) {
1140						toggleSwiperInnerVideos(swiper);
1141					},
1142					onTransitionEnd: function (swiper) {
1143						toggleSwiperCaptionAnimation(swiper);
1144					},
1145					onInit: function (swiper) {
1146						toggleSwiperInnerVideos(swiper);
1147						toggleSwiperCaptionAnimation(swiper);
1148
1149						$window.on('resize', function () {
1150							swiper.update(true);
1151						})
1152					},
1153					onSlideChangeStart: function (swiper) {
1154						var activeSlideIndex, slidesCount;
1155
1156						activeSlideIndex = swiper.activeIndex;
1157						slidesCount = swiper.slides.not(".swiper-slide-duplicate").length;
1158
1159						if (activeSlideIndex === slidesCount + 1) {
1160							activeSlideIndex = 1;
1161						} else if (activeSlideIndex === 0) {
1162							activeSlideIndex = slidesCount;
1163						}
1164						if (swiper.slides[activeSlideIndex - 1].getAttribute("data-sli
1164de-title")) {
1165							$(swiper.container).find('.swiper-button-next .title')[0].innerHTML = swiper.slides[activeSlideIndex +
1166							1].getAttribute("data-slide-title");
1167							$(swiper.container).find('.swiper-button-prev .title')[0].innerHTML = swiper.slides[activeSlideIndex -
1168							1].getAttribute("data-slide-title");
1169						}
1170
1171						if (swiper.slides[activeSlideIndex - 1].getAttribute("data-slide-subtitle")) {
1172							$(swiper.container).find('.swiper-button-prev .subtitle')[0].innerHTML = swiper.slides[activeSlideIndex -
1173							1].getAttribute("data-slide-subtitle");
1174							$(swiper.container).find('.swiper-button-next .subtitle')[0].innerHTML = swiper.slides[activeSlideIndex +
1175							1].getAttribute("data-slide-subtitle");
1176						}
1177						//Replace btn img
1178						if ($(swiper.container).find('.preview__img')[0] !== undefined) {
1179							$(swiper.container).find('.swiper-button-prev .preview__img').css("background-image", "url(" +
1180									swiper.slides[activeSlideIndex - 1].getAttribute("data-slide-bg") + ")");
1181							$(swiper.container).find('.swiper-button-next .preview__img').css("background-image", "url(" +
1182									swiper.slides[activeSlideIndex + 1].getAttribute("data-slide-bg") + ")");
1183						}
1184					}
1185				});
1186
1187				$window
1188				.on("resize", function () {
1189					var mh = getSwiperHeight(s, "min-height"),
1190							h = getSwiperHeight(s, "height");
1191					if (h) {
1192						s.css("height", mh ? mh > h ? mh : h : h);
1193					}
1194				})
1195				.trigger("resize");
1196			}
1197		}
1198
1199		// Owl carousel
1200		if ( plugins.owl.length ) {
1201			for ( var i = 0; i < plugins.owl.length; i++ ) {
1202				var carousel = $( plugins.owl[ i ] );
1203				plugins.owl[ i ].owl = carousel;
1204				initOwlCarousel( carousel );
1205			}
1206		}
1207
1208		/**
1209		 * Isotope
1210		 * @description Enables Isotope plugin
1211		 */
1212		if (plugins.isotope.length) {
1213			var i, isogroup = [];
1214			for (i = 0; i < plugins.isotope.length; i++) {
1215				var isotopeItem = plugins.isotope[i],
1216						iso = new Isotope(isotopeItem, {
1217							itemSelector: '.isotope-item',
1218							layoutMode: isotopeItem.getAttribute('data-isotope-layout') ? isotopeItem.getAttribute('data-isotope-layout') : 'masonry',
1219							filter: '*'
1220						});
1221
1222				isogroup.push(iso);
1223			}
1224
1225			$window.on('load', function () {
1226				setTimeout(function () {
1227					var i;
1228					for (i = 0; i < isogroup.length; i++) {
1229						isogroup[i].element.className += " isotope--loaded";
1230						isogroup[i].layout();
1231					}
1232				}, 600);
1233			});
1234
1235			var resizeTimout,
1236					isotopeFilter = $("[data-isotope-filter]");
1237
1238			isotopeFilter.on("click", function (e) {
1239				e.preventDefault();
1240				var filter = $(this);
1241				clearTimeout(resizeTimout);
1242				filter.parents(".isotope-filters").find('.active').removeClass("active");
1243				filter.addClass("active");
1244				var iso = $('.isotope[data-isotope-group="' + this.getAttribute("data-isotope-group") + '"]');
1245				iso.isotope({
1246					itemSelector: '.isotope-item',
1247					layoutMode: iso.attr('data-isotope-layout') ? iso.attr('data-isotope-layout') : 'masonry',
1248					filter: this.getAttribute("data-isotope-filter") == '*' ? '*' : '[data-filter*="' + this.getAttribute("data-isotope-filter") + '"]'
1249				});
1250			}).eq(0).trigger("click")
1251		}
1252
1253		/**
1254		 * WOW
1255		 * @description Enables Wow animation plugin
1256		 */
1257		if (isDesktop && $html.hasClass("wow-animation") && $(".wow").length) {
1258			new WOW().init();
1259		}
1260
1261		// Bootstrap tabs
1262		if (plugins.bootstrapTabs.length) {
1263			for (var i = 0; i < plugins.bootstrapTabs.length; i++) {
1264				var bootstrapTabsItem = $(plugins.bootstrapTabs[i]);
1265
1266				//If have slick carousel inside tab - resize slick carousel on click
1267				if (bootstrapTabsItem.find('.slick-slider').length) {
1268					bootstrapTabsItem.find('.tabs-custom-list > li > a').on('click', $.proxy(function () {
1269						var $this = $(this);
1270						var setTimeOutTime = isNoviBuilder ? 1500 : 300;
1271
1272						setTimeout(function () {
1273							$this.find('.tab-content .tab-pane.active .slick-slider').slick('setPosition');
1274						}, setTimeOutTime);
1275					}, bootstrapTabsItem));
1276				}
1277			}
1278		}
1279
1280		/**
1281		 * RD Input Label
1282		 * @description Enables RD Input Label Plugin
1283		 */
1284		if (plugins.rdInputLabel.length) {
1285			plugins.rdInputLabel.RDInputLabel();
1286		}
1287
1288		/**
1289		 * Regula
1290		 * @description Enables Regula plugin
1291		 */
1292		if (plugins.regula.length) {
1293			attachFormValidator(plugins.regula);
1294		}
1295
1296		/**
1297		 * MailChimp Ajax subscription
1298		 */
1299		if (plugins.mailchimp.length) {
1300			for (i = 0; i < plugins.mailchimp.length; i++) {
1301				var $mailchimpItem = $(plugins.mailchimp[i]),
1302						$email = $mailchimpItem.find('input[type="email"]');
1303
1304				// Required by MailChimp
1305				$mailchimpItem.attr('novalidate', 'true');
1306				$email.attr('name', 'EMAIL');
1307
1308				$mailchimpItem.on('submit', $.proxy(function (e) {
1309					e.preventDefault();
1310
1311					var $this = this;
1312
1313					var data = {},
1314							url = $this.attr('action').replace('/post?', '/post-json?').concat('&c=?'),
1315							dataArray = $this.serializeArray(),
1316							$output = $("#" + $this.attr("data-form-output"));
1317
1318					for (i = 0; i < dataArray.length; i++) {
1319						data[dataArray[i].name] = dataArray[i].value;
1320					}
1321
1322					$.ajax({
1323						data: data,
1324						url: url,
1325						dataType: 'jsonp',
1326						error: function (resp, text) {
1327							$output.html('Server error: ' + text);
1328
1329							setTimeout(function () {
1330								$output.removeClass("active");
1331							}, 4000);
1332						},
1333						success: function (resp) {
1334							$output.html(resp.msg).addClass('active');
1335
1336							setTimeout(function () {
1337								$output.removeClass("active");
1338							}, 6000);
1339						},
1340						beforeSend: function (data) {
1341							// Stop request if builder or inputs are invalide
1342							if (isNoviBuilder || !isValidated($this.find('[data-constraints]')))
1343								return false;
1344
1345							$output.html('Submitting...').addClass('active');
1346						}
1347					});
1348
1349					return false;
1350				}, $mailchimpItem));
1351			}
1352		}
1353
1354		/**
1355		 * Campaign Monitor ajax subscription
1356		 */
1357		if (plugins.campaignMonitor.length) {
1358			for (i = 0; i < plugins.campaignMonitor.length; i++) {
1359				var $campaignItem = $(plugins.campaignMonitor[i]);
1360
1361				$campaignItem.on('submit', $.proxy(function (e) {
1362					var data = {},
1363							url = this.attr('action'),
1364							dataArray = this.serializeArray(),
1365							$output = $("#" + plugins.campaignMonitor.attr("data-form-output")),
1366							$this = $(this);
1367
1368					for (i = 0; i < dataArray.length; i++) {
1369						data[dataArray[i].name] = dataArray[i].value;
1370					}
1371
1372					$.ajax({
1373						data: data,
1374						url: url,
1375						dataType: 'jsonp',
1376						error: function (resp, text) {
1377							$output.html('Server error: ' + text);
1378
1379							setTimeout(function () {
1380								$output.removeClass("active");
1381							}, 4000);
1382						},
1383						success: function (resp) {
1384							$output.html(resp.Message).addClass('active');
1385
1386							setTimeout(function () {
1387								$output.removeClass("active");
1388							}, 6000);
1389						},
1390						beforeSend: function (data) {
1391							// Stop request if builder or inputs are invalide
1392							if (isNoviBuilder || !isValidated($this.find('[data-constraints]')))
1393								return false;
1394
1395							$output.html('Submitting...').addClass('active');
1396						}
1397					});
1398
1399					return false;
1400				}, $campaignItem));
1401			}
1402		}
1403
1404		/**
1405		 * RD Mailform
1406		 * @version      3.0.0
1407		 */
1408		if (plugins.rdMailForm.length) {
1409			var i, j, k,
1410					msg = {
1411						'MF000': 'Successfully sent!',
1412						'MF001': 'Recipients are not set!',
1413						'MF002': 'Form will not work locally!',
1414						'MF003': 'Please, define email field in your form!',
1415						'MF004': 'Please, define type of your form!',
1416						'MF254': 'Something went wrong with PHPMailer!',
1417						'MF255': 'Aw, snap! Something went wrong.'
1418					},
1419					recipients = '[email protected]';
1420
1421			for (i = 0; i < plugins.rdMailForm.length; i++) {
1422				var $form = $(plugins.rdMailForm[i]),
1423						formHasCaptcha = false;
1424
1425				$form.attr('novalidate', 'novalidate').ajaxForm({
1426					data: {
1427						"form-type": $form.attr("data-form-type") || "contact",
1428						"recipients": recipients,
1429						"counter": i
1430					},
1431					beforeSubmit: function (arr, $form, options) {
1432						if (isNoviBuilder)
1433							return;
1434
1435						var form = $(plugins.rdMailForm[this.extraData.counter]),
1436								inputs = form.find("[data-constraints]"),
1437								output = $("#" + form.attr("data-form-output")),
1438								captcha = form.find('.recaptcha'),
1439								captchaFlag = true;
1440
1441						output.removeClass("active error success");
1442
1443						if (isValidated(inputs, captcha)) {
1444
1445							// veify reCaptcha
1446							if (captcha.length) {
1447								var captchaToken = captcha.find('.g-recaptcha-response').val(),
1448										captchaMsg = {
1449											'CPT001': 'Please, setup you "site key" and "secret key" of reCaptcha',
1450											'CPT002': 'Something wrong with google reCaptcha'
1451										}
1452
1453								formHasCaptcha = true;
1454
1455								$.ajax({
1456									method: "POST",
1457									url: "bat/reCaptcha.php",
1458									data: {'g-recaptcha-response': captchaToken},
1459									async: false
1460								})
1461								.done(function (responceCode) {
1462									if (responceCode != 'CPT000') {
1463										if (output.hasClass("snackbars")) {
1464											output.html('<p><span class="icon text-middle mdi mdi-check icon-xxs"></span><span>' + captchaMsg[responceCode] + '</span></p>')
1465
1466											setTimeout(function () {
1467												output.removeClass("active");
1468											}, 3500);
1469
1470											captchaFlag = false;
1471										} else {
1472											output.html(captchaMsg[responceCode]);
1473										}
1474
1475										output.addClass("active");
1476									}
1477								});
1478							}
1479
1480							if (!captchaFlag) {
1481								return false;
1482							}
1483
1484							form.addClass('form-in-process');
1485
1486							if (output.hasClass("snackbars")) {
1487								output.html('<p><span class="icon text-middle fa fa-circle-o-notch fa-spin icon-xxs"></span><span>Sending</span></p>');
1488								output.addClass("active");
1489							}
1490						} else {
1491							return false;
1492						}
1493					},
1494					error: function (result) {
1495						if (isNoviBuilder)
1496							return;
1497
1498						var output = $("#" + $(plugins.rdMailForm[this.extraData.counter]).attr("data-form-output")),
1499								form = $(plugins.rdMailForm[this.extraData.counter]);
1500
1501						output.text(msg[result]);
1502						form.removeClass('form-in-process');
1503
1504						if (formHasCaptcha) {
1505							grecaptcha.reset();
1506						}
1507					},
1508					success: function (result) {
1509						if (isNoviBuilder)
1510							return;
1511
1512						var form = $(plugins.rdMailForm[this.extraData.counter]),
1513								output = $("#" + form.attr("data-form-output"));
1514
1515						form
1516						.addClass('success')
1517						.removeClass('form-in-process');
1518
1519						if (formHasCaptcha) {
1520							grecaptcha.reset();
1521						}
1522
1523						result = result.length === 5 ? result : 'MF255';
1524						output.text(msg[result]);
1525
1526						if (result === "MF000") {
1527							if (output.hasClass("snackbars")) {
1528								output.html('<p><span class="icon text-middle mdi mdi-check icon-xxs"></span><span>' + msg[result] + '</span></p>');
1529							} else {
1530								output.addClass("active success");
1531							}
1532						} else {
1533							if (output.hasClass("snackbars")) {
1534								output.html(' <p class="snackbars-left"><span class="icon icon-xxs mdi mdi-alert-outline text-middle"></span><span>' + msg[result] + '</span></p>');
1535							} else {
1536								output.addClass("active error");
1537							}
1538						}
1539
1540						form.clearForm();
1541						form.find('input, textarea').trigger('blur');
1542
1543						setTimeout(function () {
1544							output.removeClass("active error success");
1545							form.removeClass('success');
1546						}, 3500);
1547					}
1548				});
1549			}
1550		}
1551
1552		/**
1553		 * Custom Toggles
1554		 */
1555		if (plugins.customToggle.length) {
1556			var i;
1557
1558			for (i = 0; i < plugins.customToggle.length; i++) {
1559				var $this = $(plugins.customToggle[i]);
1560
1561				$this.on('click', $.proxy(function (event) {
1562					event.preventDefault();
1563					var $ctx = $(this);
1564					$($ctx.attr('data-custom-toggle')).add(this).toggleClass('active');
1565				}, $this));
1566
1567				if ($this.attr("data-custom-toggle-hide-on-blur") === "true") {
1568					$body.on("click", $this, function (e) {
1569						if (e.target !== e.data[0]
1570								&& $(e.data.attr('data-custom-toggle')).find($(e.target)).length
1571								&& e.data.find($(e.target)).length == 0) {
1572							$(e.data.attr('data-custom-toggle')).add(e.data[0]).removeClass('active');
1573						}
1574					})
1575				}
1576
1577				if ($this.attr("data-custom-toggle-disable-on-blur") === "true") {
1578					$body.on("click", $this, function (e) {
1579						if (e.target !== e.data[0] && $(e.data.attr('data-custom-toggle')).find($(e.target)).length == 0 && e.data.find($(e.target)).length == 0) {
1580							$(e.data.attr('data-custom-toggle')).add(e.data[0]).removeClass('active');
1581						}
1582					})
1583				}
1584			}
1585		}
1586
1587		/**
1588		 * jQuery Count To
1589		 * @description Enables Count To plugin
1590		 */
1591		if (plugins.counter.length) {
1592			var i;
1593
1594			for (i = 0; i < plugins.counter.length; i++) {
1595				var $counterNotAnimated = $(plugins.counter[i]).not('.animated');
1596				$document
1597				.on("scroll", $.proxy(function () {
1598					var $this = this;
1599
1600					if ((!$this.hasClass("animated")) && (isScrolledIntoView($this))) {
1601						$this.countTo({
1602							refreshInterval: 40,
1603							from: 0,
1604							to: parseInt($this.text(), 10),
1605							speed: $this.attr("data-speed") || 1000
1606						});
1607						$this.addClass('animated');
1608					}
1609				}, $counterNotAnimated))
1610				.trigger("scroll");
1611			}
1612		}
1613
1614		/**
1615		 * TimeCircles
1616		 * @description  Enable TimeCircles plugin
1617		 */
1618		if (plugins.dateCountdown.length) {
1619			var i;
1620			for (i = 0; i < plugins.dateCountdown.length; i++) {
1621				var dateCountdownItem = $(plugins.dateCountdown[i]);
1622
1623				$window.on('load resize orientationchange', $.proxy(function () {
1624					var $this = $(this),
1625							circleColor = $this.data('circle-inner-color'),
1626							dateCountdownItemBgColor = $this.data('circle-bg'),
1627							time = {
1628								"Days": {
1629									"text": "Days",
1630									"color": circleColor,
1631									"show": true
1632								},
1633								"Hours": {
1634									"text": "Hours",
1635									"color": circleColor,
1636									"show": true
1637								},
1638								"Minutes": {
1639									"text": "Minutes",
1640									"color": circleColor,
1641									"show": true
1642								},
1643								"Seconds": {
1644									"text": "Seconds",
1645									"color": circleColor,
1646									"show": true
1647								}
1648							};
1649
1650					$this.TimeCircles({
1651						fg_width: $this.data('circle-fg-width') || 0.045,
1652						circle_bg_color: dateCountdownItemBgColor,
1653						bg_width: $this.data('circle-bg-width') || 0.9,
1654						time: time
1655					});
1656
1657					if (window.innerWidth < 479) {
1658						$this.TimeCircles({
1659							time: {
1660								Days: {
1661									"color": circleColor,
1662									"show": true
1663								},
1664								Hours: {
1665									"color": circleColor,
1666									"show": true
1667								},
1668								Minutes: {
1669									color: circleColor,
1670									show: true
1671								},
1672								Seconds: {
1673									show: false
1674								}
1675							}
1676						}).rebuild();
1677					} else if (window.innerWidth < 767) {
1678						$this.TimeCircles({
1679							time: {
1680								Days: {
1681									"color": circleColor,
1682									"show": true
1683								},
1684								Hours: {
1685									"color": circleColor,
1686									"show": true
1687								},
1688								Seconds: {show: false}
1689							}
1690						}).rebuild();
1691					} else {
1692						$this.TimeCircles({time: time}).rebuild();
1693					}
1694				}, dateCountdownItem));
1695			}
1696		}
1697
1698		// Progress Circle
1699		if ( plugins.progressCircle ) {
1700			for ( var i = 0; i < plugins.progressCircle.length; i++ ) {
1701				var
1702						container = plugins.progressCircle[i],
1703						counter = aCounter({
1704							node: container.querySelector( '.progress-circle-counter' ),
1705							duration: 500,
1706							onUpdate: function( value ) {
1707								this.custom.bar.render( value * 3.6 );
1708							}
1709						});
1710
1711				counter.params.onComplete = counter.params.onUpdate;
1712
1713				counter.custom = {
1714					container: container,
1715					bar: aProgressCircle({ node: container.querySelector( '.progress-circle-bar' ) }),
1716					onScroll: (function() {
1717						if ( Util.inViewport( this.custom.container ) && !this.custom.container.classList.contains( 'animated' ) ) {
1718							this.run();
1719							this.custom.container.classList.add( 'animated' );
1720						}
1721					}).bind( counter ),
1722					onBlur: (function() {
1723						this.params.to = parseInt( this.params.node.textContent, 10 );
1724						this.run();
1725					}).bind( counter )
1726				};
1727
1728				counter.custom.onScroll();
1729				window.addEventListener( 'scroll', counter.custom.onScroll );
1730				counter.params.node.addEventListener( 'blur', counter.custom.onBlur );
1731			}
1732		}
1733
1734		/**
1735		 * Linear Progress bar
1736		 * @description  Enable progress bar
1737		 */
1738		if (plugins.progressLinear.length) {
1739			for (i = 0; i < plugins.progressLinear.length; i++) {
1740				var progressBar = $(plugins.progressLinear[i]);
1741				$window
1742				.on("scroll load", $.proxy(function () {
1743					var bar = $(this);
1744					if (!bar.hasClass('animated-first') && isScrolledIntoView(bar)) {
1745						var end = parseInt($(this).find('.progress-value').text(), 10);
1746						bar.find('.progress-bar-linear').css({width: end + '%'});
1747						bar.find('.progress-value').countTo({
1748							refreshInterval: 40,
1749							from: 0,
1750							to: end,
1751							speed: 500
1752						});
1753						bar.addClass('animated-first');
1754					}
1755				}, progressBar));
1756			}
1757		}
1758
1759		/**
1760		 * RD Flickr Feed
1761		 * @description Enables RD Flickr Feed plugin
1762		 */
1763		if (plugins.flickrfeed.length > 0) {
1764			var i;
1765			for (i = 0; i < plugins.flickrfeed.length; i++) {
1766				var flickrfeedItem = $(plugins.flickrfeed[i]);
1767				flickrfeedItem.RDFlickr({
1768					callback: function () {
1769						var items = flickrfeedItem.find("[data-photo-swipe-item]");
1770
1771						if (items.length) {
1772							for (var j = 0; j < items.length; j++) {
1773								var image = new Image();
1774								image.setAttribute('data-index', j);
1775								image.onload = function () {
1776									items[this.getAttribute('data-index')].setAttribute('data-size', this.naturalWidth + 'x' + this.naturalHeight);
1777								};
1778								image.src = items[j].getAttribute('href');
1779							}
1780						}
1781					}
1782				});
1783			}
1784		}
1785
1786		/**
1787		 * RD Twitter Feed
1788		 * @description Enables RD Twitter Feed plugin
1789		 */
1790		if (plugins.twitterfeed.length > 0) {
1791			var i;
1792			for (i = 0; i < plugins.twitterfeed.length; i++) {
1793				var twitterfeedItem = plugins.twitterfeed[i];
1794				$(twitterfeedItem).RDTwitter({});
1795			}
1796		}
1797
1798		// Google maps
1799		if( plugins.maps.length ) {
1800			lazyInit( plugins.maps, initMaps );
1801		}
1802
1803		// lightGallery
1804		if (plugins.lightGallery.length) {
1805			for (var i = 0; i < plugins.lightGallery.length; i++) {
1806				initLightGallery(plugins.lightGallery[i]);
1807			}
1808		}
1809
1810		// lightGallery item
1811		if (plugins.lightGalleryItem.length) {
1812			// Filter carousel items
1813			var notCarouselItems = [];
1814
1815			for (var z = 0; z < plugins.lightGalleryItem.length; z++) {
1816				if (!$(plugins.lightGalleryItem[z]).parents('.owl-carousel').length &&
1817						!$(plugins.lightGalleryItem[z]).parents('.swiper-slider').length &&
1818						!$(plugins.lightGalleryItem[z]).parents('.slick-slider').length) {
1819					notCarouselItems.push(plugins.lightGalleryItem[z]);
1820				}
1821			}
1822
1823			plugins.lightGalleryItem = notCarouselItems;
1824
1825			for (var i = 0; i < plugins.lightGalleryItem.length; i++) {
1826				initLightGalleryItem(plugins.lightGalleryItem[i]);
1827			}
1828		}
1829
1830		// Dynamic lightGallery
1831		if (plugins.lightDynamicGalleryItem.length) {
1832			for (var i = 0; i < plugins.lightDynamicGalleryItem.length; i++) {
1833				initDynamicLightGallery(plugins.lightDynamicGalleryItem[i]);
1834			}
1835		}
1836
1837	});
1838
1839}());
1840

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.