1(() => { 2 'use strict'; 3 const header = document.querySelector('[data-site-header]'); 4 if (!header || header.dataset.headerInitialized === 'true') return; 5 header.dataset.headerInitialized = 'true'; 6 header.querySelectorAll('[data-currency-action]').forEach(button => { 7 button.addEventListener('click', async () => { 8 const error = header.querySelector('[data-currency-error]'); 9 error.hidden = true; 10 button.disabled = true; 11 try { 12 const cookie = document.cookie.split('; ').find(value => value.startsWith('XSRF-TOKEN=')); 13 if (!cookie) throw new Error('Missing CSRF cookie'); 14 const response = await fetch(button.dataset.currencyAction, { 15 method: 'POST', credentials: 'same-origin', 16 headers: { 'Accept': 'application/json', 'X-XSRF-TOKEN': decodeURIComponent(cookie.slice('XSRF-TOKEN='.length)) } 17 }); 18 if (!response.ok) throw new Error('Preference update failed'); 19 const result = await response.json(); 20 const target = new URL(result.redirect, window.location.origin); 21 if (target.origin !== window.location.origin) throw new Error('Invalid return URL'); 22 window.location.assign(target.href); 23 } catch (_) { 24 error.hidden = false; 25 button.disabled = false; 26 } 27 }); 28 }); 29 const mobile = window.matchMedia('(max-width: 991px)'); 30 const hover = window.matchMedia('(hover: hover) and (pointer: fine)'); 31 const menuButton = header.querySelector('.site-header__menu-toggle'); 32 const navigation = header.querySelector('.site-header__navigation'); 33 const toggles = [...header.querySelectorAll('button[aria-controls]')].filter(button => button !== menuButton); 34 const close = button => { 35 button.setAttribute('aria-expanded', 'false'); 36 document.getElementById(button.getAttribute('aria-controls')).hidden = true; 37 }; 38 const closeDropdowns = () => toggles.forEach(close); 39 const setMenu = open => { 40 menuButton.setAttribute('aria-expanded', String(open)); 41 navigation.hidden = mobile.matches && !open; 42 document.body.classList.toggle('site-menu-open', mobile.matches && open); 43 if (!open) closeDropdowns(); 44 }; 45 const setDropdown = (button, open) => { 46 closeDropdowns(); 47 button.setAttribute('aria-expanded', String(open)); 48 document.getElementById(button.getAttribute('aria-controls')).hidden = !open; 49 }; 50 toggles.forEach(button => { 51 button.addEventListener('click', () => { 52 setDropdown(button, button.getAttribute('aria-expanded') !== 'true'); 53 }); 54 const dropdown = button.closest('.site-header__dropdown'); 55 dropdown.addEventListener('mouseenter', () => { 56 if (!mobile.matches && hover.matches) setDropdown(button, true); 57 }); 58 dropdown.addEventListener('mouseleave', () => { 59 if (!mobile.matches && hover.matches) close(button); 60 }); 61 }); 62 menuButton.addEventListener('click', () => setMenu(menuButton.getAttribute('aria-expanded') !== 'true')); 63 document.addEventListener('click', event => { 64 if (!header.contains(event.target)) setMenu(false); 65 }); 66 header.addEventListener('focusout', event => { 67 if (event.relatedTarget && !header.contains(event.relatedTarget)) setMenu(false); 68 }); 69 header.addEventListener('keydown', event => { 70 if (event.key === 'Escape') { 71 const openButton = toggles.find(button => button.getAttribute('aria-expanded') === 'true'); 72 if (openButton) { close(openButton); openButton.focus(); } 73 else { setMenu(false); menuButton.focus(); } 74 } 75 if (event.key === 'Tab' && mobile.matches && menuButton.getAttribute('aria-expanded') === 'true') { 76 const focusable = [...header.querySelectorAll('a, button')].filter(element => element.getClientRects().length);
77 const first = focusable[0], last = focusable[focusable.length - 1]; 78 if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last.focus(); } 79 else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); } 80 } 81 }); 82 mobile.addEventListener('change', () => setMenu(false)); 83 setMenu(false); 84})();
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.