1export function initInfiniteScroll({ containerSelector, sentinelSelector, dataScriptId, loadingSelector, onAppend }) { 2 const container = document.querySelector(containerSelector); 3 const sentinel = document.querySelector(sentinelSelector); 4 const dataScript = document.getElementById(dataScriptId); 5 const loadingEl = loadingSelector ? document.querySelector(loadingSelector) : null; 6 if (!container || !sentinel || !dataScript) return; 7 8 let remaining = []; 9 try { 10 remaining = JSON.parse(dataScript.textContent || '[]'); 11 } catch (err) { 12 remaining = []; 13 } 14 15 const batchSize = parseInt(container.dataset.batchSize, 10) || 30; 16 17 if (remaining.length === 0) { 18 sentinel.remove(); 19 return; 20 } 21 22 function loadNextBatch() { 23 if (remaining.length === 0) return; 24 if (loadingEl) loadingEl.hidden = false; 25 26 const batch = remaining.splice(0, batchSize); 27 const temp = document.createElement('div'); 28 temp.innerHTML = batch.join('\n'); 29 const newNodes = Array.from(temp.children); 30 newNodes.forEach((node) => container.appendChild(node)); 31 32 if (loadingEl) loadingEl.hidden = true; 33 if (typeof onAppend === 'function') onAppend(newNodes); 34 35 if (remaining.length === 0) { 36 observer.unobserve(sentinel); 37 sentinel.remove(); 38 } 39 } 40 41 const observer = new IntersectionObserver( 42 (entries) => { 43 for (const entry of entries) { 44 if (entry.isIntersecting) loadNextBatch(); 45 } 46 }, 47 { rootMargin: '600px 0px' } 48 ); 49 50 observer.observe(sentinel); 51}
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.