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.