1'use strict'; 2var theme = { 3 /** 4 * Theme's components/functions list 5 * Comment out or delete the unnecessary component. 6 * Some components have dependencies (plugins). 7 * Do not forget to remove dependency from src/js/vendor/ and recompile. 8 */ 9 init: function () { 10 theme.stickyHeader(); 11 theme.subMenu(); 12 theme.offCanvas(); 13 theme.isotope(); 14 theme.onepageHeaderOffset(); 15 theme.anchorSmoothScroll(); 16 theme.svgInject(); 17 theme.backgroundImage(); 18 theme.backgroundImageMobile(); 19 theme.imageHoverOverlay(); 20 theme.rellax(); 21 theme.scrollCue(); 22 theme.swiperSlider(); 23 theme.lightbox(); 24 theme.plyr(); 25 theme.progressBar(); 26 theme.loader(); 27 theme.pageProgress(); 28 theme.counterUp(); 29 theme.bsTooltips(); 30 theme.bsPopovers(); 31 theme.bsModal(); 32 theme.iTooltip(); 33 theme.forms(); 34 theme.passVisibility(); 35 theme.pricingSwitcher(); 36 theme.textRotator(); 37 theme.codeSnippet(); 38 }, 39 /** 40 * Sticky Header 41 * Enables sticky behavior on navbar on page scroll 42 * Requires assets/js/vendor/headhesive.min.js 43 */ 44 stickyHeader: () => { 45 var navbar = document.querySelector(".navbar"); 46 if (navbar == null) return; 47 var options = { 48 offset: 350, 49 offsetSide: 'top', 50 classes: { 51 clone: 'navbar-clone fixed', 52 stick: 'navbar-stick', 53 unstick: 'navbar-unstick', 54 }, 55 onStick: function() { 56 var navbarClonedClass = this.clonedElem.classList; 57 if (navbarClonedClass.contains('transparent') && navbarClonedClass.contains('navbar-dark')) { 58 this.clonedElem.className = this.clonedElem.className.replace("navbar-dark","navbar-light"); 59 } 60 } 61 }; 62 var banner = new Headhesive('.navbar', options); 63 }, 64 /** 65 * Sub Menus 66 * Enables multilevel dropdown 67 */ 68 subMenu: function () { 69 (function($bs) { 70 const CLASS_NAME = 'has-child-dropdown-show'; 71 $bs.Dropdown.prototype.toggle = function(_original) { 72 return function() { 73 document.querySelectorAll('.' + CLASS_NAME).forEach(function(e) { 74 e.classList.remove(CLASS_NAME); 75 }); 76 let dd = this._element.closest('.dropdown').parentNode.closest('.dropdown'); 77 for (; dd && dd !== document; dd = dd.parentNode.closest('.dropdown')) { 78 dd.classList.add(CLASS_NAME); 79 } 80 return _original.call(this); 81 } 82 }($bs.Dropdown.prototype.toggle); 83 document.querySelectorAll('.dropdown').forEach(function(dd) { 84 dd.addEventListener('hide.bs.dropdown', function(e) { 85 if (this.classList.contains(CLASS_NAME)) { 86 this.classList.remove(CLASS_NAME); 87 e.preventDefault(); 88 } 89 e.stopPropagation(); 90 }); 91 }); 92 })(bootstrap); 93 }, 94 /** 95 * Offcanvas 96 * Enables offcanvas-nav, closes offcanvas on anchor clicks 97 */ 98 offCanvas: function () { 99 const navOffCanvasBtn = document.querySelectorAll(".offcanvas-nav-btn"); 100 const navOffCanvas = document.querySelector('.navbar:not(.navbar-clone) .offcanvas-nav'); 101 const bsOffCanvas = new bootstrap.Offcanvas(navOffCanvas, {scroll: true}); 102 const scrollLink = document.querySelectorAll('.onepage .navbar li a.scroll'); 103 navOffCanvasBtn.forEach(e => { 104 e.addEventListener('click', event => { 105 bsOffCanvas.show(); 106 }) 107 }); 108 scrollLink.forEach(e => { 109 e.addEventListener('click', event => { 110 bsOffCanvas.hide(); 111 }) 112 }); 113 }, 114 /** 115 * Isotope 116 * Enables isotope grid layout and filtering 117 * Requires assets/js/vendor/isotope.pkgd.min.js 118 * Requires assets/js/vendor/imagesloaded.pkgd.min.js 119 */ 120 isotope: function () { 121 var grids = document.querySelectorAll('.grid'); 122 if(grids != null) { 123 grids.forEach(g => { 124 var grid = g.querySelector('.isotope'); 125 var filtersElem = g.querySelector('.isotope-filter'); 126 var buttonGroups = g.querySelectorAll('.isotope-filter'); 127 var iso = new Isotope(grid, { 128 itemSelector: '.item', 129 layoutMode: 'masonry', 130 masonry: { 131 columnWidth: grid.offsetWidth / 12 132 }, 133 percentPosition: true, 134 transitionDuration: '0.7s' 135 }); 136 imagesLoaded(grid).on("progress", function() { 137 iso.layout({ 138 masonry: { 139 columnWidth: grid.offsetWidth / 12 140 } 141 }) 142 }), 143 window.addEventListener("resize", function() { 144 iso.arrange({ 145 masonry: { 146 columnWidth: grid.offsetWidth / 12 147 } 148 }); 149 }, true); 150 if(filtersElem != null) { 151 filtersElem.addEventListener('click', function(event) { 152 if(!matchesSelector(event.target, '.filter-item')) { 153 return; 154 } 155 var filterValue = event.target.getAttribute('data-filter'); 156 iso.arrange({ 157 filter: filterValue 158 }); 159 }); 160 for(var i = 0, len = buttonGroups.length; i < len; i++) { 161 var buttonGroup = buttonGroups[i]; 162 buttonGroup.addEventListener('click', function(event) { 163 if(!matchesSelector(event.target, '.filter-item')) { 164 return; 165 } 166 buttonGroup.querySelector('.active').classList.remove('active'); 167 event.target.classList.add('active'); 168 }); 169 } 170 } 171 }); 172 } 173 }, 174 /** 175 * Onepage Header Offset 176 * Adds an offset value to anchor point equal to sticky header height on a onepage 177 */ 178 onepageHeaderOffset: function () { 179 const header_height = document.querySelector(".navbar").offsetHeight; 180 const shrinked_header_height = 75; 181 const sections = document.querySelectorAll(".onepage section"); 182 sections.forEach(section => { 183 section.style.paddingTop = shrinked_header_height + 'px'; 184 section.style.marginTop = '-' + shrinked_header_height + 'px'; 185 }); 186 const first_section = document.querySelector(".onepage section:first-of-type"); 187 if(first_section != null) { 188 first_section.style.paddingTop = header_height + 'px'; 189 first_section.style.marginTop = '-' + header_height + 'px'; 190 } 191 }, 192 /** 193 * Anchor Smooth Scroll 194 * Adds smooth scroll animation to links with .scroll class 195 * Requires assets/js/vendor/smoothscroll.js 196 */ 197 anchorSmoothScroll: function () { 198 const links = document.querySelectorAll(".scroll"); 199 for(const link of links) { 200 link.addEventListener("click", clickHandler); 201 } 202 function clickHandler(e) { 203 e.preventDefault(); 204 this.blur(); 205 const href = this.getAttribute("href"); 206 const offsetTop = document.querySelector(href).offsetTop; 207 scroll({ 208 top: offsetTop, 209 behavior: "smooth" 210 }); 211 } 212 }, 213 /** 214 * SVGInject 215 * Replaces an img element with an inline SVG so you can apply colors to your SVGs 216 * Requires assets/js/vendor/svg-inject.min.js 217 */ 218 svgInject: function () { 219 SVGInject.setOptions({ 220 onFail: function(img, svg) { 221 img.classList.remove('svg-inject'); 222 } 223 }); 224 document.addEventListener('DOMContentLoaded', function() { 225 SVGInject(document.querySelectorAll('img.svg-inject'), { 226 useCache: true 227 }); 228 }); 229 }, 230 /**
231 * Background Image 232 * Adds a background image link via data attribute "data-image-src" 233 */ 234 backgroundImage: function () { 235 var bg = document.querySelectorAll(".bg-image"); 236 for(var i = 0; i < bg.length; i++) { 237 var url = bg[i].getAttribute('data-image-src'); 238 bg[i].style.backgroundImage = "url('" + url + "')"; 239 } 240 }, 241 /** 242 * Background Image Mobile 243 * Adds .mobile class to background images on mobile devices for styling purposes 244 */ 245 backgroundImageMobile: function () { 246 var isMobile = (navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/webOS/i) || navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/BlackBerry/i)) ? true : false; 247 if(isMobile) { 248 document.querySelectorAll(".image-wrapper").forEach(e => { 249 e.classList.add("mobile") 250 }) 251 } 252 }, 253 /** 254 * Image Hover Overlay 255 * Adds span.bg inside .overlay for simpler markup and styling purposes 256 */ 257 imageHoverOverlay: function () { 258 var overlay = document.querySelectorAll('.overlay > a, .overlay > span'); 259 for(var i = 0; i < overlay.length; i++) { 260 var overlay_bg = document.createElement('span'); 261 overlay_bg.className = "bg"; 262 overlay[i].appendChild(overlay_bg); 263 } 264 }, 265 /** 266 * Rellax.js 267 * Adds parallax animation to shapes and elements 268 * Requires assets/js/vendor/rellax.min.js 269 */ 270 rellax: function () { 271 if(document.querySelector(".rellax") != null) { 272 window.onload = function() { 273 var rellax = new Rellax('.rellax', { 274 speed: 2, 275 center: true, 276 breakpoints: [576, 992, 1201] 277 }); 278 var projects_overflow = document.querySelectorAll('.projects-overflow'); 279 imagesLoaded(projects_overflow, function() { 280 rellax.refresh(); 281 }); 282 } 283 } 284 }, 285 /** 286 * scrollCue.js 287 * Enables showing elements by scrolling 288 * Requires assets/js/vendor/scrollCue.min.js 289 */ 290 scrollCue: function () { 291 scrollCue.init({ 292 interval: -400, 293 duration: 700, 294 percentage: 0.8 295 }); 296 scrollCue.update(); 297 }, 298 /** 299 * Swiper Slider 300 * Enables carousels and sliders 301 * Requires assets/js/vendor/swiper-bundle.min.js 302 */ 303 swiperSlider: function() { 304 var carousel = document.querySelectorAll('.swiper-container'); 305 for(var i = 0; i < carousel.length; i++) { 306 var slider1 = carousel[i]; 307 slider1.classList.add('swiper-container-' + i); 308 var controls = document.createElement('div'); 309 controls.className = "swiper-controls"; 310 var pagi = document.createElement('div'); 311 pagi.className = "swiper-pagination"; 312 var navi = document.createElement('div'); 313 navi.className = "swiper-navigation"; 314 var prev = document.createElement('div'); 315 prev.className = "swiper-button swiper-button-prev"; 316 var next = document.createElement('div'); 317 next.className = "swiper-button swiper-button-next"; 318 slider1.appendChild(controls); 319 controls.appendChild(navi); 320 navi.appendChild(prev); 321 navi.appendChild(next); 322 controls.appendChild(pagi); 323 var sliderEffect = slider1.getAttribute('data-effect') ? slider1.getAttribute('data-effect') : 'slide'; 324 var sliderItems = slider1.getAttribute('data-items') ? slider1.getAttribute('data-items') : 3; // items in all devices 325 var sliderItemsXs = slider1.getAttribute('data-items-xs') ? slider1.getAttribute('data-items-xs') : 1; // start - 575 326 var sliderItemsSm = slider1.getAttribute('data-items-sm') ? slider1.getAttribute('data-items-sm') : Number(sliderItemsXs); // 576 - 767 327 var sliderItemsMd = slider1.getAttribute('data-items-md') ? slider1.getAttribute('data-items-md') : Number(sliderItemsSm); // 768 - 991 328 var sliderItemsLg = slider1.getAttribute('data-items-lg') ? slider1.getAttribute('data-items-lg') : Number(sliderItemsMd); // 992 - 1199 329 var sliderItemsXl = slider1.getAttribute('data-items-xl') ? slider1.getAttribute('data-items-xl')
329: Number(sliderItemsLg); // 1200 - end 330 var sliderItemsXxl = slider1.getAttribute('data-items-xxl') ? slider1.getAttribute('data-items-xxl') : Number(sliderItemsXl); // 1500 - end 331 var sliderSpeed = slider1.getAttribute('data-speed') ? slider1.getAttribute('data-speed') : 500; 332 var sliderAutoPlay = slider1.getAttribute('data-autoplay') !== 'false'; 333 var sliderAutoPlayTime = slider1.getAttribute('data-autoplaytime') ? slider1.getAttribute('data-autoplaytime') : 5000; 334 var sliderAutoHeight = slider1.getAttribute('data-autoheight') === 'true'; 335 var sliderMargin = slider1.getAttribute('data-margin') ? slider1.getAttribute('data-margin') : 30; 336 var sliderLoop = slider1.getAttribute('data-loop') === 'true'; 337 var swiper = slider1.querySelector('.swiper:not(.swiper-thumbs)'); 338 var swiperTh = slider1.querySelector('.swiper-thumbs'); 339 var sliderTh = new Swiper(swiperTh, { 340 slidesPerView: 5, 341 spaceBetween: 10, 342 loop: false, 343 threshold: 2 344 }); 345 if (slider1.getAttribute('data-thumbs') === 'true') { 346 var thumbsInit = sliderTh; 347 var swiperMain = document.createElement('div'); 348 swiperMain.className = "swiper-main"; 349 swiper.parentNode.insertBefore(swiperMain, swiper); 350 swiperMain.appendChild(swiper); 351 slider1.removeChild(controls); 352 swiperMain.appendChild(controls); 353 } else { 354 var thumbsInit = null; 355 } 356 var slider = new Swiper(swiper, { 357 on: { 358 beforeInit: function() { 359 if(slider1.getAttribute('data-nav') !== 'true' && slider1.getAttribute('data-dots') !== 'true') { 360 controls.remove(); 361 } 362 if(slider1.getAttribute('data-dots') !== 'true') { 363 pagi.remove(); 364 } 365 if(slider1.getAttribute('data-nav') !== 'true') { 366 navi.remove(); 367 } 368 }, 369 init: function() { 370 if(slider1.getAttribute('data-autoplay') !== 'true') { 371 this.autoplay.stop(); 372 } 373 this.update(); 374 } 375 }, 376 autoplay: { 377 delay: sliderAutoPlayTime, 378 disableOnInteraction: false 379 }, 380 speed: sliderSpeed, 381 slidesPerView: sliderItems, 382 loop: sliderLoop, 383 spaceBetween: Number(sliderMargin), 384 effect: sliderEffect, 385 autoHeight: sliderAutoHeight, 386 grabCursor: true, 387 resizeObserver: false, 388 breakpoints: { 389 0: { 390 slidesPerView: Number(sliderItemsXs) 391 }, 392 576: { 393 slidesPerView: Number(sliderItemsSm) 394 }, 395 768: { 396 slidesPerView: Number(sliderItemsMd) 397 }, 398 992: { 399 slidesPerView: Number(sliderItemsLg) 400 }, 401 1200: { 402 slidesPerView: Number(sliderItemsXl) 403 }, 404 1400: { 405 slidesPerView: Number(sliderItemsXxl) 406 } 407 }, 408 pagination: { 409 el: carousel[i].querySelector('.swiper-pagination'), 410 clickable: true 411 }, 412 navigation: { 413 prevEl: slider1.querySelector('.swiper-button-prev'), 414 nextEl: slider1.querySelector('.swiper-button-next'), 415 }, 416 thumbs: { 417 swiper: thumbsInit, 418 }, 419 }); 420 } 421 }, 422 /** 423 * GLightbox 424 * Enables lightbox functionality 425 * Requires assets/js/vendor/glightbox.js 426 */ 427 lightbox: function () { 428 const lightbox = GLightbox({ 429 selector: '*[data-glightbox]', 430 touchNavigation: true, 431 loop: false, 432 zoomable: false, 433 autoplayVideos: true, 434 moreLength: 0, 435 slideExtraAttributes: { 436 poster: '' 437 }, 438 plyr: { 439 css: '', 440 js: '', 441 config: { 442 ratio: '16:9', 443 fullscreen: { 444 enabled: false, 445 iosNative: false 446 }, 447 youtube: { 448 noCookie: true, 449 rel: 0, 450 showinfo: 0, 451 iv_load_policy: 3 452 }, 453 vimeo: { 454 byline: false, 455 portrait: false, 456 title: false, 457 transparent: false 458 } 459 } 460 }, 461 }); 462 }, 463 /** 464 * Plyr 465 * Enables media player 466 * Requires assets/js/vendor/plyr.js 467 */ 468 plyr: function () { 469 var players = Plyr.setup('.player', { 470 loadSprite: true, 471 }); 472 }, 473 /** 474 * Progressbar 475 * Enables animated progressbars 476 * Requires assets/js/vendor/progressbar.min.js 477 * Requires assets/js/vendor/noframework.waypoints.min.js 478 */ 479 progressBar: function () { 480 const pline = document.querySelectorAll(".progressbar.line"); 481 const pcircle = document.querySelectorAll(".progressbar.semi-circle"); 482 pline.forEach(e => { 483 var line = new ProgressBar.Line(e, { 484 strokeWidth: 6, 485 trailWidth: 6, 486 duration: 3000, 487 easing: 'easeInOut', 488 text: { 489 style: { 490 color: 'inherit', 491 position: 'absolute', 492 right: '0', 493 top: '-30px', 494 padding: 0, 495 margin: 0, 496 transform: null 497 }, 498 autoStyleContainer: false 499 }, 500 step: (state, line) => { 501 line.setText(Math.round(line.value() * 100) + ' %'); 502 } 503 }); 504 var value = e.getAttribute('data-value') / 100; 505 new Waypoint({ 506 element: e, 507 handler: function() { 508 line.animate(value); 509 }, 510 offset: 'bottom-in-view', 511 }) 512 }); 513 pcircle.forEach(e => { 514 var circle = new ProgressBar.SemiCircle(e, { 515 strokeWidth: 6, 516 trailWidth: 6, 517 duration: 2000,
518 easing: 'easeInOut', 519 step: (state, circle) => { 520 circle.setText(Math.round(circle.value() * 100)); 521 } 522 }); 523 var value = e.getAttribute('data-value') / 100; 524 new Waypoint({ 525 element: e, 526 handler: function() { 527 circle.animate(value); 528 }, 529 offset: 'bottom-in-view', 530 }) 531 }); 532 }, 533 /** 534 * Loader 535 * 536 */ 537 loader: function () { 538 var preloader = document.querySelector('.page-loader'); 539 if(preloader != null) { 540 document.body.onload = function(){ 541 setTimeout(function() { 542 if( !preloader.classList.contains('done') ) 543 { 544 preloader.classList.add('done'); 545 } 546 }, 1000) 547 } 548 } 549 }, 550 /** 551 * Page Progress 552 * Shows page progress on the bottom right corner of pages 553 */ 554 pageProgress: function () { 555 var progressWrap = document.querySelector('.progress-wrap'); 556 var progressPath = document.querySelector('.progress-wrap path'); 557 var pathLength = progressPath.getTotalLength(); 558 var offset = 50; 559 if(progressWrap != null) { 560 progressPath.style.transition = progressPath.style.WebkitTransition = 'none'; 561 progressPath.style.strokeDasharray = pathLength + ' ' + pathLength; 562 progressPath.style.strokeDashoffset = pathLength; 563 progressPath.getBoundingClientRect(); 564 progressPath.style.transition = progressPath.style.WebkitTransition = 'stroke-dashoffset 10ms linear'; 565 window.addEventListener("scroll", function(event) { 566 var scroll = document.body.scrollTop || document.documentElement.scrollTop; 567 var height = document.documentElement.scrollHeight - document.documentElement.clientHeight; 568 var progress = pathLength - (scroll * pathLength / height); 569 progressPath.style.strokeDashoffset = progress; 570 var scrollElementPos = document.body.scrollTop || document.documentElement.scrollTop; 571 if(scrollElementPos >= offset) { 572 progressWrap.classList.add("active-progress") 573 } else { 574 progressWrap.classList.remove("active-progress") 575 } 576 }); 577 progressWrap.addEventListener('click', function(e) { 578 e.preventDefault(); 579 window.scroll({ 580 top: 0, 581 left: 0, 582 behavior: 'smooth' 583 }); 584 }); 585 } 586 }, 587 /** 588 * Counter Up 589 * Counts up to a targeted number when the number becomes visible 590 * Requires assets/js/vendor/counterup.min.js 591 * Requires assets/js/vendor/noframework.waypoints.min.js 592 */ 593 counterUp: function () { 594 var counterUp = window.counterUp["default"]; 595 const counters = document.querySelectorAll(".counter"); 596 counters.forEach(el => { 597 new Waypoint({ 598 element: el, 599 handler: function() { 600 counterUp(el, { 601 duration: 1000, 602 delay: 50 603 }) 604 this.destroy() 605 }, 606 offset: 'bottom-in-view', 607 }) 608 }); 609 }, 610 /** 611 * Bootstrap Tooltips 612 * Enables Bootstrap tooltips 613 * Requires Poppers library 614 */ 615 bsTooltips: function () { 616 var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')) 617 var tooltipList = tooltipTriggerList.map(function(tooltipTriggerEl) { 618 return new bootstrap.Tooltip(tooltipTriggerEl, { 619 trigger: 'hover' 620 }) 621 }); 622 var tooltipTriggerWhite = [].slice.call(document.querySelectorAll('[data-bs-toggle="white-tooltip"]')) 623 var tooltipWhite = tooltipTriggerWhite.map(function(tooltipTriggerEl) { 624 return new bootstrap.Tooltip(tooltipTriggerEl, { 625 customClass: 'white-tooltip', 626 trigger: 'hover', 627 placement: 'left' 628 }) 629 }) 630 }, 631 /** 632 * Bootstrap Popovers 633 * Enables Bootstrap popovers 634 * Requires Poppers library 635 */ 636 bsPopovers: function () { 637 var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')) 638 var popoverList = popoverTriggerList.map(function(popoverTriggerEl) { 639 return new bootstrap.Popover(popoverTriggerEl) 640 }) 641 }, 642 /** 643 * Bootstrap Modal 644 * Enables Bootstrap modal popup 645 */ 646 bsModal: function () { 647 if(document.querySelector(".modal-popup") != null) { 648 var myModalPopup = new bootstrap.Modal(document.querySelector('.modal-popup')); 649 setTimeout(function() { 650 myModalPopup.show(); 651 }, 200); 652 } 653 // Fixes jumping of page progress caused by modal 654 var innerWidth = window.innerWidth; 655 var clientWidth = document.body.clientWidth; 656 var scrollSize = innerWidth - clientWidth; 657 var myModalEl = document.querySelectorAll('.modal'); 658 var navbarFixed = document.querySelector('.navbar.fixed'); 659 var pageProgress = document.querySelector('.progress-wrap'); 660 function setPadding() { 661 if(navbarFixed != null) { 662 navbarFixed.style.paddingRight = scrollSize + 'px'; 663 } 664 if(pageProgress != null) { 665 pageProgress.style.marginRight = scrollSize + 'px'; 666 } 667 } 668 function removePadding() { 669 if(navbarFixed != null) { 670 navbarFixed.style.paddingRight = ''; 671 } 672 if(pageProgress != null) { 673 pageProgress.style.marginRight = ''; 674 } 675 } 676 myModalEl.forEach(myModalEl => { 677 myModalEl.addEventListener('show.bs.modal', function(e) { 678 setPadding(); 679 }) 680 myModalEl.addEventListener('hidden.bs.modal', function(e) { 681 removePadding(); 682 }) 683 }); 684 }, 685 /** 686 * iTooltip 687 * Enables custom tooltip style for image hover docs/elements/hover.html 688 * Requires assets/js/vendor/itooltip.min.js 689 */ 690 iTooltip: function () { 691 var tooltip = new iTooltip('.itooltip') 692 tooltip.init({ 693 className: 'itooltip-inner', 694 indentX: 15, 695 indentY: 15, 696 positionX: 'right', 697 positionY: 'bottom' 698 }) 699 }, 700 /** 701 * Form Validation and Contact Form submit 702 * Bootstrap validation - Only sends messages if form has class ".contact-form" and is validated and shows success/fail messages 703 */ 704 forms: function () { 705 (function() { 706 "use strict"; 707 window.addEventListener("load", function() { 708 var forms = document.querySelectorAll(".needs-validation");
709 var validation = Array.prototype.filter.call(forms, function(form) { 710 form.addEventListener("submit", function(event) { 711 if(form.checkValidity() === false) { 712 event.preventDefault(); 713 event.stopPropagation(); 714 } 715 form.classList.add("was-validated"); 716 if(form.checkValidity() === true) { 717 event.preventDefault(); 718 form.classList.remove("was-validated"); 719 // Send message only if the form has class .contact-form 720 var isContactForm = form.classList.contains('contact-form'); 721 console.log(isContactForm); 722 if(isContactForm) { 723 var data = new FormData(form); 724 var alertClass = 'alert-danger'; 725 fetch("assets/php/contact.php", { 726 method: "post", 727 body: data 728 }).then((data) => { 729 if(data.ok) { 730 alertClass = 'alert-success'; 731 } 732 return data.text(); 733 }).then((txt) => { 734 var alertBox = '<div class="alert ' + alertClass + ' alert-dismissible fade show"><button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' + txt + '</div>'; 735 if(alertClass && txt) { 736 form.querySelector(".messages").insertAdjacentHTML('beforeend', alertBox); 737 form.reset(); 738 } 739 }).catch((err) => { 740 console.log(err); 741 }); 742 } 743 } 744 }, false); 745 }); 746 }, false); 747 })(); 748 }, 749 /** 750 * Password Visibility Toggle 751 * Toggles password visibility in password input 752 */ 753 passVisibility: function () { 754 let pass = document.querySelectorAll('.password-field'); 755 for (let i = 0; i < pass.length; i++) { 756 let passInput = pass[i].querySelector('.form-control'); 757 let passToggle = pass[i].querySelector('.password-toggle > i'); 758 passToggle.addEventListener('click', (e) => { 759 if (passInput.type === "password") { 760 passInput.type = "text"; 761 passToggle.classList.remove('uil-eye'); 762 passToggle.classList.add('uil-eye-slash'); 763 } else { 764 passInput.type = "password"; 765 passToggle.classList.remove('uil-eye-slash'); 766 passToggle.classList.add('uil-eye'); 767 } 768 }, false); 769 } 770 }, 771 /** 772 * Pricing Switcher 773 * Enables monthly/yearly switcher seen on pricing tables 774 */ 775 pricingSwitcher: function () { 776 const wrapper = document.querySelectorAll(".pricing-wrapper"); 777 wrapper.forEach(wrap => { 778 const switchers = wrap.querySelector(".pricing-switchers"); 779 const switcher = wrap.querySelectorAll(".pricing-switcher"); 780 const price = wrap.querySelectorAll(".price"); 781 switchers.addEventListener("click", (e) => { 782 switcher.forEach(s => { 783 s.classList.toggle("pricing-switcher-active"); 784 }); 785 price.forEach(p => { 786 p.classList.remove("price-hidden"); 787 p.classList.toggle("price-show"); 788 p.classList.toggle("price-hide"); 789 }); 790 }); 791 }); 792 }, 793 /** 794 * ReplaceMe.js 795 * Enables text rotator 796 * Requires assets/js/vendor/replaceme.min.js 797 */ 798 textRotator: function () { 799 if(document.querySelector(".rotator-zoom") != null) { 800 var replace = new ReplaceMe(document.querySelector('.rotator-zoom'), { 801 animation: 'animate__animated animate__zoomIn', 802 speed: 2500, 803 separator: ',', 804 clickChange: false, 805 loopCount: 'infinite' 806 }); 807 } 808 if(document.querySelector(".rotator-fade") != null) { 809 var replace = new ReplaceMe(document.querySelector('.rotator-fade'), { 810 animation: 'animate__animated animate__fadeInDown', 811 speed: 2500, 812 separator: ',', 813 clickChange: false, 814 loopCount: 'infinite' 815 }); 816 } 817 }, 818 /** 819 * Clipboard.js 820 * Enables clipboard on docs 821 * Requires assets/js/vendor/clipboard.min.js 822 */ 823 codeSnippet: function () { 824 var btnHtml = '<button type="button" class="btn btn-sm btn-white rounded-pill btn-clipboard">Copy</button>' 825 document.querySelectorAll('.code-wrapper-inner').forEach(function(element) { 826 element.insertAdjacentHTML('beforebegin', btnHtml) 827 }) 828 var clipboard = new ClipboardJS('.btn-clipboard', { 829 target: function(trigger) { 830 return trigger.nextElementSibling 831 } 832 }) 833 clipboard.on('success', event => { 834 event.trigger.textContent = 'Copied!'; 835 event.clearSelection(); 836 setTimeout(function () { 837 event.trigger.textContent = 'Copy'; 838 }, 2000); 839 }); 840 var copyIconCode = new ClipboardJS('.btn-copy-icon'); 841 copyIconCode.on('success', function(event) { 842 event.clearSelection(); 843 event.trigger.textContent = 'Copied!'; 844 window.setTimeout(function() { 845 event.trigger.textContent = 'Copy'; 846 }, 2300); 847 }); 848 }, 849}
850theme.init();
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.