Files
cell/website/themes/knr/static/js/toc.js
2026-02-08 08:25:48 -06:00

100 lines
3.2 KiB
JavaScript

(function() {
var container = document.getElementById('longform-content');
var tocList = document.getElementById('toc-list');
if (!container || !tocList) return;
var sections = container.querySelectorAll('section[id]');
var allLinks = [];
if (sections.length > 0) {
// composite page (manual, spec): section-level ToC with disclosure
sections.forEach(function(sec) {
var li = document.createElement('li');
li.className = 'toc-section';
var a = document.createElement('a');
a.href = '#' + sec.id;
a.textContent = sec.dataset.tocTitle || sec.id;
var h2s = sec.querySelectorAll('h2');
if (h2s.length > 0) {
var toggle = document.createElement('span');
toggle.className = 'toc-arrow';
toggle.textContent = '\u25B8';
li.appendChild(toggle);
li.appendChild(a);
var sub = document.createElement('ul');
sub.className = 'toc-sub';
h2s.forEach(function(h) {
if (!h.id) return;
var sli = document.createElement('li');
var sa = document.createElement('a');
sa.href = '#' + h.id;
sa.textContent = h.textContent;
sli.appendChild(sa);
sub.appendChild(sli);
});
li.appendChild(sub);
toggle.addEventListener('click', function(e) {
e.preventDefault();
li.classList.toggle('open');
});
} else {
li.appendChild(a);
}
allLinks.push({el: sec, link: a, parent: li});
tocList.appendChild(li);
});
var currentSection = null;
var observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
if (currentSection) currentSection.classList.remove('active');
var item = allLinks.find(function(i) { return i.el === entry.target; });
if (item) {
item.link.classList.add('active');
currentSection = item.link;
item.parent.classList.add('open');
}
}
});
}, {rootMargin: '0px 0px -70% 0px', threshold: 0});
sections.forEach(function(sec) { observer.observe(sec); });
} else {
// standalone page (cli, contributing): flat h2-only ToC
var headings = container.querySelectorAll('h2');
if (headings.length === 0) return;
headings.forEach(function(h) {
var li = document.createElement('li');
li.className = 'toc-section';
var a = document.createElement('a');
a.href = '#' + h.id;
a.textContent = h.textContent;
li.appendChild(a);
tocList.appendChild(li);
allLinks.push({el: h, link: a});
});
var current = null;
var obs = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
if (current) current.classList.remove('active');
var item = allLinks.find(function(i) { return i.el === entry.target; });
if (item) {
item.link.classList.add('active');
current = item.link;
}
}
});
}, {rootMargin: '0px 0px -70% 0px', threshold: 0});
headings.forEach(function(h) { obs.observe(h); });
}
})();