1export class HeaderPC { 2 #activeClass = 'is-active'; 3 #hiddenClass = 'is-hidden'; 4 #openClass = 'is-open'; 5 #scrollClass = 'is-scroll'; 6 #scrollLockClass = 'is-scrollLock'; 7 #cssVariablesName = '--header-height'; 8 #htmlElement; 9 #bodyElement; 10 #mainElement; 11 #headerParent; 12 #layer2ndBtns; 13 #layer3rdBtns; 14 #dropdownMenus; 15 #dropdownMenuArray; 16 #dropdownMenuCloseBtn = '.fn-dropdown-closeBtn'; 17 #menu4th; 18 #menu4thArray; 19 #backdrop; 20 #menuWrap; 21 #menuWrapHeight; 22 #headerFocusableElements; 23 #headerFocusableElementArray; 24 #mainFirstFocusableElement; 25 #headerlastFocusableEl; 26 constructor(root) { 27 this.#htmlElement = document.querySelector('html'); 28 this.#bodyElement = document.querySelector('body'); 29 this.#mainElement = document.querySelector('main'); 30 this.#headerParent = root.querySelector('.fn-header'); 31 this.#menuWrap = root.querySelector('.fn-menu-wrap'); 32 this.#menuWrapHeight = 0; 33 this.#layer2ndBtns = root.querySelectorAll('.fn-btn-2ndLayer'); 34 this.#dropdownMenus = root.querySelectorAll('.fn-dropdown'); 35 this.#dropdownMenuArray = [...this.#dropdownMenus]; 36 this.#layer3rdBtns = root.querySelectorAll('.fn-btn-3rdLayer'); 37 this.#menu4th = root.querySelectorAll('.fn-4th-menu'); 38 this.#menu4thArray = [...this.#menu4th]; 39 this.#backdrop = root.querySelector('.fn-backdrop'); 40 this.#headerFocusableElements = 41 this.#headerParent?.querySelectorAll('a:link, button'); 42 this.#headerFocusableElementArray = []; 43 this.#mainFirstFocusableElement = 44 this.#mainElement?.querySelector('a:link, button'); 45 if (this.#headerFocusableElements) { 46 this.#headerFocusableElementArray = [...this.#headerFocusableElements]; 47 this.#headerlastFocusableEl = this.#headerFocusableElementArray.at(-1); 48 } 49 // å®è¡ 50 this.#setClassByScrollY(); 51 this.#setMenusHidden(this.#dropdownMenus); 52 this.#setMenusHidden(this.#menu4th); 53 this.#bindHeaderEventsPC(); 54 } 55 /** PCæãããã¼å¦çã¾ã¨ã */ 56 #bindHeaderEventsPC() { 57 this.#updataHeaderHeight(); 58 this.#layer2ndBtns.forEach((btn, i) => { 59 btn.addEventListener('click', () => { 60 this.#onClickLayer2ndBtn(btn, i); 61 if (this.#headerlastFocusableEl && this.#mainFirstFocusableElement) { 62 this.#setFocus(this.#headerlastFocusableEl, this.#mainFirstFocusableElement, btn, i); 63 } 64 }); 65 this.#closeDropdownOnBackdrop(btn, i); 66 }); 67 this.#layer3rdBtns.forEach((btn, i) => { 68 btn.addEventListener('click', () => { 69 this.#onClickLayer3rdBtn(btn, i); 70 }); 71 }); 72 } 73 /** ãããã¼ã®é«ããæ´æ° */ 74 #updataHeaderHeight() { 75 if (this.#menuWrap) { 76 this.#menuWrapHeight = this.#menuWrap.clientHeight; 77 this.#htmlElement?.style.setProperty(this.#cssVariablesName, `${this.#menuWrapHeight}px`); 78 } 79 // é«ããå¤ãã£ããããããã£æ´æ° 80 const resizeObserver = new ResizeObserver((entries) => { 81 const entry = entries[0]; 82 if (!entry) { 83 return; 84 } 85 this.#menuWrapHeight = entry.borderBoxSize[0]?.blockSize; 86 this.#htmlElement?.style.setProperty(this.#cssVariablesName, `${this.#menuWrapHeight}px`); 87 }); 88 if (this.#menuWrap) { 89 resizeObserver.observe(this.#menuWrap); 90 } 91 } 92 /** 93 * ãã©ã¼ã«ã¹å¶å¾¡ 94 * @param lastEl headerå ã§ãã©ã¼ã«ã¹å¯è½ãªæå¾ã®è¦ç´ 95 * @param firstEl mianå ã§ãã©ã¼ã«ã¹å¯è½ãªæåã®è¦ç´ 96 * @param selectedBtn ã¢ã¯ãã£ãã®ç¬¬2é層ãã¿ã³ 97 * @param i ã¢ã¯ãã£ãã®ãã¿ã³ã®index 98 */ 99 #setFocus(lastEl, firstEl, selectedBtn, i) { 100 lastEl.addEventListener('keydown', (e) => { 101 if (e.key === 'Tab' && !e.shiftKey) { 102 e.preventDefault(); 103 this.#closeDropdown(selectedBtn, i); 104 lastEl?.blur();
105 firstEl.focus(); 106 } 107 }); 108 } 109 /** 110 * 第2é層ãã¿ã³ã®ã¯ãªãã¯ã¤ãã³ã 111 * @param selectedBtn 鏿ããããã¿ã³ 112 * @param i 鏿ããããã¿ã³ã®index 113 */ 114 #onClickLayer2ndBtn(selectedBtn, i) { 115 this.#bodyElement?.classList.add(this.#scrollLockClass); 116 this.#headerParent?.classList.add(this.#openClass); 117 if (this.#backdrop) { 118 this.#backdrop.classList.remove(this.#hiddenClass); 119 } 120 this.#layer3rdBtns.forEach((btn) => { 121 this.#setBtnInactive(btn); 122 }); 123 this.#setMenusHidden(this.#menu4th); 124 this.#setBtnsState(this.#layer2ndBtns, selectedBtn); 125 this.#dropdownMenuArray[i]?.classList.remove(this.#hiddenClass); 126 this.#bindCloseDropdown(selectedBtn, i); 127 } 128 /** ãããããã¦ã³ãéãã */ 129 #bindCloseDropdown(selectedBtn, i) { 130 const closeBtn = this.#dropdownMenuArray[i]?.querySelector(this.#dropdownMenuCloseBtn); 131 if (closeBtn) { 132 closeBtn.addEventListener('click', () => { 133 this.#closeDropdown(selectedBtn, i); 134 }); 135 } 136 } 137 /** 138 * 第3é層ãã¿ã³ã®ã¯ãªãã¯ã¤ãã³ã 139 * @param selectedBtn 鏿ããããã¿ã³ 140 * @param i 鏿ããããã¿ã³ã®index 141 */ 142 #onClickLayer3rdBtn(selectedBtn, i) { 143 this.#setBtnsState(this.#layer3rdBtns, selectedBtn); 144 this.#setMenusHidden(this.#menu4th); 145 this.#menu4thArray[i]?.classList.remove(this.#hiddenClass); 146 } 147 /** 148 * ã¡ãã¥ã¼ãé表示ã«ãã 149 * @param targets 150 */ 151 #setMenusHidden(targets) { 152 targets.forEach((target) => { 153 target.classList.add(this.#hiddenClass); 154 }); 155 } 156 /** 157 * 鏿ããããã¿ã³ãã¢ã¯ãã£ãã«ãã 158 * @param btns ãã¿ã³ãªã¹ã 159 * @param selecedBtn ã¢ã¯ãã£ãã«ãããã¿ã³ 160 */ 161 #setBtnsState(btns, selecedBtn) { 162 btns.forEach((btn) => { 163 this.#setBtnInactive(btn); 164 }); 165 this.#setBtnActive(selecedBtn); 166 } 167 /** 168 * ãã¿ã³ã®ã¢ã¯ãã£ããã»ãã 169 * @param btn ã¡ãã¥ã¼å±éãããã¿ã³ 170 */ 171 #setBtnActive(btn) { 172 btn.classList.add(this.#activeClass); 173 btn.setAttribute('aria-expanded', 'true'); 174 } 175 /** 176 * ãã¿ã³ã®éã¢ã¯ãã£ããã»ãã 177 * @param btn 178 */ 179 #setBtnInactive(btn) { 180 btn.classList.remove(this.#activeClass); 181 btn.setAttribute('aria-expanded', 'false'); 182 } 183 /** 184 * ããã¯ããããã«ãããããããã¦ã³ã®ã¯ãã¼ãº 185 * @param selectedBtn ã¢ã¯ãã£ãã®ãã¿ã³ 186 * @param i 表示ä¸ãããããã¦ã³ã®index 187 */ 188 #closeDropdownOnBackdrop(selectedBtn, i) { 189 this.#backdrop?.removeEventListener('click', () => { 190 this.#closeDropdown(selectedBtn, i); 191 }); 192 this.#backdrop?.addEventListener('click', () => { 193 this.#closeDropdown(selectedBtn, i); 194 }); 195 } 196 /** 197 * ãããããã¦ã³ã®ã¯ãã¼ãº 198 * @param selectedBtn ã¢ã¯ãã£ãã®ãã¿ã³ 199 * @param i 表示ä¸ãããããã¦ã³ã®index 200 */ 201 #closeDropdown(selectedBtn, i) { 202 this.#bodyElement?.classList.remove(this.#scrollLockClass); 203 this.#headerParent?.classList.remove(this.#openClass); 204 this.#setBtnInactive(selectedBtn); 205 this.#dropdownMenuArray[i]?.classList.add(this.#hiddenClass); 206 this.#backdrop?.classList.add(this.#hiddenClass); 207 } 208 /** 209 * ç»é¢ã¹ã¯ãã¼ã«ã«ããã¯ã©ã¹ä»ä¸ï¼ãããã®ã¿ï¼ 210 */ 211 #setClassByScrollY() { 212 window.addEventListener('scroll', () => { 213 if (this.#headerParent) { 214 this.#headerParent.classList.toggle(this.#scrollClass, window.scrollY > 0); 215 } 216 }); 217 } 218}
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.