1/** 2 * Resource Hero Slider 3 * Handles slider functionality for the Resource Hero component 4 */ 5(function () { 6 if (window.ResourceHeroSlider) return; // Only define once 7 8 window.ResourceHeroSlider = class { 9 constructor(element) { 10 this.slider = element; 11 if (!this.slider) return; 12 13 // Get slider elements 14 this.track = this.slider.querySelector(".slider-track"); 15 this.slides = this.slider.querySelectorAll(".slider-slide"); 16 this.prevBtn = this.slider.querySelector(".slider-prev"); 17 this.nextBtn = this.slider.querySelector(".slider-next"); 18 19 // Exit if there's only one slide 20 if (this.slides.length <= 1) return; 21 22 // Initialize state 23 this.currentSlide = 1; // Start at 1 because of cloned slide 24 this.isAnimating = false; 25 this.slideCount = this.slides.length; 26 27 // Clone first and last slides for infinite loop 28 this.setupInfiniteLoop(); 29 30 // Set initial position 31 this.track.style.transform = `translateX(-${100}%)`; // Start at first real slide 32 33 this.init(); 34 } 35 36 setupInfiniteLoop() { 37 // Clone first and last slides 38 const firstSlideClone = this.slides[0].cloneNode(true); 39 const lastSlideClone = 40 this.slides[this.slides.length - 1].cloneNode(true); 41 42 // Add classes to identify clones 43 firstSlideClone.classList.add("clone"); 44 lastSlideClone.classList.add("clone"); 45 46 // Append clones 47 this.track.appendChild(firstSlideClone); 48 this.track.insertBefore(lastSlideClone, this.track.firstChild); 49 } 50 51 init() { 52 // Bind methods 53 this.goToSlide = this.goToSlide.bind(this); 54 this.handlePrevClick = this.handlePrevClick.bind(this); 55 this.handleNextClick = this.handleNextClick.bind(this); 56 this.handleTouchStart = this.handleTouchStart.bind(this); 57 this.handleTouchEnd = this.handleTouchEnd.bind(this); 58 this.updateTrackHeight = this.updateTrackHeight.bind(this); 59 60 // Set initial height 61 this.updateTrackHeight(); 62 63 // Add event listeners 64 if (this.prevBtn) { 65 this.prevBtn.addEventListener("click", this.handlePrevClick); 66 } 67 68 if (this.nextBtn) { 69 this.nextBtn.addEventListener("click", this.handleNextClick); 70 } 71 72 // Touch events 73 this.track.addEventListener("touchstart", this.handleTouchStart, { 74 passive: true, 75 }); 76 this.track.addEventListener("touchend", this.handleTouchEnd, { 77 passive: true, 78 }); 79 80 // Update height on window resize 81 window.addEventListener("resize", this.updateTrackHeight); 82 } 83 84 updateTrackHeight() { 85 // Only adjust height on mobile-sm (screen width <= 576px) 86 if (window.innerWidth > 576) { 87 this.track.style.height = ""; 88 return; 89 } 90 91 // Get the current active slide (accounting for cloned slides) 92 const activeSlideIndex = this.currentSlide; 93 const allSlides = this.track.children; 94 95 if (activeSlideIndex >= 0 && activeSlideIndex < allSlides.length) { 96 const activeSlide = allSlides[activeSlideIndex]; 97 const slideHeight = activeSlide.offsetHeight; 98 99 // Set the track height to match the current slide 100 this.track.style.height = slideHeight + "px"; 101 } 102 } 103 104 goToSlide(index, immediate = false) { 105 if (this.isAnimating || index === this.currentSlide) return; 106 this.isAnimating = true; 107 108 // Update slides with transition 109 if (immediate) { 110 this.track.style.transition = "none"; 111 } else { 112 this.track.style.transition = "transform 0.5s ease"; 113 } 114 115 // Update transform 116 this.track.style.transform = `translateX(-${index * 100}%)`; 117 118 this.currentSlide = index; 119 120 // Update track height for mobile-sm 121 this.updateTrackHeight(); 122 123 // Handle infinite loop transitions 124 setTimeout(() => { 125 this.isAnimating = false; 126 127 // If we're at the last clone, jump to first real slide 128 if (index === this.slideCount + 1) { 129 this.goToSlide(1, true); 130 } 131 // If we're at the first clone, jump to last real slide 132 else if (index === 0) { 133 this.goToSlide(this.slideCount, true); 134 } 135 }, 500); 136 } 137 138 handlePrevClick() { 139 this.goToSlide(this.currentSlide - 1); 140 } 141 142 handleNextClick() { 143 this.goToSlide(this.currentSlide + 1); 144 } 145 146 handleTouchStart(e) { 147 this.touchStartX = e.changedTouches[0].screenX; 148 } 149 150 handleTouchEnd(e) { 151 this.touchEndX = e.changedTouches[0].screenX; 152 const diff = this.touchStartX - this.touchEndX; 153 154 if (Math.abs(diff) > 50) { 155 // Minimum swipe distance 156 if (diff > 0) { 157 this.handleNextClick(); 158 } else { 159 this.handlePrevClick(); 160 } 161 } 162 } 163 }; 164 165 // Initialize all resource hero sliders on the page 166 document.addEventListener("DOMContentLoaded", () => { 167 const sliders = document.querySelectorAll(".featured-resource-slider");
168 sliders.forEach((slider) => new ResourceHeroSlider(slider)); 169 }); 170})();
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.