1(() => { 2 const isMobile = () => window.innerWidth < 1100; 3 4 const handleOpenMenuMobile = () => { 5 const triggerButton = document.querySelector("#global-navigation-toggle") 6 const level1Menu = document.querySelector("#level-1-list") 7 const nav = document.querySelector("#global-navigation") 8 const hero = document.getElementById("hero-banner") 9 10 triggerButton.addEventListener("click", () => { 11 const isDefault = nav.getAttribute("data-default-appearance"); 12 13 triggerButton.classList.toggle("active") 14 15 16 if (level1Menu.classList.contains("level-1-open")) { 17 document.body.style.overflow = "auto" 18 level1Menu.classList.remove("level-1-open"); 19 if (isDefault == "True") return 20 setTimeout(() => { 21 // Check if hero is still intersecting with navbar 22 if (hero && nav) { 23 const heroRect = hero.getBoundingClientRect(); 24 const navRect = nav.getBoundingClientRect(); 25 const isIntersecting = heroRect.bottom > navRect.top; 26 27 if (isIntersecting) { 28 nav.classList.add("global-navigation__immersive") 29 } 30 } 31 }, 30) 32 } else { 33 document.body.style.overflow = "hidden" 34 nav.classList.remove("global-navigation__immersive") 35 setTimeout(() => { 36 level1Menu.classList.add("level-1-open"); 37 }, 10) 38 } 39 }) 40 41 } 42 43 const handleNavbarIntersection = () => { 44 const navbar = document.getElementById("global-navigation"); 45 const hero = document.getElementById("hero-banner"); 46 const level1Menu = document.querySelector("#level-1-list") 47 48 49 50 if (!hero || !navbar) return; 51 52 const observer = new IntersectionObserver( 53 (entries) => { 54 const entry = entries[0]; 55 56 if (entry.isIntersecting) { 57 // navbar is overlapping / intersecting the hero 58 navbar.classList.add("global-navigation__immersive"); 59 navbar.setAttribute("data-default-appearance", "false") 60 } else { 61 // navbar is no longer intersecting the hero 62 navbar.classList.remove("global-navigation__immersive"); 63 navbar.setAttribute("data-default-appearance", "true") 64 } 65 }, 66 { 67 root: null, // viewport 68 threshold: 0, // trigger as soon as hero goes out of view 69 rootMargin: `-${navbar.offsetHeight}px 0px 0px 0px` 70 } 71 ); 72 73 // observe the hero section 74 observer.observe(hero); 75 76 } 77 78 // const handleNavAppearanceToggle = () => { 79 // const nav = document.querySelector("#global-navigation") 80 // const isDefault = nav.getAttribute("data-default-appearance"); 81 // if (isDefault == "true") return 82 83 // else 84 // nav.classList.toggle("global-navigation__immersive") 85 // } 86 87 const handleCLickOnLevel1Button = () => { 88 const buttons = document.querySelectorAll(".global-navigation .level-1-button"); 89 90 buttons.forEach(btn => { 91 btn.addEventListener("click", () => { 92 const buttonMenu = btn.parentElement.querySelector(".menu") 93 const nav = document.querySelector("#global-navigation") 94 const isDefault = nav.getAttribute("data-default-appearance") === "True"; 95 const hero = document.getElementById("hero-banner"); 96 97 // Close any OTHER open level-1 menus 98 nav.querySelectorAll(".menu.show").forEach(openMenu => { 99 if (openMenu !== buttonMenu) { 100 openMenu.classList.remove("show"); 101 openMenu.querySelectorAll(".active-level, .show").forEach(el => { 102 el.classList.remove("active-level"); 103 el.classList.remove("show"); 104 }); 105 } 106 }); 107 108 // Clean up active states within the current nav item 109 const activeMenus = btn.parentElement.querySelectorAll(".active-level, div:not(.menu).show") 110
111 activeMenus.forEach(ele => { 112 ele.classList.remove("active-level") 113 ele.classList.remove("show") 114 }) 115 116 if (buttonMenu.classList.contains("show")) { 117 document.body.style.overflow = "auto" 118 buttonMenu.classList.remove("show"); 119 if (isDefault) return 120 setTimeout(() => { 121 // Check if hero is still intersecting with navbar 122 if (hero && nav) { 123 const heroRect = hero.getBoundingClientRect(); 124 const navRect = nav.getBoundingClientRect(); 125 const isIntersecting = heroRect.bottom > navRect.top; 126 127 if (isIntersecting) { 128 nav.classList.add("global-navigation__immersive") 129 } 130 } 131 }, 30) 132 } else { 133 document.body.style.overflow = "hidden" 134 nav.classList.remove("global-navigation__immersive") 135 setTimeout(() => { 136 buttonMenu.classList.add("show"); 137 const firstL2Btn = buttonMenu.querySelector('.global-navigation__level-2-list li button'); 138 if (firstL2Btn) { 139 if (isMobile()) { 140 const level2Items = buttonMenu.querySelectorAll('.global-navigation__level-2-list li.global-navigation__level-2-item'); 141 if (level2Items.length === 1) { 142 firstL2Btn.click(); 143 } else { 144 firstL2Btn.dispatchEvent(new Event('mouseenter')); 145 } 146 } else { 147 firstL2Btn.dispatchEvent(new Event('mouseenter')); 148 } 149 } 150 }, 10) 151 } 152 }) 153 }) 154 } 155 156 /** 157 * get level 2 back button 158 * add click listener on it 159 * hide the menu if this button is clicked 160 */ 161 const handleClickOnLevel2Back = () => { 162 document.querySelectorAll(".global-navigation__level-2-list .mobile-menu-title svg").forEach(backBtn => { 163 backBtn.addEventListener("click", () => { 164 backBtn.closest(".menu").classList.remove('show') 165 }); 166 }); 167 } 168 169 170 /** 171 * get buttons of level 2 172 * add mouseenter event on them 173 * get all level 3 and level 4 menus 174 * if we are openeing new one we close all menues in level 3 and 4 and then open the menu in level 3 correponding to this element index 175 * if we are clicking on the same one we close all and remove active-level class from clicked buttin 176 */ 177 const handleClickOnLevel2Item = () => { 178 const btns = document.querySelectorAll(".global-navigation__level-2-list li.global-navigation__level-2-item button"); 179 180 const showLevel2Submenu = (btn) => { 181 const level3Menus = btn.closest(".lists-container").querySelector(".level-3-lists-container") 182 const level4Menus = btn.closest(".lists-container").querySelector(".level-4-lists-container") 183 const siblings = Array.from(btn.parentElement.parentElement.children) 184 185 Array.from(level4Menus.children).forEach(group => { 186 group.classList.remove("show") 187 Array.from(group.children).forEach(child => child.classList.remove("show")) 188 }) 189 190 const listIndex = btn.getAttribute("data-controls").split("-")[1]; 191 192 Array.from(level3Menus.children).forEach(ele => ele.classList.remove("show")) 193 siblings.forEach(ele => ele.classList.remove("active-level")) 194 level3Menus.children[listIndex].classList.add("show") 195 btn.parentElement.classList.add("active-level") 196 level4Menus.children[listIndex].classList.add("show") 197 }; 198 199 btns.forEach(btn => { 200 btn.addEventListener("mouseenter", () => { 201 if (isMobile()) return; 202 showLevel2Submenu(btn); 203 }); 204 205 btn.addEventListener("click", (e) => { 206 if (!isMobile()) return; 207 e.preventDefault(); 208 e.stopPropagation(); 209 showLevel2Submenu(btn); 210 }); 211 }) 212 } 213 214 215 /** 216 * get level 3 buttons 217 * add click listner 218 * if level is active we close its crosponding menu in level 4 219 * if level is not active we close all the menus in level 4 and open the menu with the same index 220 */ 221 const handleClickOnLevel3Item = () => { 222 const btns = document.querySelectorAll(".global-navigation__level-3-list .global-navigation__level-3-item button"); 223 224 const showLevel3Submenu = (btn) => { 225 const level4Menus = btn.closest(".lists-container").querySelector(".level-4-lists-container") 226 const activeGroup = level4Menus.querySelector(".level-4-group.show") 227 const listIndex = btn.getAttribute("data-controls").split("-")[1]; 228 229 if (activeGroup) {
230 Array.from(activeGroup.children).forEach(ele => ele.classList.remove("show")) 231 activeGroup.children[listIndex].classList.add("show") 232 } 233 btn.parentElement.classList.add("active-level") 234 }; 235 236 btns.forEach(btn => { 237 btn.addEventListener("mouseenter", () => { 238 if (isMobile()) return; 239 showLevel3Submenu(btn); 240 }); 241 242 btn.addEventListener("click", (e) => { 243 if (!isMobile()) return; 244 e.preventDefault(); 245 e.stopPropagation(); 246 showLevel3Submenu(btn); 247 }); 248 }) 249 } 250 251 const handleClickBackFromUpperLevels = () => { 252 const btns = document.querySelectorAll(".global-navigation .mobile-menu-title svg"); 253 btns.forEach(btn => { 254 btn.addEventListener("click", () => { 255 const parentContainer = btn.parentElement.parentElement; 256 parentContainer.classList.remove("show"); 257 258 // If we're on mobile and backing out from level 3+, check if we should skip level-2 259 if (isMobile()) { 260 const listsContainer = btn.closest(".lists-container"); 261 if (listsContainer) { 262 const level2Items = listsContainer.querySelectorAll('.global-navigation__level-2-list li.global-navigation__level-2-item'); 263 // If there's only one level-2 item and we're not already at level-2, close the entire menu 264 if (level2Items.length === 1 && !btn.closest(".global-navigation__level-2-list")) { 265 const menu = btn.closest(".menu"); 266 if (menu) { 267 menu.classList.remove("show"); 268 } 269 } 270 } 271 } 272 }) 273 }) 274 } 275 276 277 const getItemMedia = (item) => { 278 if (!item) return null 279 const mediaUrl = item.dataset.mediaLink; 280 const isVideo = item.dataset.isVideo === 'true' || item.dataset.isVideo === 'True'; 281 282 return { mediaUrl, isVideo } 283 } 284 285 const getCurrentMedia = ({ image, video }) => { 286 if (!video.classList.contains("d-none")) { 287 return { 288 mediaUrl: video.querySelector("source").src, 289 isVideo: true, 290 }; 291 } 292 293 if (!image.classList.contains("d-none")) { 294 return { 295 mediaUrl: image.src, 296 isVideo: false, 297 }; 298 } 299 300 return null; 301 }; 302 303 304 const handleControlMediaShown = ({ mediaUrl, isVideo, previewImage, previewVideo }) => { 305 const current = getCurrentMedia({ image: previewImage, video: previewVideo }); 306 307 if ( 308 current && 309 current.mediaUrl.includes(mediaUrl) && 310 current.isVideo === isVideo 311 ) { 312 return; 313 } 314 315 if (isVideo) { 316 previewVideo.querySelector('source').src = mediaUrl; 317 previewVideo.load(); 318 previewVideo.classList.remove('d-none'); 319 previewVideo.play(); 320 previewImage.classList.add('d-none'); 321 previewImage.src = "" 322 } else { 323 previewImage.src = mediaUrl; 324 previewImage.classList.remove('d-none'); 325 previewVideo.classList.add('d-none'); 326 previewVideo.querySelector('source').src = ""; 327 } 328 } 329 330 const handleChangeMediaOnClick = (li) => { 331 if (li.querySelector(".level-1-link")) return // means that level 1 has no children 332 // main li 333 const closestNavigationItem = li.closest(".global-navigation__nav-item") 334 // levels 335 const level2ActiveTrigger = closestNavigationItem.querySelector(".lists-container .global-navigation__level-2-list .active-level") 336 const level3ActiveTrigger = closestNavigationItem.querySelector(".lists-container .level-3-lists-container .active-level") 337 // media container 338 const mediaContainer = closestNavigationItem.querySelector('.global-navigation__media-container'); 339 const previewVideo = mediaContainer.querySelector('.previewVideo'); 340 const previewImage = mediaContainer.querySelector('.previewImage'); 341 342 let isVideo = false; 343 let mediaUrl = "#"; 344 345 if (level3ActiveTrigger) { 346 const { mediaUrl: itemMediaUrl, isVideo: isItemMediaTypeVideo } = getItemMedia(level3ActiveTrigger) || getItemMedia(level2ActiveTrigger) || getItemMedia(closestNavigationItem) 347 isVideo = isItemMediaTypeVideo; 348 mediaUrl = itemMediaUrl 349 } else if (level2ActiveTrigger) { 350 const { mediaUrl: itemMediaUrl, isVideo: isItemMediaTypeVideo } = getItemMedia(level2ActiveTrigger) || getItemMedia(closestNavigationItem) 351 isVideo = isItemMediaTypeVideo; 352 mediaUrl = itemMediaUrl 353 } else { 354 const { mediaUrl: itemMediaUrl, isVideo: isItemMediaTypeVideo } = getItemMedia(closestNavigationItem) 355 isVideo = isItemMediaTypeVideo; 356 mediaUrl = itemMediaUrl 357 } 358 359 handleControlMediaShown({ mediaUrl, isVideo, previewImage, previewVideo }) 360 361 } 362 363 const handleAddClickListenerOnBtn = () => { 364 const buttons = document.querySelectorAll(".global-navigation__nav-item, .global-navigation__nav-item li") 365 buttons.forEach((btn) => { 366 btn.addEventListener("click", () => handleChangeMediaOnClick(btn)) 367 }) 368 } 369 370 const handleMouseOver = () => { 371 // All nav items 372 const navItems = document.querySelectorAll('.global-navigation__nav-item li'); 373
374 navItems.forEach(item => { 375 item.addEventListener('mouseenter', () => { 376 const parentElement = item.closest(".global-navigation__nav-item") 377 const mediaContainer = parentElement.querySelector('.global-navigation__media-container'); 378 const previewVideo = mediaContainer.querySelector('.previewVideo'); 379 const previewImage = mediaContainer.querySelector('.previewImage'); 380 const mediaUrl = item.dataset.mediaLink; 381 const isVideo = item.dataset.isVideo === 'true' || item.dataset.isVideo === 'True'; 382 383 if (!mediaUrl) return; 384 handleControlMediaShown({ mediaUrl, isVideo, previewImage, previewVideo }) 385 }); 386 }); 387 } 388 389 const handleMouseLeave = () => { 390 const navItems = document.querySelectorAll('.global-navigation__nav-item li'); 391 navItems.forEach(item => { 392 item.addEventListener('mouseleave', () => { 393 handleChangeMediaOnClick(item) 394 }); 395 }); 396 }; 397 398 399 const handleOpenContactModal = () => { 400 const button = document.querySelector(".nav-contact-modal-trigger"); 401 if (!button) return; 402 403 button.addEventListener("click", () => { 404 openContactModal(button); 405 }) 406 } 407 408 const pushNavTrackingEvent = (element) => { 409 if (!element || !window.GTM) return; 410 411 const linkText = element.dataset.gtmLinkText || element.textContent?.trim() || ''; 412 const linkUrl = element.dataset.gtmLinkUrl || element.href || ''; 413 const navLevel = element.dataset.gtmNavLevel; 414 const navLevel1 = element.dataset.gtmNavLevel1 || null; 415 const navLevel2 = element.dataset.gtmNavLevel2 || null; 416 417 const nav = document.querySelector("#global-navigation"); 418 const pageType = nav?.dataset.model || 'unknown'; 419 420 if (navLevel === '1') { 421 window.GTM.push({ 422 event: 'select_content', 423 content_type: 'navigation', 424 content_id: 'header_nav', 425 link_text: linkText, 426 link_url: linkUrl, 427 nav_level_1: linkText, 428 page_section: 'header', 429 page_type: pageType 430 }); 431 } else { 432 let navLevel3 = null; 433 434 if (navLevel === '2') { 435 // Level 2: level1=parent, level2=clicked, level3=null 436 } else if (navLevel === '3') { 437 navLevel3 = linkText; 438 } else if (navLevel === '4') { 439 navLevel3 = navLevel2; 440 } 441 442 window.GTM.push({ 443 event: 'select_content', 444 content_type: 'navigation', 445 content_id: 'header_nav_submenu', 446 link_text: linkText, 447 link_url: linkUrl, 448 nav_level_1: navLevel1,
449 nav_level_2: navLevel === '2' ? linkText : navLevel2, 450 nav_level_3: navLevel3, 451 page_section: 'header', 452 page_type: pageType 453 }); 454 } 455 } 456 457 const handleNavigationTracking = () => { 458 const trackingItems = document.querySelectorAll('.nav-tracking-item a, .nav-tracking-item button'); 459 460 trackingItems.forEach(element => { 461 element.addEventListener('click', () => { 462 const trackingItem = element.closest('.nav-tracking-item'); 463 if (trackingItem) { 464 pushNavTrackingEvent(trackingItem); 465 } 466 }); 467 }); 468 } 469 470 // Initialize dropdowns after page load 471 window.addEventListener("load", () => { 472 handleNavbarIntersection(); 473 handleOpenMenuMobile(); 474 handleCLickOnLevel1Button(); 475 handleClickOnLevel2Back(); 476 handleClickOnLevel2Item(); 477 handleClickOnLevel3Item(); 478 handleClickBackFromUpperLevels(); 479 handleMouseOver(); 480 handleMouseLeave(); 481 handleAddClickListenerOnBtn(); 482 addFallBackImage({ 483 selector: ".global-navigation__TC-image", 484 fallbackUrl: "/assets/profile_placeholder_medium.png" 485 }) 486 handleOpenContactModal(); 487 handleNavigationTracking(); 488 }); 489 490})()
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.