1// customElements.define('child-menu', class extends HTMLElement { 2// connectedCallback(){ 3// this.innerHTML = `<div>Menu Component</div>`; 4// } 5// }); 6customElements.define('mobile-menu-component', 7 class extends HTMLElement { 8 async connectedCallback() { 9 const url = new URL('/nav/master_list.shtml', import.meta.url); 10 const html = await fetch(url).then(r => r.text()); 11 this.innerHTML = html; 12 13 const expandedMenu = this.querySelector('.expanded-menu'); 14 const menuButton = this.querySelector('#menuButton'); 15 const menuButtonWithIcon = this.querySelector('.menu-with-icon'); 16 const closeBtn = this.querySelector('.close-btn'); 17 18 /* ------------------ OPEN / CLOSE MAIN MENU ------------------ */ 19 20 const toggleMainMenu = () => { 21 expandedMenu.style.display = 22 expandedMenu.style.display === 'block' ? 'none' : 'block'; 23 }; 24 25 menuButtonWithIcon?.addEventListener('click', toggleMainMenu); 26 closeBtn?.addEventListener('click', toggleMainMenu); 27 28 /* ------------------ SUBMENU menu-toggle ------------------ */ 29 30 this.querySelectorAll('.arrow').forEach(arrow => { 31 arrow.addEventListener('click', (e) => { 32 e.stopPropagation(); 33 const currentToggle = arrow.closest('.menu-toggle'); 34 const currentSubmenu = currentToggle?.nextElementSibling; 35 if (!currentSubmenu || !currentSubmenu.classList.contains('submenu')) { 36 return; 37 } 38 39 const parentMenu = currentToggle.closest('ul'); 40 const isOpen = currentSubmenu.style.display === 'block'; 41 42 // Close other submenus at same level 43 parentMenu 44 .querySelectorAll(':scope > li > .submenu') 45 .forEach(submenu => { 46 if (submenu !== currentSubmenu) { 47 this.closeSubmenuRecursively(submenu); 48 } 49 }); 50 51 // menu-toggle current submenu 52 if (isOpen) { 53 this.closeSubmenuRecursively(currentSubmenu); 54 } else { 55 currentSubmenu.style.display = 'block'; 56 arrow.classList.add('open'); 57 } 58 }); 59 }); 60 61 /* ------------------ PREVENT INNER CLICKS ------------------ */ 62 63 this.querySelectorAll('.submenu').forEach(submenu => { 64 submenu.addEventListener('click', e => e.stopPropagation()); 65 }); 66 67 /* ------------------ CLICK OUTSIDE ------------------ */ 68 69 document.addEventListener('click', (e) => { 70 if (!this.contains(e.target)) { 71 this.querySelectorAll('.submenu') 72 .forEach(submenu => this.closeSubmenuRecursively(submenu)); 73 74 this.querySelectorAll('.arrow') 75 .forEach(arrow => arrow.classList.remove('open')); 76 77 expandedMenu.style.display = 'none'; 78 } 79 }); 80 } 81 82 /* ------------------ RECURSIVE CLOSE ------------------ */ 83 84 closeSubmenuRecursively(submenu) { 85 submenu.querySelectorAll('.submenu') 86 .forEach(child => this.closeSubmenuRecursively(child)); 87 88 submenu.style.display = 'none'; 89 90 const arrow = submenu.previousElementSibling?.querySelector('.arrow'); 91 arrow?.classList.remove('open'); 92 } 93 } 94 95); 96 97// customElements.define('mobile-menu-component', MobileMenuComponent);
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.