1// This is messy, because docs content isn't nested in <section>s. Instead, we: 2// 1. Detect the ToC anchors (links) 3// 2. Query the <article> for these headings 4// 3. Re-format the ToC (in Hugo v0.70.0, the template is not customizable) 5// 4. Split the <article>'s childNodes into <section>s with these headings as boundaries 6// 5. Use the new parent <sections> as IntersectionObserver entries 7(function () { 8 // 1 9 const $toc = document.getElementById('TableOfContents'); 10 if (!$toc) return; 11 const $tocElements = Array.from($toc.querySelectorAll('li')).filter($el => $el.innerHTML.trim()); 12 const tocLinks = $tocElements.map($li => ( 13 `#${CSS.escape($li.querySelector('a').getAttribute('href').replace('#', ''))}` 14 )); 15 16 // 2 17 const $headings = Array.from(document.querySelectorAll(tocLinks.join(','))); 18 // 3 19 $headings.map(($heading, i) => ( 20 $tocElements[i].classList.add($heading.tagName.toLowerCase()) 21 )); 22 while($toc.firstChild){ 23 $toc.removeChild($toc.firstChild); 24 } 25 $tocElements.forEach($el => $toc.appendChild($el)); 26 27 // 4 28 const $article = document.querySelector('main article h1').parentElement; 29 const $articleNodes = Array.from($article.childNodes); 30 // Use Set for unique indices 31 const sectionBoundaries = [...new Set([ 32 0, 33 ...$headings.map($heading => ( 34 // $heading.tagName === 'H2' ? $articleNodes.indexOf($heading) : 0 35 $articleNodes.indexOf($heading) 36 )), 37 $articleNodes.length - 1 38 ])]; 39 for (let i=1; i < sectionBoundaries.length; i++) { 40 const $section = document.createElement('section'); 41 $article.appendChild($section); 42 $articleNodes.slice(sectionBoundaries[i-1], sectionBoundaries[i]).map($child => $section.appendChild($child)); 43 } 44 45 // 5 46 const observer = new IntersectionObserver(entries => { 47 entries.forEach(entry => { 48 const id = CSS.escape(entry.target.firstChild.getAttribute('id')); 49 const $li = $toc.querySelector(`a[href="#${id}"]`).parentElement; 50 if (entry.intersectionRatio > 0) { 51 $li.classList.add('active'); 52 } else { 53 $li.classList.remove('active'); 54 } 55 }); 56 }, { rootMargin: '-125px 0px -60px' });
57 $headings.forEach(heading => observer.observe(heading.parentElement)); 58})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.