1let scrollTimeout;
2
3const listenActive = () => {
4 const elems = document.querySelector(".pagetoc").children;
5 [...elems].forEach((el) => {
6 el.addEventListener("click", (event) => {
7 clearTimeout(scrollTimeout);
8 [...elems].forEach((el) => el.classList.remove("active"));
9 el.classList.add("active");
10 // Prevent scroll updates for a short period
11 scrollTimeout = setTimeout(() => {
12 scrollTimeout = null;
13 }, 100); // Adjust timing as needed
14 });
15 });
16};
17
18const getPagetoc = () =>
19 document.querySelector(".pagetoc") || autoCreatePagetoc();
20
21const autoCreatePagetoc = () => {
22 const main = document.querySelector("#content > main");
23 const content = Object.assign(document.createElement("div"), {
24 className: "content-wrap",
25 });
26 content.append(...main.childNodes);
27 main.prepend(content);
28 main.insertAdjacentHTML(
29 "afterbegin",
30 '<div class="sidetoc"><nav class="pagetoc"></nav></div>',
31 );
32 return document.querySelector(".pagetoc");
33};
34const updateFunction = () => {
35 if (scrollTimeout) return; // Skip updates if within the cooldown period from a click
36 const headers = [...document.getElementsByClassName("header")];
37 const scrolledY = window.scrollY;
38 let lastHeader = null;
39
40 // Find the last header that is above the current scroll position
41 for (let i = headers.length - 1; i >= 0; i--) {
42 if (scrolledY >= headers[i].offsetTop) {
43 lastHeader = headers[i];
44 break;
45 }
46 }
47
48 const pagetocLinks = [...document.querySelector(".pagetoc").children];
49 pagetocLinks.forEach((link) => link.classList.remove("active"));
50
51 if (lastHeader) {
52 const activeLink = pagetocLinks.find(
53 (link) => lastHeader.href === link.href,
54 );
55 if (activeLink) activeLink.classList.add("active");
56 }
57};
58
59window.addEventListener("load", () => {
60 const pagetoc = getPagetoc();
61 const headers = [...document.getElementsByClassName("header")];
62
63 const nonH1Headers = headers.filter(
64 (header) => !header.parentElement.tagName.toLowerCase().startsWith("h1"),
65 );
66 const sidetoc = document.querySelector(".sidetoc");
67
68 if (nonH1Headers.length === 0) {
69 if (sidetoc) {
70 sidetoc.style.display = "none";
71 }
72 return;
73 }
74
75 headers.forEach((header) => {
76 const link = Object.assign(document.createElement("a"), {
77 textContent: header.text,
78 href: header.href,
79 className: `pagetoc-${header.parentElement.tagName}`,
80 });
81 pagetoc.appendChild(link);
82 });
83 updateFunction();
84 listenActive();
85 window.addEventListener("scroll", updateFunction);
86});