1function slider() { 2 return { 3 paused: false, 4 speed: 100, 5 touchStartX: 0, 6 touchCurrentX: 0, 7 8 startAutoScroll() { 9 this.paused = false; 10 const track = this.$refs.track; 11 if (track) track.style.animationPlayState = 'running'; 12 }, 13 14 pauseAutoScroll() { 15 this.paused = true; 16 const track = this.$refs.track; 17 if (track) track.style.animationPlayState = 'paused'; 18 }, 19 20 calibrate() { 21 const track = this.$refs.track; 22 if (!track) return; 23 24 // Get all rendered divs (skip the <template> tag) 25 const sets = track.querySelectorAll(':scope > div'); 26 if (!sets.length) return; 27 28 const firstSet = sets[0]; 29 const setWidth = firstSet.getBoundingClientRect().width; 30 if (setWidth === 0) { 31 setTimeout(() => this.calibrate(), 200); 32 return; 33 } 34 35 // We need at least 2x the viewport width of content for seamless looping 36 const viewportWidth = track.parentElement.getBoundingClientRect().width; 37 const minWidth = viewportWidth * 2; 38 39 // Remove any extra clones from previous calibrations (keep first two from x-for) 40 while (track.querySelectorAll(':scope > div').length > 2) { 41 track.removeChild(track.lastElementChild); 42 } 43 44 // Clone the first set until we have enough width 45 const currentSets = track.querySelectorAll(':scope > div'); 46 let totalWidth = 0; 47 currentSets.forEach(s => totalWidth += s.getBoundingClientRect().width); 48 49 while (totalWidth < minWidth) { 50 const clone = firstSet.cloneNode(true); 51 track.appendChild(clone); 52 totalWidth += setWidth; 53 } 54 55 // Now measure one set's width for the animation distance 56 // The animation should scroll exactly half the total track 57 // so we need an even number of sets 58 const allSets = track.querySelectorAll(':scope > div'); 59 const halfCount = Math.ceil(allSets.length / 2); 60 const distance = halfCount * setWidth; 61 62 // Ensure even duplication: if odd number, add one more 63 if (allSets.length % 2 !== 0) { 64 track.appendChild(firstSet.cloneNode(true)); 65 } 66 67 const finalTrackWidth = track.scrollWidth; 68 const scrollDistance = finalTrackWidth / 2; 69 const duration = scrollDistance / this.speed; 70
71 track.style.animation = 'none'; 72 void track.offsetHeight; 73 track.style.animation = `scroll-left ${duration}s linear infinite`; 74 if (this.paused) track.style.animationPlayState = 'paused'; 75 }, 76 77 onTouchStart(e) { 78 this.pauseAutoScroll(); 79 this.touchStartX = e.touches[0].clientX; 80 }, 81 82 onTouchMove(e) { 83 this.touchCurrentX = e.touches[0].clientX; 84 }, 85 86 onTouchEnd() { 87 this.startAutoScroll(); 88 }, 89 90 init() { 91 this.$nextTick(() => this.calibrate()); 92 window.addEventListener('resize', () => this.calibrate()); 93 94 setTimeout(() => { 95 const imgs = this.$refs.track?.querySelectorAll('img'); 96 if (imgs) { 97 imgs.forEach(img => { 98 if (!img.complete) { 99 img.addEventListener('load', () => this.calibrate(), { once: true }); 100 } 101 }); 102 } 103 this.calibrate(); 104 }, 100); 105 } 106 }; 107}
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.