1document.addEventListener("DOMContentLoaded", () => { 2 3 function initializeMarquees() { 4 5 // Select all elements with the class 'fs-marquee' 6 const marquees = document.querySelectorAll('.fs-marquee'); 7 8 /** 9 * Calculate the total width of all marquee items and update CSS properties. 10 * @param {HTMLElement} marquee - The marquee element. 11 * @param {HTMLElement} container - The container element within the marquee. 12 * @param {NodeList} items - Collection of items within the container. 13 * @param {HTMLElement} progress - The progress element if available. 14 */ 15 const calculateWidth = (marquee, container, items, progress) => { 16 try { 17 const totalWidth = Array.from(items).reduce((total, item) => { 18 if (!item.hasAttribute('aria-hidden')) { 19 // Use offsetWidth for more reliable width calculation 20 return total + item.offsetWidth; 21 } 22 return total; 23 }, 0); 24 25 // Set CSS custom property for the total width 26 marquee.style.setProperty('--fs-marquee-total-width', `-${totalWidth.toFixed(3)}px`); 27 resumeAnimations(container, progress); 28 } catch (error) { 29 console.error("Error calculating marquee width:", error); 30 } 31 }; 32 33 /** 34 * Pause animations for both container and progress elements. 35 * @param {HTMLElement} container - The container element of marquee items. 36 * @param {HTMLElement} progress - The progress bar, if available. 37 */ 38 const pauseAnimations = (container, progress) => { 39 container.style.animationPlayState = 'paused'; 40 if (progress) progress.style.animationPlayState = 'paused'; 41 }; 42 43 /** 44 * Resume animations for both container and progress elements. 45 * @param {HTMLElement} container - The container element of marquee items. 46 * @param {HTMLElement} progress - The progress bar, if available. 47 */ 48 const resumeAnimations = (container, progress) => { 49 container.style.animationPlayState = 'running'; 50 if (progress) progress.style.animationPlayState = 'running'; 51 }; 52 53 /** 54 * Debounce utility function to limit the rate of execution. 55 * @param {Function} fn - The function to debounce. 56 * @param {number} delay - The debounce delay in milliseconds. 57 * @returns {Function} - A debounced version of the input function. 58 */ 59 const debounce = (fn, delay) => { 60 let timeoutId; 61 return (...args) => { 62 clearTimeout(timeoutId); 63 timeoutId = setTimeout(() => fn.apply(this, args), delay); 64 }; 65 }; 66 67 // Initialize marquees 68 marquees.forEach(marquee => {
69 const container = marquee.querySelector('.fs-marquee-items'); 70 const items = marquee.querySelectorAll('.fs-marquee-items > .fs-marquee-item:not([aria-hidden])'); 71 const progress = marquee.querySelector('.fs-marquee-progress'); 72 73 if (!container || items.length === 0) return; // Exit if no valid container or items 74 75 let lastWindowWidth = window.innerWidth; // Track width per marquee 76 77 const startCalculation = () => { 78 calculateWidth(marquee, container, items, progress); 79 }; 80 81 // Use ResizeObserver to dynamically handle container size changes 82 const resizeObserver = new ResizeObserver(() => { 83 if (resizeObserverActive) { 84 startCalculation(); 85 } 86 }); 87 88 // Observe changes in the marquee container 89 try { 90 resizeObserver.observe(container); 91 } catch (error) { 92 console.error('Failed to observe marquee container:', error); 93 } 94 95 let resizeObserverActive = true; 96 97 const handleResize = debounce(() => { 98 startCalculation(); 99 resumeAnimations(container, progress); 100 if (!resizeObserverActive) { 101 resizeObserver.observe(container); 102 resizeObserverActive = true; 103 } 104 }, 500); 105 106 // Add resize event listener for each marquee 107 window.addEventListener('resize', () => { 108 const currentWindowWidth = window.innerWidth; 109 110 if (currentWindowWidth !== lastWindowWidth) { 111 pauseAnimations(container, progress); 112 113 if (resizeObserverActive) { 114 resizeObserver.disconnect(); 115 resizeObserverActive = false; 116 } 117 118 handleResize(); 119 lastWindowWidth = currentWindowWidth; 120 } 121 }); 122 123 // Detect when the browser tab becomes active 124 document.addEventListener('visibilitychange', () => { 125 if (!document.hidden) { 126 startCalculation(); 127 resumeAnimations(container, progress); 128 } else { 129 startCalculation(); 130 pauseAnimations(container, progress); 131 } 132 }); 133 134 // Recalculate when fonts are loaded (important for accurate text sizing) 135 document.fonts.ready.then(() => { 136 startCalculation(); 137 }); 138 139 }); 140 } 141 142 // Wait until the window is fully loaded before initializing marquees 143 window.onload = initializeMarquees; 144 145});
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.