PageSourceSearch

https://effortless-croquembouche-a4c39e.netlify.app/js/script.js

js effortless-croquembouche-a4c39e.netlify.app collected 2026-10-03 10:41:09 UTC 60,362 bytes, 1,987 lines download raw bytes

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

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.