PageSourceSearch

https://www.senate.gov/resources/assets/js/components/mobile-menu/mobile-menu.js

js senate.gov collected 2026-09-24 06:23:22 UTC 3,853 bytes, 97 lines download raw bytes

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.