/** * Bongoto – Header JS (Updated for 5️⃣) * - Drawer (ESC, outside click, close button, link click, focus trap, body scroll lock) * - Sticky shadow on scroll * - Desktop search dropdown (mobile-এ নিষ্ক্রিয়) * - Minor a11y improvements (ARIA states, initial focus) */ (function () { 'use strict'; // ---------- Tiny 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; // ---------- Drawer ---------- const toggleBtn = qs('.bt-menu-toggle'); const drawer = qs('.bt-drawer'); const drawerInner = drawer ? qs('.bt-drawer-inner', drawer) : null; const drawerClose = drawer ? qs('.bt-drawer-close', drawer) : null; let scrollY = 0; let lastFocus = null; const FOCUSABLE = 'a,button,input,select,textarea,[tabindex]:not([tabindex="-1"])'; function lockScroll() { scrollY = window.pageYOffset; document.body.style.position = 'fixed'; document.body.style.top = `-${scrollY}px`; document.body.style.left = '0'; document.body.style.right = '0'; document.body.style.width = '100%'; } function unlockScroll() { document.body.style.position = ''; document.body.style.top = ''; document.body.style.left = ''; document.body.style.right = ''; document.body.style.width = ''; window.scrollTo(0, scrollY); } function openDrawer() { if (!drawer) return; lastFocus = document.activeElement; drawer.classList.add('is-open'); drawer.setAttribute('aria-hidden', 'false'); if (toggleBtn) toggleBtn.setAttribute('aria-expanded', 'true'); lockScroll(); // Focus first focusable element inside drawer const first = drawerInner && drawerInner.querySelector(FOCUSABLE); if (first && first.focus) first.focus(); } function closeDrawer() { if (!drawer) return; drawer.classList.remove('is-open'); drawer.setAttribute('aria-hidden', 'true'); if (toggleBtn) toggleBtn.setAttribute('aria-expanded', 'false'); unlockScroll(); // Return focus to last trigger if (toggleBtn && document.body.contains(toggleBtn)) { toggleBtn.focus(); } else if (lastFocus && lastFocus.focus) { lastFocus.focus(); } } // Open on toggle if (toggleBtn && drawer) { toggleBtn.setAttribute('aria-expanded', 'false'); toggleBtn.setAttribute('aria-controls', 'bt-drawer'); drawer.id = 'bt-drawer'; toggleBtn.addEventListener('click', function (e) { e.preventDefault(); openDrawer(); }); } // Close on close button if (drawerClose) { drawerClose.addEventListener('click', function (e) { e.preventDefault(); closeDrawer(); }); } // Close on outside click on('click', (e) => { if (!drawer || !drawer.classList.contains('is-open')) return; const clickInside = drawerInner && drawerInner.contains(e.target); const clickToggle = toggleBtn && toggleBtn.contains(e.target); if (!clickInside && !clickToggle) closeDrawer(); }); // Close when clicking a link inside drawer (navigate away) if (drawerInner) { drawerInner.addEventListener('click', (e) => { const a = e.target.closest('a'); if (!a) return; // Allow normal navigation, just close visually closeDrawer(); }); } // Focus trap & Escape key document.addEventListener('keydown', (e) => { if (!drawer || !drawer.classList.contains('is-open')) return; if (e.key === 'Escape') { e.preventDefault(); closeDrawer(); return; } if (e.key === 'Tab') { const focusables = qsa(FOCUSABLE, drawer); if (!focusables.length) return; const first = focusables[0]; const last = focusables[focusables.length - 1]; if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); } else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); } } }); // Auto-close drawer on desktop resize window.addEventListener('resize', () => { if (isDesktop() && drawer && drawer.classList.contains('is-open')) { closeDrawer(); } }, { passive: true }); // Prevent touch scroll "rubber band" inside drawer (optional polish) if (drawerInner) { drawerInner.addEventListener('touchmove', (e) => { // Allow scrolling inside if content overflows; otherwise prevent body scroll const target = e.currentTarget; const atTop = target.scrollTop === 0; const atBottom = target.scrollHeight - target.scrollTop === target.clientHeight; if ((atTop && e.touches[0].clientY > 0) || atBottom) { e.preventDefault(); } }, { passive: false }); } // ---------- Sticky shadow ---------- const header = qs('.bt-header'); if (header && header.classList.contains('bt-header--sticky')) { const apply = () => { if (window.scrollY > 10) header.classList.add('bt-header-scrolled'); else header.classList.remove('bt-header-scrolled'); }; window.addEventListener('scroll', apply, { passive: true }); apply(); } // ---------- Desktop search dropdown ---------- // Requirements: // - Button with class .bt-search-toggle (inside .bt-header-search) // - Dropdown panel with class .bt-search-dropdown (sibling/child) // - Mobile-এ dropdown কাজ করবে না (header.css ইতিমধ্যে mobile search দেয়) function closeAllSearchDropdowns() { qsa('.bt-search-dropdown').forEach((dd) => { dd.hidden = true; const host = dd.closest('.bt-header-search'); const btn = host && host.querySelector('.bt-search-toggle'); if (btn) btn.setAttribute('aria-expanded', 'false'); }); } qsa('.bt-search-toggle').forEach((btn) => { btn.setAttribute('aria-expanded', 'false'); btn.addEventListener('click', function (e) { e.preventDefault(); if (!isDesktop()) return; // mobile-এ চালু নয় const host = this.closest('.bt-header-search'); const dd = host && host.querySelector('.bt-search-dropdown'); if (!dd) return; const willOpen = dd.hidden; closeAllSearchDropdowns(); if (willOpen) { dd.hidden = false; this.setAttribute('aria-expanded', 'true'); const input = dd.querySelector('input[type="search"],input[type="text"]'); if (input && input.focus) input.focus(); } }); }); // Click outside to close desktop search dropdowns document.addEventListener('click', (e) => { if (!isDesktop()) return; const insideDropdown = e.target.closest('.bt-search-dropdown'); const isToggle = e.target.closest('.bt-search-toggle'); if (!insideDropdown && !isToggle) { closeAllSearchDropdowns(); } }, { passive: true }); // ---------- Upload button license check + Get Pro Modal ---------- document.addEventListener('DOMContentLoaded', function() { const uploadBtn = document.querySelector('.bt-header-upload a.upload-btn'); if (!uploadBtn) return; // 🔹 Popup HTML inject (hidden by default) const modal = document.createElement('div'); modal.innerHTML = `
`; document.body.appendChild(modal); const modalBox = document.getElementById('bongoto-pro-modal'); function showModal() { modalBox.style.display = 'flex'; } function hideModal() { modalBox.style.display = 'none'; } document.getElementById('bongoto-close-pro').addEventListener('click', hideModal); document.getElementById('bongoto-get-pro').addEventListener('click', function() { hideModal(); // 🔗 Replace this link with your real Pro product URL window.open('https://bongoto.com/product/bongoto-pro-digital-marketplace-addon/', '_blank'); }); uploadBtn.addEventListener('click', function(e) { e.preventDefault(); fetch(bongoto_ajax.ajax_url + '?action=bongoto_check_license') .then(res => res.json()) .then(data => { if (data.active) { window.location.href = this.href; } else { showModal(); } }) .catch(() => { alert('Something went wrong while checking license status.'); }); }); }); })();