|
addEventListener("DOMContentLoaded", trackScrollHeadingInTOC); |
|
addEventListener("DOMContentLoaded", listenForClickToOpenOrCloseTOC); |
|
|
|
|
|
function trackScrollHeadingInTOC() { |
|
const updateVisibleHeading = () => { |
|
const content = Array.from(document.querySelectorAll("article > *")); |
|
|
|
|
|
let firstVisible = content.find((element) => element.getBoundingClientRect().bottom >= 0); |
|
|
|
|
|
let heading = firstVisible; |
|
while (heading && !heading.tagName.match(/^H[1-6]$/)) { |
|
if (!heading.nextElementSibling) break; |
|
heading = heading.nextElementSibling; |
|
} |
|
|
|
|
|
if (heading && heading.getBoundingClientRect().bottom > window.innerHeight) { |
|
prevHeading = firstVisible; |
|
while (prevHeading && !prevHeading.tagName.match(/^H[1-6]$/)) { |
|
if (!prevHeading.previousElementSibling) break; |
|
prevHeading = prevHeading.previousElementSibling; |
|
} |
|
|
|
if (prevHeading && prevHeading.tagName.match(/^H[1-6]$/)) heading = prevHeading; |
|
} |
|
|
|
|
|
if (!heading || !heading.tagName.match(/^H[1-6]$/)) { |
|
const filtered = content.filter((element) => element.tagName.match(/^H[1-6]$/)); |
|
heading = filtered[filtered.length - 1]; |
|
} |
|
|
|
|
|
if (!heading) heading = document.querySelector("article > h1"); |
|
|
|
|
|
const existingActive = document.querySelector("aside.contents li.active"); |
|
existingActive?.classList.remove("active"); |
|
|
|
|
|
if (!heading) return; |
|
|
|
|
|
const tocHeading = document.querySelector(`aside.contents a[href="#${heading.id}"]`)?.parentElement; |
|
if (tocHeading instanceof HTMLElement) tocHeading.classList.add("active"); |
|
}; |
|
|
|
addEventListener("scroll", updateVisibleHeading); |
|
updateVisibleHeading(); |
|
} |
|
|
|
function listenForClickToOpenOrCloseTOC() { |
|
|
|
document.querySelector("[data-open-chapter-selection]")?.addEventListener("click", () => { |
|
|
|
setTimeout(() => { |
|
document.querySelector("[data-chapters]")?.classList.add("open"); |
|
}); |
|
}); |
|
|
|
|
|
document.querySelector("[data-close-chapter-selection]")?.addEventListener("click", () => { |
|
document.querySelector("[data-chapters]")?.classList.remove("open"); |
|
}); |
|
|
|
|
|
document.querySelector("main")?.addEventListener("click", (e) => { |
|
const chapters = document.querySelector("[data-chapters]"); |
|
if (chapters?.classList.contains("open") && !e.target.closest("[data-chapters]")) { |
|
chapters.classList.remove("open"); |
|
} |
|
}); |
|
} |
|
|