document.addEventListener("DOMContentLoaded", () => { const tocContainer = document.querySelector("[toc-container]"); const tocSources = document.querySelectorAll("[toc-source]"); if (!tocContainer || tocSources.length === 0) { return; } const createSlug = (text) => { return text .toLowerCase() .replace(/ /g, "-") .replace(/[^\w-]+/g, ""); }; const generateToc = () => { tocContainer.innerHTML = ""; const tocList = document.createElement("ul"); tocContainer.appendChild(tocList); let lastLevel = 0; let currentList = tocList; tocSources.forEach((source) => { const headings = source.querySelectorAll("h1, h2, h3, h4, h5, h6"); headings.forEach((heading) => { const level = parseInt(heading.tagName.substring(1)); const text = heading.textContent; const slug = createSlug(text); heading.id = slug; const listItem = document.createElement("li"); const link = document.createElement("a"); link.textContent = text; link.href = `#${slug}`; listItem.appendChild(link); if (level > lastLevel) { const newList = document.createElement("ul"); if (currentList.lastChild) { currentList.lastChild.appendChild(newList); } else { currentList.appendChild(newList); } currentList = newList; } else if (level < lastLevel) { for (let i = 0; i < lastLevel - level; i++) { currentList = currentList.parentElement.parentElement; } } currentList.appendChild(listItem); lastLevel = level; }); }); }; generateToc(); const observer = new MutationObserver(generateToc); tocSources.forEach((source) => { observer.observe(source, { childList: true, subtree: true, characterData: true, }); }); tocContainer.addEventListener("click", (e) => { if (e.target.tagName === "A") { e.preventDefault(); const targetId = e.target.getAttribute("href"); const targetElement = document.querySelector(targetId); if (targetElement) { targetElement.scrollIntoView({ behavior: "smooth", }); } } }); });