import { CLASS_ACCORDION_TOGGLE, CLASS_MENU_SECTION } from "./constants"; const MOBILE_MEDIA_QUERY = "(max-width: 479.98px)"; interface FooterSection { element: HTMLElement; toggle: HTMLButtonElement | null; panel: HTMLElement | null; } export default class Footer { element!: HTMLElement; sections!: FooterSection[]; mediaQueryList!: MediaQueryList; onToggleClick!: (event: Event) => void; onMediaQueryChange!: () => void; constructor(element: HTMLElement) { if ((element as any).ODS_Footer) { return (element as any).ODS_Footer; } this.element = element; this.sections = []; this.mediaQueryList = window.matchMedia(MOBILE_MEDIA_QUERY); this.onToggleClick = this.handleToggleClick.bind(this); this.onMediaQueryChange = this.syncViewportState.bind(this); (this.element as any).ODS_Footer = this; this.init(); return this; } static getInstance(el: HTMLElement): Footer | null { return el && (el as any).ODS_Footer ? (el as any).ODS_Footer : null; } init(): void { this.sections = Array.from( this.element.querySelectorAll( `[data-footer-section].${CLASS_MENU_SECTION}`, ), ).map((section) => { const toggle = section.querySelector( `.${CLASS_ACCORDION_TOGGLE}`, ) as HTMLButtonElement | null; const panelId = toggle?.getAttribute("aria-controls"); const panel = panelId ? (this.element.querySelector(`#${panelId}`) as HTMLElement | null) : null; if (toggle) { toggle.addEventListener("click", this.onToggleClick); } return { element: section as HTMLElement, toggle, panel, }; }); this.mediaQueryList.addEventListener("change", this.onMediaQueryChange); this.syncViewportState(); } private setSectionState(section: FooterSection, isExpanded: boolean): void { if (!section.toggle || !section.panel) return; section.toggle.setAttribute("aria-expanded", String(isExpanded)); section.panel.hidden = !isExpanded; } private syncViewportState(): void { const isMobile = this.mediaQueryList.matches; this.sections.forEach((section, index) => { if (!section.toggle || !section.panel) return; if (!isMobile) { this.setSectionState(section, true); section.element.removeAttribute("data-footer-mobile-initialized"); return; } const isInitialized = section.element.getAttribute("data-footer-mobile-initialized") === "true"; if (!isInitialized) { this.setSectionState(section, index === 0); section.element.setAttribute("data-footer-mobile-initialized", "true"); return; } const isExpanded = section.toggle.getAttribute("aria-expanded") === "true"; this.setSectionState(section, isExpanded); }); } private handleToggleClick(event: Event): void { if (!this.mediaQueryList.matches) return; const toggle = event.currentTarget as HTMLButtonElement; const section = this.sections.find((item) => item.toggle === toggle); if (!section || !section.toggle) return; const isExpanded = section.toggle.getAttribute("aria-expanded") === "true"; this.setSectionState(section, !isExpanded); } destroy(): void { this.sections.forEach((section) => { if (!section.toggle) return; section.toggle.removeEventListener("click", this.onToggleClick); }); this.mediaQueryList.removeEventListener("change", this.onMediaQueryChange); } update(): void { this.destroy(); this.init(); } }