1require(['domReady', 2 'droplet/EasyAccessNav/EasyAccessNav'], 3 function (domReady, easyAccessNav) { 4 'use strict'; 5 6 let windowResize = new CustomEvent('window:resize'); 7 let windowScroll = new CustomEvent('window:scroll'); 8 9 /** @var {Object} */ 10 const elements = {}; 11 12 /** @var {Object} */ 13 const storage = { 14 menuCount: 0, 15 menuWidths: [], 16 accountMenuIsSmall: 0, 17 menuWidthCalculationsRoundingDifferences: 2 18 }; 19 20 /** @var {Object} */ 21 const classNames = { 22 mainMenuMobile: 'site--mainMenuMobile', 23 }; 24 25 function init () { 26 // Create elements 27 elements.body = document.querySelector('body'); 28 elements.headerInner = document.querySelector('.header__content'); 29 elements.headerLogo = document.querySelectorAll('.header .--main .logoImage'); 30 elements.headerTools = document.querySelector('.header__tools'); 31 elements.navMain = document.querySelector('.nav.--main > ul'); 32 elements.navMeta = document.querySelector('.nav.--meta > ul'); 33 elements.navMainItems = document.querySelectorAll('.nav.--main > ul:first-of-type > li'); 34 elements.navAccount = document.querySelector('.nav.--account'); 35 36 let useCategoryAsPage = elements.body.dataset.categoryaspage === 'true'; 37 38 // Functions 39 easyAccessNav('#js-mainNavigation', { openOnHover: true, useCategoryAsPage: useCategoryAsPage }); 40 easyAccessNav('#js-metaNavigation', { openOnHover: true, useCategoryAsPage: useCategoryAsPage }); 41 easyAccessNav('#js-accountNavigation', { openOnHover: true, useCategoryAsPage: false }); 42 easyAccessNav('#js-mobileNavigation', { openOnHover: false, useCategoryAsPage: useCategoryAsPage, closeOnPageClick: false, openClass: 'open' }); 43 44 addLogoAspectRatioClass(); 45 addMainMenuMoreLink(); 46 storeInitialMainMenuState(); 47 handleOverflowingMainMenuItems(); 48 49 document.addEventListener('window:resize', handleOverflowingMainMenuItems); 50 51 /** fire custom events at least once */ 52 document.dispatchEvent(windowResize); 53 document.dispatchEvent(windowScroll); 54 } 55 56 /** 57 * Store width of various header items 58 * We store each individual menu-item's width so we know when we can put them back once the viewport becomes larger 59 */ 60 function storeInitialMainMenuState () { 61 let totalSpace = 0; 62 let i; 63 64 for (i = 0; elements.navMainItems.length > i; i++) { 65 totalSpace += elements.navMainItems[i].getBoundingClientRect().width; 66 storage.menuWidths.push(totalSpace); 67 storage.menuCount += 1; 68 } 69 70 if (elements.headerLogo) { 71 /** 72 * elements.headerLogo can contain two images (light and/or dark). 73 * One (or both) image(s) can be hidden, depending on the scroll position of the page. 74 * We only need to calculate the width of the *displayed* image. 75 */ 76 storage.headerLogoWidth = 0; 77 for (let i = 0; i < elements.headerLogo.length; i++) { 78 if (window.getComputedStyle(elements.headerLogo[i]).display === 'block') { 79 storage.headerLogoWidth = elements.headerLogo[i].getAttribute('width'); 80 } 81 } 82 } 83 storage.headerToolsWidth = elements.headerTools ? elements.headerTools.offsetWidth : 0; 84 storage.navMoreWidth = elements.navMore ? elements.navMore.offsetWidth : 0; 85 storage.minimumSpace = storage.menuCount >= 2 86 ? storage.menuWidths[1] + storage.navMoreWidth // 2 items + more link 87 : 300; 88 } 89 90 function addMainMenuMoreLink () { 91 let item = document.createElement('li'); 92 let link = document.createElement('a'); 93 let list = document.createElement('ul'); 94 95 item.classList.add('moreLink'); 96 link.classList.add('sub'); 97 link.setAttribute('href', ''); 98 link.append(document.createTextNode('More')); 99 item.append(link); 100 item.append(list); 101 102 elements.navMore = item; 103 elements.navMoreList = list; 104 if (elements.navMain) { 105 elements.navMain.append(item); 106 } 107 } 108 109 function makeAccountMenuSmaller () { 110 if (storage.accountMenuIsSmall === 0 && elements.navAccount) { 111 elements.navAccount.classList.add('--compact'); 112 storage.accountMenuIsSmall = 1; 113 storage.headerToolsWidth = elements.headerTools ? elements.headerTools.offsetWidth : 0; 114 handleOverflowingMainMenuItems(); 115 return true; 116 } 117 return false;
118 } 119 120 function handleOverflowingMainMenuItems () { 121 let headerStyles = elements.headerInner ? window.getComputedStyle(elements.headerInner) : {}; 122 let gapWidth = headerStyles ? headerStyles.columnGap.substring(0, headerStyles.columnGap.length - 2) * 2 : 0; 123 let showMore = storage.menuCount < elements.navMainItems.length; 124 let headerInnerWidth = elements.headerInner ? elements.headerInner.offsetWidth : 0; 125 let availableSpace = headerInnerWidth - storage.headerLogoWidth - storage.headerToolsWidth - gapWidth - storage.menuWidthCalculationsRoundingDifferences; 126 let navMoreSpace = showMore ? storage.navMoreWidth : 0; 127 let requiredSpace = Math.round(storage.menuWidths[storage.menuCount - 1]); 128 let desiredSpace = storage.menuWidths[storage.menuCount]; 129 130 /** At some point (< 768px) we always want the mobile menu */ 131 if (availableSpace < storage.minimumSpace || window.matchMedia('(max-width: 767px)').matches) { 132 if (makeAccountMenuSmaller()) { 133 return; 134 } 135 elements.body.classList.add(classNames.mainMenuMobile); 136 return; 137 } 138 139 elements.body.classList.remove(classNames.mainMenuMobile); 140 141 if (requiredSpace + navMoreSpace > availableSpace) { 142 if (makeAccountMenuSmaller()) { 143 return; 144 } 145 // There is not enough space, so move last item to hidden links 146 let lastElement = elements.navMainItems[storage.menuCount - 1]; 147 148 if (lastElement) { 149 elements.navMoreList.prepend(lastElement); 150 storage.menuCount -= 1; 151 handleOverflowingMainMenuItems(); 152 return; 153 } 154 } else if (elements.navMoreList.firstChild && availableSpace > desiredSpace + navMoreSpace) { 155 // There is enough space, move first item from hidden to visible links 156 elements.navMain.insertBefore(elements.navMoreList.firstChild, elements.navMore); 157 storage.menuCount += 1; 158 handleOverflowingMainMenuItems(); 159 return; 160 } 161 162 if (showMore) { 163 elements.navMore.style.display = null; 164 } else { 165 elements.navMore.style.display = 'none'; 166 } 167 } 168 169 /** 170 * Get aspect ratio for header image 171 */ 172 function addLogoAspectRatioClass () { 173 if (!elements.headerLogo) { 174 return; 175 } 176 177 let aspectRatio = elements.headerLogo.offsetWidth / elements.headerLogo.offsetHeight; 178 if (aspectRatio < .5) { 179 elements.headerLogo.parentNode.classList.add('--tall'); 180 } 181 } 182 183 domReady(init); 184 });
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.