PageSourceSearch

https://dubaiairports.ae/resourcepackages/da/assets/js/main-nav.js

js dubaiairports.ae collected 2026-10-02 02:42:35 UTC 15,984 bytes, 414 lines download raw bytes

1const observer = new MutationObserver(() => {
2    const accessibilityElement = document.getElementById("userwayAccessibilityIcon");
3
4    // Check if the screen width matches mobile view
5    if (accessibilityElement) {
6        accessibilityElement.removeAttribute("style");
7        observer.disconnect(); // Stop observing after the element is found
8    }
9});
10
11observer.observe(document.body, { childList: true, subtree: true });
12
13document.addEventListener("DOMContentLoaded", () => {
14    const pageHeader = document.querySelector('header');
15    /* ---
16        Mobile (hamburger) trigger menu
17    */
18    const menuTrigger = document.getElementById("menutrigger");
19
20    menuTrigger.addEventListener("click", (event) => {
21        const mobileMenu = document.getElementById(menuTrigger.getAttribute("aria-controls"));
22
23        mobileMenu.setAttribute("aria-hidden",
24            mobileMenu.getAttribute("aria-hidden") === "true"
25                ? "false"
26                : "true"
27        );
28
29        menuTrigger.setAttribute("aria-expanded",
30            menuTrigger.getAttribute("aria-expanded") === "true"
31                ? "false"
32                : "true"
33        );
34
35        if (menuTrigger.getAttribute('aria-expanded') === "true") {
36            pageHeader.classList.add('mobile-menu-open');
37            document.documentElement.style.overflow = 'hidden'; // Applies to the <html> tag
38            document.body.style.overflow = 'hidden'; // Applies to the <body> tag
39
40            const sideMenuBottomLinks = document.getElementById("sideMenuBottomLinks");
41            if (sideMenuBottomLinks) {
42                sideMenuBottomLinks.style.display = "flex";
43            }
44
45            // FIX: Ensure main-nav-menu stays visible when mobile menu opens
46            const mainNavMenu = document.getElementById("main-nav-menu");
47            if (mainNavMenu) {
48                mainNavMenu.classList.add('fixed', 'top-0', 'w-screen');
49                mainNavMenu.style.zIndex = '9999'; // Ensure it's on top
50            }
51
52        } else {
53            pageHeader.classList.remove('mobile-menu-open');
54            document.documentElement.style.overflow = 'auto'; // Applies to the <html> tag
55            document.body.style.overflow = 'auto'; // Applies to the <body> tag
56
57            const sideMenuBottomLinks = document.getElementById("sideMenuBottomLinks");
58            if (sideMenuBottomLinks) {
59                sideMenuBottomLinks.style.display = "none";
60            }
61
62            // Reset z-index when closing
63            const mainNavMenu = document.getElementById("main-nav-menu");
64            if (mainNavMenu) {
65                mainNavMenu.style.zIndex = '';
66            }
67        }
68
69    });
70
71
72    /*---
73        Mobile- and footer menu
74
75        MenuLists: these are used in the mobile menu and in the footer.
76        The footer ones work individually but the mobile menu ones work together:
77        there can only be one of the menu lists open, so when clicking on one of them,
78        the already open list will close.
79        */
80
81    const liveChatButton = document.getElementById('open-live-chat-mobile');
82
83    if (liveChatButton) {
84        liveChatButton.addEventListener('click', () => {
85            menutrigger.checked = false;
86            window.liveChat.show();
87        });
88    }
89
90    const menuLists = document.querySelectorAll('[data-menulist]');
91
92    menuLists.forEach(elem => {
93        const title = elem.querySelector('h3');
94        const isHeaderItem = elem.closest('header');
95        title.addEventListener('click', () => toggleMobileMenu(title, isHeaderItem));
96    });
97
98    function toggleMobileMenu(title, isHeaderItem) {
99        const isOpenClass = "is-open";
100
101        pageHeader.querySelectorAll(".subnav").forEach((item) => {
102            item.setAttribute("aria-hidden", true);
103            item.removeAttribute("tabindex");
104        });
105
106        document.querySelectorAll("[data-menulist] > div").forEach((item) => {
107            item.setAttribute("aria-hidden", true);
108            item.removeAttribute("tabindex");
109        });
110
111        if (isHeaderItem) {
112            const openMenuList = document.querySelector(`[data-menulist] .${isOpenClass}`);
113
114            if (openMenuList && openMenuList != title) {
115                openMenuList.classList.remove(isOpenClass);
116            }
117        }
118
119        if (title.classList.contains(isOpenClass)) {
120            title.classList.remove(isOpenClass)
121            title.setAttribute("aria-expanded", false);
122        } else {
123            title.classList.add(isOpenClass);
124            title.setAttribute("aria-expanded", true);
125            document.getElementById(title.getAttribute("aria-controls")).setAttribute("aria-hidden", false);
126        }
127    }
128
129    function startLiveChatFromMobileMenu(event) {
130        event.preventDefault();
131        window.liveChat.show();
132    }
133
134    /* ---
135        Desktop menu
136
137        SubNavigation: on desktop for every main navigation item there is a subnavigation component with its own content;
138        The callback function toggleDesktopMenu handles opening and closing the subnavigation.
139    */
140
141    const mainNavItems = document.querySelectorAll('[data-main-nav-item]');
142    const headerBackdrop = document.getElementById('header-backdrop');
143
144    mainNavItems.forEach(elem => {
145        const title = elem.getAttribute('data-main-nav-item');
146
147
148        elem.addEventListener('click', (event) => toggleDesktopMenu(event, title));
149    });
150
151    function toggleDesktopMenu(event, title) {
152        event.preventDefault();
153
154        // Getting tabindex from main header element
155        const tabAttribute = event.target.getAttribute('tabindex');
156        let targetElement = event.target;
157
158        if (targetElement.tagName != 'A') {
159            targetElement = targetElement.closest('a');
160        }
161
162        const subnav = document.getElementById(title);
163        const subNavOpenClass = "subnav-open";
164        const isActiveClass = "is-active";
165        const openSubnav = document.querySelector(`.subnav.${subNavOpenClass}`);
166        const isActiveItem = document.querySelector(`header .${isActiveClass}`);
167
168        headerBackdrop.classList.remove(isActiveClass);
169        pageHeader.querySelectorAll(".subnav").forEach((item) => {
170            item.setAttribute("aria-hidden", true);
171        });
172
173        document.querySelectorAll("#main-nav-menu a").forEach((item) => {
174            item.setAttribute("aria-expanded", false);
175        });
176
177        document.querySelector('#Search [data-search-results]')?.setAttribute("aria-hidden", true);
178        document.querySelector('#Search [data-search-suggestions]')?.setAttribute("aria-hidden", false);
179
180        if (openSubnav && openSubnav !== subnav) {
181            openSubnav.classList.remove(subNavOpenClass);
182
183            //Remove tabindex from sub header element and set new tabindex 
184            openSubnav.querySelectorAll('.tabIndexSet').forEach((elem) => {
185                if (elem) {
186                    elem.removeAttribute('tabindex');
187                    elem.setAttribute('tabindex', '-1');
188                } else {
189                    console.error('Sub-element not found');
190                }
191            });
192
193            if (isActiveItem) {
194                isActiveItem.classList.remove(isActiveClass);
195            }
196        }
197
198        if (subnav) {
199            if (subnav.classList.contains(subNavOpenClass)) {
200                pageHeader.classList.remove(subNavOpenClass);
201                subnav.classList.remove(subNavOpenClass);
202
203                //Remove tabindex from sub header element and set new tabindex 
204                subnav.querySelectorAll('.tabIndexSet').forEach((elem) => {
205                    if (elem) {
206                        elem.removeAttribute('tabindex');
207                        elem.setAttribute('tabindex', '-1');
208                    } else {
209                        console.error('Sub-element not found');
210                    }
211                });
212                targetElement.classList.remove(isActiveClass);
213                subnav.setAttribute("aria-hidden", true);
214
215            } else {
216                pageHeader.classList.add(subNavOpenClass);
217                subnav.classList.add(subNavOpenClass);
218
219                //Remove tabindex from sub header element and set new tabindex 
220                subnav.querySelectorAll('.tabIndexSet').forEach((elem) => {
221                    if (elem) {
222                        elem.removeAttribute('tabindex', '-1');
223                        elem.setAttribute('tabindex', tabAttribute);
224                    } else {
225                        console.error('Sub-element not found');
226                    }
227                });
228
229                targetElement.classList.add(isActiveClass);
230                targetElement.setAttribute("aria-expanded", true);
231                subnav.setAttribute("aria-hidden", false);
232
233                headerBackdrop.classList.add(isActiveClass);
234
235                window.addEventListener("click", closeDesktopMenu);
236                headerBackdrop.addEventListener("click", closeDesktopMenu);
237                document.addEventListener("keydown", closeByEscapeKey);
238            }
239        }
240
241    }
242
243    /* ---
244        Closing all menu's
245    */
246
247    function closeDesktopMenu(event) {
248        if ((event?.type == "keydown" && event?.keyCode === 27) || !event?.target.closest('.wrapper > header')) {
249            const isActiveClass = "is-active";
250            const isOpenClass = "is-open";
251
252            pageHeader.classList.remove("subnav-open");
253
254            pageHeader.querySelectorAll(".subnav").forEach((item) => {
255                item.setAttribute("aria-hidden", true)
256            });
257
258            document.querySelector('#Search [data-search-results]')?.setAttribute("aria-hidden", true);
259            document.querySelector('#Search [data-search-suggestions]')?.setAttribute("aria-hidden", false);
260
261            document.querySelectorAll("#main-nav-menu a").forEach((item) => {
262                item.setAttribute("aria-expanded", false);
263                item.classList.remove(isActiveClass);
264            });
265
266            headerBackdrop.classList.remove(isActiveClass);
267
268            pageHeader.querySelector(`div.${isOpenClass}`)?.classList.remove(isOpenClass);
269
270            pageHeader.querySelectorAll(".subnav-open").forEach((item) => {
271                item.classList.remove("subnav-open");
272            });
273            pageHeader.querySelectorAll(`#desktop-menu li a.${isActiveClass}`).forEach((item) => {
274                item.classList.remove(isActiveClass);
275                item.removeAttribute('tabindex'); //  //Remove tabindex from sub header element
276            });
277
278
279            document.removeEventListener("keydown", closeByEscapeKey);
280            headerBackdrop.removeEventListener("click", closeDesktopMenu);
281        }
282    }
283
284    function closeByEscapeKey(event) {
285        if (event.keyCode === 27) {
286            closeDesktopMenu(null);
287        }
288
289    }
290
291
292    // Added aria-expanded for accessibility
293    var megaMenuLinks = document.querySelectorAll('navElementDesktop');
294    for (var i = 0; i < megaMenuLinks.length; i++) {
295        megaMenuLinks[i].addEventListener('click', handleLinkClicked)
296    }
297
298    function handleLinkClicked(e) {
299        e.preventDefault();
300        var target = document.querySelector(`${e.target.getAttribute("navElement")}`);
301
302        if (target.getAttribute('aria-expanded') === 'true') {
303            target.setAttribute('aria-expanded', 'false');
304        } else {
305            target.setAttribute('aria-expanded', 'true');
306        }
307    }
308
309    /* ---
310        Search
311    */
312
313    const toggleMobileSearch = document.querySelector('[data-toggle-search]');
314    const mobileMenuContent = document.querySelector('[data-mob-menu]');
315    const toggleMobileMenuBack = document.querySelector('[data-mob-backtomenu]');
316    const mobileSearchContent = document.querySelector('[data-mob-search]');
317
318    toggleMobileSearch?.addEventListener('click', (event) => toggleMobileMenuContent(event, 'search'));
319    toggleMobileMenuBack?.addEventListener('click', (event) => toggleMobileMenuContent(event, 'menu'));
320
321    function toggleMobileMenuContent(event, target) {
322        console.log(event.type, 'toggle content to ' + target);
323
324        if (target == 'search') {
325            if (mobileMenuContent) {
326                mobileMenuContent.classList.add('hidden');
327                mobileMenuContent.setAttribute("aria-hidden", true);
328                toggleMobileSearch.setAttribute("aria-expanded", false);
329                toggleMobileMenuBack.setAttribute("aria-expanded", true);
330            }
331            if (mobileSearchContent) {
332                mobileSearchContent.classList.remove('hidden');
333                mobileSearchContent.setAttribute("aria-hidden", false);
334                toggleMobileSearch.setAttribute("aria-expanded", true);
335                toggleMobileMenuBack.setAttribute("aria-expanded", false);
336            }
337        }
338        if (target == 'menu') {
339            if (mobileMenuContent) {
340                mobileMenuContent.classList.remove('hidden');
341                mobileMenuContent.setAttribute("aria-hidden", false);
342                toggleMobileSearch.setAttribute("aria-expanded", true);
343                toggleMobileMenuBack.setAttribute("aria-expanded", false);
344            }
345            if (mobileSearchContent) {
346                mobileSearchContent.classList.add('hidden');
347                mobileSearchContent.setAttribute("aria-hidden", true);
348                toggleMobileSearch.setAttribute("aria-expanded", false);
349                toggleMobileMenuBack.setAttribute("aria-expanded", true);
350            }
351        }
352    }
353
354    /* ---
355        Language switch
356    */
357
358    const languageSwitch = document.getElementById('languageSwitch');
359    const languageSwitchDropdown = document.getElementById('languageSwitchDropdown');
360    const isOpenClass = "is-open";
361    languageSwitch.addEventListener('click', toggleLanguageSwitchDropdown);
362
363    function toggleLanguageSwitchDropdown(event) {
364        if (languageSwitch.parentElement.classList.contains(isOpenClass)) {
365            languageSwitch.parentElement.classList.remove(isOpenClass);
366            languageSwitch.setAttribute("aria-expanded", false);
367            languageSwitchDropdown.setAttribute("aria-hidden", true);
368        } else {
369            languageSwitch.parentElement.classList.add(isOpenClass);
370            languageSwitch.setAttribute("aria-expanded", true);
371            languageSwitchDropdown.setAttribute("aria-hidden", false);
372        }
373    }
374
375    /* ---
376        General close any open dropdown or menu when clicking outside
377    */
378    document.addEventListener('click', (e) => {
379        if (!e.target.closest('#languageSwitch')) {
380            languageSwitch.parentElement.classList.remove('is-open');
381            languageSwitch.setAttribute("aria-expanded", false);
382            languageSwitchDropdown.setAttribute("aria-hidden", true);
383        }
384
385        // TODO: add scripting for closing the submenu and search dropdown when it is o
385pen
386    });
387
388    /* ---
389        Header sticky when scrolling up
390    */
391
392    let lastScrollTop = 0;
393
394    document.addEventListener('scroll', () => {
395        const st = window.scrollY || document.documentElement.scrollTop;
396        pageHeader.classList.toggle('is-scrolling-down', st > lastScrollTop);
397        pageHeader.classList.toggle('is-scrolling-up', st <= lastScrollTop);
398
399        const mh = document.getElementById("main-nav-menu");
400        if (mh) {
401            // At document top, never pin #main-nav-menu as fixed — it leaves the flow and overlaps content below.
402            if (st <= 0) {
403                mh.classList.remove('fixed', 'top-0', 'w-screen');
404            } else {
405                const pinMainNav = st <= lastScrollTop;
406                mh.classList.toggle('fixed', pinMainNav);
407                mh.classList.toggle('top-0', pinMainNav);
408                mh.classList.toggle('w-screen', pinMainNav);
409            }
410        }
411
412        lastScrollTop = st <= 0 ? 0 : st;
413    }, false);
414});

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.