1/** 2 * Window event bus. 3 * 4 * One throttled `scroll` listener and one debounced `resize`/`orientationchange` 5 * listener for the whole page; features register callbacks instead of each 6 * binding their own window listener. This is a shared singleton (ES module), so 7 * the core entry and any conditional entry register into the same queues. 8 * 9 * Why: scroll/resize fire dozens of times a second â coalescing to one 10 * rAF-throttled scroll pass and one debounced resize pass avoids layout 11 * thrashing and redundant work. 12 * 13 * @module ui/events 14 */ 15import { debounce, rafThrottle } from "../core/raf.js"; 16 17const $ = window.jQuery; 18const $window = $(window); 19const NS = ".tmEvents"; 20 21/** @type {Array<() => void>} */ 22const scrollHandlers = []; 23/** @type {Array<() => void>} */ 24const resizeHandlers = []; 25 26let bound = false; 27let firedInitial = false; 28 29/** 30 * Register a scroll callback (deduplicated). 31 * @param {() => void} handler 32 */ 33export function onScroll(handler) { 34 if (typeof handler === "function" && !scrollHandlers.includes(handler)) { 35 scrollHandlers.push(handler); 36 } 37} 38 39/** 40 * Register a resize/orientationchange callback (deduplicated). 41 * @param {() => void} handler 42 */ 43export function onResize(handler) { 44 if (typeof handler === "function" && !resizeHandlers.includes(handler)) { 45 resizeHandlers.push(handler); 46 } 47} 48 49function runScroll() { 50 scrollHandlers.forEach((handler) => handler()); 51} 52 53function runResize() { 54 resizeHandlers.forEach((handler) => handler()); 55} 56 57/** Run every registered handler once (used after registration and on load). */ 58export function runAll() { 59 runResize(); 60 runScroll(); 61} 62 63const throttledScroll = rafThrottle(runScroll); 64const debouncedResize = debounce(runResize, 150); 65 66/** 67 * Bind the window listeners exactly once and do an initial pass on load. Safe to 68 * call from multiple entries â only the first call binds. 69 */ 70export function ensureWindowEvents() { 71 if (bound) return; 72 bound = true; 73 74 $window 75 .on(`scroll${NS}`, throttledScroll) 76 .on(`resize${NS} orientationchange${NS}`, debouncedResize); 77 78 const fireInitial = () => { 79 if (firedInitial) return; 80 firedInitial = true; 81 runAll(); 82 }; 83 84 if (document.readyState === "complete") { 85 fireInitial(); 86 } else { 87 $window.on(`load${NS}`, fireInitial); 88 } 89}
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.