1(function (window, document) { 2 function register($toc) { 3 const currentInView = new Set(); 4 const headingToMenu = new Map(); 5 const $menus = Array.from($toc.querySelectorAll('.menu-list > li > a')); 6 7 for (const $menu of $menus) { 8 const elementId = $menu.getAttribute('href').trim().slice(1); 9 const $heading = document.getElementById(elementId); 10 if ($heading) { 11 headingToMenu.set($heading, $menu); 12 } 13 } 14 15 const $headings = Array.from(headingToMenu.keys()); 16 17 const callback = (entries) => { 18 for (const entry of entries) { 19 if (entry.isIntersecting) { 20 currentInView.add(entry.target); 21 } else { 22 currentInView.delete(entry.target); 23 } 24 } 25 let $heading; 26 if (currentInView.size) { 27 // heading is the first in-view heading 28 $heading = [...currentInView].sort(($el1, $el2) => $el1.offsetTop - $el2.offsetTop)[0]; 29 } else if ($headings.length) { 30 // heading is the closest heading above the viewport top 31 $heading = $headings 32 .filter(($heading) => $heading.offsetTop < window.scrollY) 33 .sort(($el1, $el2) => $el2.offsetTop - $el1.offsetTop)[0]; 34 } 35 if ($heading && headingToMenu.has($heading)) { 36 $menus.forEach(($menu) => $menu.classList.remove('is-active')); 37 38 const $menu = headingToMenu.get($heading); 39 $menu.classList.add('is-active'); 40 let $menuList = $menu.parentElement.parentElement; 41 while ( 42 $menuList.classList.contains('menu-list') && 43 $menuList.parentElement.tagName.toLowerCase() === 'li' 44 ) { 45 $menuList.parentElement.children[0].classList.add('is-active'); 46 $menuList = $menuList.parentElement.parentElement; 47 } 48 } 49 }; 50 const observer = new IntersectionObserver(callback, { threshold: 0 }); 51 52 for (const $heading of $headings) { 53 observer.observe($heading); 54 // smooth scroll to the heading 55 if (headingToMenu.has($heading)) { 56 const $menu = headingToMenu.get($heading); 57 $menu.setAttribute('data-href', $menu.getAttribute('href')); 58 $menu.setAttribute('href', 'javascript:;'); 59 $menu.addEventListener('click', () => { 60 if (typeof $heading.scrollIntoView === 'function') { 61 $heading.scrollIntoView({ behavior: 'smooth' }); 62 } 63 const anchor = $menu.getAttribute('data-href'); 64 if (history.pushState) { 65 history.pushState(null, null, anchor); 66 } else { 67 location.hash = anchor; 68 } 69 }); 70 $heading.style.scrollMargin = '1em'; 71 } 72 } 73 } 74 75 if (typeof window.IntersectionObserver === 'undefined') { 76 return; 77 } 78 79 document.querySelectorAll('#toc').forEach(register); 80})(window, document);
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.