2025-10-13 14:43:58 +02:00

90 lines
2.5 KiB
JavaScript

function renderTableOfContents() {
const root = document.querySelector("table-of-contents");
const list = document.createElement("ul");
const headers = document.querySelectorAll("h2,h3,h4,h5,h6");
const ancestors = [];
for (const header of headers) {
if (header.textContent === "Contents") {
continue;
}
const depth = parseInt(header.tagName.slice(1)) - 1;
while (ancestors.length >= depth) {
ancestors.pop();
}
const li = document.createElement("li");
const a = document.createElement("a");
if (header.querySelector("code") !== null) {
const code = document.createElement("code");
code.textContent = header.textContent;
a.append(code);
} else {
a.textContent = header.textContent;
}
a.href = `#${header.id}`;
const ul = document.createElement("ul");
li.replaceChildren(a, ul);
const mostRecent = ancestors[ancestors.length - 1];
if (mostRecent === undefined) {
list.appendChild(li);
} else {
mostRecent.appendChild(li);
}
ancestors.push(ul);
}
root.replaceChildren(list);
}
function groupHeadersInDiv(headerTag) {
const firstElement = document.querySelector(headerTag);
if (firstElement === null) {
return;
}
let container = document.createElement("div");
firstElement.replaceWith(container);
container.append(firstElement);
while (true) {
const sib = container.nextSibling;
if (sib === null) {
break;
}
if (sib.nodeName === headerTag.toUpperCase()) {
container = document.createElement("div");
sib.replaceWith(container);
}
container.append(sib);
}
}
function slugify(elements) {
console.log(elements);
return elements
.map((element, i) => {
if (i === 0) return null;
return element.textContent.trim();
})
.filter((x) => x !== null)
.join("-");
}
function attachIdToHeaders() {
const headers = document.querySelectorAll("h1,h2,h3,h4,h5,h6");
const ancestors = [];
for (const header of headers) {
const depth = parseInt(header.tagName.slice(1));
while (ancestors.length >= depth) {
ancestors.pop();
}
ancestors.push(header);
if (depth > 1) header.id = slugify(ancestors);
}
}
attachIdToHeaders();
renderTableOfContents();
groupHeadersInDiv("h2");