datatracker/ietf/static/js/nav.js
Lars Eggert efb9f135c3
fix: Apply various suggestions from @martinthomson (#4849)
* With bs 5.2.3, no need to rewrite dots in ids and hrefs.

* Remove leftover console.log().

* Inherit color for <code>

* Don't wrap boilerplate URLs; makes it look more like text version.
2022-12-08 08:58:28 -06:00

100 lines
2.7 KiB
JavaScript

import debounce from "lodash/debounce";
function make_nav() {
const nav = document.createElement("nav");
nav.classList.add("nav-pills", "ps-3", "flex-column");
return nav;
}
function get_level(el) {
let h;
if (el.tagName.match(/^h\d/i)) {
h = el.tagName
} else {
el.classList.forEach(cl => {
if (cl.match(/^h\d/i)) {
h = cl;
return;
}
});
}
return h.charAt(h.length - 1);
}
export function populate_nav(nav, heading_selector, classes) {
// Extract section headings from document
const headings = document.querySelectorAll(heading_selector);
const min_level = Math.min(...Array.from(headings)
.map(get_level));
let nav_stack = [nav];
let cur_level = 0;
let n = 0;
headings.forEach(el => {
const level = get_level(el) - min_level;
if (level < cur_level) {
while (level < cur_level) {
let nav = nav_stack.pop();
cur_level--;
nav_stack[level].appendChild(nav);
}
} else {
while (level > cur_level) {
nav_stack.push(make_nav());
cur_level++;
}
}
const link = document.createElement("a");
link.classList.add("nav-link", "ps-1", "d-flex", "hyphenate",
classes);
if (!el.id) {
el.id = `autoid-${++n}`;
}
link.href = `#${el.id}`;
const words = el.innerText.split(/\s+/);
let nr = "";
if (words[0].includes(".")) {
nr = words.shift();
} else if (words.length > 1 && words[1].includes(".")) {
nr = words.shift() + " " + words.shift();
nr = nr.replace(/\s*Appendix\s*/, "");
}
if (nr) {
const number = document.createElement("div");
number.classList.add("pe-1");
number.textContent = nr;
link.appendChild(number);
}
const text = document.createElement("div");
text.classList.add("text-break");
text.textContent = words.join(" ");
link.appendChild(text);
nav_stack[level].appendChild(link);
});
for (var i = nav_stack.length - 1; i > 0; i--) {
nav_stack[i - 1].appendChild(nav_stack[i]);
}
// Chrome apparently wants this debounced to something >10ms,
// otherwise the main view doesn't scroll?
document.addEventListener("scroll", debounce(function () {
const items = nav.querySelectorAll(".active");
const item = [...items].pop();
if (item) {
item.scrollIntoView({
block: "center",
behavior: "smooth"
});
}
}, 100));
}