document.addEventListener('DOMContentLoaded', function () { const HEADER_OFFSET = 100; let isScrollingProgrammatically = false; let allNavLinks = []; function clearAllActiveStates() { allNavLinks.forEach(link => { link.classList.remove('is-active'); }); } function setActiveLink(letter) { clearAllActiveStates(); const targetLink = allNavLinks.find( link => link.getAttribute('glossary-link') === letter ); if (targetLink) { targetLink.classList.add('is-active'); } } function organizeGlossaryByAlphabet() { const itemsContainer = document.getElementById('glossary-items-container'); const allItems = document.querySelectorAll('[glossary="item"]'); if (!itemsContainer || allItems.length === 0) { return []; } const itemsByLetter = new Map(); allItems.forEach(item => { const headingElement = item.querySelector('[glossary-item="heading"]'); if (!headingElement) return; const headingText = headingElement.textContent.trim(); if (!headingText) return; const firstLetter = headingText[0].toUpperCase(); if (!itemsByLetter.has(firstLetter)) { itemsByLetter.set(firstLetter, []); } itemsByLetter.get(firstLetter).push(item); }); const sortedLetters = Array.from(itemsByLetter.keys()).sort(); itemsContainer.innerHTML = ''; sortedLetters.forEach(letter => { const sectionWrapper = document.createElement('div'); const sectionId = `letter-${letter}`; sectionWrapper.id = sectionId; sectionWrapper.className = 'glossary-section'; sectionWrapper.setAttribute('glossary-section', letter); const letterHeading = document.createElement('h2'); letterHeading.className = 'glossary-section-heading'; letterHeading.textContent = letter; letterHeading.style.display = 'none'; sectionWrapper.appendChild(letterHeading); const items = itemsByLetter.get(letter); items.sort((a, b) => { const textA = a .querySelector('[glossary-item="heading"]') .textContent.trim(); const textB = b .querySelector('[glossary-item="heading"]') .textContent.trim(); return textA.localeCompare(textB); }); items.forEach(item => sectionWrapper.appendChild(item)); itemsContainer.appendChild(sectionWrapper); }); return sortedLetters; } function scrollToWithOffset(targetElement) { const elementPosition = targetElement.getBoundingClientRect().top; const offsetPosition = elementPosition + window.pageYOffset - HEADER_OFFSET; window.scrollTo({ top: offsetPosition, behavior: 'smooth', }); } function generateAndSetupAlphaLinks(activeLetters) { const linkListContainer = document.querySelector('[glossary-link="list"]'); if (!linkListContainer) return; linkListContainer.innerHTML = ''; allNavLinks = []; activeLetters.forEach(letter => { const link = document.createElement('a'); const targetId = `letter-${letter}`; link.setAttribute('glossary-link', letter); link.setAttribute('data-glossary-nav', 'true'); link.textContent = letter; link.className = 'table-conent_item is-glossary'; link.addEventListener('click', event => { event.preventDefault(); const targetElement = document.getElementById(targetId); if (targetElement) { isScrollingProgrammatically = true; scrollToWithOffset(targetElement); setActiveLink(letter); // Longer timeout to ensure scroll completes setTimeout(() => { isScrollingProgrammatically = false; }, 1000); } }); linkListContainer.appendChild(link); allNavLinks.push(link); }); } function setupScrollSpy() { const sections = document.querySelectorAll('.glossary-section'); if (sections.length === 0 || allNavLinks.length === 0) return; function updateActiveSection() { if (isScrollingProgrammatically) return; // Use a point just below the header const checkPoint = HEADER_OFFSET + 20; let currentSection = null; // Find the section whose top is closest to (but above) the checkpoint sections.forEach(section => { const rect = section.getBoundingClientRect(); // Section is in view if its top is above the checkpoint // and its bottom is below it if (rect.top <= checkPoint && rect.bottom > checkPoint) { currentSection = section; } }); // Fallback: find the last section whose top we've scrolled past if (!currentSection) { sections.forEach(section => { const rect = section.getBoundingClientRect(); if (rect.top <= checkPoint) { currentSection = section; } }); } const currentLetter = currentSection ? currentSection.getAttribute('glossary-section') : null; if (currentLetter) { setActiveLink(currentLetter); } } let ticking = false; function onScroll() { if (!ticking) { window.requestAnimationFrame(() => { updateActiveSection(); ticking = false; }); ticking = true; } } window.addEventListener('scroll', onScroll, { passive: true }); updateActiveSection(); } const activeLetters = organizeGlossaryByAlphabet(); if (activeLetters.length > 0) { generateAndSetupAlphaLinks(activeLetters); setupScrollSpy(); } });