Files
baron_qa_write/SW문의_소스패키지/assets/js/header-login.js
T
root 308c06516c
Deploy EG-BIM QA Gateway / deploy (push) Successful in 1m0s
fix: 전체 UI 개선
2026-11-02 13:26:14 +09:00

85 lines
3.5 KiB
JavaScript

// 헤더 로그인 팝오버 보조 스크립트
// - 기존 CSS의 hover/focus-within 표시는 그대로 두고, 클릭(터치) 열기·바깥 클릭 닫기·Esc 닫기·aria-expanded만 보완한다.
// - 로그인/로그아웃 링크의 주소, 문구, 노출 여부는 common.js(configureHeaderActions)가 SSO 상태에 맞춰 설정하므로 여기서 다루지 않는다.
// - 헤더는 AJAX로 늦게 삽입되므로 document 이벤트 위임으로 처리한다.
const WRAPPER_SELECTOR = ".header_login";
const TRIGGER_SELECTOR = ".header_login_trigger";
function setExpanded(wrapper, expanded) {
wrapper.querySelector(TRIGGER_SELECTOR)?.setAttribute("aria-expanded", String(expanded));
}
function openMenu(wrapper) {
document.querySelectorAll(`${WRAPPER_SELECTOR}.is-open`).forEach((other) => {
if (other !== wrapper) closeMenu(other);
});
wrapper.classList.remove("is-dismissed");
wrapper.classList.add("is-open");
setExpanded(wrapper, true);
}
// dismiss: hover/focus가 남아 있어도 포인터·포커스가 벗어날 때까지 닫힌 상태를 유지한다(Esc).
function closeMenu(wrapper, { dismiss = false } = {}) {
wrapper.classList.remove("is-open");
wrapper.classList.toggle("is-dismissed", dismiss);
setExpanded(wrapper, false);
}
function isMenuVisible(wrapper) {
if (wrapper.hidden || wrapper.classList.contains("is-dismissed")) return false;
return wrapper.classList.contains("is-open") || wrapper.matches(":hover, :focus-within");
}
if (!window.__baronHeaderLoginBound) {
window.__baronHeaderLoginBound = true;
document.addEventListener("pointerover", (event) => {
if (event.pointerType === "touch") return;
const wrapper = event.target.closest?.(WRAPPER_SELECTOR);
if (wrapper && !wrapper.contains(event.relatedTarget) && !wrapper.classList.contains("is-dismissed")) {
setExpanded(wrapper, true);
}
});
document.addEventListener("pointerout", (event) => {
if (event.pointerType === "touch") return;
const wrapper = event.target.closest?.(WRAPPER_SELECTOR);
if (wrapper && !wrapper.contains(event.relatedTarget) && !wrapper.contains(document.activeElement)) {
closeMenu(wrapper);
}
});
document.addEventListener("focusin", (event) => {
const wrapper = event.target.closest?.(WRAPPER_SELECTOR);
if (wrapper && !wrapper.classList.contains("is-dismissed")) setExpanded(wrapper, true);
});
document.addEventListener("focusout", (event) => {
const wrapper = event.target.closest?.(WRAPPER_SELECTOR);
if (wrapper && !wrapper.contains(event.relatedTarget) && !wrapper.matches(":hover")) {
closeMenu(wrapper);
}
});
document.addEventListener("click", (event) => {
const trigger = event.target.closest?.(TRIGGER_SELECTOR);
const wrapper = trigger?.closest(WRAPPER_SELECTOR);
if (wrapper) {
openMenu(wrapper);
return;
}
if (!event.target.closest?.(WRAPPER_SELECTOR)) {
document.querySelectorAll(`${WRAPPER_SELECTOR}.is-open`).forEach((openWrapper) => closeMenu(openWrapper));
}
});
document.addEventListener("keydown", (event) => {
if (event.key !== "Escape") return;
const wrapper = [...document.querySelectorAll(WRAPPER_SELECTOR)].find(isMenuVisible);
if (!wrapper) return;
const hadFocus = wrapper.contains(document.activeElement);
closeMenu(wrapper, { dismiss: true });
if (hadFocus) wrapper.querySelector(TRIGGER_SELECTOR)?.focus({ preventScroll: true });
});
}