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