1import { LanguageSelector } from '../'; 2export class MainNavigation { 3 /** 4 * Creates a new instance of the MainNavigation Class 5 * @param {HTMLElement} element MainNavigation DOM Element 6 */ 7 constructor(element) { 8 this.element = element; 9 10 this._refs = { 11 el: element, 12 body: document.querySelector('body'), 13 header: document.querySelector('#header'), 14 languageSelector: element.querySelector('.language-selector'), 15 mainList: element.querySelector('.main-navigation__main-list'), 16 ctaList: element.querySelector('.main-navigation__cta-list'), 17 navItems: Array.from(element.querySelectorAll('.main-navigation__item > a')), 18 subNavItems: Array.from(element.querySelectorAll('.main-navigation__menu__sub-item a')), 19 toggl: element.querySelector('.main-navigation__main-menu-toggler') 20 }; 21 22 this._props = { 23 visible: false, 24 } 25 26 // Top notice-handling 27 const oTopnotice = this._refs.header.querySelector('.top-notice'); 28 if(oTopnotice !== null) { 29 this._refs.header.classList.add('header-top-notice'); 30 } 31 32 // Language selector 33 if(this._refs.languageSelector !== null) { 34 this.lang = new LanguageSelector(this._refs.languageSelector); 35 } 36 37 // Event handlings 38 this._refs.navItems.forEach(item => { 39 // WCAG 40 item.addEventListener('keydown', this._onMainNavigationItemKeyDown.bind(this)); 41 42 ["click", "keydown"].forEach((event) => 43 item.addEventListener(event, () => 44 localStorage.removeItem("scrollposition") 45 ) 46 ); 47 48 // Caret bindings 49 const oCaret = item.parentElement.querySelector('.main-navigation__caret'); 50 if(oCaret !== null) { 51 oCaret.addEventListener('click', this._onMainNavigationItemCaretClick.bind(this)); 52 } 53 }); 54 55 this._refs.subNavItems.forEach(item => item.addEventListener('keydown', this._onSubNavigationItemKeyDown.bind(this))); 56 57 if(this._refs.toggl !== null) { 58 this._refs.toggl.addEventListener('click', this._onTogglClick.bind(this)); 59 } 60 } 61 62 /** 63 * Handler for WCAG implementation on sub-navigational items 64 * @param {Event} e - Event interface 65 */ 66 _onSubNavigationItemKeyDown (e = Event) { 67 const 68 oTarget = e.target, 69 oMainMenuItem = oTarget.closest('.main-navigation__item'), 70 oMainMenuItemLink = oMainMenuItem.children[0]; 71 72 switch(e.keyCode) { 73 case 27: // ESC 74 oMainMenuItem.classList.remove('is-current-page'); 75 oMainMenuItemLink.setAttribute('aria-expanded', 'false'); 76 77 this._refs.subNavItems.forEach(item => item.setAttribute('tabindex', '-1')) 78 79 oMainMenuItemLink.focus(); 80 break; 81 } 82 } 83 84 /** 85 * Handler for WCAG implementation on main navigational items 86 * @param {Event} e - Event Interface 87 */ 88 _onMainNavigationItemKeyDown (e = Event) { 89 const 90 // Classes 91 strItemActiveClass = 'is-current-page', 92 // Elements 93 oTarget = e.target, 94 oParent = oTarget.parentElement, 95 oSubmenuItems = Array.from(oParent.querySelectorAll('.main-navigation__menu__sub-item a')), 96 // States 97 isToggled = oParent.classList.contains(strItemActiveClass); 98 99 switch(e.keyCode) { 100 case 32: // Space 101 // Element has a submenu 102 e.preventDefault(); 103 104 // if item has no sub menu, go to page instead 105 if(!oSubmenuItems.length) { 106 window.location.href = oTarget.getAttribute('href'); 107 return true; 108 } 109 110 // Reset states
111 this._refs.navItems.forEach(x => x.parentElement.classList.remove(strItemActiveClass)); 112 113 // Toggle active state 114 if(isToggled) { 115 oTarget.parentElement.classList.remove(strItemActiveClass); 116 oTarget.setAttribute('aria-expanded', 'false'); 117 oSubmenuItems.forEach(x => { 118 x.setAttribute('tabindex', '-1'); 119 }); 120 } else { 121 oTarget.parentElement.classList.add(strItemActiveClass); 122 oTarget.setAttribute('aria-expanded', 'true'); 123 124 // Set children as tabbable 125 oSubmenuItems.forEach((x, i) => { 126 if(i === 0) { 127 x.focus(); 128 } 129 130 x.setAttribute('tabindex', '0'); 131 }); 132 } 133 break; 134 } 135 } 136 137 /** 138 * Handler for toggling menus on mobile devices 139 * @param {Event} e - Event Interface 140 */ 141 _onMainNavigationItemCaretClick (e = Event) { 142 const 143 oElement = e.target, 144 oMainElement = oElement.parentElement, 145 // Classnames 146 strClassMenuIsExposed = 'secondary-level-is-expanded', 147 strClassCurrentPage = 'is-current-page'; 148 149 if (oMainElement.classList.contains(strClassMenuIsExposed)) { 150 oMainElement.classList.remove(strClassMenuIsExposed); 151 oMainElement.classList.remove(strClassCurrentPage); 152 } else { 153 this._refs.navItems.forEach(item => { 154 item.parentElement.classList.remove(strClassMenuIsExposed); 155 item.parentElement.classList.remove(strClassCurrentPage); 156 }); 157 oMainElement.classList.add(strClassMenuIsExposed); 158 } 159 } 160 161 /** 162 * Handler for helping toggling between visible/non-visible on mobile devices 163 */ 164 _onTogglClick () { 165 const 166 strMenuClassVisibility = 'main-list-is-visible', 167 strBodyClassMenuVisibility = 'main-navigation-is-visible'; 168 169 if(this._props.visible) { 170 this._refs.body.classList.remove(strBodyClassMenuVisibility); 171 this._refs.el.classList.remove(strMenuClassVisibility); 172 } else { 173 this._refs.body.classList.add(strBodyClassMenuVisibility); 174 this._refs.el.classList.add(strMenuClassVisibility); 175 } 176 177 this._props.visible = !this._props.visible; 178 } 179}
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.