1export class HeaderSP { 2 // #activeClass = 'is-active'; 3 #hiddenClass = 'is-hidden'; 4 #openClass = 'is-open'; 5 #scrollClass = 'is-scroll'; 6 #scrollLockClass = 'is-scrollLock'; 7 #bodyElement; 8 // #mainElement: HTMLElement | null; 9 #headerParent; 10 #layer2ndBtns; 11 #layer2ndBtnArray; 12 #layer3rdBtns; 13 #subMenus; 14 #subMenuArray; 15 #menu4th; 16 #menu4thArray; 17 #headerMain; 18 #hamburgerBtn; 19 #hamburgerBtnText; 20 #backBtns2nd; 21 #backBtns3rd; 22 #headerPrimary; 23 #headerSecondary; 24 #menu2nd; 25 #menu2ndArray; 26 #menu3rd; 27 #menu3rdArray; 28 #menu2ndBtns; 29 #headerFocusableElements; 30 #headerFocusableElementArray; 31 // #mainFirstFocusableElement: HTMLElement | null | undefined; 32 #headerLastFocusableEl; 33 constructor(root) { 34 this.#bodyElement = document.querySelector('body'); 35 // this.#mainElement = document.querySelector('main'); 36 this.#headerParent = root.querySelector('.fn-header'); 37 this.#headerMain = root.querySelector('.fn-header-main'); 38 this.#headerPrimary = root.querySelector('.fn-header-primary'); 39 this.#headerSecondary = root.querySelector('.fn-header-secondary'); 40 this.#layer2ndBtns = root.querySelectorAll('.fn-btn-2ndLayer'); 41 this.#layer2ndBtnArray = [...this.#layer2ndBtns]; 42 this.#layer3rdBtns = root.querySelectorAll('.fn-btn-3rdLayer'); 43 this.#subMenus = root.querySelectorAll('.fn-submenu'); 44 this.#subMenuArray = [...this.#subMenus]; 45 this.#menu4th = root.querySelectorAll('.fn-4th-menu'); 46 this.#menu4thArray = [...this.#menu4th]; 47 this.#hamburgerBtn = root.querySelector('.fn-hamburger-btn'); 48 this.#hamburgerBtnText = root.querySelector('.fn-hamburger-text'); 49 this.#backBtns2nd = root.querySelectorAll('.fn-btn-back2nd'); 50 this.#backBtns3rd = root.querySelectorAll('.fn-btn-back3rd'); 51 // get height 52 this.#menu2nd = root.querySelectorAll('.fn-2nd-menu'); 53 // miteigi 54 this.#menu2ndArray = [...this.#menu2nd]; 55 this.#menu3rd = root.querySelectorAll('.fn-3rd-menu'); 56 this.#menu3rdArray = [...this.#menu3rd]; 57 this.#menu2ndBtns = root.querySelectorAll('.fn-header-primary-btn'); 58 // this.#focusableElement = root.querySelectorAll('a:link, button'); 59 this.#headerFocusableElements = 60 this.#headerParent?.querySelectorAll('a:link, button'); 61 this.#headerFocusableElementArray = []; 62 if (this.#headerFocusableElements) { 63 this.#headerFocusableElementArray = [...this.#headerFocusableElements]; 64 this.#headerLastFocusableEl = this.#headerFocusableElementArray.at(-1); 65 } 66 // å®è¡ 67 this.#setClassByScrollY(); 68 this.#setMenusHidden(this.#subMenus); 69 this.#setMenusHidden(this.#menu4th); 70 this.#bindHeaderEventsSP(); 71 } 72 // SPæãããã¼å¦çã¾ã¨ã 73 #bindHeaderEventsSP() { 74 // ãã³ãã¼ã¬ã¼ãã¿ã³ 75 if (this.#hamburgerBtn === null) { 76 return; 77 } 78 this.#hamburgerBtn.setAttribute('aria-expanded', 'false'); 79 this.#hamburgerBtn.addEventListener('click', () => { 80 const isMenuOpen = this.#hamburgerBtn?.classList.contains(this.#openClass); 81 isMenuOpen ? this.#close() : this.#open(); 82 }); 83 // ããã¾ã§ï¼ãã³ãã¼ã¬ã¼ãã¿ã³ 84 // 第2é層ãã¿ã³ 85 this.#layer2ndBtns.forEach((btn, i) => { 86 btn.addEventListener('click', () => { 87 this.#onClickLayer2ndBtn(i); 88 }); 89 // æ»ããã¿ã³ã¯ãªã㯠â 第2éå±¤ã«æ»ãã»ãã©ã¼ã«ã¹æ»ã 90 this.#backBtns2nd[i]?.addEventListener('click', () => { 91 this.#subMenuArray[i]?.classList.add(this.#hiddenClass); 92 // 第2é層ãã¿ã³ããã¹ã¦è¡¨ç¤º 93 this.#menu2ndBtns.forEach((btn) => { 94 btn.classList.remove(this.#hiddenClass); 95 }); 96 btn.focus(); 97 }); 98 this.#setFocusOnBackBtn(this.#backBtns2nd, i); 99 }); 100 // ã¡ãã¥ã¼ãéãã¦ããæãæå¾ã®ãªã³ã¯ä¸ã§ã¿ããã¼ã¯ãªãã¯ã§ãã³ãã¼ã¬ã¼ã«ãã©ã¼ã«ã¹ããã 101 this.#headerLastFocusableEl?.addEventListener('keydown', (e) => { 102 const isMenuOpen = this.#hamburgerBtn?.classList.contains(this.#openClass); 103 if (isMenuOpen) { 104 if (e.key === 'Tab' && !e.shiftKey) { 105 e.preventDefault();
106 this.#hamburgerBtn?.focus(); 107 } 108 } 109 }); 110 const menuLinkArray2 = document.querySelectorAll('a:link, button'); 111 this.#layer3rdBtns.forEach((btn, i) => { 112 btn.addEventListener('click', () => { 113 this.#onClickLayer3rdBtn(i); 114 }); 115 // æ»ããã¿ã³ã¯ãªã㯠â 第3éå±¤ã«æ»ãã»ãã©ã¼ã«ã¹æ»ã 116 this.#backBtns3rd[i]?.addEventListener('click', () => { 117 this.#menu4thArray[i]?.classList.add(this.#hiddenClass); 118 this.#backBtns2nd.forEach((btn) => { 119 btn.classList.remove(this.#hiddenClass); 120 }); 121 menuLinkArray2.forEach((el) => { 122 el.classList.remove(this.#hiddenClass); 123 }); 124 btn.focus(); 125 }); 126 this.#setFocusOnBackBtn(this.#backBtns3rd, i); 127 }); 128 // é«ãåå¾ã¨ã¹ã¿ã¤ã«è¨å® 129 if (this.#headerSecondary === null || this.#headerParent === null) { 130 return; 131 } 132 const secondaryMenuHeight = this.#headerSecondary.clientHeight; 133 const headerHeight = this.#headerParent.clientHeight; 134 this.#headerPrimary?.style.setProperty('--secondary-menu-height', `${secondaryMenuHeight}px`); 135 this.#headerPrimary?.style.setProperty('--header-height', `${headerHeight}px`); 136 this.#menu3rdArray.forEach((el) => { 137 el.style.setProperty('--secondary-menu-height', `${secondaryMenuHeight}px`); 138 el.style.setProperty('--header-height', `${headerHeight}px`); 139 }); 140 } 141 /** 142 * æ»ããã¿ã³ä¸ã§ã¿ããã¼ â ãã³ãã¼ã¬ã¼ã¡ãã¥ã¼ã«ãã©ã¼ã«ã¹ç§»å 143 * @param btns æ»ããã¿ã³ã®é å 144 * @param i å¯¾è±¡ã®æ»ããã¿ã³ã®index 145 */ 146 #setFocusOnBackBtn(btns, i) { 147 btns[i]?.addEventListener('keydown', (e) => { 148 if (e.key === 'Tab' && e.shiftKey) { 149 e.preventDefault(); 150 this.#hamburgerBtn?.focus(); 151 } 152 }); 153 } 154 /** 155 * ä¸å±¤ã¡ãã¥ã¼ã®è¡¨ç¤º 156 * @param layers ä¸å±¤ã¡ãã¥ã¼ãªã¹ã 157 */ 158 #setMenusHidden(layers) { 159 layers.forEach((layer) => { 160 layer.classList.add(this.#hiddenClass); 161 }); 162 } 163 /** 164 * 第2é層ãã¿ã³ã®ã¯ãªãã¯ã¤ãã³ã 165 * @param i 鏿ããããã¿ã³ã®index 166 */ 167 #onClickLayer2ndBtn(i) { 168 this.#subMenuArray[i]?.classList.remove(this.#hiddenClass); 169 this.#menu2ndBtns.forEach((btn) => { 170 btn.classList.add(this.#hiddenClass); 171 }); 172 this.#backBtns2nd[i]?.focus(); 173 const menu3rdFocusableElementArray = [ 174 ...(this.#menu3rdArray[i]?.querySelectorAll('.fn-3rd-link') ?? []), 175 ]; 176 const menu3rdLastFocusableEl = menu3rdFocusableElementArray.at(-1); 177 menu3rdLastFocusableEl?.addEventListener('keydown', (e) => { 178 if (e.key === 'Tab' && !e.shiftKey) { 179 e.preventDefault(); 180 this.#backBtns2nd[i]?.focus(); 181 } 182 }); 183 // height 184 const imageHeight = this.#menu2ndArray[i]?.clientHeight; 185 this.#menu3rdArray[i]?.style.setProperty('--2ndLayer-image-height', `${imageHeight}px`); 186 } 187 // 第3é層ãã¿ã³ã®ã¯ãªãã¯ã¤ãã³ã 188 #onClickLayer3rdBtn(i) { 189 this.#backBtns3rd[i]?.classList.remove(this.#hiddenClass); 190 this.#menu4thArray[i]?.classList.remove(this.#hiddenClass); 191 this.#backBtns2nd.forEach((btn) => { 192 btn.classList.add(this.#hiddenClass); 193 }); 194 const menuLinkArray2 = document.querySelectorAll('.fn-menu-link'); 195 menuLinkArray2.forEach((el) => { 196 el.classList.add(this.#hiddenClass); 197 }); 198 this.#backBtns3rd[i]?.focus(); 199 // æå¾ã®ã¡ãã¥ã¼ä¸ã§tabãã¼ â æ»ããã¿ã³ã«ãã©ã¼ã«ã¹ 200 const menu4thFocusableElementArray = [ 201 ...(this.#menu4thArray[i]?.querySelectorAll('a:link, button') ?? []), 202 ]; 203 const menu4thLastFocusableEl = menu4thFocusableElementArray.at(-1); 204 menu4thLastFocusableEl?.addEventListener('keydown', (e) => { 205 if (e.key === 'Tab' && !e.shiftKey) { 206 e.preventDefault();
207 this.#backBtns3rd[i]?.focus(); 208 } 209 }); 210 } 211 /** 212 * ãã³ãã¼ã¬ã¼ã¡ãã¥ã¼éãã 213 */ 214 #close() { 215 this.#bodyElement?.classList.remove(this.#scrollLockClass); 216 this.#headerParent?.classList.remove(this.#openClass); 217 this.#headerMain?.classList.remove(this.#openClass); 218 this.#hamburgerBtn?.classList.remove(this.#openClass); 219 this.#hamburgerBtn?.setAttribute('aria-expanded', 'false'); 220 if (this.#hamburgerBtnText) { 221 this.#hamburgerBtnText.textContent = 'ã¡ãã¥ã¼ãéã'; 222 } 223 } 224 /** 225 * ãã³ãã¼ã¬ã¼ã¡ãã¥ã¼éã 226 */ 227 #open() { 228 this.#bodyElement?.classList.add(this.#scrollLockClass); 229 this.#headerParent?.classList.add(this.#openClass); 230 this.#headerMain?.classList.add(this.#openClass); 231 this.#hamburgerBtn?.classList.add(this.#openClass); 232 this.#hamburgerBtn?.setAttribute('aria-expanded', 'true'); 233 if (this.#hamburgerBtnText) { 234 this.#hamburgerBtnText.textContent = 'ã¡ãã¥ã¼ãéãã'; 235 } 236 this.#hamburgerBtn?.blur(); 237 this.#layer2ndBtnArray[0]?.focus(); 238 } 239 /** 240 * ç»é¢ã¹ã¯ãã¼ã«ã«ããã¯ã©ã¹ä»ä¸ï¼ãããã®ã¿ï¼ 241 */ 242 #setClassByScrollY() { 243 let lastScrollY = window.scrollY; 244 window.addEventListener('scroll', () => { 245 const currentY = window.scrollY; 246 if (this.#headerParent) { 247 this.#headerParent.classList.toggle(this.#scrollClass, window.scrollY > 72); 248 // ãããã¼åã¹ã¯ãã¼ã«ä»¥ä¸ã§æ©è½ããã 249 if (currentY >= 72) { 250 if (currentY > lastScrollY) { 251 // ä¸ã«ã¹ã¯ãã¼ã« â é表示 252 this.#headerParent.classList.add('is-none'); 253 } 254 else { 255 // ä¸ã«ã¹ã¯ãã¼ã« â 表示 256 this.#headerParent.classList.remove('is-none'); 257 } 258 } 259 } 260 lastScrollY = currentY; 261 }); 262 } 263}
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.