1"use strict"; 2 3// ìëì° ì¬ì´ì¦ ì²´í¬ 4const windowSize = { 5 winSize: null, 6 breakPoint: 1024, 7 8 setWinSize() { 9 this.winSize = window.innerWidth >= this.breakPoint ? "pc" : "mob"; 10 }, 11 12 getWinSize() { 13 return this.winSize; 14 }, 15}; 16 17// ì¤í¬ë¡¤ ë°©í¥ ì²´í¬ 18const scrollManager = { 19 _scrollY: 0, 20 _scrollH: 0, 21 _lastScrollY: 0, 22 23 updateScrollValues() { 24 this._scrollY = window.scrollY; 25 this._scrollH = document.body.scrollHeight; 26 }, 27 28 handleScrollDirection() { 29 const $wrap = document.querySelector("#wrap"); 30 if ($wrap) { 31 const _conOffsetTop = document.querySelector("#container").offsetTop; 32 const _scrollY = window.scrollY; 33 const _scrollDown = _scrollY > this._lastScrollY; 34 const _scrollUp = _scrollY < this._lastScrollY; 35 36 if (_scrollY > _conOffsetTop + 50 && _scrollDown) { 37 $wrap.classList.add("scroll-down"); 38 $wrap.classList.remove("scroll-up"); 39 } else if (_scrollY > _conOffsetTop + 50 && _scrollUp) { 40 $wrap.classList.add("scroll-up"); 41 $wrap.classList.remove("scroll-down"); 42 } else { 43 $wrap.classList.remove("scroll-down", "scroll-up"); 44 } 45 46 this._lastScrollY = _scrollY; 47 } 48 }, 49 50 getscrollY() { 51 return this._scrollY; 52 }, 53 54 getScrollH() { 55 return this._scrollH; 56 }, 57}; 58 59// common 60const common = { 61 focusTrap(trap) { 62 const focusableElements = trap.querySelectorAll(`a, button, [tabindex="0"], input, textarea, select`); 63 64 if (!focusableElements.length) return; 65 66 const firstFocusableElement = focusableElements[0]; 67 const lastFocusableElement = focusableElements[focusableElements.length - 1]; 68 69 trap.addEventListener("keydown", (event) => { 70 if (event.key === "Tab") { 71 if (event.shiftKey && document.activeElement === firstFocusableElement) { 72 event.preventDefault(); 73 lastFocusableElement.focus(); 74 } else if (!event.shiftKey && document.activeElement === lastFocusableElement) { 75 event.preventDefault(); 76 firstFocusableElement.focus(); 77 // ëª¨ë¬ ì¤í í 첫 ì´ì ìë°©í¥ ì ì´(modal-contentê° ì²«ì´ì ì´ ìëë©´ ì¬ì© ìí´ë ë¨) 78 } else if (event.key === "Tab" && event.shiftKey && document.activeElement === trap) { 79 event.preventDefault(); 80 lastFocusableElement.focus(); 81 } 82 } 83 }); 84 }, 85}; 86 87/*** * krds_mainMenuPC * ***/ 88const krds_mainMenuPC = { 89 init() { 90 const gnbMenu = document.querySelector(".krds-main-menu:not(.sample) .gnb-menu"); 91 92 if (!gnbMenu) return; 93 94 // gnb ìì±ì¤ì 95 gnbMenu.setAttribute("aria-label", "ë©ì¸ ë©ë´"); 96 97 // dimed ìì를 ì¤ì , 기존 dimedê° ìì ê²½ì° ìì± 98 this.backdrop = document.querySelector(".gnb-backdrop") || this.createBackdrop(); 99 100 // 주 ë©ë´ ë° ìë¸ ë©ë´ì í¸ë¦¬ê±°ë¥¼ ì¤ì íê³ , ê° í¸ë¦¬ê±°ì ì´ë²¤í¸ë¥¼ ì°ê²° 101 const mainTriggers = gnbMenu.querySelectorAll(".gnb-main-trigger"); 102 const subTriggers = gnbMenu.querySelectorAll(".gnb-sub-trigger:not(.is-link)"); 103 mainTriggers.forEach((mainTrigger) => this.setupMainTrigger(mainTrigger)); 104 this.attachEvents(mainTriggers, subTriggers); 105 this.setupKeyboardNavigation(mainTriggers); 106 }, 107 setupMainTrigger(mainTrigger) { 108 const toggleWrap = mainTrigger.nextElementSibling; 109 if (toggleWrap) { 110 const uniqueIdx = `gnb-main-menu-${Math.random().toString(36).substring(2, 9)}`; 111 mainTrigger.setAttribute("aria-controls", uniqueIdx); 112 mainTrigger.setAttribute("aria-expanded", "false"); 113 mainTrigger.setAttribute("aria-haspopup", "true"); 114 toggleWrap.setAttribute("id", uniqueIdx); 115 116 // íì ë©ë´ ì¤ì 117 const mainList = toggleWrap.querySelector(".gnb-main-list"); 118 if (mainList?.getAttribute("data-has-submenu") === "true") { 119 const subTriggers = mainList.querySelectorAll(".gnb-sub-trigger"); 120 subTriggers.forEach((subTrigger) => this.setupSubTrigger(subTrigger)); 121 if (subTriggers.length >
121 0 && !subTriggers[0].classList.contains("is-link")) { 122 subTriggers[0].classList.add("active"); 123 subTriggers[0].setAttribute("aria-expanded", "true"); 124 subTriggers[0].nextElementSibling?.classList.add("active"); 125 } 126 } 127 } 128 }, 129 setupSubTrigger(subTrigger) { 130 const hasMenu = subTrigger.nextElementSibling; 131 if (hasMenu) { 132 const uniqueIdx = `gnb-sub-menu-${Math.random().toString(36).substring(2, 9)}`; 133 subTrigger.setAttribute("aria-controls", uniqueIdx); 134 subTrigger.setAttribute("aria-expanded", "false"); 135 subTrigger.setAttribute("aria-haspopup", "true"); 136 hasMenu.setAttribute("id", uniqueIdx); 137 } 138 }, 139 toggleMainMenu(mainTrigger) { 140 const isActive = mainTrigger.classList.contains("active"); 141 const isDropDown = mainTrigger.classList.contains("is-dropdown"); 142 if (!isActive && mainTrigger.nextElementSibling) { 143 this.resetMainMenu(); 144 mainTrigger.setAttribute("aria-expanded", "true"); 145 mainTrigger.classList.add("active"); 146 mainTrigger.nextElementSibling.classList.add("is-open"); 147 if (!isDropDown) { 148 this.toggleBackdrop(true); 149 this.toggleScrollbar(true); 150 this.adjustSubMenuHeight(mainTrigger.nextElementSibling.querySelector(".gnb-main-list")); 151 } 152 } else { 153 this.closeMainMenu(); 154 } 155 }, 156 toggleSubMenu(subTrigger) { 157 const otherSubTriggers = subTrigger.closest("ul").querySelectorAll(".gnb-sub-trigger:not(.is-link)"); 158 otherSubTriggers.forEach((trigger) => { 159 trigger.classList.remove("active"); 160 trigger.setAttribute("aria-expanded", "false"); 161 trigger.nextElementSibling?.classList.remove("active"); 162 }); 163 subTrigger.classList.add("active"); 164 subTrigger.setAttribute("aria-expanded", "true"); 165 subTrigger.nextElementSibling?.classList.add("active"); 166 this.adjustSubMenuHeight(subTrigger.closest(".gnb-main-list")); 167 }, 168 createBackdrop() { 169 const backdrop = document.createElement("div"); 170 backdrop.classList.add("gnb-backdrop"); 171 document.body.appendChild(backdrop); 172 // backdrop.style.display = "none"; 173 return backdrop; 174 }, 175 toggleBackdrop(isOpen) { 176 this.backdrop?.classList.toggle("active", isOpen); 177 document.body.classList.toggle("is-gnb-web", isOpen); 178 // this.backdrop.style.display = isOpen ? "block" : "none"; 179 }, 180 adjustSubMenuHeight(target) { 181 // ìë¸ ë©ë´ ëì´ë¥¼ íì± ë©ë´ì ë§ì¶° ì¡°ì 182 const activeSubList = target.querySelector(".gnb-sub-list.active"); 183 const height = activeSubList?.scrollHeight || 0; 184 target.style.minHeight = `${height}px`; 185 }, 186 toggleScrollbar(isEnabled) { 187 const isScrollNeeded = document.body.scrollHeight > window.innerHeight; 188 document.body.classList.toggle("hasScrollY", isEnabled && isScrollNeeded); 189 }, 190 resetMainMenu() { 191 document.querySelectorAll(".krds-main-menu:not(.sample) .gnb-main-trigger:not(.is-link)").forEach((mainTrigger) => { 192 mainTrigger.classList.remove("active"); 193 mainTrigger.setAttribute("aria-expanded", "false"); 194 }); 195 document.querySelectorAll(".krds-main-menu:not(.sample) .gnb-toggle-wrap").forEach((toggleWrap) => { 196 toggleWrap.classList.remove("is-open"); 197 }); 198 }, 199 closeMainMenu() { 200 this.resetMainMenu(); 201 this.toggleBackdrop(false); 202 this.toggleScrollbar(false); 203 }, 204 attachEvents(mainTriggers, subTriggers) { 205 // krds-main-menu ì¸ë¶ í´ë¦ì ë«ê¸° 206 document.addEventListener("click", ({ target }) => { 207 if (!target.closest(".krds-main-menu")) this.closeMainMenu(); 208 }); 209 210 // ë°±ëë¡ í´ë¦ ì ë©ë´ ë«ê¸° 211 // this.backdrop.addEventListener("click", () => this.closeMainMenu()); 212 213 // ESC í¤ë¥¼ ëë¬ ë©ë´ë¥¼ ë«ê±°ë, TAB í¤ë¡ ì´ì ì´ ë©ë´ ì¸ë¶ë¡ ì´ëíì ë ë©ë´ ë«ê¸° 214 document.addEventListener("keyup", (event) => { 215 if (event.code === "Escape" || !event.target.closest(".krds-main-menu")) { 216 this.closeMainMenu(); 217 } 218 }); 219 220 // ë©ì¸ ë©ë´ í¸ë¦¬ê±° ì¤ì
221 mainTriggers.forEach((mainTrigger) => { 222 mainTrigger.addEventListener("click", () => this.toggleMainMenu(mainTrigger)); 223 }); 224 225 // ìë¸ ë©ë´ í¸ë¦¬ê±° ì¤ì 226 subTriggers.forEach((subTrigger) => { 227 subTrigger.addEventListener("click", () => this.toggleSubMenu(subTrigger)); 228 }); 229 }, 230 setupKeyboardNavigation(mainTriggers) { 231 const focusMenuItem = (element) => { 232 if (element) { 233 element.focus(); 234 } 235 }; 236 const findFocusableElement = (element, direction) => { 237 const sibling = direction === "next" ? "nextElementSibling" : "previousElementSibling"; 238 const parent = element.closest("li")?.[sibling]; 239 return parent ? parent.querySelector("[data-trigger]") : null; 240 }; 241 // Home, End, ë°©í¥í¤ë¥¼ íµí´ ë©ë´ í목 ê°ì ì´ëì ì²ë¦¬ 242 document.addEventListener("keydown", (event) => { 243 const target = event.target; 244 if (target.getAttribute("data-trigger")) { 245 switch (event.key) { 246 case "Home": 247 event.preventDefault(); 248 focusMenuItem(mainTriggers[0]); 249 break; 250 case "End": 251 event.preventDefault(); 252 focusMenuItem(mainTriggers[mainTriggers.length - 1]); 253 break; 254 case "ArrowRight": 255 case "ArrowDown": 256 event.preventDefault(); 257 const nextElement = findFocusableElement(target, "next"); 258 focusMenuItem(nextElement); 259 break; 260 case "ArrowLeft": 261 case "ArrowUp": 262 event.preventDefault(); 263 const previousElement = findFocusableElement(target, "prev"); 264 focusMenuItem(previousElement); 265 break; 266 default: 267 break; 268 } 269 } 270 }); 271 }, 272}; 273 274/*** * krds_mainMenuMobile * ***/ 275const krds_mainMenuMobile = { 276 init() { 277 const mobileGnb = document.querySelector(".krds-main-menu-mobile:not(.sample)"); 278 279 if (!mobileGnb) return; 280 281 if (mobileGnb.classList.contains("is-open")) { 282 this.openMainMenu(mobileGnb); 283 } else { 284 mobileGnb.style.display = "none"; 285 } 286 287 // gnb ì¸ë¶ í´ë¦ ì²ë¦¬ 288 mobileGnb.addEventListener("click", (event) => { 289 if (!event.target.closest(".gnb-wrap")) { 290 mobileGnb.querySelector(".gnb-wrap").focus(); 291 } 292 }); 293 294 // ì ê·¼ì± ì¤ì (tab) 295 this.setupAriaAttributes(mobileGnb); 296 297 this.attachEvents(mobileGnb); 298 }, 299 setupAriaAttributes(mobileGnb) { 300 const tabList = mobileGnb.querySelector(".menu-wrap"); 301 if (tabList) { 302 tabList.querySelector(".menu-wrap ul").setAttribute("role", "tablist"); 303 tabList.querySelectorAll(".menu-wrap li").forEach((li) => li.setAttribute("role", "none")); 304 305 const tabs = document.querySelectorAll(".menu-wrap .gnb-main-trigger");
306 tabs.forEach((item, idx) => { 307 item.setAttribute("role", "tab"); 308 item.setAttribute("aria-selected", "false"); 309 item.setAttribute("aria-controls", item.getAttribute("href").substring(1)); 310 item.setAttribute("id", `tab-${idx}`); 311 312 // gnb-main-trigger í´ë¦ì í´ë¹ ìì¹ë¡ ì¤í¬ë¡¤ 313 item.addEventListener("click", (event) => { 314 event.preventDefault(); 315 const id = item.getAttribute("aria-controls"); 316 const top = document.getElementById(id).offsetTop 317 const gnbBody = document.querySelector(".gnb-body"); 318 gnbBody.scrollTo({ 319 left: 0, 320 top: top, 321 behavior: "smooth", 322 }); 323 }) 324 }); 325 326 const tabPanels = document.querySelectorAll(".submenu-wrap .gnb-sub-list"); 327 tabPanels.forEach((item, idx) => { 328 item.setAttribute("role", "tabpanel"); 329 item.setAttribute("aria-labelledby", `tab-${idx}`); 330 }); 331 } 332 }, 333 attachEvents(mobileGnb) { 334 const id = mobileGnb.getAttribute("id"); 335 const openGnb = document.querySelector(`[aria-controls=${id}]`); 336 const closeGnb = mobileGnb.querySelector("#close-nav"); 337 338 openGnb.addEventListener("click", () => this.openMainMenu(mobileGnb)); 339 closeGnb.addEventListener("click", () => this.closeMainMenu(mobileGnb)); 340 this.setupAnchorScroll(mobileGnb); 341 this.setupAnchorLinks(mobileGnb); 342 343 // ë°ìí ì²ë¦¬ 344 window.addEventListener("resize", () => { 345 const isPC = windowSize.getWinSize() === "pc"; 346 if (isPC) this.closeMainMenu(mobileGnb); 347 }); 348 }, 349 openMainMenu(mobileGnb) { 350 const navContainer = mobileGnb.querySelector(".gnb-wrap"); 351 // const id = mobileGnb.getAttribute("id"); 352 // const openGnb = document.querySelector(`[aria-controls=${id}]`); 353 // const header = document.querySelector("#krds-header"); 354 355 mobileGnb.style.display = "block"; 356 navContainer.setAttribute("tabindex", 0); 357 // openGnb.setAttribute("aria-expanded", "true"); 358 // header.style.zIndex = "1000"; 359 360 // active ë©ë´ë¡ ì¤í¬ë¡¤ ì´ë 361 const activeTrigger = document.querySelector(".gnb-main-trigger.active"); 362 if (activeTrigger) { 363 const id = activeTrigger.getAttribute("aria-controls"); 364 const top = document.getElementById(id).offsetTop; 365 const gnbBody = document.querySelector(".gnb-body"); 366 gnbBody.style.scrollBehavior = "auto"; 367 gnbBody.scrollTop = top 368 } 369 370 setTimeout(() => { 371 mobileGnb.classList.add("is-backdrop"); 372 mobileGnb.classList.add("is-open"); 373 document.body.classList.add("is-gnb-mobile"); 374 }, 100); 375 376 // transition ì¢ ë£í ì¤í 377 mobileGnb.addEventListener("transitionend", function onTransitionEnd() { 378 navContainer.focus(); 379 mobileGnb.removeEventListener("transitionend", onTransitionEnd); 380 381 // inert ì¤ì 382 document.querySelector("#krds-header .header-in").setAttribute("inert", ""); 383 document.getElementById("container")?.setAttribute("inert", ""); 384 document.getElementById("footer")?.setAttribute("inert", ""); 385 386 // í¬ì»¤ì¤ í¸ë© ì¤ì 387 common.focusTrap(mobileGnb); 388 }); 389 390 }, 391 closeMainMenu(mobileGnb) { 392 const id = mobileGnb.getAttribute("id"); 393 const openGnb = document.querySelector(`[aria-controls=${id}]`); 394 // const header = document.querySelector("#krds-header"); 395 396 mobileGnb.classList.remove("is-backdrop"); 397 mobileGnb.classList.remove("is-open"); 398 // openGnb.setAttribute("aria-expanded", "false"); 399 // header.style.zIndex = ""; 400 401 // inert ì¤ì 402 document.querySelector("#krds-header .header-in").removeAttribute("inert"); 403 document.getElementById("container")?.removeAttribute("inert"); 404 document.getElementById("footer")?.removeAttribute("inert"); 405 406 // transition ì¢ ë£í ì¤í 407 mobileGnb.addEventListener("transitionend", function onTransitionEnd() { 408 openGnb.focus(); 409 mobileGnb.removeEventListener("transitionend", onTransitionEnd); 410 });
411 412 setTimeout(() => { 413 mobileGnb.style.display = "none"; 414 document.body.classList.remove("is-gnb-mobile"); 415 }, 400); 416 }, 417 setupAnchorScroll(mobileGnb) { 418 const gnbBody = mobileGnb.querySelector(".gnb-body"); 419 const navContainer = mobileGnb.querySelector(".gnb-wrap"); 420 const navItems = mobileGnb.querySelectorAll(".submenu-wrap .gnb-sub-list"); 421 const headerTabArea = mobileGnb.querySelector(".gnb-tab-nav"); 422 const headerTabMenu = headerTabArea?.querySelector(".menu-wrap"); 423 424 gnbBody.addEventListener("scroll", () => { 425 const scrollTop = gnbBody.scrollTop; 426 const scrollHeight = gnbBody.scrollHeight; 427 const bodyHeight = gnbBody.clientHeight; 428 429 navItems.forEach((item) => { 430 const id = item.getAttribute("id"); 431 const menuLink = mobileGnb.querySelector(`[href="#${id}"]`); 432 const offset = item.offsetTop; 433 if (scrollTop >= offset || bodyHeight + scrollTop >= scrollHeight) { 434 this.resetAnchorMenu(); 435 menuLink.classList.add("active"); 436 menuLink.setAttribute("aria-selected", "true"); 437 if (headerTabArea) { 438 const headerTabMenuUl = headerTabMenu.querySelector("ul"); 439 gnbBody.addEventListener("scrollend", () => { 440 headerTabMenuUl.scrollLeft = menuLink.offsetLeft; 441 }); 442 } 443 } 444 }); 445 446 this.handleTopScroll(headerTabArea, navContainer, gnbBody); 447 }); 448 }, 449 handleTopScroll(headerTabArea, navContainer, gnbBody) { 450 // gnb-mobile-type1(headerTabArea: gnb-tab-nav) 451 let lastBodyScrollY = 0; 452 453 if (!headerTabArea) return; // ììê° ìì ê²½ì° í¨ì ì¢ ë£ 454 455 gnbBody.addEventListener("scroll", (event) => { 456 const bodyScrollY = event.target.scrollTop; 457 458 if (bodyScrollY > 0) { 459 headerTabArea.style.height = `${headerTabArea.scrollHeight}px`; 460 headerTabArea.style.transition = "ease-out .4s"; 461 navContainer.classList.add("is-active"); 462 } else if (bodyScrollY < 50 && bodyScrollY < lastBodyScrollY) { 463 headerTabArea.style.height = ""; 464 headerTabArea.style.transition = "ease-out .4s .2s"; 465 setTimeout(() => { 466 navContainer.classList.remove("is-active"); 467 }, 600); 468 } 469 470 lastBodyScrollY = bodyScrollY; 471 }); 472 }, 473 setupAnchorLinks(mobileGnb) { 474 const menuItems = mobileGnb.querySelectorAll(".menu-wrap .gnb-main-trigger"); 475 const navItems = mobileGnb.querySelectorAll(".submenu-wrap .gnb-sub-list"); 476 477 if (!document.querySelector(".menu-wrap .gnb-main-trigger.active")) { 478 menuItems[0].classList.add("active"); 479 menuItems[0].setAttribute("aria-selected", "true"); 480 } 481 482 // 3depth 483 navItems.forEach((item) => { 484 const depth3Items = item.querySelectorAll(".has-depth3"); 485 if (depth3Items.length > 0) { 486 depth3Items.forEach((item) => { 487 if (item.classList.contains("active")) { 488 item.classList.add("active"); 489 item.setAttribute("aria-expanded", "true"); 490 item.nextElementSibling.classList.add("is-open"); 491 } else { 492 item.setAttribute("aria-expanded", "false"); 493 } 494 item.addEventListener("click", (event) => this.handleDepth3Click(event, item)); 495 }); 496 } 497 }); 498 499 // 4depth 500 navItems.forEach((item) => { 501 const depth4Items = item.querySelectorAll(".has-depth4"); 502 if (depth4Items.length > 0) { 503 depth4Items.forEach((item) => { 504 item.addEventListener("click", (event) => this.handleDepth4Click(event, item)); 505 }); 506 } 507 }); 508 }, 509 handleDepth3Click(event) { 510 const isActive = event.target.classList.contains("active"); 511 512 const resetList = () => { 513 document.querySelectorAll(".has-depth3").forEach((depth3) => { 514 depth3.classList.remove("active"); 515 depth3.setAttribute("aria-expanded", "false"); 516 depth3.nextElementSibling.classList.remove("is-open"); 517 }); 518 }; 519 520 if (!isActive) { 521 // resetList(); 522 event.target.classList.add("active"); 523 event.target.setAttribute("aria-expanded", "true"); 524 event.target.nextElementSibling.classList.add("is-open"); 525 } else { 526 // resetList(); 527 event.target.classList.remove("active"); 528 event.target.setAttribute("aria-expanded", "false"); 529 event.target.nextElementSibling.classList.remove("is-open"); 530 } 531 }, 532 handleDepth4Click(event) { 533 const target = event.target.nextElementSibling; 534 const prevButton = target.querySelector(".trigger-prev"); 535 const closeButton = target.querySelector(".trigger-close"); 536 537 target.style.display = "block"; 538 setTimeout(() => { 539 target.classList.add("is-open"); 540 }, 0); 541 prevButton.focus(); 542 543 const depth4Close = () => { 544 target.classList.remove("is-open");
545 event.target.focus(); 546 setTimeout(() => { 547 target.style.display = ""; 548 }, 400); 549 }; 550 551 prevButton.addEventListener("click", depth4Close); 552 closeButton.addEventListener("click", depth4Close); 553 554 // í¬ì»¤ì¤ í¸ë© ì¤ì 555 common.focusTrap(target); 556 }, 557 resetAnchorMenu() { 558 document.querySelectorAll(".krds-main-menu-mobile .menu-wrap .gnb-main-trigger").forEach((menu) => { 559 menu.classList.remove("active"); 560 menu.setAttribute("aria-selected", "false"); 561 }); 562 }, 563}; 564 565/*** * krds_sideNavigation * ***/ 566const krds_sideNavigation = { 567 init() { 568 this.setupSideNavLists(); 569 this.setupToggleEvents(); 570 this.setupPopupEvents(); 571 }, 572 setupSideNavLists() { 573 const sideNavLists = document.querySelectorAll(".krds-side-navigation .lnb-list"); 574 sideNavLists.forEach((navList) => { 575 const navItems = navList.querySelectorAll("li"); 576 navItems.forEach((navItem) => this.setupNavItem(navItem)); 577 }); 578 }, 579 setupNavItem(navItem) { 580 const navButton = navItem.querySelector(".lnb-btn"); 581 if (!navButton || !navButton.className.includes("lnb-toggle")) return; 582 583 const uniqueIdx = `lnbmenu-${Math.random().toString(36).substring(2, 9)}`; 584 const navSubmenu = navButton.nextElementSibling; 585 586 // aria ì¤ì 587 navButton.setAttribute("aria-controls", uniqueIdx); 588 navButton.setAttribute("aria-expanded", navButton.classList.contains("active")); 589 590 // ìë¸ë©ë´ id ì¤ì ë° popup ì²ë¦¬ 591 if (navButton.classList.contains("lnb-toggle-popup")) { 592 navButton.setAttribute("aria-haspopup", "true"); 593 } 594 if (navSubmenu && navSubmenu.className.includes("lnb-submenu")) { 595 const navSubmenuList = navSubmenu.classList.contains("lnb-submenu-lv2") ? navSubmenu : navSubmenu.querySelector(":scope > ul"); 596 navSubmenuList?.setAttribute("id", uniqueIdx); 597 } 598 }, 599 setupToggleEvents() { 600 const toggleButtons = document.querySelectorAll(".krds-side-navigation .lnb-list:not(.exception-case) .lnb-toggle"); 601 toggleButtons.forEach((toggleButton) => { 602 toggleButton.addEventListener("click", () => { 603 const expand = toggleButton.getAttribute("aria-expanded") !== "true"; 604 605 //this.toggleMenu(toggleButton, expand); í´ë¦ ì í´ë¹ ë²í¼ë§ íì±í ìíë¡ ë³ê²½ëì´ í´ë¹ ì´ë²¤í¸ 주ìì²ë¦¬. 606 //this.closeSiblingMenus(toggleButton); í´ë¦ ì í´ë¹ ë²í¼ë§ íì±í ìíë¡ ë³ê²½ëì´ í´ë¹ ì´ë²¤í¸ 주ìì²ë¦¬. 607 this.setActiveNav(toggleButton, expand); 608 }); 609 }); 610 }, 611 setActiveNav(toggleButton, expand){ 612 const parentListItem = toggleButton.closest("li"); 613 toggleButton.setAttribute('aria-expanded', expand ? 'true' : 'false'); 614 parentListItem.classList.toggle('active', expand); 615 }, 616 setupPopupEvents() { 617 let lastClickedButton = null; 618 619 const popupToggleButtons = document.querySelectorAll(".lnb-toggle-popup"); 620 const popupSubmenus = document.querySelectorAll(".lnb-submenu-lv2"); 621 622 // íì í ê¸ ë²í¼ 623 popupToggleButtons.forEach((button) => { 624 button.addEventListener("click", () => { 625 const popupSubmenu = button.nextElementSibling; 626 if (popupSubmenu && popupSubmenu.classList.contains("lnb-submenu-lv2")) { 627 popupSubmenu.classList.add("active"); 628 button.setAttribute("aria-expanded", "true"); 629 630 popupSubmenu.addEventListener( 631 "transitionend", 632 () => { 633 popupSubmenu.querySelector(".lnb-btn-tit")?.focus(); 634 }, 635 { once: true } 636 ); 637 638 lastClickedButton = button; 639 } 640 }); 641 }); 642 643 // ìë¸ ë©ë´ê° í¬ì»¤ì¤ë¥¼ ìì¼ë©´ ë¹íì±í 644 popupSubmenus.forEach((popupSubmenu) => { 645 popupSubmenu.addEventListener("focusout", (event) => { 646 // í¬ì»¤ì¤ê° ìë¸ë©ë´ ë°ì¼ë¡ ëê°ëì§ íì¸ 647 if (!popupSubmenu.contains(event.relatedTarget)) { 648 popupSubmenu.classList.remove("active"); 649 650 if (lastClickedButton) { 651 lastClickedButton.setAttribute("aria-expanded", "false"); 652 popupSubmenu.addEventListener( 653 "transitionend", 654 () => { 655 lastClickedButton.focus(); 656 }, 657 { once: true } 658 ); 659 } 660 } 661 }); 662 663 // lnb-btn-tit í´ë¦ ì ìë¸ë©ë´ ë«ê¸° 664 const subMenuTitleButton = popupSubmenu.querySelector(".lnb-btn-tit"); 665 subMenuTitleButton?.addEventListener("click", () => { 666 lastClickedButton?.focus(); 667 }); 668 });
669 }, 670 toggleMenu(toggleButton, expand) { 671 const parentListItem = toggleButton.closest("li"); 672 toggleButton.setAttribute("aria-expanded", expand); 673 toggleButton.classList.toggle("active", expand); 674 parentListItem.classList.toggle("active", expand); 675 }, 676 closeSiblingMenus(toggleButton) { 677 const parentListItem = toggleButton.closest("li"); 678 const siblingButtons = parentListItem.parentNode.querySelectorAll(":scope > li > .lnb-toggle"); 679 siblingButtons.forEach((siblingButton) => { 680 if (siblingButton !== toggleButton) { 681 this.toggleMenu(siblingButton, false); 682 } 683 }); 684 }, 685 setActiveCurrentPage() { 686 // íì±íë íì´ì§ë¥¼ ì°¾ë ì(ê°ë° íê²½ì ë§ê² ìì ) 687 const currentPage = window.location.pathname.split("/").slice(-1)[0].replace(".html", ""); 688 const lnbLinks = document.querySelectorAll(".krds-side-navigation .lnb-link"); 689 lnbLinks.forEach((link) => { 690 const linkPage = link.getAttribute("href").split("/").pop().replace(".html", ""); 691 if (linkPage === currentPage) { 692 link.closest(".lnb-item").classList.add("active"); 693 link.closest(".lnb-item").querySelector(".lnb-toggle")?.classList.add("active"); 694 link.closest(".lnb-item").querySelector(".lnb-toggle")?.setAttribute("aria-expanded", "true"); 695 link.closest("li").classList.add("active"); 696 // ì ê·¼ì± íì¬ íì´ì§ íì aria-current 697 link.setAttribute("aria-current", "page"); 698 } 699 }); 700 }, 701}; 702 703/*** * krds_tab * ***/ 704const krds_tab = { 705 layerTabArea: null, 706 init() { 707 this.layerTabArea = document.querySelectorAll(".krds-tab-area.layer"); 708 709 if (!this.layerTabArea.length) return; 710 711 this.setupTabs(); 712 }, 713 setupTabs() { 714 this.layerTabArea.forEach((tabArea) => { 715 const layerTabs = tabArea.querySelectorAll(".tab > ul > li"); 716 717 // í ì¤ì 718 layerTabs.forEach((tab) => { 719 // ì´ë¯¸ ì´ë²¤í¸ê° ì°ê²°ë íì ê±´ëë 720 if (!tab.dataset.listenerAttached) { 721 // ì°ê²°ë í í¨ë 찾기 722 const control = tab.getAttribute("aria-controls"); 723 const selectedTabPanel = document.getElementById(control); 724 725 // aria ì¤ì 726 tab.setAttribute("aria-selected", "false"); 727 tab.setAttribute("role", "tab"); 728 selectedTabPanel.setAttribute("role", "tabpanel"); 729 730 // ì´ê¸° active ì¤ì 731 if (tab.classList.contains("active")) { 732 if (!tab.querySelector("button .sr-only")) { 733 tab.setAttribute("aria-selected", "true"); 734 tab.querySelector("button").append(this.createAccText()); // ì´ì ì´ ë²í¼ì´ë¼ aria-selected ëì²´ í ì¤í¸ íì 735 } 736 } 737 738 // í´ë¦ ì´ë²¤í¸ 739 tab.addEventListener("click", () => { 740 const closestTabs = tab.closest(".krds-tab-area.layer > .tab").querySelectorAll("li"); 741 const closestTabPanels = tab.closest(".krds-tab-area.layer").querySelectorAll(":scope > .tab-conts-wrap > .tab-conts"); 742 743 this.resetTabs(closestTabs, closestTabPanels); 744 745 tab.classList.add("active"); 746 tab.querySelector("button").append(this.createAccText()); 747 tab.setAttribute("aria-selected", "true"); 748 selectedTabPanel.classList.add("active"); 749 }); 750 751 // í¤ë³´ë ì´ë²¤í¸ 752 this.setupKeyboardNavigation(tab); 753 754 // ì´ë²¤í¸ê° ì¶ê°ë íì íì 755 tab.dataset.listenerAttached = "true"; 756 } 757 }); 758 }); 759 }, 760 createAccText() { 761 const tabAccTag = document.createElement("i"); 762 tabAccTag.classList.add("sr-only"); 763 tabAccTag.textContent = "ì íë¨"; 764 return tabAccTag; 765 }, 766 resetTabs(closestTabs, closestTabPanels) { 767 closestTabs.forEach((tab) => { 768 tab.classList.remove("active"); 769 tab.setAttribute("aria-selected", "false"); 770 // ëì²´ í ì¤í¸ ìì 771 const srOnly = tab.querySelector(".sr-only"); 772 if (srOnly) tab.querySelector("button").removeChild(srOnly); 773 });
774 closestTabPanels.forEach((panel) => { 775 panel.classList.remove("active"); 776 }); 777 }, 778 setupKeyboardNavigation(tab) { 779 tab.addEventListener("keydown", function (event) { 780 let newTab; 781 if (event.key === "ArrowRight") { 782 event.preventDefault(); 783 newTab = tab.nextElementSibling?.querySelector("button"); 784 } else if (event.key === "ArrowLeft") { 785 newTab = tab.previousElementSibling?.querySelector("button"); 786 } 787 newTab?.focus(); 788 }); 789 }, 790}; 791 792/*** * krds_accordion * ***/ 793const krds_accordion = { 794 accordionButtons: null, 795 accordionHandlers: new Map(), 796 init() { 797 this.accordionButtons = document.querySelectorAll(".btn-accordion"); 798 799 if (!this.accordionButtons.length) return; 800 801 this.setupAccordions(); 802 }, 803 accordionToggle(button, accordionItems, accordionType, currentItem) { 804 const isExpanded = button.getAttribute("aria-expanded") === "true"; 805 // singleOpen íì ì¼ ê²½ì°, ë¤ë¥¸ í목 ë«ê¸° 806 if (accordionType !== "multiOpen" && !currentItem.classList.contains("active")) { 807 accordionItems.forEach((otherItem) => { 808 const otherButton = otherItem.querySelector(".btn-accordion"); 809 otherButton.setAttribute("aria-expanded", "false"); 810 otherButton.classList.remove("active"); 811 otherItem.classList.remove("active"); 812 }); 813 } 814 // íì¬ í목 ìí í ê¸ 815 button.setAttribute("aria-expanded", !isExpanded); 816 button.classList.toggle("active", !isExpanded); 817 currentItem.classList.toggle("active", !isExpanded); 818 }, 819 setupAccordions() { 820 this.accordionButtons.forEach((button, idx) => { 821 const accordionContainer = button.closest(".krds-accordion"); 822 const accordionItems = accordionContainer.querySelectorAll(".accordion-item"); 823 const currentItem = button.closest(".accordion-item"); 824 const accordionContent = currentItem.querySelector(".accordion-collapse"); 825 const accordionType = accordionContainer.dataset.type || "singleOpen"; 826 const isOpen = accordionContainer.classList.contains("is-open"); 827 828 // ì ê·¼ì± ìì± ì´ê¸°ê° ì¤ì 829 this.setupAriaAttributes(button, accordionContent, idx); 830 831 // ì´ê¸° ì¤í ìí ì¤ì 832 if (isOpen || currentItem.classList.contains("active")) { 833 button.setAttribute("aria-expanded", "true"); 834 button.classList.add("active"); 835 currentItem.classList.add("active"); 836 } 837 838 // í¸ë¤ë¬ ê³ ì ë° ì ì¥ 839 let toggleHandler = this.accordionHandlers.get(button); 840 if (!toggleHandler) { 841 toggleHandler = this.accordionToggle.bind(this, button, accordionItems, accordionType, currentItem); 842 this.accordionHandlers.set(button, toggleHandler); 843 } 844 845 // 기존 ì´ë²¤í¸ 리ì¤ë ì ê±° ë° ìë¡ ë±ë¡ 846 button.removeEventListener("click", toggleHandler); 847 button.addEventListener("click", toggleHandler); 848 }); 849 }, 850 setupAriaAttributes(button, accordionContent, idx) { 851 const uniqueIdx = `${idx}${Math.random().toString(36).substring(2, 9)}`; 852 button.setAttribute("aria-expanded", "false"); 853 button.setAttribute("id", `accordionHeader-id-${uniqueIdx}`); 854 button.setAttribute("aria-controls", `accordionCollapse-id-${uniqueIdx}`); 855 accordionContent.setAttribute("role", "region"); 856 accordionContent.setAttribute("id", `accordionCollapse-id-${uniqueIdx}`); 857 accordionContent.setAttribute("aria-labelledby", `accordionHeader-id-${uniqueIdx}`); 858 }, 859}; 860 861/*** * krds_modal * ***/ 862const krds_modal = { 863 modalOpenTriggers: null, 864 modalCloseTriggers: null, 865 outsideClickHandlers: {}, 866 init() { 867 this.modalOpenTriggers = document.querySelectorAll(".open-modal"); 868 this.modalCloseTriggers = document.querySelectorAll(".close-modal"); 869 870 if (!this.modalOpenTriggers.length || !this.modalCloseTriggers.length) return; 871 872 this.setupTriggers(); 873 }, 874 setupTriggers() { 875 // ëª¨ë¬ ì´ê¸° ì´ë²¤í¸ ì¤ì 876 this.modalOpenTriggers.forEach((trigger) => { 877 trigger.addEventListener("click", (event) => { 878 event.preventDefault(); 879 const modalId = trigger.getAttribute("data-target"); 880 if (modalId) { 881 // aria ì¤ì 882 trigger.setAttribute("data-modal-id", modalId); 883 trigger.classList.add("modal-opened"); 884 trigger.setAttribute("tabindex", "-1"); 885 886 this.openModal(modalId); 887 } 888 }); 889 });
890 // ëª¨ë¬ ë«ê¸° ì´ë²¤í¸ ì¤ì 891 this.modalCloseTriggers.forEach((trigger) => { 892 trigger.addEventListener("click", (event) => { 893 event.preventDefault(); 894 const modalId = trigger.closest(".krds-modal").getAttribute("id"); 895 896 if (modalId) { 897 this.closeModal(modalId); 898 } 899 }); 900 }); 901 }, 902 openModal(id) { 903 const modalElement = document.getElementById(id); 904 const dialogElement = modalElement.querySelector(".modal-content"); 905 const modalBack = modalElement.querySelector(".modal-back"); 906 // const modalTitle = modalElement.querySelector(".modal-title"); 907 const modalConts = modalElement.querySelector(".modal-conts"); 908 909 document.querySelector("body").classList.add("scroll-no"); 910 dialogElement.removeAttribute("tabindex"); 911 modalElement.setAttribute("role", "dialog"); 912 modalElement.classList.add("shown"); 913 modalBack.classList.add("in"); 914 // modalTitle.setAttribute("tabindex", "0"); 915 916 // modal-conts ì¤í¬ë¡¤ ì¼ë tabindex ì²ë¦¬ 917 if (modalConts.scrollHeight > modalConts.clientHeight) { 918 modalConts.setAttribute("tabindex", "0"); 919 } else { 920 modalConts.removeAttribute("tabindex"); 921 } 922 923 // css transition ëë ì´ 924 setTimeout(() => { 925 modalElement.classList.add("in"); 926 }, 150); 927 928 //ì´ë¦° íì ì°½ í¬ì»¤ì¤ 929 const focusables = modalElement.querySelectorAll(`a, button, [tabindex="0"], input, textarea, select`); 930 setTimeout(() => { 931 // modalTitle.focus(); 932 focusables[0].focus(); 933 }, 350); 934 935 // ESC ëª¨ë¬ ë«ê¸° 936 dialogElement.addEventListener( 937 "keydown", 938 (event) => { 939 if (event.key === "Escape" || event.key === "Esc") { 940 this.closeModal(dialogElement.closest(".krds-modal").id
940); 941 } 942 }, 943 { once: true } 944 ); 945 946 // ëª¨ë¬ ì¸ë¶ í´ë¦ ì²ë¦¬ í¸ë¤ë¬ ì ì ë° ì ì¥ 947 if (!this.outsideClickHandlers[id]) { 948 this.outsideClickHandlers[id] = (event) => { 949 if (!event.target.closest(".modal-content")) { 950 // modalTitle.focus(); 951 focusables[0].focus(); 952 953 // dialogElement.focus(); 954 // this.closeModal(id); 955 } 956 }; 957 } 958 // ì´ë²¤í¸ 리ì¤ë ì ê±° í ë¤ì ë±ë¡ 959 modalElement.removeEventListener("click", this.outsideClickHandlers[id]); 960 modalElement.addEventListener("click", this.outsideClickHandlers[id]); 961 962 // í¬ì»¤ì¤ í¸ë© ì¤ì 963 common.focusTrap(dialogElement); 964 965 // 2ê° ì´ìì 모ë¬ì´ ì´ë ¤ ìë ê²½ì° z-index ì ë°ì´í¸ 966 this.updateZIndex(modalElement); 967 968 // inert ì¤ì 969 document.getElementById("wrap")?.setAttribute("inert", ""); 970 }, 971 closeModal(id) { 972 const modalElement = document.getElementById(id); 973 const openModals = document.querySelectorAll(".modal.in:not(.sample)"); 974 const modalBack = modalElement.querySelector(".modal-back"); 975 976 modalElement.classList.remove("in"); 977 modalBack.classList.remove("in"); 978 979 // css transition ëë ì´ 980 setTimeout(() => { 981 modalElement.classList.remove("shown"); 982 }, 350); 983 984 // ë§ì§ë§ 모ë¬ì´ ë«í ë íì´ì§ ì¤í¬ë¡¤ ë³µì 985 if (openModals.length < 2) { 986 document.querySelector("body").classList.remove("scroll-no"); 987 } 988 989 // inert ì¤ì 990 document.getElementById("wrap")?.removeAttribute("inert"); 991 992 // 모ë¬ì ì´ìë ë²í¼ì¼ë¡ í¬ì»¤ì¤ ë³µê· 993 this.returnFocusToTrigger(id); 994 }, 995 updateZIndex(modalElement) { 996 const openModals = document.querySelectorAll(".modal.in:not(.sample)"); 997 const openModalsLengtn = openModals.length + 1; 998 const newZIndex = 1010 + openModalsLengtn; 999 if (openModalsLengtn > 1) { 1000 modalElement.style.zIndex = newZIndex; 1001 modalElement.querySelector(".modal-back").classList.remove("in"); 1002 } 1003 }, 1004 returnFocusToTrigger(id) { 1005 const triggerButton = document.querySelector(`.modal-opened[data-modal-id="${id}"]`); 1006 if (triggerButton) { 1007 triggerButton.focus(); 1008 triggerButton.setAttribute("tabindex", "0"); 1009 triggerButton.classList.remove("modal-opened"); 1010 triggerButton.removeAttribute("data-modal-id"); 1011 } 1012 }, 1013}; 1014 1015/*** * krds_contextualHelp * ***/ 1016const krds_contextualHelp = { 1017 tooltipButtons: null, 1018 init() { 1019 this.tooltipButtons = document.querySelectorAll(".krds-contextual-help .tooltip-btn"); 1020 1021 if (!this.tooltipButtons.length) return; 1022 1023 this.setupTooltips(); 1024 this.setupFocusOutEvent(); 1025 }, 1026 setupTooltips() { 1027 this.tooltipButtons.forEach((button) => { 1028 const tooltipContainer = button.closest(".krds-contextual-help"); 1029 const tooltipPopover = tooltipContainer.querySelector(".tooltip-popover"); 1030 const closeButton = tooltipPopover.querySelector(".tooltip-close"); 1031 1032 button.setAttribute("aria-expanded", "false"); 1033 tooltipPopover.setAttribute("role", "tooltip"); 1034 1035 // tooltipWrapì í¬ì§ì ì´ ììë ê¸°ë³¸ê° ì¤ì 1036 if (tooltipContainer && tooltipContainer.classList.length === 1) { 1037 tooltipContainer.classList.add("top", "left"); 1038 } 1039 1040 button.addEventListener("click", () => { 1041 this.toggleTooltip(button, tooltipPopover, tooltipContainer); 1042 }); 1043 closeButton.addEventListener("click", () => { 1044 this.closeAllTooltips(); 1045 }); 1046 1047 window.addEventListener("resize", () => { 1048 this.adjustTooltipPosition(tooltipContainer, tooltipPopover); 1049 }); 1050 1051 // ESC ë«ê¸° 1052 document.addEventListener("keydown", (event) => { 1053 if (event.key === "Escape" || event.key === "Esc") { 1054 this.closeAllTooltips(); 1055 } 1056 }); 1057 }); 1058 }, 1059 toggleTooltip(button, tooltipPopover, tooltipContainer) { 1060 const isVisible = tooltipPopover.style.display === "block"; 1061 1062 this.closeAllTooltips(); 1063 1064 if (!isVisible) { 1065 tooltipPopover.style.display = "block"; 1066 const focusables = tooltipPopover.querySelector(`a, button, [tabindex="0"], input, textarea, select`);
1067 focusables?.focus(); 1068 button.setAttribute("aria-expanded", "true"); 1069 1070 this.adjustTooltipPosition(tooltipContainer, tooltipPopover); 1071 } 1072 }, 1073 closeAllTooltips() { 1074 const otherPopovers = document.querySelectorAll(".krds-contextual-help .tooltip-popover"); 1075 otherPopovers.forEach((popover) => { 1076 popover.style.display = "none"; 1077 }); 1078 this.tooltipButtons.forEach((button) => { 1079 button.setAttribute("aria-expanded", "false"); 1080 }); 1081 }, 1082 adjustTooltipPosition(tooltipContainer, tooltipPopover) { 1083 // const isMobile = windowSize.getWinSize() === "mob"; 1084 const isMobile = window.innerWidth <= 768; 1085 const tooltipAction = tooltipContainer.querySelector(".tooltip-action"); 1086 1087 if (isMobile) { 1088 const rootStyles = getComputedStyle(document.querySelector(":root")); 1089 const contentsPaddingX = rootStyles.getPropertyValue("--krds-contents-padding-x").trim().split("px")[0]; 1090 const tooltipActionRect = tooltipAction.getBoundingClientRect(); 1091 const offsetLeft = tooltipActionRect.left - contentsPaddingX; 1092 const width = document.body.clientWidth - (contentsPaddingX * 2); 1093 tooltipPopover.style.left = `-${offsetLeft}px`; 1094 tooltipPopover.style.width = `${width}px`; 1095 } else { 1096 tooltipPopover.style.left = ""; 1097 tooltipPopover.style.right = ""; 1098 tooltipPopover.style.width = "360px"; 1099 } 1100 }, 1101 setupFocusOutEvent() { 1102 document.addEventListener("click", (event) => { 1103 const clickedInsideTooltip = event.target.closest(".tooltip-action"); 1104 if (!clickedInsideTooltip ) { 1105 this.closeAllTooltips(); 1106 } else { 1107 const FocusPopover = clickedInsideTooltip.querySelector('.tooltip-close'); 1108 FocusPopover.addEventListener('focusout', ()=>{ 1109 this.closeAllTooltips(); 1110 clickedInsideTooltip.querySelector(".tooltip-btn")?.focus(); 1111 }); 1112 } 1113 }); 1114 }, 1115}; 1116 1117/*** * krds_tooltip * ***/ 1118const krds_tooltip = { 1119 tooltip: null, 1120 isMobile: null, 1121 init() { 1122 this.tooltip = document.querySelectorAll(".krds-tooltip"); 1123 this.isMobile = windowSize.getWinSize() === "mob"; 1124 1125 if (!this.tooltip.length) return; 1126 1127 this.setupTooltips(); 1128 this.setupGlobalEvents(); 1129 }, 1130 setupTooltips() { 1131 this.tooltip.forEach((item, index) => { 1132 // tooltipText 1133 const tooltipText = item.getAttribute("data-tooltip"); 1134 const disabled = item.hasAttribute("disabled"); 1135 1136 if (!tooltipText || disabled) return; 1137 1138 // ID ë¶ì¬ 1139 const uniqueIdx = `tooltip-popover-${index}${Math.random().toString(36).substring(2, 9)}`; 1140 item.setAttribute("aria-labelledby", uniqueIdx); 1141 1142 // TooltipPopover ìì± 1143 const tooltipBtnText = item.innerText; 1144 const tooltipPopover = this.createTooltipPopover(uniqueIdx, tooltipBtnText, tooltipText); 1145 item.parentNode.insertBefore(tooltipPopover, item.nextSibling); 1146 1147 // Show/Hide í¨ì ì ì 1148 const showTooltip = () => this.showTooltip(item, tooltipPopover); 1149 1150 // ì´ë²¤í¸ ë±ë¡ 1151 this.registerEvents(item, showTooltip); 1152 1153 // ESC ë«ê¸° 1154 document.addEventListener("keydown", (event) => { 1155 if (event.key === "Escape" || event.key === "Esc") { 1156 this.closeAllTooltips(); 1157 } 1158 }); 1159 }); 1160 }, 1161 createTooltipPopover(uniqueIdx, tooltipBtnText, tooltipText) { 1162 const tooltipPopover = document.createElement("div"); 1163 tooltipPopover.classList.add("krds-tooltip-popover"); 1164 tooltipPopover.setAttribute("id", uniqueIdx); 1165 tooltipPopover.setAttribute("aria-hidden", "true"); 1166 tooltipPopover.innerHTML = ""; 1167 tooltipPopover.innerHTML = ` 1168 <span class="sr-only">${tooltipBtnText}</span> 1169 ${tooltipText} 1170 `; 1171 1172 return tooltipPopover; 1173 }, 1174 registerEvents(item, showTooltip) { 1175 item.addEventListener("mouseover", showTooltip); 1176 item.addEventListener("mouseout", this.closeAllTooltips); 1177 item.addEventListener("focus", showTooltip); 1178 item.addEventListener("focusout", this.closeAllTooltips); 1179 }, 1180 showTooltip(item, tooltipPopover) { 1181 // tooltip-box 1182 if (item.classList.contains("tooltip-box")) { 1183 tooltipPopover.classList.add("tooltip-box"); 1184 } 1185 // tooltip-vertical 1186 if (item.classList.contains("tooltip-vertical")) { 1187 tooltipPopover.classList.add("tooltip-vertical"); 1188 } 1189 1190 tooltipPopover.classList.add("active"); 1191 1192 const { top, left } = this.calculateTooltipPosition(item, tooltipPopover); 1193 const mobileSmall = window.innerWidth <= 420; 1194 tooltipPopover.style.top = `${top}px`; 1195 tooltipPopover.style.left = mobileSmall ? "50%" : `${left}px`; 1196 }, 1197 closeAllTooltips() { 1198 const otherPopovers = document.querySelectorAll(".krds-tooltip-popover");
1199 otherPopovers.forEach((popover) => { 1200 if (!popover.classList.contains("active")) return; 1201 popover.style = ""; 1202 popover.className = "krds-tooltip-popover"; 1203 }); 1204 }, 1205 calculateTooltipPosition(item, tooltipPopover) { 1206 // í´íê³¼ ê¸°ì¤ ìì ê°ê²© 1207 const tooltipGap = 12; 1208 const { clientHeight: tooltipHeight, clientWidth: tooltipWidth } = tooltipPopover; 1209 const { top: itemTop, left: itemLeft, right: itemRight, height: itemHeight, width: itemWidth } = item.getBoundingClientRect(); 1210 const halfWindowWidth = window.innerWidth / 2; 1211 const halfWindowHeight = window.innerHeight / 2; 1212 1213 let tooltipTop; 1214 let tooltipLeft; 1215 1216 const isVertical = this.isMobile || item.classList.contains("tooltip-box") || item.classList.contains("tooltip-vertical"); 1217 1218 if (isVertical) { 1219 if (itemTop + itemHeight > halfWindowHeight) { 1220 tooltipTop = itemTop - tooltipHeight - tooltipGap; // ì쪽 1221 tooltipPopover.classList.add("top"); 1222 } else { 1223 tooltipTop = itemTop + itemHeight + tooltipGap; // ìë쪽 1224 tooltipPopover.classList.add("bottom"); 1225 } 1226 // ì¢ì° ìì¹ 1227 if (itemLeft + itemWidth > halfWindowWidth) { 1228 tooltipLeft = itemRight - tooltipWidth; // ì¤ë¥¸ìª½ ì ë ¬ 1229 tooltipPopover.classList.add("right"); 1230 // íë©´ ì¤ë¥¸ìª½ ì¬ì ê³µê°ì´ ì¶©ë¶í ë ê°ì´ë° ì ë ¬ 1231 if (window.innerWidth - (itemLeft + itemWidth) > tooltipWidth / 2) { 1232 tooltipLeft = itemLeft + (itemWidth - tooltipWidth) / 2; 1233 tooltipPopover.classList.remove("right"); 1234 } 1235 } else { 1236 // íë©´ ì¼ìª½ ì¬ì ê³µê°ì´ ì¶©ë¶í ë ê°ì´ë° ì ë ¬ 1237 tooltipLeft = itemLeft + (itemWidth - tooltipWidth) / 2; 1238 // ì¼ìª½ ê³µê° ë¶ì¡± ì ë³´ì 1239 if (tooltipLeft < 0) { 1240 tooltipLeft = itemLeft; 1241 tooltipPopover.classList.add("left"); 1242 } else { 1243 tooltipPopover.classList.remove("left"); 1244 } 1245 } 1246 } else { 1247 // ê°ë¡í í´í 1248 tooltipTop = itemTop + (itemHeight - tooltipHeight) / 2; 1249 if (itemLeft + itemWidth > halfWindowWidth) { 1250 tooltipLeft = itemLeft - tooltipWidth - tooltipGap; // ì¼ìª½ 1251 tooltipPopover.classList.add("right"); 1252 } else { 1253 tooltipLeft = itemRight + tooltipGap; // ì¤ë¥¸ìª½ 1254 tooltipPopover.classList.remove("right"); 1255 } 1256 } 1257 return { top: tooltipTop, left: tooltipLeft }; 1258 }, 1259 setupGlobalEvents() { 1260 window.addEventListener("scroll", () => { 1261 this.closeAllTooltips(); 1262 }); 1263 window.addEventListener("resize", () => { 1264 this.isMobile = windowSize.getWinSize() === "mob"; 1265 this.closeAllTooltips(); 1266 }); 1267 }, 1268}; 1269 1270/*** * krds_calendar * ***/ // *btn-set-date: aria-pressed > aria-selected ë³ê²½ í´ì¼í¨(ìì ìì±ë ê°ì´) 1271const krds_calendar = { 1272 datePickerArea: null, 1273 activeDateSelector: null, 1274 init() { 1275 this.datePickerArea = document.querySelectorAll(".krds-calendar-area"); 1276 1277 if (!this.datePickerArea.length) return; 1278 1279 this.setupDatePicker(); 1280 this.setupGlobalListeners(); 1281 this.setupOpenCloseEvents(); 1282 this.setupDateComboBox("init"); 1283 this.toggleDateSelector(); 1284 this.actionDatePicker(); 1285 1286 // ui ëì íì¸ì© í ì¤í¸ ì½ë 1287 this.example(); 1288 }, 1289 setupDatePicker() { 1290 this.datePickerArea.forEach((datePicker) => { 1291 datePicker.querySelector(".calendar-wrap").setAttribute("tabindex", "0"); 1292 1293 // ì ê·¼ì± ì´ê¸°ê° ì¤ì 1294 datePicker.querySelectorAll(".calendar-tbl td").forEach((cell) => { 1295 const dateButton = cell.querySelector(".btn-set-date"); 1296 if (!dateButton) return; 1297 if (cell.classList.contains("period")) { 1298 dateButton.setAttribute("aria-pressed", "true"); 1299 } 1300 if (cell.classList.contains("day-event")) { 1301 dateButton.setAttribute("aria-label", `${dateButton.innerText} ì¼ì ìì`); 1302 } 1303 if (cell.classList.contains("today")) { 1304 dateButton.setAttribute("aria-label", `${dateButton.innerText} ì¤ë`); 1305 } 1306 }); 1307 });
1308 }, 1309 setupGlobalListeners() { 1310 document.addEventListener("click", (event) => { 1311 if (!event.target.closest(".calendar-conts")) { 1312 this.closeAllDatePickers(); 1313 } 1314 }); 1315 }, 1316 setupOpenCloseEvents() { 1317 const datePickerButtons = document.querySelectorAll(".form-btn-datepicker"); 1318 datePickerButtons.forEach((button) => { 1319 button.addEventListener("click", () => this.openDatePicker(button)); 1320 }); 1321 1322 // í ì´ë ë«ê¸° 1323 this.datePickerArea.forEach((datePicker) => { 1324 // ë§ì§ë§ ë²í¼ì´ blurë ë datepicker ë«ê¸°(í¬ì»¤ì¤ í¸ë©ì ì¬ì©íì§ ììë ì ì©) 1325 // const lastActionButton = datePicker.querySelector(".calendar-btn-wrap .krds-btn:last-child"); 1326 // if (lastActionButton) { 1327 // lastActionButton.addEventListener("blur", () => this.closeAllDatePickers()); 1328 // } 1329 1330 // calendar-selectì ë§ì§ë§ ë²í¼ì´ blurë ë ì í기 ë«ê¸° 1331 datePicker.querySelectorAll(".calendar-select").forEach((select) => { 1332 const lastSelectButton = select.querySelector(".sel > li:last-child > button"); 1333 if (lastSelectButton) { 1334 lastSelectButton.addEventListener("blur", () => { 1335 this.resetDateSelector(); 1336 }); 1337 } 1338 }); 1339 }); 1340 }, 1341 openDatePicker(button) { 1342 // ì´ë ¤ìë ë¬ë ¥ 모ë ë«ê¸° 1343 this.closeAllDatePickers(); 1344 1345 const currentDatePicker = button.closest(".calendar-conts").querySelector(".krds-calendar-area"); 1346 currentDatePicker.classList.add("active"); 1347 1348 // ì ê·¼ì± 1349 button.setAttribute("aria-expanded", "true"); 1350 1351 // í¬ì»¤ì¤ í¸ë© ì¤ì 1352 common.focusTrap(currentDatePicker); 1353 1354 // í¬ì»¤ì¤ ì´ë 1355 setTimeout(() => { 1356 currentDatePicker.querySelector(".calendar-wrap").focus(); 1357 }, 50); 1358 }, 1359 resetDateSelector() { 1360 this.datePickerArea.forEach((datePicker) => { 1361 const selectMenus = datePicker.querySelectorAll(".calendar-select"); 1362 selectMenus.forEach((select) => select.classList.remove("active")); 1363 this.setupDateComboBox("reset"); 1364 this.activeDateSelector = null; 1365 }); 1366 }, 1367 closeAllDatePickers() { 1368 this.datePickerArea.forEach((datePicker) => { 1369 if (datePicker.classList.contains("active")) { 1370 const target = datePicker.closest(".calendar-conts").querySelector(".form-btn-datepicker"); 1371 target.focus(); 1372 } 1373 datePicker.classList.remove("active"); 1374 this.resetDateSelector(); 1375 }); 1376 1377 // ì ê·¼ì± 1378 const datePickerButtons = document.querySelectorAll(".form-btn-datepicker"); 1379 datePickerButtons.forEach((button) => { 1380 button.setAttribute("aria-expanded", "false"); 1381 }); 1382 }, 1383 setupDateComboBox(option, target) { 1384 const comboBoxs = document.querySelectorAll(".calendar-drop-down > button"); 1385 if (option === "init") { 1386 comboBoxs.forEach((comboBox, idx) => { 1387 const listBox = comboBox.nextElementSibling.querySelector(".sel"); 1388 const listOptions = listBox.querySelectorAll("button"); 1389 const uniqueIdx = `${idx}${Math.random().toString(36).substring(2, 9)}`; 1390 1391 comboBox.setAttribute("role", "combobox"); 1392 comboBox.setAttribute("aria-haspopup", "listbox"); 1393 comboBox.setAttribute("aria-expanded", "false"); 1394 comboBox.setAttribute("aria-controls", `combo-list-${uniqueIdx}`); 1395 1396 listBox.setAttribute("role", "listbox"); 1397 listBox.setAttribute("id", `combo-list-${uniqueIdx}`); 1398 listBox.querySelectorAll("li").forEach((li) => li.setAttribute("role", "none")); 1399 1400 listOptions.forEach((listOption) => { 1401 listOption.setAttribute("role", "option"); 1402 listOption.setAttribute("aria-selected", "false"); 1403 if (listOption.classList.contains("active")) { 1404 listOption.setAttribute("aria-selected", "true"); 1405 comboBox.innerHTML = listOption.innerHTML; 1406 } 1407 }); 1408 }); 1409 } 1410 if (option === "reset") { 1411 comboBoxs.forEach((comboBox) => { 1412 comboBox.setAttribute("aria-expanded", "false"); 1413 }); 1414 if (target) { 1415 target.setAttribute("aria-expanded", "true"); 1416 } 1417 } 1418 if (option === "change") { 1419 comboBoxs.forEach((comboBox) => { 1420 const listBox = comboBox.nextElementSibling.querySelector(".sel"); 1421 const listOptions = listBox.querySelectorAll("button"); 1422 1423 comboBox.setAttribute("aria-expanded", "false"); 1424 1425 listOptions.forEach((listOption) => { 1426 listOption.classList.remove("active"); 1427 listOption.setAttribute("aria-selected", "false"); 1428 }); 1429 }); 1430 if (target) { 1431 target.setAttribute("aria-selected", "true"); 1432 target.classList.add("active"); 1433 target.closest(".calendar-drop-down").querySelector("button").innerHTML = target.innerHTML; 1434 } 1435 1436 // ui ëì íì¸ì© í ì¤í¸ ì½ë 1437 this.example(); 1438 } 1439 }, 1440 toggleDateSelector() { 1441 this.datePickerArea.forEach((datePicker) => { 1442 const selectToggleButtons = datePicker.querySelectorAll(".calendar-drop-down .btn-cal-switch"); 1443 const selectOptions = datePicker.querySelectorAll(".calendar-select .sel button"); 1444 1445 // ê³µíµ ì´ë²¤í¸ ì²ë¦¬ 1446 const handleBtnClick = (event, selectMenu) => { 1447 const layer = selectMenu; 1448 1449 // ì´ë¯¸ íì±íë ë ì´ì´ ë«ê¸° 1450 if (this.activeDateSelector === layer) { 1451 layer.classList.remove("active"); 1452 this.setupDateComboBox("reset"); 1453 this.activeDateSelector = null; 1454 return; 1455 } 1456 1457 // íì¬ ì´ë ¤ ìë ë ì´ì´ê° ìì¼ë©´ ë«ì 1458 if (this.activeDateSelector) { 1459 this.activeDateSelector.classList.remove("active"); 1460 this.setupDateComboBox("reset"); 1461 } 1462 1463 // í´ë¦í ë²í¼ì í´ë¹íë ë ì´ì´ ì´ê¸° 1464 layer.classList.add("active"); 1465 this.setupDateComboBox("reset", event.target); 1466 this.activeDateSelector = layer; 1467 }; 1468 1469 // ì ë í° ì¤ì 1470 selectToggleButtons.forEach((toggle) => { 1471 toggle.addEventListener("click", (event) => { 1472 const selectMenu = event.target.closest(".calendar-drop-down").querySelector(".calendar-select"); 1473 handleBtnClick(event, selectMenu); 1474 }); 1475 }); 1476 1477 // ë ë, ì ì í 1478 selectOptions.forEach((option) => { 1479 option.addEventListener("click", (event) => { 1480 this.resetDateSelector(); 1481 this.setupDateComboBox("change", event.target); 1482 1483 // í¬ì»¤ì¤ ì´ë 1484 setTimeout(() => { 1485 option.closest(".calendar-drop-down").querySelector(".btn-cal-switch")?.focus(); 1486 }, 50); 1487 }); 1488 }); 1489 1490 // esc ë«ê¸° 1491 datePicker.addEventListener("keydown", (event) => { 1492 if (event.code === "Escape") { 1493 this.resetDateSelector(); 1494 } 1495 }); 1496 });
1497 }, 1498 actionDatePicker() { 1499 this.datePickerArea.forEach((datePicker) => { 1500 const actionButtons = datePicker.querySelectorAll(".calendar-btn-wrap button:not(#get-today)"); 1501 actionButtons.forEach((button) => { 1502 button.addEventListener("click", () => { 1503 this.closeAllDatePickers(); 1504 }); 1505 }); 1506 }); 1507 }, 1508 // ui ëì íì¸ì© í ì¤í¸ ì½ë 1509 example() { 1510 this.datePickerArea.forEach((datePicker) => { 1511 const year = datePicker.querySelector(".calendar-switch-wrap .year").innerText.slice(0, -1); 1512 const month = datePicker.querySelector(".calendar-switch-wrap .month").innerText.slice(0, -1); 1513 const caption = datePicker.querySelector(".calendar-tbl caption"); 1514 const tblCells = datePicker.querySelectorAll(".calendar-tbl td"); 1515 const tblCellBtns = datePicker.querySelectorAll(".calendar-tbl td .btn-set-date"); 1516 const actionBtns = datePicker.querySelectorAll(".calendar-btn-wrap button"); 1517 let clickCount = 0; 1518 let startTd = null; 1519 1520 // 캡ì ì¤ì 1521 caption.innerHTML = `${year}ë ${month}ì`; 1522 1523 // í ì¤í¸ì© (ì¤ì 구íììë ë ì§ ë°°ì´ì ë°ì ì²ë¦¬í¨) 1524 tblCells.forEach((cell) => { 1525 const day = cell.querySelector(".btn-set-date").innerText.padStart(2, "0"); 1526 let [numberYear, numberMonth] = [parseFloat(year), parseFloat(month)]; 1527 if (cell.classList.contains("old")) { 1528 if (numberMonth === 1) { 1529 numberYear -= 1; 1530 numberMonth = 12; 1531 } else { 1532 numberMonth -= 1; 1533 } 1534 } else if (cell.classList.contains("new")) { 1535 if (numberMonth === 12) { 1536 numberYear += 1; 1537 numberMonth = 1; 1538 } else { 1539 numberMonth += 1;
1540 } 1541 } 1542 cell.setAttribute("data-date", `${numberYear}.${String(numberMonth).padStart(2, "0")}.${day}`); 1543 }); 1544 1545 // action 1546 const accReset = (action, btn, type) => { 1547 // ì¸í ë¨ì¼ 1548 const targetInput = btn.closest(".calendar-conts").querySelector("input.datepicker.cal"); 1549 // ì¸í ë¶í 1550 const targetInputStart = btn.closest(".calendar-conts").querySelector(".input-group.range.set li:first-child input.datepicker"); 1551 const targetInputEnd = btn.closest(".calendar-conts").querySelector(".input-group.range.set li:last-child input.datepicker"); 1552 1553 action.addEventListener("click", () => { 1554 if (targetInput) { 1555 targetInput.setAttribute("type", "text"); 1556 const target = action.innerText; 1557 if (target === "ì¤ë") { 1558 accSet(); 1559 } 1560 if (target === "íì¸") { 1561 if (type === "single") { 1562 const value = action.closest(".krds-calendar-area").querySelector("td.period.start.end").getAttribute("data-date"); 1563 targetInput.value = value; 1564 } else { 1565 const value1 = action.closest(".krds-calendar-area").querySelector("td.period.start")?.getAttribute("data-date"); 1566 const value2 = action.closest(".krds-calendar-area").querySelector("td.period.end")?.getAttribute("data-date") || ""; 1567 targetInput.value = `${value1} ~ ${value2}`; 1568 } 1569 } 1570 } else { 1571 targetInputStart.setAttribute("type", "text"); 1572 targetInputEnd.setAttribute("type", "text"); 1573 const target = action.innerText; 1574 if (target === "ì¤ë") { 1575 accSet(); 1576 } 1577 if (target === "íì¸") { 1578 const value1 = action.closest(".krds-calendar-area").querySelector("td.period.start")?.getAttribute("data-date"); 1579 const value2 = action.closest(".krds-calendar-area").querySelector("td.period.end")?.getAttribute("data-date") || ""; 1580 targetInputStart.value = value1; 1581 targetInputEnd.value = value2; 1582 } 1583 } 1584 }); 1585 // ê³µíµ ì ê·¼ì± 1586 const accSet = () => { 1587 const prevItems = action.closest(".krds-calendar-area").querySelectorAll(".period"); 1588 prevItems.forEach((prev) => { 1589 prev.classList.remove("period", "start", "end"); 1590 prev.querySelector(".btn-set-date").removeAttribute("aria-pressed"); 1591 }); 1592 action.closest(".krds-calendar-area").querySelector("td.today").classList.add("period", "start", "end"); 1593 action.closest(".krds-calendar-area").querySelector("td.today .btn-set-date").setAttribute("aria-pressed", "true"); 1594 }; 1595 }; 1596 1597 // btn-set-date 1598 tblCellBtns.forEach((btn) => { 1599 // disabled ì¤ì 1600 if (btn.closest("td.new, td.old")) { 1601 btn.setAttribute("disabled", "true"); 1602 } 1603 1604 // var 1605 const isSingle = btn.closest(".calendar-wrap").classList.contains("single"); 1606 1607 if (isSingle) { 1608 btn.addEventListener("click", () => { 1609 tblCellBtns.forEach((otherBtn) => { 1610 otherBtn.closest("td").classList.remove("period", "start", "end"); 1611 otherBtn.removeAttribute("aria-pressed"); 1612 }); 1613 btn.closest("td").classList.add("period", "start", "end"); 1614 btn.setAttribute("aria-pressed", "true"); 1615 }); 1616 // action 1617 actionBtns.forEach((action) => { 1618 accReset(action, btn, "single"); 1619 }); 1620 } else { 1621 btn.addEventListener("click", () => { 1622 const currentTd = btn.closest("td"); 1623 // íì¬ tdì ë ì§ 1624 const currentDate = new Date(currentTd.getAttribute("data-date")); 1625 // ë ë²ì§¸ í´ë¦ì¼ ë, ììë ì§ ì´ì ì´ë©´ ì´ê¸°í 1626 if (startTd) { 1627 const startDate = new Date(startTd.getAttribute("data-date")); 1628 if (currentDate < startDate) { 1629 console.log("ììë ì§ ì´ì ì ì íí ì ììµëë¤."); 1630 startTd = null; 1631 clickCount = 0; 1632 // return; 1633 } 1634 } 1635 1636 clickCount++; 1637 1638 if (clickCount % 2 === 1) { 1639 tblCellBtns.forEach((otherBtn) => { 1640 otherBtn.closest("td").classList.remove("period", "start", "end"); 1641 otherBtn.removeAttribute("aria-pressed"); 1642 }); 1643 btn.closest("td").classList.add("period", "start"); 1644 btn.setAttribute("aria-pressed", "true"); 1645 startTd = currentTd; 1646 } else { 1647 btn.closest("td").classList.add("period", "end"); 1648 btn.setAttribute("aria-pressed", "true"); 1649 let started = false; 1650 tblCellBtns.forEach((otherBtn) => { 1651 const td = otherBtn.closest("td"); 1652 if (td === startTd) { 1653 started = true; 1654 } 1655 if (started && td !== currentTd) { 1656 td.classList.add("period"); 1657 otherBtn.setAttribute("aria-pressed", "true"); 1658 } 1659 if (td === currentTd) { 1660 started = false; 1661 } 1662 }); 1663 startTd = null; 1664 } 1665 }); 1666 // action 1667 actionBtns.forEach((action) => { 1668 accReset(action, btn); 1669 }); 1670 } 1671 }); 1672 });
1673 }, 1674}; 1675 1676/*** * krds_inPageNavigation * ***/ 1677const krds_inPageNavigation = { 1678 quickIndicators: null, 1679 init() { 1680 this.quickIndicators = document.querySelectorAll(".krds-in-page-navigation-type .krds-in-page-navigation-area:not(.sample) .in-page-navigation-list"); 1681 1682 if (!this.quickIndicators.length) return; 1683 1684 this.observeListChanges(); 1685 this.setupAnchorScroll(); 1686 this.updateActiveSection(); 1687 }, 1688 observeListChanges() { 1689 // in-page-navigation-list ë³ê²½ ì setupAnchorScroll í¸ì¶ 1690 const quickList = document.querySelector(".krds-in-page-navigation-type .in-page-navigation-list"); 1691 if (!quickList) return; 1692 const observer = new MutationObserver(() => { 1693 this.setupAnchorScroll(); 1694 }); 1695 observer.observe(quickList, { 1696 childList: true, 1697 subtree: true, 1698 }); 1699 }, 1700 setupAnchorScroll() { 1701 this.quickIndicators.forEach((indicator) => { 1702 const locationList = indicator.querySelectorAll("a"); 1703 locationList.forEach((anchor) => { 1704 const target = document.querySelector(anchor.getAttribute("href")); 1705 if (target) { 1706 anchor.removeEventListener("click", this.applyScroll); 1707 anchor.removeEventListener("keydown", this.applyScroll); 1708 anchor.addEventListener("click", this.applyScroll.bind(this, target)); 1709 anchor.addEventListener("keydown", (event) => { 1710 if (event.key === "Enter" || event.key === " ") { 1711 this.applyScroll(target, event); 1712 } 1713 }); 1714 } 1715 }); 1716 }); 1717 }, 1718 applyScroll(target, event) { 1719 event.preventDefault(); 1720 const headerHeight = this.calculateHeaderHeight(); 1721 1722 window.scrollTo({ 1723 left: 0, 1724 top: target.getBoundingClientRect().top + window.scrollY - headerHeight, 1725 behavior: "smooth", 1726 }); 1727 1728 // enter ì´ì ì´ë 1729 if (event.type === "keydown") { 1730 const focusable = target.querySelector(".sec-tit"); 1731 1732 if (focusable) { 1733 focusable.setAttribute("tabindex", "-1"); 1734 focusable.focus({ preventScroll: true }); 1735 } 1736 } 1737 }, 1738 calculateHeaderHeight() { 1739 const headerTop = document.querySelector("#krds-masthead")?.clientHeight || 0; 1740 const headerInner = document.querySelector("#krds-header .header-in")?.clientHeight || 0; 1741 return headerTop + headerInner; 1742 }, 1743 updateActiveSection() { 1744 if (!this.quickIndicators) return; 1745 1746 const winHeight = window.innerHeight; 1747 let sectionArea = []; 1748 const activeTab = document.querySelector(".tab-conts:not(.sample).active"); 1749 1750 // íì´ ìëëì íì¼ë sectionArea ì¤ì 1751 if (activeTab) { 1752 const id = activeTab.getAttribute("id"); 1753 const dataTrue = activeTab.getAttribute("data-quick-nav"); 1754 if (dataTrue === "true") { 1755 sectionArea = document.querySelectorAll(`#${id} .section-link`); 1756 } 1757 } else { 1758 sectionArea = document.querySelectorAll(".scroll-check .section-link"); 1759 } 1760 1761 //íì´ì§ ì¤í¬ë¡¤ ì íµ ë¤ë¹ê²ì´ì í´ë¹ë©ë´ active 1762 if (sectionArea.length > 0) { 1763 const topHeight = Math.ceil(winHeight / 5); // ìëì°ì 20% 1764 const firstSecTop = sectionArea[0].offsetTop; 1765 const scrollBottom = window.scrollY + winHeight; 1766 const scrollHeight = document.body.scrollHeight; 1767 sectionArea.forEach((current) => { 1768 const sectionHeight = current.offsetHeight; 1769 const sectionTop = current.offsetTop - topHeight; 1770 const sectionId = current.getAttribute("id"); 1771 const navLink = document.querySelector(`.krds-in-page-navigation-area a[href*=${sectionId}]`); 1772 const firstAnchor = document.querySelector(".krds-in-page-navigation-area .in-page-navigation-list li:first-of-type a"); 1773 const lastAnchor = document.querySelector(".krds-in-page-navigation-area .in-page-navigation-list li:last-of-type a"); 1774 if (scrollBottom >= scrollHeight) { 1775 // ì¤í¬ë¡¤ì´ íì´ì§ ëì ëë¬íì ë 1776 this.setActiveIndicator(lastAnchor); 1777 } 1778 else if (window.scrollY <= firstSecTop) { 1779 // ì¤í¬ë¡¤ì´ 첫ë²ì§¸ ì¹ì ë³´ë¤ ìì ììë 1780 this.setActiveIndicator(firstAnchor); 1781 } else if (window.scrollY > sectionTop && window.scrollY <= sectionTop + sectionHeight) { 1782 // íì¬ ì¹ì ì ìì ë 1783 this.setActiveIndicator(navLink); 1784 } 1785 }); 1786 } 1787 }, 1788 setActiveIndicator(anchor) { 1789 if (anchor) {
1790 this.quickIndicators.forEach((indicator) => { 1791 const locationList = indicator.querySelectorAll("a"); 1792 locationList.forEach((anchor) => { 1793 anchor.classList.remove("active"); 1794 }); 1795 }); 1796 anchor.classList.add("active"); 1797 } 1798 }, 1799}; 1800 1801/*** * krds_helpPanel * ***/ 1802const krds_helpPanel = { 1803 helpPanel: null, 1804 lastFocusedButton: null, 1805 executeButton: null, 1806 collapseButton: null, 1807 init() { 1808 this.helpPanel = document.querySelector(".krds-help-panel"); 1809 1810 if (!this.helpPanel) return; 1811 1812 this.executeButton = document.querySelectorAll(".btn-help-exec"); 1813 this.collapseButton = this.helpPanel.querySelector(".btn-help-panel.fold"); 1814 1815 this.setupPadding(); 1816 this.observeMastHead(); 1817 this.setupHelpButtons(); 1818 this.toggleScrollLock(); 1819 }, 1820 setupPadding() { 1821 const topBannerHeight = document.querySelector("#krds-masthead")?.offsetHeight; 1822 const headerHeight = document.querySelector("#krds-header .header-in")?.offsetHeight; 1823 const defaultPadding = topBannerHeight + headerHeight; 1824 const hiddenBannerPadding = headerHeight; 1825 1826 const expandBox = document.querySelector(".help-panel-wrap"); 1827 const expandButton = document.querySelector(".btn-help-panel.expand"); 1828 1829 const applyPadding = (padding) => { 1830 expandButton.style.marginTop = padding; 1831 if (windowSize.getWinSize() === "pc") { 1832 expandBox.style.paddingTop = padding; 1833 this.collapseButton.style.marginTop = padding; 1834 } else { 1835 expandBox.removeAttribute("style"); 1836 this.collapseButton.removeAttribute("style"); 1837 } 1838 }; 1839 1840 // bn-hidden: í¤ë ë°°ë ì¨ê¹, scroll-down: í¤ë ì¨ê¹ 1841 if (document.body.classList.contains("bn-hidden")) { 1842 if (document.querySelector("#wrap").classList.contains("scroll-down")) { 1843 applyPadding("0"); 1844 } else { 1845 applyPadding(`${hiddenBannerPadding}px`); 1846 } 1847 } else { 1848 applyPadding(`${defaultPadding}px`); 1849 } 1850 }, 1851 observeMastHead() { 1852 const topBanner = document.querySelector("#krds-masthead"); 1853 if (!topBanner) return; 1854 const body = document.body; 1855 const observer = new IntersectionObserver( 1856 (entries) => { 1857 entries.forEach((entry) => { 1858 body.classList.toggle("bn-hidden", !entry.isIntersecting); 1859 }); 1860 }, 1861 { root: null, threshold: 0 } 1862 ); 1863 observer.observe(topBanner); 1864 }, 1865 setupHelpButtons() { 1866 this.executeButton.forEach((btn) => { 1867 btn.addEventListener("click", () => { 1868 this.lastFocusedButton = btn; 1869 this.toggleHelpPanel("open", btn); 1870 }); 1871 btn.setAttribute("aria-expanded", "false"); 1872 }); 1873 if (this.collapseButton) { 1874 this.collapseButton.addEventListener("click", () => { 1875 this.toggleHelpPanel("close"); 1876 }); 1877 } 1878 }, 1879 toggleHelpPanel(action, triggerBtn) { 1880 const helpWrap = document.querySelector(".help-panel-wrap"); 1881 const innerContainer = document.querySelector("#container > .inner"); 1882 1883 if (!helpWrap || !innerContainer || !this.helpPanel) return; 1884 1885 if (action === "open") { 1886 if (windowSize.getWinSize() === "mob") { 1887 document.body.classList.add("scroll-no"); 1888 } 1889 1890 this.helpPanel.classList.add("expand"); 1891 helpWrap.setAttribute("tabindex", "0"); 1892 1893 if (triggerBtn) { 1894 setTimeout(() => { 1895 helpWrap.focus(); 1896 }, 50); 1897 } 1898 1899 // ëìí¨ëì íì´ì§ì íê°ë§ ìê³ ì»¨í¸ë¡¤íë ë²í¼ì ì¬ë¬ê°ì¼ë 1900 this.executeButton.forEach((btn) => { 1901 btn.setAttribute("aria-expanded", "true"); 1902 }); 1903 1904 // innerê° flexibleì¸ ê²½ì° 1905 if (innerContainer.classList.contains("help-panel-flexible")) { 1906 innerContainer.classList.add("help-panel-expanded"); 1907 } 1908 } else if (action === "close") { 1909 if (windowSize.getWinSize() === "mob") { 1910 document.body.classList.remove("scroll-no"); 1911 } 1912 1913 this.helpPanel.classList.remove("expand"); 1914 helpWrap.removeAttribute("tabindex"); 1915 1916 if (this.lastFocusedButton) { 1917 this.lastFocusedButton.focus(); 1918 } else { 1919 // ì²ì ë¶í° ì¤íì¼ë ì§ì ë²í¼ì¼ë¡ í¬ì»¤ì¤ ì´ë 1920 document.querySelector(".btn-help-panel.expand").focus(); 1921 } 1922 1923 // ëìí¨ëì íì´ì§ì íê°ë§ ìê³ ì»¨í¸ë¡¤íë ë²í¼ì ì¬ë¬ê°ì¼ë 1924 this.executeButton.forEach((btn) => { 1925 btn.setAttribute("aria-expanded", "false"); 1926 }); 1927 1928 // innerê° flexibleì¸ ê²½ì° 1929 if (innerContainer.classList.contains("help-panel-flexible")) { 1930 innerContainer.classList.remove("help-panel-expanded"); 1931 } 1932 } 1933 }, 1934 toggleScrollLock() { 1935 setTimeout(() => { 1936 if (windowSize.getWinSize() === "mob" && this.helpPanel.classList.contains("expand")) { 1937 document.body.classList.add("scroll-no"); 1938 } else { 1939 document.body.classList.remove("scroll-no"); 1940 } 1941 }, 0); 1942 }, 1943}; 1944 1945/*** * krds_disclosure * ***/ 1946const krds_disclosure = { 1947 disclosures: null, 1948 init() { 1949 this.disclosures = document.querySelectorAll(".krds-disclosure"); 1950 1951 if (!this.disclosures.length) return; 1952 1953 this.setupDisclosure(); 1954 }, 1955 setupDisclosure() {
1956 this.disclosures.forEach((disclosure) => { 1957 const disclosureButton = disclosure.querySelector(".btn-conts-expand"); 1958 const disclosureContent = disclosure.querySelector(".expand-wrap"); 1959 const uniqueIdx = `disclosure-${Math.random().toString(36).substring(2, 9)}`; 1960 1961 // ìì¸ ì²ë¦¬: disclosureButton ìì´ active ìí를 ì§ì ì¤ì íì¬ íì¥ ìí를 ì ì´íë ê²½ì° 1962 if (!disclosureButton) return; 1963 1964 // aria ìì± ì¤ì 1965 disclosureButton.setAttribute("aria-expanded", "false"); 1966 disclosureButton.setAttribute("aria-controls", uniqueIdx); 1967 disclosureContent.setAttribute("id", uniqueIdx); 1968 // disclosureContent.setAttribute("aria-hidden", "true"); // ìì: disclosure ë´ì©ì´ ì¼ë¶ë§ ë ¸ì¶ëë ê²½ì° 1969 disclosureContent.setAttribute("inert", ""); 1970 if (disclosure.classList.contains("active")) { 1971 disclosureButton.setAttribute("aria-expanded", "true"); 1972 // disclosureContent.setAttribute("aria-hidden", "false"); // ìì: disclosure ë´ì©ì´ ì¼ë¶ë§ ë ¸ì¶ëë ê²½ì° 1973 disclosureContent.removeAttribute("inert"); 1974 } 1975 1976 disclosureButton.addEventListener("click", () => { 1977 this.toggleDisclosure(disclosure, disclosureButton, disclosureContent); 1978 }); 1979 }); 1980 }, 1981 toggleDisclosure(disclosure, disclosureButton, disclosureContent) { 1982 const isExpanded = disclosureButton.getAttribute("aria-expanded") === "true"; 1983 1984 disclosure.classList.toggle("active", !isExpanded); 1985 disclosureButton.setAttribute("aria-expanded", !isExpanded); 1986 1987 // disclosureContent.setAttribute("aria-hidden", isExpanded); // ìì: disclosure ë´ì©ì´ ì¼ë¶ë§ ë ¸ì¶ëë ê²½ì° 1988 if (isExpanded) { 1989 disclosureContent.setAttribute("inert", ""); 1990 } else { 1991 disclosureContent.removeAttribute("inert"); 1992 } 1993 }, 1994}; 1995 1996/*** * krds_adjustContentScale * ***/ 1997const krds_adjustContentScale = { 1998 body: document.body, 1999 scaleLevel: 1, 2000 minScale: 0.5, 2001 maxScale: 2, 2002 init() { 2003 const scaleButtons = document.querySelectorAll("[data-adjust] [data-adjust-scale]"); 2004 2005 if (!scaleButtons.length) return; 2006 2007 // root ë³ììì ì¤ì¼ì¼ ê°ì ê°ì ¸ì¤ê¸° 2008 2009 const zoomSmall = 0.9; 2010 const zoomMedium = 1; 2011 const zoomLarge = 1.1; 2012 const zoomXlarge = 1.2; 2013 const zoomXxlarge = 1.3; 2014 2015 //const root = document.querySelector(":root"); 2016 //const rootStyles = getComputedStyle(root); 2017 //const zoomSmall = rootStyles.getPropertyValue("--krds-zoom-small").trim(); 2018 //const zoomMedium = rootStyles.getPropertyValue("--krds-zoom-medium").trim(); 2019 //const zoomLarge = rootStyles.getPropertyValue("--krds-zoom-large").trim(); 2020 //const zoomXlarge = rootStyles.getPropertyValue("--krds-zoom-xlarge").trim(); 2021 //const zoomXxlarge = rootStyles.getPropertyValue("--krds-zoom-xxlarge").trim(); 2022 2023 2024 scaleButtons.forEach((button) => { 2025 button.addEventListener("click", () => { 2026 const scale = button.getAttribute("data-adjust-scale"); 2027 switch (scale) { 2028 case "sm": 2029 this.scaleValue(zoomSmall); 2030 break; 2031 case "md": 2032 const others = button.closest(".drop-menu").querySelectorAll(".item-link"); 2033 const defaultSize = button.closest(".drop-menu").querySelector(".item-link.md"); 2034 others.forEach((item) => { 2035 item.classList.remove("active"); 2036 item.setAttribute("aria-selected", "false"); 2037 item.querySelector(".sr-only").innerHTML = ""; 2038 }); 2039 defaultSize.classList.add("active"); 2040 defaultSize.querySelector(".sr-only").innerHTML = "ì íë¨"; 2041 this.scaleValue(zoomMedium); 2042 break; 2043 case "lg": 2044 this.scaleValue(zoomLarge); 2045 break; 2046 case "xlg": 2047 this.scaleValue(zoomXlarge); 2048 break; 2049 case "xxlg": 2050 this.scaleValue(zoomXxlarge); 2051 break; 2052 default: 2053 break; 2054 } 2055 }); 2056 });
2057 }, 2058 scaleValue(value) { 2059 this.scaleLevel = value; 2060 document.body.style.zoom = this.scaleLevel; 2061 }, 2062 scaleDefault() { 2063 this.scaleLevel = 1; 2064 document.body.style.zoom = this.scaleLevel; 2065 }, 2066/* scaleMin() { 2067 this.scaleLevel = this.minScale; 2068 this.body.style.zoom = this.scaleLevel; 2069 }, 2070 scaleMax() { 2071 this.scaleLevel = this.maxScale; 2072 this.body.style.zoom = this.scaleLevel; 2073 }, 2074 scaleUp() { 2075 if (this.scaleLevel < this.maxScale) { 2076 this.scaleLevel += 0.1; 2077 if (this.scaleLevel > this.maxScale) this.scaleLevel = this.maxScale; 2078 this.body.style.zoom = this.scaleLevel; 2079 } 2080 }, 2081 scaleDown() { 2082 if (this.scaleLevel > this.minScale) { 2083 this.scaleLevel -= 0.1; 2084 if (this.scaleLevel < this.minScale) this.scaleLevel = this.minScale; 2085 this.body.style.zoom = this.scaleLevel; 2086 } 2087 }, */ 2088}; 2089 2090/*** * krds_toggleSwitch * ***/ 2091const krds_toggleSwitch = { 2092 init() { 2093 const toggleSwitch = document.querySelectorAll(".krds-form-toggle-switch"); 2094 2095 if (!toggleSwitch.length) return; 2096 2097 toggleSwitch.forEach((toggle) => { 2098 const input = toggle.querySelector("input"); 2099 if (!input) return; 2100 input.addEventListener("focus", () => { 2101 toggle.classList.add("focus"); 2102 }); 2103 input.addEventListener("focusout", () => { 2104 toggle.classList.remove("focus"); 2105 }); 2106 }); 2107 }, 2108}; 2109 2110/*** * krds_infoList * ***/ 2111const krds_infoList = { 2112 init() { 2113 const infoLists = document.querySelectorAll(".krds-info-list"); 2114 2115 if (!infoLists.length) return; 2116 2117 infoLists.forEach((list) => { 2118 list.setAttribute("role", "list"); 2119 const listItems = list.querySelectorAll("li"); 2120 listItems.forEach((item) => { 2121 item.setAttribute("role", "listitem"); 2122 }); 2123 }); 2124 }, 2125}; 2126 2127/*** * krds_dropEvent(gnb utils / page-title-wrap) * ***/ 2128const krds_dropEvent = { 2129 dropButtons: null, 2130 init() { 2131 this.dropButtons = document.querySelectorAll(".krds-drop-wrap:not(.sample) .drop-btn"); 2132 2133 if (!this.dropButtons.length) return; 2134 2135 this.setupEventListeners(); 2136 this.setupFocusOutEvent(); 2137 }, 2138 setupEventListeners() { 2139 this.dropButtons.forEach((button) => { 2140 const menu = button.nextElementSibling; 2141 button.setAttribute("aria-expanded", "false"); 2142 2143 button.addEventListener("click", () => { 2144 const isOpen = menu.style.display === "block"; 2145 this.closeAllDropdowns(); 2146 if (!isOpen) { 2147 this.openDropdown(button, menu); 2148 } 2149 }); 2150 2151 this.setupMenuItems(menu); 2152 }); 2153 }, 2154 setupMenuItems(menu) { 2155 if (!menu) return; // â null ì²´í¬ ì¶ê° 2156 const items = menu.querySelectorAll(".item-link"); 2157 2158 items.forEach((item) => { 2159 item.innerHTML += `<span class="sr-only"></span>`; 2160 if (item.classList.contains("active")) { 2161 item.querySelector(".sr-only").innerHTML = "ì íë¨"; 2162 } 2163 2164 item.addEventListener("click", () => { 2165 this.activateMenuItem(item); 2166 this.closeAllDropdowns(); 2167 const button = item.closest(".krds-drop-wrap").querySelector(".drop-btn"); 2168 button?.focus(); 2169 }); 2170 2171 item.addEventListener("focus", () => { 2172 document.querySelectorAll(".krds-drop-wrap .drop-list .item-link").forEach((item) => { 2173 item.style.position = "relative"; 2174 item.style.zIndex = "0"; 2175 }); 2176 item.style.zIndex = "1"; 2177 }); 2178 }); 2179 }, 2180 activateMenuItem(selectedItem) { 2181 const menu = selectedItem.closest(".drop-menu"); 2182 const items = menu.querySelectorAll(".item-link"); 2183 2184 items.forEach((item) => { 2185 item.classList.remove("active"); 2186 item.setAttribute("aria-selected", "false"); 2187 item.querySelector(".sr-only").innerText = ""; 2188 }); 2189 2190 selectedItem.classList.add("active"); 2191 selectedItem.setAttribute("aria-selected", "true"); 2192 selectedItem.querySelector(".sr-only").innerText = "ì íë¨"; 2193 }, 2194 openDropdown(button, menu) { 2195 menu.style.display = "block"; 2196 button.classList.add("active"); 2197 button.setAttribute("aria-expanded", "true"); 2198 2199 // ì¬ë°±ì ë°ë¼ ìì¹ ì¡°ì 2200 const menuRect = menu.getBoundingClientRect(); 2201 const windowWidth = window.innerWidth; 2202 if (menuRect.left < 0) { 2203 menu.closest(".krds-drop-wrap").classList.add("drop-left"); 2204 } else if (windowWidth < menuRect.left + menuRect.width) { 2205 menu.closest(".krds-drop-wrap").classList.add("drop-right"); 2206 } 2207 2208 }, 2209 closeAllDropdowns() { 2210 document.querySelectorAll(".krds-drop-wrap .drop-menu").forEach((menu) => { 2211 menu.style.display = "none"; 2212 });
2213 this.dropButtons.forEach((button) => { 2214 button.classList.remove("active"); 2215 button.setAttribute("aria-expanded", "false"); 2216 }); 2217 }, 2218 setupFocusOutEvent() { 2219 // ESC ë«ê¸° 2220 document.addEventListener("keydown", (event) => { 2221 if (event.key === "Escape" || event.key === "Esc") { 2222 this.closeAllDropdowns(); 2223 event.target.closest(".krds-drop-wrap")?.querySelector(".drop-btn")?.focus(); 2224 } 2225 }); 2226 2227 // ëë¡ë¤ì´ ì¸ë¶ í´ë¦ ì ë«ê¸° 2228 document.addEventListener("click", (event) => { 2229 if (!event.target.closest(".krds-drop-wrap")) { 2230 this.closeAllDropdowns(); 2231 } 2232 }); 2233 2234 // ëë¡ë¤ì´ í¬ì»¤ì¤ ìì ì²ë¦¬ 2235 this.dropButtons.forEach((button) => { 2236 const menu = button.nextElementSibling; 2237 2238 if (!menu) return; 2239 2240 // ëë¡ë¤ì´ ë©ë´ì í¬ì»¤ì¤ ìì ì²ë¦¬ 2241 menu.addEventListener("focusout", (event) => { 2242 const isFocusInside = menu.contains(event.relatedTarget) || button.contains(event.relatedTarget); 2243 if (!isFocusInside) { 2244 this.closeAllDropdowns(); 2245 } 2246 }); 2247 2248 // ë²í¼ì í¬ì»¤ì¤ ìì ì²ë¦¬ 2249 button.addEventListener("focusout", (event) => { 2250 const isFocusInside = menu.contains(event.relatedTarget) || button.contains(event.relatedTarget); 2251 if (!isFocusInside) { 2252 this.closeAllDropdowns(); 2253 } 2254 }); 2255 }); 2256 }, 2257}; 2258 2259/*** * krds_chkBox ë°ì¤í ì²´í¬ë°ì¤ ìíì ë°ë¥¸ ëìì¸ ë³ê²½ * ***/ 2260const krds_chkBox = { 2261 init() { 2262 const box = document.querySelectorAll(".chk-group-wrap"); 2263 box.forEach((e) => { 2264 const boxList = e.querySelectorAll("li"); 2265 boxList.forEach((ele) => { 2266 ele.removeAttribute("class"); 2267 const thisList = ele.closest("li"); 2268 const checkbox = ele.querySelector("input[type=checkbox]"); 2269 if (checkbox != null) { 2270 const is_disabled = checkbox.disabled; 2271 let is_checked = checkbox.checked; 2272 2273 if (is_disabled == true) { 2274 thisList.classList.add("disabled"); 2275 } else { 2276 if (is_checked == true) { 2277 thisList.classList.add("checked"); 2278 } 2279 } 2280 2281 checkbox.addEventListener("click", () => { 2282 if (is_checked == true) { 2283 thisList.classList.remove("checked"); 2284 is_checked = false; 2285 } else { 2286 thisList.classList.add("checked"); 2287 is_checked = true; 2288 } 2289 }); 2290 } 2291 2292 const rdo = ele.querySelector("input[type=radio]"); 2293 if (rdo != null) { 2294 const is_disabled = rdo.disabled; 2295 let is_checked = rdo.checked; 2296 2297 if (is_disabled == true) { 2298 thisList.classList.add("disabled"); 2299 } else { 2300 if (is_checked == true) { 2301 thisList.classList.add("checked"); 2302 } 2303 } 2304 2305 rdo.addEventListener("click", (e) => { 2306 const rdoGroup = rdo.closest(".chk-group-wrap"); 2307 const rdoLi = rdoGroup.querySelectorAll("li"); 2308 let is_checked2 = e.checked; 2309 rdoLi.forEach((ele) => { 2310 ele.classList.remove("checked"); 2311 is_checked2 = false; 2312 }); 2313 if (is_checked2 == true) { 2314 thisList.classList.remove("checked"); 2315 is_checked2 = false; 2316 } else { 2317 thisList.classList.add("checked"); 2318 is_checked2 = true; 2319 } 2320 }); 2321 } 2322 }); 2323 }); 2324 2325 this.formChipFocus(); 2326 }, 2327 formChipFocus() { 2328 // form_chip ì¼ë í¬ì»¤ì¤ ì²ë¦¬ 2329 const formChip = document.querySelectorAll(".krds-form-chip"); 2330 2331 if (!formChip.length) return; 2332 2333 formChip.forEach((chip) => { 2334 const input = chip.querySelector("input"); 2335 if (!input) return; 2336 input.addEventListener("focus", () => { 2337 chip.classList.add("focus"); 2338 }); 2339 input.addEventListener("focusout", () => { 2340 chip.classList.remove("focus"); 2341 }); 2342 });
2343 2344 }, 2345}; 2346 2347/*** * krds_fileUpload íì¼ ì ë¡ë : drag ìì * ***/ 2348const krds_fileUpload = { 2349 init() { 2350 const fileUploads = document.querySelectorAll(".file-upload"); 2351 fileUploads.forEach((fileUpload) => { 2352 const inputFile = fileUpload.querySelector('input[type="file"]'); 2353 const inputButton = fileUpload.querySelector("button"); 2354 2355 inputButton.addEventListener("click", () => { 2356 inputFile.click(); 2357 }); 2358 2359 fileUpload.addEventListener("dragover", (e) => { 2360 fileUpload.classList.add("active"); 2361 e.preventDefault(); 2362 }); 2363 2364 fileUpload.addEventListener("dragleave", (e) => { 2365 fileUpload.classList.remove("active"); 2366 e.preventDefault(); 2367 }); 2368 2369 fileUpload.addEventListener("drop", (e) => { 2370 fileUpload.classList.remove("active"); 2371 e.preventDefault(); 2372 // const files = e.dataTransfer.files; 2373 }); 2374 }); 2375 }, 2376}; 2377 2378/*** * nuriToggleEvent ëë¦¬ì§ í ê¸ ì´ë²¤í¸ íì¬ë ì¬ì© ì í¨ * ***/ 2379const nuriToggleEvent = { 2380 init() { 2381 const _toggleBtns = document.querySelectorAll("#krds-masthead .toggle-btn"); 2382 _toggleBtns.forEach(($toggleBtn) => { 2383 $toggleBtn.addEventListener("click", ($btnAct) => { 2384 const $target = $btnAct.target.closest(".toggle-head"); 2385 const $targetBody = $target.nextElementSibling; 2386 const _targetBodyH = $targetBody.querySelector(".inner").scrollHeight; 2387 const $srEl = $btnAct.target.querySelector(".sr-only"); 2388 2389 if (!$target.classList.contains("active")) { 2390 $srEl.innerText = "ë«í"; 2391 $target.classList.add("active"); 2392 $targetBody.classList.add("active"); 2393 $targetBody.style.height = `${_targetBodyH}px`; 2394 window.addEventListener("resize", () => { 2395 if ($targetBody.classList.contains("active")) { 2396 const _targetBodyH = $targetBody.querySelector(".inner").scrollHeight; 2397 $targetBody.style.height = `${_targetBodyH}px`; 2398 } 2399 }); 2400 } else { 2401 $srEl.innerText = "ì´ë¦¼"; 2402 $target.classList.remove("active"); 2403 $targetBody.classList.remove("active"); 2404 $targetBody.style.height = ""; 2405 } 2406 }); 2407 }); 2408 }, 2409}; 2410 2411/*** * krds_tts * ***/ 2412const krds_tts = { 2413 speechSynthesis: null, 2414 activeButton: null, 2415 2416 init() { 2417 this.speechSynthesis = window.speechSynthesis; 2418 // Chromeìì voices ì´ê¸°í í¸ë¦¬ê±°(ë¹ë기 ë¡ëëëë¼ë speakë ì§ì° ìì´ í¸ì¶í´ì¼ í¨) 2419 try { 2420 this.speechSynthesis && this.speechSynthesis.getVoices(); 2421 } catch (e) {} 2422 2423 const ttsButtons = document.querySelectorAll(".krds-tts:not([disabled]):not(.disabled)"); 2424 2425 ttsButtons.forEach((button) => { 2426 button.setAttribute("aria-pressed", "false"); 2427 // onclickì´ ìì¼ë©´ ì´ë²¤í¸ 리ì¤ë ì¶ê° 2428 if (!button.getAttribute("onclick")) { 2429 button.addEventListener("click", (e) => { 2430 e.preventDefault(); 2431 const text = button.getAttribute("data-tts-text"); 2432 if (text) { 2433 this.toggle(button, text); 2434 } 2435 }); 2436 } 2437 }); 2438 }, 2439 2440 toggle(button, text) { 2441 const isPlaying = button.classList.contains("is-playing"); 2442 2443 if (isPlaying) { 2444 this.stop(button); 2445 } else { 2446 this.play(button, text); 2447 } 2448 }, 2449 2450 play(button, text) { 2451 if (!text || text.trim() === '') return; 2452 if (!this.speechSynthesis) return; 2453 2454 // ë¤ë¥¸ ë²í¼ì´ ì¬ì ì¤ì´ë©´ ë©ì¶¤ 2455 if (this.activeButton && this.activeButton !== button) { 2456 this.stop(this.activeButton); 2457 } 2458 2459 // ìí ì ë°ì´í¸ 2460 const isPlayType = button.classList.contains("play"); 2461 if (isPlayType) { 2462 this.changeToPause(button); 2463 } 2464 2465 button.classList.add("is-playing"); 2466 button.setAttribute("aria-pressed", "true"); 2467 this.activeButton = button; 2468 this.updateText(button, "ë©ì¶¤"); 2469 2470 // TTS ì¬ì 2471 this.speak(text, button); 2472 }, 2473 2474 stop(button) { 2475 if (this.speechSynthesis) { 2476 this.speechSynthesis.cancel(); 2477 } 2478 2479 button.classList.remove("is-playing"); 2480 button.setAttribute("aria-pressed", "false"); 2481 2482 // Play íì ì´ìë ê²½ì° ìëëë¡ ë³µì 2483 if (button.classList.contains("pause") && button.dataset.wasPlayType === "true") { 2484 this.changeToPlay(button); 2485 } 2486 2487 this.updateText(button, "ì¬ì"); 2488 2489 if (this.activeButton === button) { 2490 this.activeButton = null; 2491 } 2492 }, 2493 2494 speak(text, button) { 2495 if (!this.speechSynthesis) return; 2496 // Chrome: user gesture ììì speakê° ì¤íëì´ì¼ í´ì ì§ì° í¸ì¶(setTimeout ë±) ê¸ì§ 2497 if (this.speechSynthesis.paused) { 2498 this.speechSynthesis.resume(); 2499 } 2500 this.startUtterance(text, button); 2501 }, 2502 2503 startUtterance(text, button) { 2504 if (!this.speechSynthesis) return; 2505 const utterance = new SpeechSynthesisUtterance(text); 2506 // Chromeììë lang/voice íì´ë° ì´ìê° ìì´ ê°ì ì¤ì ì ìµìí 2507 utterance.rate = 1; 2508 utterance.pitch = 1; 2509 utterance.volume = 1; 2510 2511 // ê°ë¥í ê²½ì°ìë§ ko ìì±/ì¸ì´ ì ì© (ìì¼ë©´ ë¸ë¼ì°ì 기본ì¼ë¡ ì§í) 2512 try { 2513 const voices = this.speechSynthesis.getVoices?.() || [];
2514 const ko = voices.find((v) => (v.lang || "").toLowerCase().startsWith("ko")); 2515 if (ko) { 2516 utterance.lang = "ko-KR"; 2517 utterance.voice = ko; 2518 } 2519 } catch (e) {} 2520 2521 utterance.onend = () => { 2522 if (this.activeButton === button) { 2523 this.stop(button); 2524 } 2525 }; 2526 2527 utterance.onerror = (event) => { 2528 // canceledë ì¬ì©ì/ì½ë cancel()ë¡ ì ì ë°ì ê°ë¥ 2529 if (event.error !== "canceled" && this.activeButton === button) { 2530 this.stop(button); 2531 } 2532 }; 2533 2534 try { 2535 // Chrome ì°í: ê°ì í´ë¦ ì ì¤ì² ììì cancel/resume/speak를 í ë²ì ìí 2536 // (ë¹ë기 ì§ì°ì user-gesture를 깨ì 무ìì´ ë ì ìì´ ì¬ì©íì§ ìì) 2537 this.speechSynthesis.cancel(); 2538 if (this.speechSynthesis.paused) this.speechSynthesis.resume(); 2539 this.speechSynthesis.speak(utterance); 2540 // ì¼ë¶ Chromeìì speak ì§í resumeì´ íìí ëê° ìì 2541 if (this.speechSynthesis.paused) this.speechSynthesis.resume(); 2542 } catch (error) { 2543 if (this.activeButton === button) { 2544 this.stop(button); 2545 } 2546 } 2547 }, 2548 2549 changeToPause(button) { 2550 if (!button.dataset.wasPlayType) { 2551 button.dataset.wasPlayType = "true"; 2552 } 2553 button.classList.remove("play"); 2554 button.classList.add("pause"); 2555 const icon = button.querySelector(".krds-tts-icon .svg-icon"); 2556 if (icon) { 2557 icon.classList.remove("ico-play"); 2558 icon.classList.add("ico-stop"); 2559 } 2560 }, 2561 2562 changeToPlay(button) { 2563 button.classList.remove("pause"); 2564 button.classList.add("play"); 2565 const icon = button.querySelector(".krds-tts-icon .svg-icon"); 2566 if (icon) { 2567 icon.classList.remove("ico-stop"); 2568 icon.classList.add("ico-play"); 2569 } 2570 delete button.dataset.wasPlayType; 2571 }, 2572 2573 updateText(button, newText) { 2574 const textElement = button.querySelector(".krds-tts-text"); 2575 if (!textElement) return; 2576 2577 // ìë í ì¤í¸ ì ì¥ (ì²ì í ë²ë§) 2578 if (!textElement.dataset.originalText) { 2579 textElement.dataset.originalText = textElement.textContent.trim(); 2580 } 2581 2582 // ìë í ì¤í¸ê° "ì¬ì"ì¸ ê²½ì°ë§ ë³ê²½ 2583 const originalText = textElement.dataset.originalText; 2584 if (originalText === "ì¬ì") { 2585 textElement.textContent = newText === "ë©ì¶¤" ? "ë©ì¶¤" : "ì¬ì"; 2586 } 2587 }, 2588}; 2589 2590// ì ì í¨ì: onclickìì ì¬ì© 2591// ì¬ì©ë²: onclick="krds_playTts('ì½ì ë´ì©', this)" 2592window.krds_playTts = function(text, buttonElement) { 2593 if (!text || text.trim() === '') return; 2594 // ìµì ì§ë¨(Chrome 무ì ìì¸ íì ì©): voicesê° 0ì´ë©´ íê²½/ë¡ë© 문ì ê°ë¥ì± í¼ 2595 try { 2596 if (window.speechSynthesis) { 2597 console.log("[krds-tts] protocol:", location.protocol, "voices:", window.speechSynthesis.getVoices().length); 2598 } 2599 } catch (e) {} 2600 2601 // buttonElement 찾기 2602 if (!buttonElement) { 2603 const event = window.event || (typeof event !== 'undefined' ? event : null); 2604 if (event) { 2605 buttonElement = event.currentTarget || event.target?.closest('.krds-tts'); 2606 } 2607 if (!buttonElement) { 2608 buttonElement = document.activeElement; 2609 } 2610 } 2611 2612 if (!buttonElement || !buttonElement.classList.contains("krds-tts")) return; 2613 2614 // aria-pressed ì´ê¸°ê° ì¤ì 2615 if (!buttonElement.hasAttribute("aria-pressed")) { 2616 buttonElement.setAttribute("aria-pressed", "false"); 2617 } 2618 2619 // ì¬ì/ë©ì¶¤ í ê¸ 2620 const isPlaying = buttonElement.classList.contains("is-playing"); 2621 if (isPlaying) { 2622 krds_tts.stop(buttonElement); 2623 } else { 2624 krds_tts.play(buttonElement, text); 2625 } 2626}; 2627 2628// ì´ê¸° ì´ë²¤í¸ 2629window.addEventListener("DOMContentLoaded", () => { 2630 // ìëì° ì¬ì´ì¦ ì²´í¬ 2631 windowSize.setWinSize(); 2632 2633 krds_mainMenuPC.init(); 2634 krds_mainMenuMobile.init(); 2635 krds_sideNavigation.init(); 2636 krds_tab.init(); 2637 krds_accordion.init(); 2638 krds_modal.init(); 2639 krds_contextualHelp.init(); 2640 krds_tooltip.init(); 2641 krds_disclosure.init(); 2642 krds_dropEvent.init();
2643 krds_calendar.init(); 2644 krds_inPageNavigation.init(); 2645 krds_adjustContentScale.init(); 2646 krds_toggleSwitch.init(); 2647 krds_infoList.init(); 2648 krds_chkBox.init(); 2649 krds_fileUpload.init(); 2650 krds_tts.init(); 2651 2652 krds_helpPanel.init(); 2653 if (windowSize.getWinSize() === "pc") { 2654 krds_helpPanel.toggleHelpPanel("open"); 2655 } 2656}); 2657 2658// ì¤í¬ë¡¤ ì´ë²¤í¸ 2659window.addEventListener("scroll", () => { 2660 scrollManager.updateScrollValues(); 2661 scrollManager.handleScrollDirection(); 2662 2663 krds_mainMenuPC.closeMainMenu(); 2664 krds_inPageNavigation.updateActiveSection(); 2665 krds_helpPanel.init(); 2666}); 2667 2668// 리ì¬ì´ì¦ ì´ë²¤í¸ 2669window.addEventListener("resize", () => { 2670 windowSize.setWinSize(); 2671 krds_helpPanel.init(); 2672});
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.