/** * Blog Build Theme Scripts * * Contains implementations for: * 1. Menu Accessibility * 1. Dark/Light Mode Toggle * 2. Search Bar Toggle * 3. Sidebar Menu Toggle * * @package BlogBuild * @since 1.0.0 */ document.addEventListener('DOMContentLoaded', function() { "use strict"; // Get the menu element const magicElementorMenu = document.getElementById('main-menu'); // Initialize accessible dropdown if menu exists if (magicElementorMenu) { blogBuildAccessibleDropDown(magicElementorMenu); } }); /** * Makes dropdown menus keyboard accessible * * @param {HTMLElement} el - The menu element to make accessible */ function blogBuildAccessibleDropDown(el) { // Find all links within the menu const menuLinks = el.querySelectorAll('a'); // Add event listeners to each link menuLinks.forEach(function(link) { // Track navigation direction for Shift+Tab handling link.addEventListener('keydown', function(e) { if (e.key === 'Tab' && e.shiftKey) { // Mark that we're doing Shift+Tab navigation el.setAttribute('data-shift-tab', 'true'); setTimeout(() => { el.removeAttribute('data-shift-tab'); }, 100); } }); // When link gets focus - manage all hover states link.addEventListener('focus', function() { const parentLi = findParentLi(this); const isShiftTabbing = el.hasAttribute('data-shift-tab'); // For Shift+Tab, don't clear dropdowns immediately if (!isShiftTabbing) { // First clear all hover states for normal Tab navigation el.querySelectorAll('li.hover').forEach(li => { li.classList.remove('hover'); }); } // Then add hover to current parent li and all its ancestors if (parentLi) { parentLi.classList.add('hover'); // Also add hover to parent menu items if this is a submenu let currentParent = parentLi.parentElement; while (currentParent && currentParent !== el) { if (currentParent.tagName === 'UL') { const parentMenuItem = findParentLi(currentParent); if (parentMenuItem) { parentMenuItem.classList.add('hover'); currentParent = parentMenuItem.parentElement; } else { break; } } else { break; } } } // For Shift+Tab, clean up other dropdowns after a delay if (isShiftTabbing) { setTimeout(() => { el.querySelectorAll('li.hover').forEach(li => { if (li !== parentLi && !isParentOf(li, parentLi) && !isParentOf(parentLi, li)) { li.classList.remove('hover'); } }); }, 50); } }); }); // Close dropdowns when clicking outside document.addEventListener('click', function(e) { if (!el.contains(e.target)) { el.querySelectorAll('li.hover').forEach(li => { li.classList.remove('hover'); }); } }); } /** * Helper function to find parent li element * * @param {HTMLElement} element - The element to find parent for * @return {HTMLElement|null} - The parent li element or null */ function findParentLi(element) { let currentElement = element; // Traverse up the DOM until we find an li or reach the top while (currentElement && currentElement.tagName !== 'LI') { currentElement = currentElement.parentElement; } return currentElement; } /** * Helper function to check if one element is a parent of another * * @param {HTMLElement} parent - The potential parent element * @param {HTMLElement} child - The potential child element * @return {boolean} - True if parent contains child */ function isParentOf(parent, child) { if (!parent || !child) return false; return parent.contains(child); }