From ca6e64d45180f0c7c6d77fd8f5e97941ba78ef95 Mon Sep 17 00:00:00 2001 From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Date: Sun, 30 Nov 2025 13:11:20 -0300 Subject: [PATCH] docs: Fix bug on table of contents (#43840) We were previously always highlighting the last header in the table of contents as active even if you were at the top of the page. This is now fixed, where upon loading the page, no header is highlighted, and as you scroll, we highlight the top-most heading one by one. Release Notes: - N/A --- docs/theme/page-toc.js | 58 +++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/docs/theme/page-toc.js b/docs/theme/page-toc.js index 1ca6f621de9c34723e8ccd3be3d293a57f802d08..627416fddf06ae1330e53d88da7ae950b2bd46ca 100644 --- a/docs/theme/page-toc.js +++ b/docs/theme/page-toc.js @@ -3,21 +3,18 @@ let scrollTimeout; const listenActive = () => { const elems = document.querySelector(".pagetoc").children; [...elems].forEach((el) => { - el.addEventListener("click", (event) => { + el.addEventListener("click", (_) => { clearTimeout(scrollTimeout); [...elems].forEach((el) => el.classList.remove("active")); el.classList.add("active"); - // Prevent scroll updates for a short period + scrollTimeout = setTimeout(() => { scrollTimeout = null; - }, 100); // Adjust timing as needed + }, 100); }); }); }; -const getPagetoc = () => - document.querySelector(".pagetoc") || autoCreatePagetoc(); - const autoCreatePagetoc = () => { const main = document.querySelector("#content > main"); const content = Object.assign(document.createElement("div"), { @@ -27,30 +24,41 @@ const autoCreatePagetoc = () => { main.prepend(content); main.insertAdjacentHTML( "afterbegin", - '
', + '
', ); return document.querySelector(".pagetoc"); }; + +const getPagetoc = () => + document.querySelector(".pagetoc") || autoCreatePagetoc(); + const updateFunction = () => { - if (scrollTimeout) return; // Skip updates if within the cooldown period from a click + if (scrollTimeout) return; + const headers = [...document.getElementsByClassName("header")]; - const scrolledY = window.scrollY; - let lastHeader = null; - - // Find the last header that is above the current scroll position - for (let i = headers.length - 1; i >= 0; i--) { - if (scrolledY >= headers[i].offsetTop) { - lastHeader = headers[i]; - break; + if (headers.length === 0) return; + + const threshold = 100; + let activeHeader = null; + + for (const header of headers) { + const rect = header.getBoundingClientRect(); + + if (rect.top <= threshold) { + activeHeader = header; } } + if (!activeHeader && headers.length > 0) { + activeHeader = headers[0]; + } + const pagetocLinks = [...document.querySelector(".pagetoc").children]; pagetocLinks.forEach((link) => link.classList.remove("active")); - if (lastHeader) { + if (activeHeader) { const activeLink = pagetocLinks.find( - (link) => lastHeader.href === link.href, + (link) => activeHeader.href === link.href, ); if (activeLink) activeLink.classList.add("active"); } @@ -63,13 +71,9 @@ document.addEventListener("DOMContentLoaded", () => { const nonH1Headers = headers.filter( (header) => !header.parentElement.tagName.toLowerCase().startsWith("h1"), ); - const sidetoc = document.querySelector(".sidetoc"); const tocContainer = document.querySelector(".toc-container"); if (nonH1Headers.length === 0) { - if (sidetoc) { - sidetoc.style.display = "none"; - } if (tocContainer) { tocContainer.classList.add("no-toc"); } @@ -84,6 +88,7 @@ document.addEventListener("DOMContentLoaded", () => { className: "toc-title", textContent: "On This Page", }); + pagetoc.appendChild(tocTitle); headers.forEach((header) => { @@ -94,7 +99,14 @@ document.addEventListener("DOMContentLoaded", () => { }); pagetoc.appendChild(link); }); + updateFunction(); listenActive(); - window.addEventListener("scroll", updateFunction); + + const pageElement = document.querySelector(".page"); + if (pageElement) { + pageElement.addEventListener("scroll", updateFunction); + } else { + window.addEventListener("scroll", updateFunction); + } });