1(function() { 2 let cardImagesObserverInitialized = false; 3 4 const cardImagesObserver = new IntersectionObserver((entries) => { 5 if (!cardImagesObserverInitialized) { 6 cardImagesObserverInitialized = true; 7 return; 8 } 9 10 entries.forEach(entry => { 11 const slide = entry.target; 12 const viewport = slide.parentElement; 13 const slides = Array.from(viewport.children); 14 const currentIndex = slides.indexOf(slide); 15 const card = viewport.closest('.js-product'); 16 if (!card) return; 17 18 if (entry.isIntersecting) { 19 const currentImg = slide.classList.contains('js-alt-img') 20 ? slide 21 : slide.querySelector('.js-alt-img'); 22 23 if (currentImg && currentImg.dataset.src) { 24 preloadImage(currentImg); 25 } 26 27 const preloadAheadCount = 1; 28 29 for (let i = 1; i <= preloadAheadCount; i++) { 30 const nextSlide = slides[currentIndex + i]; 31 if (!nextSlide) break; 32 33 const nextImg = nextSlide.classList.contains('js-alt-img') 34 ? nextSlide 35 : nextSlide.querySelector('.js-alt-img'); 36 37 if (nextImg && nextImg.dataset.src) { 38 preloadImage(nextImg); 39 } 40 } 41 } 42 43 if (entry.isIntersecting && entry.intersectionRatio >= 0.5) { 44 const counter = card.querySelector('.product__img-count span'); 45 46 if (counter) { 47 counter.innerText = `${currentIndex + 1}/${slides.length}`; 48 } 49 updateButtons(card, currentIndex, slides.length); 50 } 51 }); 52 }, { 53 threshold: [0.01, 0.5], 54 rootMargin: "0px 100px" 55 }); 56 57 function preloadImage(img) { 58 if (!img || !img.dataset.src) return; 59 60 img.classList.add('placeholder', 'placeholder-wave'); 61 62 if (img.dataset.srcset) { 63 img.srcset = img.dataset.srcset; 64 img.removeAttribute('data-srcset'); 65 } 66 img.src = img.dataset.src; 67 img.removeAttribute('data-src'); 68 69 const handleFinalize = () => { 70 img.classList.remove('placeholder', 'placeholder-wave'); 71 img.classList.add('is-loaded'); 72 }; 73 74 // Megvárjuk, amÃg a böngészÅ valóban ki tudja rajzolni a képet 75 img.decode() 76 .then(() => { 77 handleFinalize(); 78 }) 79 .catch(() => { 80 if (img.complete) { 81 handleFinalize(); 82 } else { 83 img.addEventListener('load', handleFinalize, { once: true }); 84 img.addEventListener('error', handleFinalize, { once: true }); 85 } 86 }); 87 } 88 89 function updateButtons(card, currentIndex, total) { 90 const prevBtn = card.querySelector('.product__img-prev-btn'); 91 const nextBtn = card.querySelector('.product__img-next-btn'); 92 if (!prevBtn || !nextBtn) return; 93 94 prevBtn.disabled = currentIndex === 0; 95 nextBtn.disabled = currentIndex === total - 1; 96 } 97 98 window.initProductImageCarousels = function(container = document) { 99 if (typeof container === 'string') { 100 const selector = container.startsWith('#') || container.startsWith('.') 101 ? container 102 : `#${container}`; 103 104 container = document.querySelector(selector); 105 if (!container) return; 106 } 107 108 let cursor = document.getElementById('cursor'); 109 const newViewports = container.querySelectorAll('.js-scrollable:not(.is-ready)'); 110 111 newViewports.forEach(viewport => { 112 const card = viewport.closest('.js-product'); 113 const slides = Array.from(viewport.querySelectorAll('img')); 114 let scrollTimeout; 115 let wheelTimeout; 116 let scrollEndTimeout; 117 let isThrottled = false;
118 let startX = 0; 119 let startY = 0; 120 let isHorizontal = null; 121 let firstIsPreloaded = false; 122 123 slides.forEach(slide => cardImagesObserver.observe(slide)); 124 125 const preloadNextPending = (count = 1) => { 126 const nextImgs = Array.from( 127 viewport.querySelectorAll('.js-alt-img[data-src]') 128 ).slice(0, count); 129 130 nextImgs.forEach(img => preloadImage(img)); 131 }; 132 133 const handleIsPaging = () => { 134 if (card) card.classList.add('is-paging'); 135 clearTimeout(scrollTimeout); 136 scrollTimeout = setTimeout(() => { 137 if (card) card.classList.remove('is-paging'); 138 }, 3000); 139 }; 140 141 const scrollToSlide = (direction) => { 142 const scrollAmount = viewport.offsetWidth * direction; 143 viewport.scrollTo({ 144 left: viewport.scrollLeft + scrollAmount, 145 behavior: 'smooth' 146 }); 147 148 handleIsPaging(); 149 150 clearTimeout(scrollEndTimeout); 151 scrollEndTimeout = setTimeout(() => { 152 isThrottled = false; 153 }, 300); 154 }; 155 156 viewport.addEventListener('scrollend', () => { 157 clearTimeout(scrollEndTimeout); 158 isThrottled = false; 159 }, { passive: true }); 160 161 const handleWheelThrottled = (e) => { 162 const isAtStart = viewport.scrollLeft <= 0; 163 const isAtEnd = Math.abs(viewport.scrollLeft + viewport.offsetWidth - viewport.scrollWidth) < 5; 164 const isScrollingRight = e.deltaY > 0; 165 const isScrollingLeft = e.deltaY < 0; 166 167 if ((isScrollingRight && !isAtEnd) || (isScrollingLeft && !isAtStart)) { 168 if (isThrottled) return; 169 const delta = e.deltaMode === 1 ? e.deltaY * 40 : e.deltaY; 170 const direction = delta > 0 ? 1 : -1; 171 isThrottled = true; 172 scrollToSlide(direction); 173 } 174 }; 175 176 const handleWheelPaging = (e) => { 177 if (viewport.scrollWidth > viewport.offsetWidth) { 178 e.preventDefault(); 179 if (!localStorage.getItem('hasScrolled')) { 180 localStorage.setItem('hasScrolled', '1'); 181 if (card) card.classList.remove('is-hovered'); 182 if (cursor) cursor.style.display = "none"; 183 viewport.removeEventListener('pointermove', moveCursorMovement); 184 } 185 handleWheelThrottled(e); 186 } 187 }; 188 189 const moveCursorMovement = (e) => { 190 if (cursor) cursor.style.transform = `translate(${e.clientX - cursor.offsetWidth / 2}px, ${e.clientY - cursor.offsetHeight / 2}px)`; 191 }; 192 193 const initButtons = () => { 194 const prevBtn = card.querySelector('.product__img-prev-btn'); 195 const nextBtn = card.querySelector('.product__img-next-btn'); 196 if (!prevBtn || !nextBtn) return; 197 198 prevBtn.addEventListener('click', () => scrollToSlide(-1)); 199 nextBtn.addEventListener('click', () => scrollToSlide(1)); 200 201 updateButtons(card, 0, slides.length); 202 }; 203 204 viewport.addEventListener('pointerenter', (e) => { 205 wheelTimeout = setTimeout(() => { 206 viewport.addEventListener('wheel', handleWheelPaging, { passive: false }); 207 if (!firstIsPreloaded) { 208 preloadNextPending(); 209 firstIsPreloaded = true; 210 } 211 }, 300); 212 213 if (e.pointerType !== 'mouse' || localStorage.getItem('hasScrolled')) return; 214 if (card) card.classList.add('is-hovered'); 215 if (cursor) cursor.style.display = "block"; 216 viewport.addEventListener("pointermove", moveCursorMovement); 217 }); 218 219 viewport.addEventListener('pointerleave', (e) => { 220 if (e.pointerType !== 'mouse') return; 221 222 clearTimeout(wheelTimeout); 223 clearTimeout(scrollTimeout); 224 viewport.removeEventListener('wheel', handleWheelPaging); 225 if (card) card.classList.remove('is-paging', 'is-hovered'); 226 viewport.removeEventListener('pointermove', moveCursorMovement); 227 if (cursor) cursor.style.display = "none"; 228 }); 229 230 viewport.addEventListener('touchstart', (e) => { 231 startX = e.touches[0].clientX; 232 startY = e.touches[0].clientY; 233 isHorizontal = null; 234 235 if (!firstIsPreloaded) { 236 preloadNextPending(2); 237 firstIsPreloaded = true; 238 } 239 }, { passive: true }); 240 241 viewport.addEventListener('touchmove', (e) => { 242 const diffX = e.touches[0].clientX - startX; 243 const diffY = e.touches[0].clientY - startY; 244 245 if (isHorizontal === null) { 246 isHorizontal = Math.abs(diffX) > Math.abs(diffY); 247 } 248 249 if (!isHorizontal) return; 250
251 handleIsPaging(); 252 }, { passive: true }); 253 254 viewport.addEventListener('touchend', () => { 255 isHorizontal = null; 256 }, { passive: true }); 257 258 if (card) initButtons(); 259 260 viewport.classList.add('is-ready'); 261 }); 262 }; 263 264 const eventProductImageCarouselReady = new CustomEvent('productImageCarouselReady'); 265 document.dispatchEvent(eventProductImageCarouselReady); 266})();
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.