/** * Bongoto – Header JS (CLEAN FINAL) * --------------------------------- * ✅ Drawer (ESC, click-outside, focus trap, scroll lock) * ✅ Sticky header shadow * ✅ Desktop search dropdown * ✅ Upload license modal (Get Pro) * ✅ Accessible & optimized version */ (function () { 'use strict'; // ---------- Helpers ---------- const qs = (s, r = document) => r.querySelector(s); const qsa = (s, r = document) => Array.from(r.querySelectorAll(s)); const on = (t, h, o = document) => o.addEventListener(t, h, { passive: true }); const isDesktop = () => window.matchMedia('(min-width: 769px)').matches; const FOCUSABLE = 'a,button,input,select,textarea,[tabindex]:not([tabindex="-1"])'; // ---------- Drawer ---------- const drawer = qs('.bt-drawer'); const drawerInner = qs('.bt-drawer-inner', drawer); const toggleBtn = qs('.bt-menu-toggle'); const closeBtn = qs('.bt-drawer-close'); let scrollY = 0, lastFocus = null; const lockScroll = () => { scrollY = window.scrollY; Object.assign(document.body.style, { position: 'fixed', top: `-${scrollY}px`, left: 0, right: 0, width: '100%' }); }; const unlockScroll = () => { Object.assign(document.body.style, { position: '', top: '', left: '', right: '', width: '' }); window.scrollTo(0, scrollY); }; const openDrawer = () => { if (!drawer) return; lastFocus = document.activeElement; drawer.classList.add('is-open'); drawer.setAttribute('aria-hidden', 'false'); toggleBtn?.setAttribute('aria-expanded', 'true'); lockScroll(); // Focus first element inside drawer drawerInner?.querySelector(FOCUSABLE)?.focus?.(); }; const closeDrawer = () => { if (!drawer) return; drawer.classList.remove('is-open'); drawer.setAttribute('aria-hidden', 'true'); toggleBtn?.setAttribute('aria-expanded', 'false'); unlockScroll(); (toggleBtn || lastFocus)?.focus?.(); }; // Open / Close listeners toggleBtn?.addEventListener('click', (e) => { e.preventDefault(); openDrawer(); }); closeBtn?.addEventListener('click', (e) => { e.preventDefault(); closeDrawer(); }); // Outside click on('click', (e) => { if (!drawer?.classList.contains('is-open')) return; const inside = drawerInner?.contains(e.target); const onToggle = toggleBtn?.contains(e.target); if (!inside && !onToggle) closeDrawer(); }); // Inside link click drawerInner?.addEventListener('click', (e) => { if (e.target.closest('a')) closeDrawer(); }); // Keyboard controls document.addEventListener('keydown', (e) => { if (!drawer?.classList.contains('is-open')) return; if (e.key === 'Escape') { e.preventDefault(); closeDrawer(); } else if (e.key === 'Tab') { const focusables = qsa(FOCUSABLE, drawer); if (!focusables.length) return; const first = focusables[0], last = focusables.at(-1); if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); } else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); } } }); // Auto-close on resize on('resize', () => { if (isDesktop() && drawer?.classList.contains('is-open')) closeDrawer(); }); // Prevent drawer rubber-band drawerInner?.addEventListener('touchmove', (e) => { const el = e.currentTarget; const atTop = el.scrollTop === 0; const atBottom = el.scrollHeight - el.scrollTop === el.clientHeight; if ((atTop && e.touches[0].clientY > 0) || atBottom) e.preventDefault(); }, { passive: false }); // ---------- Sticky Shadow ---------- const header = qs('.bt-header'); if (header?.classList.contains('bt-header--sticky')) { const applyShadow = () => { header.classList.toggle('bt-header-scrolled', window.scrollY > 10); }; applyShadow(); on('scroll', applyShadow, window); } // ---------- Desktop Search Dropdown ---------- function closeAllSearchDropdowns() { qsa('.bt-search-dropdown').forEach((dd) => { dd.hidden = true; dd.closest('.bt-header-search') ?.querySelector('.bt-search-toggle') ?.setAttribute('aria-expanded', 'false'); }); } qsa('.bt-search-toggle').forEach((btn) => { btn.setAttribute('aria-expanded', 'false'); btn.addEventListener('click', (e) => { e.preventDefault(); if (!isDesktop()) return; const host = btn.closest('.bt-header-search'); const dropdown = host?.querySelector('.bt-search-dropdown'); if (!dropdown) return; const willOpen = dropdown.hidden; closeAllSearchDropdowns(); if (willOpen) { dropdown.hidden = false; btn.setAttribute('aria-expanded', 'true'); dropdown.querySelector('input[type="search"],input[type="text"]')?.focus?.(); } }); }); document.addEventListener('click', (e) => { if (!isDesktop()) return; const inside = e.target.closest('.bt-search-dropdown, .bt-search-toggle'); if (!inside) closeAllSearchDropdowns(); }, { passive: true }); // ---------- Upload License Check + Modal ---------- document.addEventListener('DOMContentLoaded', () => { const uploadBtn = qs('.bt-header-upload a.upload-btn'); if (!uploadBtn) return; // Create modal const modal = document.createElement('div'); modal.id = 'bongoto-pro-modal'; modal.style.cssText = ` display:none;position:fixed;inset:0;background:rgba(0,0,0,.6); z-index:9999;align-items:center;justify-content:center; `; modal.innerHTML = `
Please activate Bongoto Pro license to use this feature.