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