Last active
May 28, 2019 15:02
-
-
Save florianpircher/4100a2675fe2f01eba2720c2615a7994 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(() => { | |
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