1/** 2 * This methods is the main controller for AV Carousel Elements 3 * It automatically builds carousels tagged with data-av-carousel attribute 4 * Starts after DOMLoaded event and relies on PHP output from WP Customizer 5 * 6 * If there are less than 4 elements (via PHP) it will stop immediately 7 */ 8(function () { 9 // Add OnDOMLoaded AV Carousel Preparation 10 if (document.readyState === 'loading') { 11 document.addEventListener('DOMContentLoaded', makeAVCarousels); 12 } else { 13 makeAVCarousels(); 14 } 15 16 function makeAVCarousels() { 17 // Get all carousels in page on DOM Loaded 18 let carousels = document.querySelectorAll('[data-av-carousel]'); 19 20 // Enable all carousels in page 21 carousels.forEach(carousel => { 22 23 // If there are too few articles in the carousel, disable the system entirely 24 // Set first slide as active to allow displaying content even if disabled 25 if (carousel.classList.contains("not-enough-articles")) { 26 carousel.querySelector(".av-carousel-slide").classList.add("slide-active"); 27 return; 28 } 29 30 // Declare some data 31 let container = carousel.querySelector(".av-carousel-slides"); 32 let leftButton = carousel.querySelector(".av-carousel-button.left"); 33 let rightButton = carousel.querySelector(".av-carousel-button.right"); 34 let slides = container.querySelectorAll(".av-carousel-slide"); 35 let dots = carousel.querySelector(".av-carousel-dots"); 36 let isAnimating = false; 37 let autoSlidingInterval; 38 let slidingDirection = false; 39 40 // Set first slide as active and get first and last one 41 let activeSlide = slides[0]; 42 let firstSlide = slides[0]; 43 let lastSlide = slides[slides.length - 1]; 44 activeSlide.classList.add("slide-active"); 45 46 // Mark all slides 47 enumSlides(); 48 49 // Add transition class after a few millisec to enable transitions and avoid repaints 50 setTimeout(() => {container.classList.add("transitions-enabled")}, 100); 51 52 // Main animation function 53 function slideTo(dir) { 54 // Avoid running if already animating 55 if (isAnimating) return; 56 57 // Save sliding direction and set flag 58 isAnimating = true; 59 slidingDirection = dir; 60 61 // Make buttons fade a bit and avoid clicks 62 leftButton.classList.add("disabled"); 63 rightButton.classList.add("disabled"); 64 65 // Switch based on direction: 66 // Going right -> We need to pop the last slide to first position before animation 67 // Going left -> No problem: we always have a next slide 68 let nextActiveSlide = activeSlide.nextElementSibling; 69 if (dir === "right") { 70 moveLastSlideFirst(); 71 nextActiveSlide = activeSlide.previousElementSibling; 72 } 73 74 // Slide to right or left after allowing DOM to setup 75 setTimeout(() => { 76 activeSlide.classList.remove("slide-active"); 77 activeSlide = nextActiveSlide; 78 activeSlide.classList.add("slide-active"); 79 }, 20); 80 81 // Dots system (if present) 82 if (dots) { 83 let currDot = dots.querySelector(".active"); 84 let nextDot = dir === "left" ? currDot.nextElementSibling : currDot.previousElementSibling; 85 if (!nextDot) { 86 // Reached limit: rewind dots 87 nextDot = dir === "left" ? dots.firstChild : dots.lastChild; 88 } 89 90 // Move active class 91 currDot.classList.remove("active"); 92 nextDot.classList.add("active"); 93 } 94 } 95 96 // Manage Animation End for current slide 97 container.addEventListener("transitionend", (e) => { 98 99 // Only trigger event on active slide 100 if (!e.target.classList.contains("slide-active")) return; 101 102 // Reset slide numeration 103 enumSlides(); 104 105 // If slide current active index is > 0 there is a leftover slide at the beginning 106 // Proceed moving this slide at the end and enumerate again 107 if (e.target.dataset.index > 0) { 108 moveFirstSlideLast(); 109 enumSlides(); 110 } 111 112 // Re-enable controls 113 leftButton.classList.remove("disabled"); 114 rightButton.classList.remove("disabled"); 115 116 // Disable animation status 117 isAnimating = false; 118 119 }); 120 121 // Enumerate and order the slides after DOM Manipulation 122 function enumSlides() { 123 slides = container.querySelectorAll(".av-carousel-slide");
124 slides.forEach((slide, i) => slide.dataset.index = i); 125 } 126 127 // Functions for moving slides order in DOM 128 function moveLastSlideFirst() { 129 let newSlide = lastSlide; 130 lastSlide = newSlide.previousElementSibling; 131 container.insertBefore(newSlide, container.firstChild); 132 firstSlide = newSlide; 133 } 134 135 function moveFirstSlideLast() { 136 let newSlide = firstSlide; 137 firstSlide = newSlide.nextElementSibling; 138 container.appendChild(newSlide); 139 lastSlide = newSlide; 140 } 141 142 // Swipe Detection System 143 function enableSwiping() { 144 // States: 0 - no swipe, 1 - swipe started, 2 - swipe released 145 let swipeState = 0; 146 let threshold = 80; 147 let startX = 0; 148 let pixelOffsetX = 0; 149 150 // Bind and unbind methods 151 function addListenerMulti(el, list, fn) { 152 list.split(' ').forEach(e => el.addEventListener(e, fn, {capture: false, passive: true})); 153 } 154 155 addListenerMulti(carousel, 'mousedown touchstart', swipeStart); 156 addListenerMulti(carousel, 'mouseup touchend', swipeEnd); 157 addListenerMulti(carousel, 'mousemove touchmove', swiping); 158 159 // Swipe Functions 160 function swipeStart(event) { 161 if (event.touches) 162 event = event.touches[0]; 163 164 if (swipeState === 0) { 165 swipeState = 1; 166 startX = event.screenX; 167 } 168 } 169 170 function swipeEnd() { 171 // Check if over thresholds 172 if (pixelOffsetX > threshold) { 173 manualSlide("right"); 174 } else if (pixelOffsetX < -threshold) { 175 manualSlide("left"); 176 } 177 178 // Reset data 179 startX = 0; 180 pixelOffsetX = 0; 181 swipeState = 0; 182 } 183 184 function swiping(event) { 185 if (swipeState === 1 || swipeState === 2) { 186 if (event.touches) 187 event = event.touches[0]; 188 pixelOffsetX = event.screenX - startX; 189 } 190 } 191 } 192 193 // Bind click events only when not disabled 194 leftButton.onclick = () => manualSlide("right"); 195 rightButton.onclick = () => manualSlide("left"); 196 197 function manualSlide(direction) { 198 // Avoid click resetting timer if already animating 199 if (isAnimating) return; 200 201 // Reset auto scrolling to 0 if enabled 202 if (carousel.classList.contains("av-carousel-autoplay")) { 203 clearInterval(autoSlidingInterval); 204 autoSlidingInterval = setInterval(() => { slideTo("left"); }, 8000); 205 } 206 207 // Do the slide 208 slideTo(direction); 209 } 210 211 // Enable Touch/Mouse Swiping 212 enableSwiping(); 213 214 // Set auto scrolling every 8 seconds if enabled 215 if (carousel.classList.contains("av-carousel-autoplay")) 216 autoSlidingInterval = setInterval(() => { slideTo("left"); }, 8000); 217 218 }); 219 } 220})();
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.