1document.addEventListener("DOMContentLoaded", function () { 2 const toc = document.querySelector("#toc"); 3 if (!toc) return; 4 5 const offset = 120; 6 7 const tocLinks = Array.from(toc.querySelectorAll("a[href^='#']")); 8 const items = tocLinks 9 .map(link => { 10 const href = link.getAttribute("href") || ""; 11 const id = href.startsWith("#") ? href.substring(1) : ""; 12 const heading = id ? document.getElementById(id) : null; 13 return { link, heading, id }; 14 }) 15 .filter(x => x.heading); 16 17 if (items.length === 0) return; 18 19 const headings = items.map(x => x.heading); 20 21 function clearActive() { 22 tocLinks.forEach(link => { 23 link.classList.remove("active"); 24 link.removeAttribute("aria-current"); 25 }); 26 toc.querySelectorAll("li.active").forEach(li => li.classList.remove("active")); 27 } 28 29 function activate(link) { 30 if (!link) return; 31 32 link.classList.add("active"); 33 link.setAttribute("aria-current", "true"); 34 35 const li = link.closest("li"); 36 if (li) li.classList.add("active"); 37 38 const topLi = link.closest("#toc > li"); 39 if (topLi) topLi.classList.add("active"); 40 } 41 42 function setActiveById(id) { 43 if (!id) return; 44 45 const selector = `a[href="#${CSS.escape(id)}"]`; 46 const link = toc.querySelector(selector); 47 if (!link) return; 48 49 clearActive(); 50 activate(link); 51 } 52 53 function getHeadingY(el) { 54 return el.getBoundingClientRect().top + (window.pageYOffset || document.documentElement.scrollTop || 0); 55 } 56 57 function fallbackSpy() { 58 const scrollY = window.pageYOffset || document.documentElement.scrollTop || 0; 59 const targetY = scrollY + offset; 60 61 let best = headings[0]; 62 for (let i = 0; i < headings.length; i++) { 63 if (getHeadingY(headings[i]) <= targetY) { 64 best = headings[i]; 65 } 66 } 67 68 if (best?.id) setActiveById(best.id); 69 } 70 71 toc.addEventListener( 72 "click", 73 function (e) { 74 const a = e.target?.closest?.("a[href^='#']"); 75 if (!a) return; 76 77 const href = a.getAttribute("href") || ""; 78 const id = href.startsWith("#") ? href.substring(1) : ""; 79 if (!id) return; 80 81 e.preventDefault(); 82 setActiveById(id); 83 84 const target = document.getElementById(id); 85 if (target) { 86 const y = target.getBoundingClientRect().top + window.pageYOffset - offset; 87 window.scrollTo({ top: y, behavior: "smooth" }); 88 setTimeout(fallbackSpy, 400); 89 } 90 }, 91 true 92 ); 93 94 window.addEventListener("scroll", fallbackSpy, { passive: true }); 95 window.addEventListener("resize", fallbackSpy, { passive: true }); 96 97 window.__tocSetActive = setActiveById; 98 99 fallbackSpy(); 100}); 101 102const searchForm = document.getElementById('searchForm'); 103if (searchForm) { 104 searchForm.addEventListener('submit', function () { 105 if (window.location.hash) { 106 history.replaceState(null, '', window.location.pathname + window.location.search); 107 } 108 }); 109}
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.