1// Mobile nav drawer behavior + year stamp. 2// The burger button uses an inline onclick (see layout.js template). 3// The top-level nav-link <a> uses inline onclick to toggle .is-open on its parent <li>. 4(function () { 5 // When the user expands a top-level item, scroll the open header to the 6 // top of the drawer so the sub-items have maximum vertical room. 7 // (We watch for class mutations on the parent <ul> rather than wiring 8 // a separate click handler so we don't double-fire with the inline onclick.) 9 function watchDrawer() { 10 var drawer = document.getElementById('navLinks') || document.querySelector('.nav-links'); 11 if (!drawer || drawer.__watched) return; 12 drawer.__watched = true; 13 var obs = new MutationObserver(function (mutations) { 14 mutations.forEach(function (m) { 15 if (m.type !== 'attributes' || m.attributeName !== 'class') return; 16 var li = m.target; 17 if (!li.classList.contains('is-open')) return; 18 if (!drawer.classList.contains('open')) return; 19 // Scroll the opened header to the top of the drawer. 20 // Wait a tick so the .mega has rendered before measuring. 21 setTimeout(function () { 22 var link = li.querySelector(':scope > .nav-link'); 23 if (!link) return; 24 var offset = link.offsetTop - drawer.scrollTop; 25 drawer.scrollBy({ top: offset - 4, left: 0, behavior: 'smooth' }); 26 }, 30); 27 }); 28 }); 29 // Observe every .nav-item child for class changes 30 drawer.querySelectorAll('.nav-item').forEach(function (li) { 31 obs.observe(li, { attributes: true, attributeFilter: ['class'] }); 32 }); 33 } 34 35 // Wire up after DOM is ready (and again on first burger tap, in case the 36 // drawer markup is injected late). 37 if (document.readyState === 'loading') { 38 document.addEventListener('DOMContentLoaded', watchDrawer); 39 } else { watchDrawer(); } 40 // Re-arm whenever the burger opens the drawer 41 document.addEventListener('click', function (e) { 42 if (e.target.closest && e.target.closest('.nav-toggle')) { 43 setTimeout(watchDrawer, 20); 44 } 45 }); 46 47 // Close the entire drawer when a real link (menu-item) inside it is tapped. 48 document.addEventListener('click', function (e) { 49 var link = e.target.closest && e.target.closest('#navLinks .menu-item, .nav-links .menu-item'); 50 if (!link) return; 51 var links = document.getElementById('navLinks') || document.querySelector('.nav-links'); 52 if (links && links.classList.contains('open')) { 53 links.classList.remove('open'); 54 document.body.classList.remove('nav-open'); 55 links.querySelectorAll('.nav-item.is-open').forEach(function (n) { n.classList.remove('is-open'); }); 56 var btn = document.querySelector('.nav-toggle'); 57 if (btn) btn.setAttribute('aria-expanded', 'false'); 58 } 59 }); 60 61 // Year stamp 62 document.querySelectorAll('[data-year]').forEach(function (el) { 63 el.textContent = new Date().getFullYear(); 64 }); 65 66 // Make sure no element stays invisible from old reveal styles 67 document.querySelectorAll('[data-reveal]').forEach(function (el) { 68 el.style.opacity = '1'; 69 el.style.transform = 'none'; 70 }); 71})();
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.