1/** 2 * Acaysha Theme â Global Navigation & Interaction Controller 3 * Lightweight Vanilla JS with global window handlers & smooth back-to-top support. 4 */ 5(function() { 6 'use strict'; 7 8 function getElements() { 9 return { 10 drawer: document.getElementById('siteNavDrawer'), 11 openBtn: document.getElementById('navDrawerOpenBtn'), 12 closeBtn: document.getElementById('navDrawerCloseBtn'), 13 overlay: document.getElementById('navDrawerCloseOverlay'), 14 searchModal: document.getElementById('siteSearchModal'), 15 searchInput: document.getElementById('siteSearchInput'), 16 searchOpenBtn: document.getElementById('searchModalTrigger'), 17 searchCloseBtn: document.getElementById('searchModalCloseBtn'), 18 searchOverlay: document.getElementById('searchModalCloseOverlay') 19 }; 20 } 21 22 function openDrawer(e) { 23 if (e && e.preventDefault) e.preventDefault(); 24 const { drawer, openBtn } = getElements(); 25 if (!drawer) return; 26 drawer.style.setProperty('display', 'block', 'important'); 27 drawer.classList.add('is-active'); 28 drawer.setAttribute('aria-hidden', 'false'); 29 if (openBtn) openBtn.setAttribute('aria-expanded', 'true'); 30 document.body.classList.add('nav-drawer-open'); 31 } 32 33 function closeDrawer(e) { 34 if (e && e.preventDefault) e.preventDefault(); 35 const { drawer, openBtn } = getElements(); 36 if (!drawer) return; 37 drawer.classList.remove('is-active'); 38 drawer.style.setProperty('display', 'none', 'important'); 39 drawer.setAttribute('aria-hidden', 'true'); 40 if (openBtn) openBtn.setAttribute('aria-expanded', 'false'); 41 document.body.classList.remove('nav-drawer-open'); 42 } 43 44 function openSearch(e) { 45 if (e && e.preventDefault) e.preventDefault(); 46 const { searchModal, searchInput } = getElements(); 47 if (!searchModal) return; 48 searchModal.style.setProperty('display', 'flex', 'important'); 49 searchModal.classList.add('is-active'); 50 searchModal.setAttribute('aria-hidden', 'false'); 51 document.body.classList.add('search-modal-open'); 52 setTimeout(function() { 53 if (searchInput) { 54 searchInput.focus(); 55 searchInput.select(); 56 } 57 }, 50); 58 } 59 60 function closeSearch(e) { 61 if (e && e.preventDefault) e.preventDefault(); 62 const { searchModal } = getElements(); 63 if (!searchModal) return; 64 searchModal.classList.remove('is-active'); 65 searchModal.style.setProperty('display', 'none', 'important'); 66 searchModal.setAttribute('aria-hidden', 'true'); 67 document.body.classList.remove('search-modal-open'); 68 } 69 70 // Expose globally so inline onclick handlers and 3rd party scripts work reliably 71 window.acayshaOpenDrawer = openDrawer; 72 window.acayshaCloseDrawer = closeDrawer; 73 window.acayshaOpenSearch = openSearch; 74 window.acayshaCloseSearch = closeSearch; 75 76 function initNavigation() { 77 const { 78 openBtn, 79 closeBtn, 80 overlay, 81 searchOpenBtn, 82 searchCloseBtn, 83 searchOverlay 84 } = getElements(); 85 86 // Direct Element Listeners 87 if (openBtn) openBtn.addEventListener('click', openDrawer); 88 if (closeBtn) closeBtn.addEventListener('click', closeDrawer); 89 if (overlay) overlay.addEventListener('click', closeDrawer); 90 91 if (searchOpenBtn) searchOpenBtn.addEventListener('click', openSearch); 92 if (searchCloseBtn) searchCloseBtn.addEventListener('click', closeSearch); 93 if (searchOverlay) searchOverlay.addEventListener('click', closeSearch); 94 95 // Global Document Event Delegation 96 document.addEventListener('click', function(e) { 97 if (e.target.closest('#searchModalTrigger') || e.target.closest('.site-header__action-btn') || e.target.closest('[data-open-search]')) { 98 openSearch(e); 99 return; 100 } 101 if (e.target.closest('#searchModalCloseBtn') || e.target.closest('#searchModalCloseOverlay') || e.target.closest('[data-close-search]')) { 102 closeSearch(e); 103 return; 104 } 105 if (e.target.closest('#navDrawerOpenBtn') || e.target.closest('.site-header__menu-btn')) { 106 openDrawer(e); 107 return; 108 } 109 if (e.target.closest('#navDrawerCloseBtn') || e.target.closest('#navDrawerCloseOverlay')) { 110 closeDrawer(e); 111 return; 112 } 113 114 // Back to top smooth scroll 115 const backToTop = e.target.closest('#backToTopLink') || e.target.closest('.back-to-top-link') || e.target.closest('a[href="#masthead"]'); 116 if (backToTop) { 117 e.preventDefault(); 118 window.scrollTo({ top: 0, behavior: 'smooth' }); 119 } 120 }); 121 122 // Keyboard handling: Escape to close active modals, Cmd+K to open search 123 document.addEventListener('keydown', function(e) { 124 const { searchModal, drawer } = getElements(); 125 if (e.key === 'Escape') { 126 if (searchModal && (searchModal.classList.contains('is-active') || searchModal.style.display === 'flex')) { 127 closeSearch(); 128 } 129 if (drawer && (drawer.classList.contains('is-active') || drawer.style.display === 'block')) { 130 closeDrawer(); 131 } 132 } 133 134 if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') { 135 e.preventDefault(); 136 if (searchModal && searchModal.classList.contains('is-active')) { 137 closeSearch(); 138 } else { 139 openSearch(); 140 } 141 } 142 }); 143 } 144 145 if (document.readyState === 'loading') { 146 document.addEventListener('DOMContentLoaded', initNavigation); 147 } else { 148 initNavigation(); 149 } 150})();
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.