Skip to content

Instantly share code, notes, and snippets.

@florianpircher
Last active May 28, 2019 15:02
Show Gist options
  • Save florianpircher/4100a2675fe2f01eba2720c2615a7994 to your computer and use it in GitHub Desktop.
Save florianpircher/4100a2675fe2f01eba2720c2615a7994 to your computer and use it in GitHub Desktop.
(() => {
const tocItemId = (item) => {
return item.path.map(x => x.index).concat(item.index).join('-');
};
const idenitifyItemHeading = (item) => {
if (item.element.id === '') {
item.element.id = `heading-${tocItemId(item)}`;
}
};
const headingLevel = (element) => {
if (!/^H[1-6]$/.test(element.tagName)) return null;
return parseInt(element.tagName[1]);
};
const peekAtLevel = (stack, level) => {
const path = [];
let offset = stack.length;
while (level > 1) {
const item = stack[stack.length - 1]
stack = item.children;
offset = item.children.length
path.push(item);
level -= 1;
}
return {stack, path, offset};
};
const parseToc = (headings) => {
const toc = [];
let saveLevel = 1;
for (const heading of headings) {
const level = headingLevel(heading);
if (level > saveLevel + 1) continue;
saveLevel = level;
const {stack, path, offset} = peekAtLevel(toc, level);
stack.push({
element: heading,
label: heading.textContent,
level: level,
path: path,
index: offset + 1,
children: [],
});
}
return toc;
};
const setHeadingIds = (toc) => {
for (const item of toc) {
idenitifyItemHeading(item);
if (item.children.length > 0) setHeadingIds(item.children);
}
};
const renderToc = (toc) => {
const ol = document.createElement('ol');
for (const item of toc) {
const li = document.createElement('li');
const a = document.createElement('a');
a.textContent = item.label;
a.href = `#${item.element.id}`;
li.appendChild(a);
if (item.children.length > 0) {
li.appendChild(renderToc(item.children));
}
ol.appendChild(li);
}
return ol;
};
const tocNode = document.getElementById('table-of-contents');
const headings = Array.from(document.querySelectorAll('main :matches(h1, h2, h3, h4, h5, h6)'));
const toc = parseToc(headings);
setHeadingIds(toc);
tocNode.appendChild(renderToc(toc));
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment