1jQuery(document).ready(function () { 2 // Add state change to header on scroll ****************************** // 3 4 if (jQuery("#masthead").length) { 5 var header = jQuery("#masthead"); 6 jQuery(window).scroll(function () { 7 var scroll = jQuery(window).scrollTop(); 8 if (scroll >= 20) { 9 header.addClass("header-scroll"); 10 } else { 11 header.removeClass("header-scroll"); 12 } 13 }); 14 } 15 16 //Tabbed Content ****************************** // 17 18 if (jQuery(".tab-wrapper").length) { 19 var jQuerywrapper = jQuery(".tab-wrapper"), 20 jQueryallTabs = jQuerywrapper.find( 21 ".tab-content > div.tab-content__wrapper" 22 ), 23 jQuerytabMenu = jQuerywrapper.find(".tab-menu li"); 24 25 jQueryallTabs.not(":first-of-type").hide(); 26 jQuerytabMenu.filter(":first-of-type").addClass("active"); 27 jQuerytabMenu.filter(":first-of-type").find(":first").width("100%"); 28 29 jQuerytabMenu.each(function (i) { 30 jQuery(this).attr("data-tab", "tab" + i); 31 }); 32 33 jQueryallTabs.each(function (i) { 34 jQuery(this).attr("data-tab", "tab" + i); 35 }); 36 37 jQuerytabMenu.on("click", function () { 38 var dataTab = jQuery(this).data("tab"), 39 jQuerygetWrapper = jQuery(this).closest(jQuerywrapper); 40 41 jQuerygetWrapper.find(jQuerytabMenu).removeClass("active"); 42 jQuery(this).addClass("active"); 43 44 jQuerygetWrapper.find(jQueryallTabs).hide(); 45 jQuerygetWrapper 46 .find(jQueryallTabs) 47 .filter("[data-tab=" + dataTab + "]") 48 .show(); 49 }); 50 } 51 52 // Tabbed Content Mobile - Optional ****************************** // 53 54 if (jQuery('.tab-content-mobile').length) { 55 jQuery('.tab-mobile-single-wrap:first-of-type').addClass('active'); 56 jQuery('.tab-mobile-single-wrap:first-of-type .tab-information').slideDown(); 57 58 jQuery('.tab-topic').on('click', function () { 59 60 if (jQuery(this).parent('.tab-mobile-single-wrap').hasClass('active')) { 61 62 jQuery(this).siblings('.tab-information').slideToggle(); 63 64 } else { 65 66 jQuery('.tab-mobile-single-wrap').removeClass('active');
67 jQuery('.tab-information').slideUp(); 68 jQuery(this).parent('.tab-mobile-single-wrap').addClass('active'); 69 jQuery(this).siblings('.tab-information').slideToggle(); 70 71 }; 72 73 }); 74 } 75 76 // Product Tab Content ****************************** // 77 78 if (jQuery(".individual-lines-wrapper").length) { 79 jQuery(".line-tab:first-of-type").addClass("active"); // Add active class to the first tab 80 jQuery(".line-tab-info:first-of-type").addClass("active"); // Add active class to the first content 81 82 jQuery(".line-tab").on("click", function () { 83 if (jQuery(this).hasClass("active")) { 84 // do nothing 85 } else { 86 var dataTab = jQuery(this).data("menu-tab"); // Get the data-tab value 87 console.log(dataTab); 88 89 jQuery(this).siblings(".line-tab").removeClass("active"); // Remove active class from siblings 90 91 jQuery(this) // Add active class to the clicked tab 92 .closest(".line-tab-menu-wrapper") 93 .siblings(".line-tab-info-wrapper") 94 .children(".line-tab-info") 95 .removeClass("active"); 96 97 jQuery(this).closest(".line-tab-info").removeClass("active"); // Remove active class from all content 98 jQuery(this).addClass("active"); // Add active class to the clicked tab 99 jQuery("." + dataTab).addClass("active"); // Show the corresponding content based on data-tab value 100 } 101 }); 102 } 103 104 // Product Sliders with Slick Loop ****************************** // 105 // Loops through 10 numbers, giving each slider a unique class and also the next/prev buttons a unique class 106 107 [1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10].forEach(function (i) { 108 jQuery(`.prod-gallery-wrapper-${i}`).slick({ 109 infinite: true, 110 slidesToShow: 3, 111 slidesToScroll: 1, 112 nextArrow: jQuery(`.next-btn-${i}`), 113 prevArrow: jQuery(`.prev-btn-${i}`), 114 responsive: [{ 115 breakpoint: 768, 116 settings: { 117 slidesToShow: 2, 118 infinite: true, 119 }, 120 }, 121 { 122 breakpoint: 600, 123 settings: { 124 slidesToShow: 2, 125 }, 126 }, 127 { 128 breakpoint: 550, 129 settings: { 130 slidesToShow: 1, 131 slidesToScroll: 1, 132 }, 133 }, 134 ], 135 }); 136 }); 137 138 // Timeline Slider ****************************** // 139 140 if (jQuery(".timeline-slider").length) { 141 jQuery(".timeline-slider").slick({ 142 infinite: false, 143 slidesToShow: 3, 144 slidesToScroll: 1, 145 arrows: true, 146 nextArrow: jQuery(".next-btn"), 147 prevArrow: jQuery(".prev-btn"), 148 responsive: [{ 149 breakpoint: 475, 150 settings: { 151 slidesToShow: 1, 152 }, 153 }, 154 { 155 breakpoint: 768, 156 settings: { 157 slidesToShow: 2, 158 }, 159 }, 160 ], 161 }); 162 } 163 164 // Reviews Tiny Slider ****************************** // 165 166 if (jQuery(".reviews__slider").length) { 167 if (document.getElementsByClassName(".reviews__slider")) { 168 let reviews_slider = tns({ 169 container: ".reviews__slider", 170 loop: true, 171 mouseDrag: true, 172 items: 3, 173 slideBy: 1, 174 edgePadding: 0, 175 gutter: 30, 176 autoplay: true, 177 autoplayButtonOutput: false, 178 nav: false, 179 controls: false, 180 speed: 600, 181 responsive: { 182 375: { 183 items: 1, 184 edgePadding: 32, 185 }, 186 768: { 187 items: 2, 188 }, 189 992: { 190 items: 3, 191 edgePadding: 0, 192 }, 193 }, 194 }); 195 } 196 } 197 198 // Trust Factor Tiny Slider For Hero Component ****************************** // 199 200 if (jQuery(".trust-factors__slider").length) { 201 if (document.getElementsByClassName(".trust-factors__slider")) { 202 let tf_slider = tns({ 203 container: ".trust-factors__slider", 204 autoWidth: true, 205 items: 5, 206 slideBy: 1, 207 gutter: 30, 208 autoplay: true, 209 autoplayButtonOutput: false, 210 mouseDrag: true, 211 nav: false, 212 controls: false, 213 speed: 600,
214 responsive: { 215 375: { 216 items: 1, 217 }, 218 768: { 219 items: 3, 220 }, 221 992: { 222 items: 5, 223 }, 224 }, 225 }); 226 } 227 } 228 229 // Trust Factor Tiny Slider For PB Layout ****************************** // 230 231 if (jQuery(".section-trust-factors__slider").length) { 232 if (document.getElementsByClassName(".section-trust-factors__slider")) { 233 let tf_section_slider = tns({ 234 container: ".section-trust-factors__slider", 235 //autoWidth: true, 236 items: 4, 237 slideBy: 1, 238 gutter: 30, 239 autoplay: true, 240 autoplayButtonOutput: false, 241 mouseDrag: true, 242 nav: false, 243 controls: false, 244 speed: 600, 245 responsive: { 246 375: { 247 items: 2, 248 }, 249 768: { 250 items: 4, 251 }, 252 992: { 253 items: 4, 254 }, 255 }, 256 }); 257 } 258 } 259 260 if (jQuery(".faqs__wrapper").length) { 261 jQuery(".faq-single:first-of-type").addClass("active"); 262 jQuery(".faq-single:first-of-type .faq-content").slideDown(); 263 264 jQuery(".faq-single").click(function () { 265 if (jQuery(this).hasClass("active")) { 266 jQuery(".faq-single").removeClass("active"); 267 jQuery(".faq-content").slideUp(); 268 } else { 269 jQuery(".faq-single").removeClass("active"); 270 jQuery(this).addClass("active"); 271 jQuery(".faq-content").slideUp(); 272 jQuery(this).find(".faq-content").slideDown(); 273 } 274 }); 275 } 276 277 278 // core Value Accordion 279 280 jQuery(document).ready(function ($) { 281 if ($(".core-values-accordion-wrapper").length) { 282 283 // Hide all accordion content and side content 284 $(".core-value-accordion-item .cv-acc-content").hide(); 285 $(".core-value-accordion-item").removeClass("cv-active"); 286 $(".section-head .cv-acc-content").hide(); 287 $(".core-values-image").hide(); 288 289 // Open first accordion item 290 $(".core-value-accordion-item:first-of-type").addClass("cv-active"); 291 $(".core-value-accordion-item:first-of-type .cv-acc-content").slideDown(); 292 293 // Show first side content 294 $(".section-head .cv-acc-content:first-of-type").show(); 295 296 // Show first background image 297 $(".core-values-image:first-of-type").show(); 298 299 // Toggle accordion with content and image switching 300 $(".cv-acc-title").click(function () { 301 let parent = $(this).closest(".core-value-accordion-item"); 302 let index = parent.index(); 303 304 if (parent.hasClass("cv-active")) { 305 // Close if already active 306 $(".core-value-accordion-item").removeClass("cv-active"); 307 $(".core-value-accordion-item .cv-acc-content").slideUp(); 308 $(".section-head .cv-acc-content").hide(); 309 $(".core-values-image").hide(); 310 } else { 311 // Open clicked item 312 $(".core-value-accordion-item").removeClass("cv-active"); 313 parent.addClass("cv-active"); 314 315 // Toggle accordion content 316 $(".core-value-accordion-item .cv-acc-content").slideUp(); 317 parent.find(".cv-acc-content").slideDown(); 318 319 // Switch side content based on index 320 $(".section-head .cv-acc-content").hide(); 321 $(".section-head .cv-acc-content").eq(index).show(); 322 323 // Switch background image based on index 324 $(".core-values-image").hide(); 325 $(".core-values-image").eq(index).show(); 326 } 327 }); 328 329 } 330 }); 331 332 333 334 // Magnifi Pop-up ****************************** // 335 336 if (jQuery(".yt-video").length) { 337 jQuery(document).ready(function (jQuery) { 338 jQuery(".yt-video").magnificPopup({ 339 type: "iframe", 340 }); 341 }); 342 } 343 if (jQuery(".image-popup").length) { 344 jQuery(document).ready(function (jQuery) { 345 jQuery(".image-popup").magnificPopup({ 346 type: "image", 347 }); 348 }); 349 } 350 if (jQuery(".content-popup").length) { 351 jQuery(document).ready(function (jQuery) { 352 jQuery(".content-popup").magnificPopup({ 353 type: "inline", 354 preloader: false, 355 focus: "#name", 356 }); 357 }); 358 } 359 if (jQuery(".popup").length) { 360 jQuery(document).ready(function (jQuery) { 361 jQuery(".popup").magnificPopup({ 362 type: "iframe", 363 }); 364 }); 365 } 366 367 // Reloads Jquery script after FacetWP is triggered ****************************** // 368 document.addEventListener("facetwp-loaded", function () { 369 if (jQuery(".image-popup").length) { 370 jQuery(document).ready(function (jQuery) { 371 jQuery(".image-popup").magnificPopup({ 372 type: "image", 373 }); 374 }); 375 } 376 }); 377 378 // Single post scroll progress ****************************** // 379 380 if (jQuery(".post-progress").length) { 381 window.onscroll = function () { 382 blogProgress(); 383 }; 384 385 function blogProgress() { 386 var winScroll = 387 document.body.scrollTop || document.documentElement.scrollTop; 388 var height = 389 document.documentElement.scrollHeight - 390 document.documentElement.clientHeight; 391 var scrolled = (winScroll / height) * 100; 392 document.getElementById("scroll-progress").style.width = scrolled + "%"; 393 } 394 } 395 396 // Removes Card Links on PPC Page ****************************** // 397 398 jQuery(".page-template-page-ppc .card--block-link").on("click", function (e) { 399 e.preventDefault(); 400 }); 401 jQuery(".page-template-page-ppc .ppc-no-link").on("click", function (e) { 402 e.preventDefault(); 403 }); 404 405 jQuery(".page-template-page-ppc .ppc-no-link").on("click", function (e) { 406 e.preventDefault(); 407 }); 408 409 // Removes Card Links on Product Pages ****************************** // 410 jQuery("a.link-no").on("click", function (e) { 411 e.preventDefault(); 412 }); 413 414 // Removes Card Links on Project Slider ****************************** // 415 jQuery(".proj-gal-single a ").on("click", function (e) { 416 e.preventDefault(); 417 }); 418 419 // Slick Slider ****************************** // 420 421 jQuery(".slick-center").slick({ 422 centerMode: true, 423 slidesToShow: 3, 424 arrows: true, 425 nextArrow: jQuery(".next-btn-proj"), 426 prevArrow: jQuery(".prev-btn-proj"), 427 responsive: [{ 428 breakpoint: 1200, 429 settings: {
430 arrows: false, 431 centerMode: true, 432 slidesToShow: 1, 433 // centerPadding: "200px", 434 }, 435 }, 436 { 437 breakpoint: 968, 438 settings: { 439 arrows: false, 440 centerMode: true, 441 slidesToShow: 1, 442 centerPadding: "60px", 443 }, 444 }, 445 { 446 breakpoint: 400, 447 settings: { 448 arrows: false, 449 centerMode: true, 450 slidesToShow: 1, 451 centerPadding: "20px", 452 }, 453 }, 454 ], 455 }); 456 457 jQuery(".slick-center-process").slick({ 458 centerMode: true, 459 slidesToShow: 3, 460 infinite: false, 461 dots: true, 462 responsive: [{ 463 breakpoint: 968, 464 settings: { 465 arrows: false, 466 centerMode: true, 467 slidesToShow: 1, 468 }, 469 }, 470 { 471 breakpoint: 480, 472 settings: { 473 arrows: false, 474 centerMode: true, 475 slidesToShow: 1, 476 }, 477 }, 478 ], 479 }); 480 481 jQuery(".slick-process-vert").slick({ 482 //centerMode: true, 483 slidesToShow: 2, 484 infinite: false, 485 //dots: true, 486 vertical: true, 487 verticalSwiping: true, 488 responsive: [{ 489 breakpoint: 968, 490 settings: { 491 arrows: false, 492 centerMode: true, 493 slidesToShow: 2, 494 }, 495 }, 496 { 497 breakpoint: 480, 498 settings: { 499 arrows: false, 500 centerMode: true, 501 slidesToShow: 2, 502 }, 503 }, 504 ], 505 }); 506 507 jQuery(".slick-trust").slick({ 508 infinite: true, 509 slidesToShow: 4, 510 slidesToScroll: 4, 511 autoplay: true, 512 autoplaySpeed: 5000, 513 514 responsive: [ 515 { 516 breakpoint: 1699, 517 settings: { 518 slidesToShow: 4, 519 slidesToScroll: 4, 520 }, 521 }, 522 { 523 breakpoint: 991, 524 settings: { 525 slidesToShow: 3, 526 slidesToScroll: 3, 527 dots: true, 528 }, 529 }, 530 { 531 breakpoint: 576, 532 settings: { 533 slidesToShow: 2, 534 slidesToScroll: 2, 535 dots: true, 536 }, 537 }, 538 { 539 breakpoint: 420, 540 settings: { 541 slidesToShow: 1, 542 slidesToScroll: 1, 543 dots: true, 544 }, 545 }, 546 ], 547 }); 548 549 // Recent Article Tiny Slider ****************************** // 550 551 if (jQuery(".recent-article-slider").length) { 552 if (document.getElementsByClassName(".recent-article-slider")) { 553 let reviews_slider = tns({ 554 container: ".recent-article-slider", 555 loop: true, 556 mouseDrag: true, 557 items: 3, 558 slideBy: 1, 559 edgePadding: 0, 560 gutter: 24, 561 autoplay: false, 562 autoplayButtonOutput: false, 563 nav: false, 564 controls: true, 565 speed: 600, 566 responsive: { 567 1: { 568 items: 1, 569 }, 570 768: { 571 items: 2, 572 }, 573 992: { 574 items: 3, 575 }, 576 }, 577 }); 578 } 579 } 580 581 if (jQuery(".process-main-layout-flow .tab-wrapper").length) { 582 jQuery('.process-main-layout-flow .process_heading').on('click', function () { 583 if (jQuery(this).parents(".process-tab-content").hasClass("active")) { 584 jQuery(this).parents('.process-tab-content').removeClass("active");
585 jQuery(this).next('.process-info').slideUp(); 586 } else { 587 jQuery(".process-main-layout-flow .process-tab-content").removeClass("active"); 588 jQuery(".process-main-layout-flow .process-info").slideUp("active"); 589 jQuery(this).parents('.process-tab-content').addClass("active"); 590 jQuery(this).next('.process-info').slideDown(); 591 } 592 }); 593 } 594 595 if (jQuery(".company-promise .map-graphic-image").length) { 596 jQuery(function ($) { 597 const $section = $('.company-promise'); // change to your section selector 598 const addedClass = 'anim-active'; 599 600 function checkSectionAtTop() { 601 const scrollTop = $(window).scrollTop(); 602 const sectionOffset = $section.offset().top - 100; 603 604 if (scrollTop >= sectionOffset && !$section.hasClass(addedClass)) { 605 $section.addClass(addedClass); 606 } 607 } 608 609 $(window).on('scroll resize', checkSectionAtTop); 610 checkSectionAtTop(); // run on page load 611 }); 612 } 613 614 jQuery('.loc-tab-btn').on('click', function () { 615 var tab_id = jQuery(this).data('tab'); 616 617 jQuery('.loc-tab-btn').removeClass('active'); 618 jQuery(this).addClass('active'); 619 620 jQuery('.location-tab-panel').removeClass('active'); 621 jQuery('#' + tab_id).addClass('active'); 622 }); 623 624 625 jQuery('.area-tab-btn').on('click', function () { 626 var tabId = jQuery(this).data('tab'); 627 628 // Remove active classes from tabs and tab content lists 629 jQuery('.area-tab-btn').removeClass('active'); 630 jQuery('.service-tab-content').removeClass('active'); 631 632 // Remove active from all maps 633 jQuery('.service-map--code').removeClass('active'); 634 635 // Add active class to clicked tab and corresponding content & map 636 jQuery(this).addClass('active'); 637 jQuery('#' + tabId).addClass('active'); 638 639 // Activate matching map code div, assuming id "area-map-X" 640 var mapId = tabId.replace('area-tab', 'area-map'); 641 jQuery('#' + mapId).addClass('active'); 642 }); 643 644 document.querySelectorAll('a[href^="#"]:not(.proj-gal-single a, .image-popup)').forEach(anchor => { 645 anchor.addEventListener('click', function (e) { 646 e.preventDefault(); 647 648 const targetID = this.getAttribute('href').slice(1); // Remove the '#' from the href 649 const targetElement = document.getElementById(targetID); 650 651 if (targetElement) { 652 const headerHeight = document.querySelector('#masthead')?.offsetHeight || 0; 653 const targetPosition = targetElement.getBoundingClientRect().top + window.pageYOffset - headerHeight; 654 655 window.scrollTo({ 656 top: targetPosition, 657 behavior: 'smooth' 658 }); 659 } 660 }); 661 }); 662 663 jQuery('.form-with-cta .form_btn').on('click', function (e) { 664 e.preventDefault(); 665 var parent = jQuery(this).closest('.form-with-cta'); 666 parent.find('.form_inner').hide(); 667 parent.find('.form-block').fadeIn(); 668 }); 669 670 console.log("All Scrips Loaded"); 671}); // End Document.Ready 672 673(function () { 674 // Utility to decide if an element is visually hidden 675 function isHidden(el) { 676 if (!el) return true; 677 // hidden attribute or aria-hidden 678 if (el.hidden) return true; 679 if (el.getAttribute && el.getAttribute('aria-hidden') === 'true') return true; 680 681 // inline style explicitly hiding 682 var inlineStyle = el.getAttribute && el.getAttribute('style'); 683 if (inlineStyle && /display\s*:\s*none/.test(inlineStyle)) return true; 684 685 // computed style (covers CSS rules) 686 var cs = window.getComputedStyle(el); 687 if (!cs || cs.display === 'none' || cs.visibility === 'hidden' || cs.opacity === '0') return true; 688 689 // fallback: if it's not in layout 690 if (el.offsetParent === null && cs.position !== 'fixed') return true; 691 692 return false;
693 } 694 695 // Apply or remove class on the nearest .tns-outer for one controls element 696 function syncControlsToOuter(controlsEl) { 697 var outer = controlsEl.closest ? controlsEl.closest('.tns-outer') : document.querySelector('.tns-outer'); 698 if (!outer) return; 699 if (isHidden(controlsEl)) { 700 outer.classList.add('no-controls'); 701 } else { 702 outer.classList.remove('no-controls'); 703 } 704 } 705 706 // Set up observer for a particular controls element 707 function observeControls(controlsEl) { 708 // Initial sync 709 syncControlsToOuter(controlsEl); 710 711 // Observe attribute changes (style, class, hidden, aria-hidden) 712 var mo = new MutationObserver(function (mutations) { 713 // Quick check if any relevant attribute changed; debounce tiny bursts 714 var shouldSync = false; 715 for (var i = 0; i < mutations.length; i++) { 716 var m = mutations[i]; 717 if (m.type === 'attributes' && (m.attributeName === 'style' || m.attributeName === 'class' || m.attributeName === 'hidden' || m.attributeName === 'aria-hidden')) { 718 shouldSync = true; 719 break; 720 } 721 if (m.type === 'childList') { 722 shouldSync = true; 723 break; 724 } 725 } 726 if (shouldSync) { 727 // small timeout to let other scripts finish 728 clearTimeout(controlsEl.__syncTimeout); 729 controlsEl.__syncTimeout = setTimeout(function () { 730 syncControlsToOuter(controlsEl); 731 }, 50); 732 } 733 }); 734 735 mo.observe(controlsEl, { 736 attributes: true, 737 attributeFilter: ['style', 'class', 'hidden', 'aria-hidden'], 738 childList: true, 739 subtree: false 740 }); 741 742 // Also observe the nearest parent for inline style/class changes that might hide controls indirectly 743 var parent = controlsEl.parentElement; 744 if (parent) { 745 var parentMo = new MutationObserver(function () { 746 clearTimeout(controlsEl.__syncTimeout); 747 controlsEl.__syncTimeout = setTimeout(function () { 748 syncControlsToOuter(controlsEl); 749 }, 50); 750 }); 751 parentMo.observe(parent, { attributes: true, attributeFilter: ['style', 'class'] }); 752 } 753 } 754 755 // Find existing controls and observe them 756 function initExistingControls() { 757 var controls = document.querySelectorAll('.tns-controls'); 758 controls.forEach(function (ctrl) { 759 observeControls(ctrl); 760 }); 761 } 762 763 // Watch for dynamically added controls (in case the slider is initialized after page load) 764 var bodyObserver = new MutationObserver(function (mutations) { 765 mutations.forEach(function (m) { 766 if (m.addedNodes && m.addedNodes.length) { 767 m.addedNodes.forEach(function (node) { 768 if (!(node instanceof Element)) return; 769 if (node.matches && node.matches('.tns-controls')) { 770 observeControls(node); 771 } else { 772 var nested = node.querySelector && node.querySelector('.tns-controls'); 773 if (nested) observeControls(nested); 774 } 775 }); 776 } 777 }); 778 }); 779 780 document.addEventListener('DOMContentLoaded', function () { 781 initExistingControls(); 782 bodyObserver.observe(document.body, { childList: true, subtree: true }); 783 }); 784 785 // If script loaded after DOM ready 786 if (document.readyState === 'interactive' || document.readyState === 'complete') { 787 initExistingControls(); 788 bodyObserver.observe(document.body, { childList: true, subtree: true }); 789 } 790})(); 791if (jQuery(".process-wrapper").length) { 792 document.addEventListener("DOMContentLoaded", function () { 793 const steps = document.querySelectorAll(".multi-steps li"); 794 const progressFill = document.querySelector(".progress-fill"); 795 const handle = document.querySelector(".progress-handle"); 796 const contents = document.querySelectorAll(".process-tab-content"); 797 const track = document.querySelector(".progress-track"); 798 799 let activeStep = 0; 800 let dragging = false;
801 802 function getStepPercent(index) { 803 if (steps.length <= 1) return 0; 804 return (index / (steps.length - 1)) * 100; 805 } 806 807 function updateStep(stepIndex) { 808 activeStep = stepIndex; 809 810 const percent = getStepPercent(stepIndex); 811 progressFill.style.width = `${percent}%`; 812 handle.style.left = `${percent}%`; 813 814 steps.forEach((step, i) => { 815 step.classList.toggle("is-active", i === stepIndex); 816 }); 817 818 contents.forEach((content, i) => { 819 content.classList.toggle("active", i === stepIndex); 820 }); 821 } 822 823 // Step click 824 steps.forEach((step, index) => { 825 step.addEventListener("click", () => updateStep(index)); 826 }); 827 828 // Drag 829 handle.addEventListener("mousedown", () => { 830 dragging = true; 831 document.body.style.userSelect = "none"; 832 }); 833 834 document.addEventListener("mouseup", () => { 835 dragging = false; 836 document.body.style.userSelect = ""; 837 }); 838 839 document.addEventListener("mousemove", (e) => { 840 if (!dragging) return; 841 842 const rect = track.getBoundingClientRect(); 843 let offsetX = e.clientX - rect.left; 844 offsetX = Math.max(0, Math.min(offsetX, rect.width)); 845 846 const percent = (offsetX / rect.width) * 100; 847 const stepIndex = Math.round((percent / 100) * (steps.length - 1)); 848 849 updateStep(stepIndex); 850 }); 851 852 // Initialize 853 updateStep(0); 854 855 }); 856}
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.