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('.itemgrid'); 131 if(grids != null) { 132 grids.forEach(g => { 133 var itemgrid = g.querySelector('.isotope'); 134 var filtersElem = g.querySelector('.isotope-filter'); 135 var buttonGroups = g.querySelectorAll('.isotope-filter'); 136 var iso = new Isotope(itemgrid, { 137 itemSelector: '.item', 138 layoutMode: 'masonry', 139 masonry: { 140 columnWidth: itemgrid.offsetWidth / 12 141 }, 142 percentPosition: true, 143 transitionDuration: '0.7s' 144 }); 145 imagesLoaded(itemgrid).on("progress", function() { 146 iso.layout({ 147 masonry: { 148 columnWidth: itemgrid.offsetWidth / 12 149 } 150 }) 151 }), 152 window.addEventListener("resize", function() { 153 iso.arrange({ 154 masonry: { 155 columnWidth: itemgrid.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 fullscreen: { enabled: true, iosNative: true }, 523 muted: false 524 }); 525 }, 526 /** 527 * Progressbar 528 * Enables animated progressbars 529 * Requires assets/js/vendor/progressbar.min.js 530 * Requires assets/js/vendor/noframework.waypoints.min.js 531 */ 532 progressBar: () => { 533 const pline = document.querySelectorAll(".progressbar.line"); 534 const pcircle = document.querySelectorAll(".progressbar.semi-circle"); 535 pline.forEach(e => { 536 var line = new ProgressBar.Line(e, { 537 strokeWidth: 6, 538 trailWidth: 6, 539 duration: 3000, 540 easing: 'easeInOut', 541 text: { 542 style: { 543 color: 'inherit', 544 position: 'absolute', 545 right: '0', 546 top: '-30px', 547 padding: 0, 548 margin: 0, 549 transform: null 550 }, 551 autoStyleContainer: false 552 }, 553 step: (state, line) => { 554 line.setText(Math.round(line.value() * 100) + ' %'); 555 } 556 }); 557 var value = e.getAttribute('data-value') / 100; 558 new Waypoint({ 559 element: e, 560 handler: function() { 561 line.animate(value); 562 }, 563 offset: 'bottom-in-view', 564 }) 565 }); 566 pcircle.forEach(e => { 567 var circle = new ProgressBar.SemiCircle(e, { 568 strokeWidth: 6, 569 trailWidth: 6, 570 duration: 2000,
571 easing: 'easeInOut', 572 step: (state, circle) => { 573 circle.setText(Math.round(circle.value() * 100)); 574 } 575 }); 576 var value = e.getAttribute('data-value') / 100; 577 new Waypoint({ 578 element: e, 579 handler: function() { 580 circle.animate(value); 581 }, 582 offset: 'bottom-in-view', 583 }) 584 }); 585 }, 586 /** 587 * Loader 588 * 589 */ 590 loader: () => { 591 var preloader = document.querySelector('.page-loader'); 592 if(preloader != null) { 593 document.body.onload = function(){ 594 setTimeout(function() { 595 if( !preloader.classList.contains('done') ) 596 { 597 preloader.classList.add('done'); 598 } 599 }, 1000) 600 } 601 } 602 }, 603 /** 604 * Page Progress 605 * Shows page progress on the bottom right corner of pages 606 */ 607 pageProgress: () => { 608 var progressWrap = document.querySelector('.progress-wrap'); 609 if(progressWrap != null) { 610 var progressPath = document.querySelector('.progress-wrap path'); 611 var pathLength = progressPath.getTotalLength(); 612 var offset = 50; 613 progressPath.style.transition = progressPath.style.WebkitTransition = 'none'; 614 progressPath.style.strokeDasharray = pathLength + ' ' + pathLength; 615 progressPath.style.strokeDashoffset = pathLength; 616 progressPath.getBoundingClientRect(); 617 progressPath.style.transition = progressPath.style.WebkitTransition = 'stroke-dashoffset 10ms linear'; 618 window.addEventListener("scroll", function(event) { 619 var scroll = document.body.scrollTop || document.documentElement.scrollTop; 620 var height = document.documentElement.scrollHeight - document.documentElement.clientHeight; 621 var progress = pathLength - (scroll * pathLength / height); 622 progressPath.style.strokeDashoffset = progress; 623 var scrollElementPos = document.body.scrollTop || document.documentElement.scrollTop; 624 if(scrollElementPos >= offset) { 625 progressWrap.classList.add("active-progress") 626 } else { 627 progressWrap.classList.remove("active-progress") 628 } 629 }); 630 progressWrap.addEventListener('click', function(e) { 631 e.preventDefault(); 632 window.scroll({ 633 top: 0, 634 left: 0, 635 behavior: 'smooth' 636 }); 637 }); 638 } 639 }, 640 /** 641 * Counter Up 642 * Counts up to a targeted number when the number becomes visible 643 * Requires assets/js/vendor/counterup.min.js 644 * Requires assets/js/vendor/noframework.waypoints.min.js 645 */ 646 counterUp: () => { 647 var counterUp = window.counterUp["default"]; 648 const counters = document.querySelectorAll(".counter"); 649 counters.forEach(el => { 650 new Waypoint({ 651 element: el, 652 handler: function() { 653 counterUp(el, { 654 duration: 1000, 655 delay: 50 656 }) 657 this.destroy() 658 }, 659 offset: 'bottom-in-view', 660 }) 661 }); 662 }, 663 /** 664 * Bootstrap Tooltips 665 * Enables Bootstrap tooltips 666 * Requires Poppers library 667 */ 668 bsTooltips: () => { 669 var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')) 670 var tooltipList = tooltipTriggerList.map(function(tooltipTriggerEl) { 671 return new bootstrap.Tooltip(tooltipTriggerEl, { 672 trigger: 'hover' 673 }) 674 }); 675 var tooltipTriggerWhite = [].slice.call(document.querySelectorAll('[data-bs-toggle="white-tooltip"]')) 676 var tooltipWhite = tooltipTriggerWhite.map(function(tooltipTriggerEl) { 677 return new bootstrap.Tooltip(tooltipTriggerEl, { 678 customClass: 'white-tooltip', 679 trigger: 'hover', 680 placement: 'left' 681 }) 682 }) 683 }, 684 /** 685 * Bootstrap Popovers 686 * Enables Bootstrap popovers 687 * Requires Poppers library 688 */ 689 bsPopovers: () => { 690 var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')) 691 var popoverList = popoverTriggerList.map(function(popoverTriggerEl) { 692 return new bootstrap.Popover(popoverTriggerEl) 693 }) 694 }, 695 /** 696 * Bootstrap Modal 697 * Enables Bootstrap modal popup 698 */ 699 bsModal: () => { 700 if(document.querySelector(".modal-popup") != null) { 701 var myModalPopup = new bootstrap.Modal(document.querySelector('.modal-popup')); 702 setTimeout(function() { 703 myModalPopup.show(); 704 }, 200); 705 } 706 // Fixes jumping of page progress caused by modal 707 var innerWidth = window.innerWidth; 708 var clientWidth = document.body.clientWidth; 709 var scrollSize = innerWidth - clientWidth; 710 var myModalEl = document.querySelectorAll('.modal'); 711 var navbarFixed = document.querySelector('.navbar.fixed'); 712 var pageProgress = document.querySelector('.progress-wrap'); 713 function setPadding() { 714 if(navbarFixed != null) { 715 navbarFixed.style.paddingRight = scrollSize + 'px'; 716 } 717 if(pageProgress != null) { 718 pageProgress.style.marginRight = scrollSize + 'px'; 719 } 720 } 721 function removePadding() { 722 if(navbarFixed != null) { 723 navbarFixed.style.paddingRight = ''; 724 } 725 if(pageProgress != null) { 726 pageProgress.style.marginRight = ''; 727 } 728 } 729 myModalEl.forEach(myModalEl => { 730 myModalEl.addEventListener('show.bs.modal', function(e) { 731 setPadding(); 732 }) 733 myModalEl.addEventListener('hidden.bs.modal', function(e) { 734 removePadding(); 735 }) 736 }); 737 }, 738 /** 739 * iTooltip 740 * Enables custom tooltip style for image hover docs/elements/hover.html 741 * Requires assets/js/vendor/itooltip.min.js 742 */ 743 iTooltip: () => { 744 var tooltip = new iTooltip('.itooltip') 745 tooltip.init({ 746 className: 'itooltip-inner', 747 indentX: 15, 748 indentY: 15, 749 positionX: 'right', 750 positionY: 'bottom' 751 }) 752 }, 753 /** 754 * Form Validation and Contact Form submit 755 * Bootstrap validation - Only sends messages if form has class ".contact-form" and is validated and shows success/fail messages 756 */ 757 forms: () => { 758 (function() { 759 "use strict"; 760 window.addEventListener("load", function() { 761 var forms = document.querySelectorAll(".needs-validation"); 762 var inputRecaptcha = document.querySelector("input[data-recaptcha]"); 763 window.verifyRecaptchaCallback = function (response) { 764 inputRecaptcha.value = response; 765 inputRecaptcha.dispatchEvent(new Event("change")); 766 } 767 window.expiredRecaptchaCallback = function () { 768 var inputRecaptcha = document.querySelector("input[data-recaptcha]"); 769 inputRecaptcha.value = ""; 770 inputRecaptcha.dispatchEvent(new Event("change")); 771 }
772 var validation = Array.prototype.filter.call(forms, function(form) { 773 form.addEventListener("submit", function(event) { 774 if(form.checkValidity() === false) { 775 event.preventDefault(); 776 event.stopPropagation(); 777 } 778 form.classList.add("was-validated"); 779 if(form.checkValidity() === true) { 780 event.preventDefault(); 781 form.classList.remove("was-validated"); 782 // Send message only if the form has class .contact-form 783 var isContactForm = form.classList.contains('contact-form'); 784 if(isContactForm) { 785 var data = new FormData(form); 786 var alertClass = 'alert-danger'; 787 fetch("assets/php/contact.php", { 788 method: "post", 789 body: data 790 }).then((data) => { 791 if(data.ok) { 792 alertClass = 'alert-success'; 793 } 794 return data.text(); 795 }).then((txt) => { 796 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>'; 797 if(alertClass && txt) { 798 form.querySelector(".messages").insertAdjacentHTML('beforeend', alertBox); 799 form.reset(); 800 grecaptcha.reset(); 801 } 802 }).catch((err) => { 803 console.log(err); 804 }); 805 } 806 } 807 }, false); 808 }); 809 }, false); 810 })(); 811 }, 812 /** 813 * Password Visibility Toggle 814 * Toggles password visibility in password input 815 */ 816 passVisibility: () => { 817 let pass = document.querySelectorAll('.password-field'); 818 for (let i = 0; i < pass.length; i++) { 819 let passInput = pass[i].querySelector('.form-control'); 820 let passToggle = pass[i].querySelector('.password-toggle > i'); 821 passToggle.addEventListener('click', (e) => { 822 if (passInput.type === "password") { 823 passInput.type = "text"; 824 passToggle.classList.remove('uil-eye'); 825 passToggle.classList.add('uil-eye-slash'); 826 } else { 827 passInput.type = "password"; 828 passToggle.classList.remove('uil-eye-slash'); 829 passToggle.classList.add('uil-eye'); 830 } 831 }, false); 832 } 833 }, 834 /** 835 * Pricing Switcher 836 * Enables monthly/yearly switcher seen on pricing tables 837 */ 838 pricingSwitcher: () => { 839 if(document.querySelector(".pricing-switchers") != null) { 840 const wrapper = document.querySelectorAll(".pricing-wrapper"); 841 wrapper.forEach(wrap => { 842 const switchers = wrap.querySelector(".pricing-switchers"); 843 const switcher = wrap.querySelectorAll(".pricing-switcher"); 844 const price = wrap.querySelectorAll(".price"); 845 switchers.addEventListener("click", (e) => { 846 switcher.forEach(s => { 847 s.classList.toggle("pricing-switcher-active"); 848 }); 849 price.forEach(p => { 850 p.classList.remove("price-hidden"); 851 p.classList.toggle("price-show"); 852 p.classList.toggle("price-hide"); 853 }); 854 }); 855 }); 856 } 857 }, 858 /** 859 * ReplaceMe.js 860 * Enables text rotator 861 * Requires assets/js/vendor/replaceme.min.js 862 */ 863 textRotator: () => { 864 if(document.querySelector(".rotator-zoom") != null) { 865 var replace = new ReplaceMe(document.querySelector('.rotator-zoom'), { 866 animation: 'animate__animated animate__zoomIn', 867 speed: 2500, 868 separator: ',', 869 clickChange: false, 870 loopCount: 'infinite' 871 }); 872 } 873 if(document.querySelector(".rotator-fade") != null) { 874 var replace = new ReplaceMe(document.querySelector('.rotator-fade'), { 875 animation: 'animate__animated animate__fadeInDown', 876 speed: 2500, 877 separator: ',', 878 clickChange: false, 879 loopCount: 'infinite' 880 }); 881 } 882 }, 883 /** 884 * Clipboard.js 885 * Enables clipboard on docs 886 * Requires assets/js/vendor/clipboard.min.js 887 */ 888 codeSnippet: () => { 889 var btnHtml = '<button type="button" class="btn btn-sm btn-white rounded-pill btn-clipboard">Copy</button>' 890 document.querySelectorAll('.code-wrapper-inner').forEach(function(element) { 891 element.insertAdjacentHTML('beforebegin', btnHtml) 892 }) 893 var clipboard = new ClipboardJS('.btn-clipboard', { 894 target: function(trigger) { 895 return trigger.nextElementSibling 896 } 897 }) 898 clipboard.on('success', event => { 899 event.trigger.textContent = 'Copied!'; 900 event.clearSelection(); 901 setTimeout(function () { 902 event.trigger.textContent = 'Copy'; 903 }, 2000); 904 }); 905 var copyIconCode = new ClipboardJS('.btn-copy-icon'); 906 copyIconCode.on('success', function(event) { 907 event.clearSelection(); 908 event.trigger.textContent = 'Copied!'; 909 window.setTimeout(function() { 910 event.trigger.textContent = 'Copy'; 911 }, 2300); 912 }); 913 }, 914}
915theme.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.