PageSourceSearch

https://padang.go.id/assets/frontend/js/theme.js

js padang.go.id collected 2026-09-24 09:57:42 UTC 32,680 bytes, 950 lines download raw bytes

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.