docs/headers.js

80 lines
2.5 KiB
JavaScript

for (const el of document.querySelectorAll("[id]")) {
el.classList.add("haspara");
const pilcrow = document.createElement("a");
pilcrow.className = "pilcrow";
pilcrow.href = "#" + el.id;
pilcrow.innerHTML = "¶";
el.prepend(pilcrow);
}
const foldable = (root, children) => {
let state = true;
root.addEventListener("click", (e) => {
if (e.target.classList.contains("pilcrow")) state = true;
else state = !state;
children.style.height = state ? "auto" : "0";
children.style.overflow = state ? "visible" : "hidden";
if (state) root.classList.remove("closed");
else root.classList.add("closed");
});
root.classList.add("toggle-root");
};
const make_foldable = (root) => {
const child_stacks = new Array(10).fill(null).map(() => ({ children: [], root: null }));
const flush_header = (this_level, sibling) => {
for (let level = 9; level >= this_level; level--) {
const stack = child_stacks[level];
if (!stack.root) continue;
const new_e = document.createElement("div");
for (const old_e of stack.children) {
old_e.remove();
new_e.appendChild(old_e);
}
if (stack.root.tagName !== "H1") foldable(stack.root, new_e);
let parent_level;
for (parent_level = level - 1; parent_level > 0; parent_level--) if (child_stacks[parent_level].root) break;
if (parent_level === -1) {
if (sibling) root.insertBefore(new_e, sibling);
else root.appendChild(new_e);
} else {
stack.root.remove();
child_stacks[parent_level].children.push(stack.root);
child_stacks[parent_level].children.push(new_e);
}
stack.root = null;
stack.children.length = 0;
}
};
for (const child of [...root.children]) {
if (/^H\d$/.test(child.tagName)) {
const this_level = parseInt(child.tagName[1]) - 1;
flush_header(this_level, child);
child_stacks[this_level].root = child;
continue;
}
for (let level = 9; level >= 0; level--) {
if (child_stacks[level].root) {
child_stacks[level].children.push(child);
break;
}
}
}
for (let level = 9; level >= 0; level--) {
flush_header(level, null);
}
};
make_foldable(document.body);