✨table of contents
replit: toc
// "DOMContentLoaded" event handler (on document)
// - automatically generates a table of contents for the document.
document.addEventListener("DOMContentLoaded", () => {
// find the TOC container element.
// if there isn't one, create one at the start of the document.
let toc = document.querySelector("#toc") || (() => {
let div = `<div id="toc"></div>`.htmlToElement();
document.body.prepend(div);
return div;
})();
// find all section headings, assuming:
// - title: <h1>
// - sections: <h2> - <h6>
let headings = document.querySelectorAll("h2,h3,h4,h5,h6");
// keeps track of section numbers.
const sectionNumberManager = {
_numbers: [0, 0, 0, 0, 0], // h2, h3, h4, h5, h6
// generate section number for current heading in for-of loop
sectionNumberForHeading(heading){
// h2 -> 0, h3 -> 1, ...
let i = level(heading) - 2;
// increment the section number for this heading level
this._numbers[i] += 1;
// reset all lower heading level numbers to zero.
for (let j = i + 1; j < this._numbers.length; j++) {
this._numbers[j] = 0;
}
// combine section numbers for all heading levels
// to produce a section number like 2.3.1.
return this._numbers.slice(0, i+1).join(".");
},
};
// h2 -> 2, h3 -> 3, ...
function level(heading){
return parseInt(heading.tagName.charAt(1));
}
// loop through section headings.
for (let heading of headings) {
// skip if it's inside the TOC container.
if (heading.parentNode === toc) continue;
// generate section number for current `heading`
let sectionNumber = sectionNumberManager.sectionNumberForHeading(heading);
// add section number to `heading`.
heading.insertAdjacentHTML(
'afterbegin',
`<span class="TOCSectNum">${sectionNumber}</span>` // place in a <span> to make it styleable.
);
// wrap `heading` in "named anchor" <a> so we can link to it.
let anchorID = `TOC${sectionNumber}`;
heading.wrappedWithHTML(`<a id="${anchorID}"></a>`);
// add link (to `heading`) to TOC container.
toc.insertAdjacentHTML('beforeend',
`<div class="TOCEntry TOCLevel${level(heading)-1}">
<a href="#${anchorID}">${heading.innerHTML}</a>
</div>`
);
}
});
name attribute is obsolete, use id instead.
Document ⟩ .createElement()
Last updated