const {$} = (window as any).fwdekker; import {blurActiveElement} from "./Common"; /** * A modal dialog displayed in HTML. */ export class ModalDialog { private readonly dialog: HTMLElement; private readonly openButton?: HTMLElement; private readonly onOpen?: () => void; /** * Constructs a new modal dialog wrapper. * * @param dialog the dialog maintained by this instance * @param openButton the element that opens the dialog when clicked * @param onOpen the callback to invoke when the dialog is opened * @param form the form contained in the dialog * @param closeButton the element that closes the dialog's form when clicked * @param submitButton the element that submits the dialog's form when clicked * @param onSubmit the callback to invoke when the dialog's form is submitted */ constructor( { dialog, openButton, onOpen, form, closeButton, submitButton, onSubmit }: { dialog: HTMLElement, openButton?: HTMLElement, onOpen?: (() => void), form?: HTMLFormElement, closeButton?: HTMLElement, submitButton?: HTMLElement, onSubmit?: (() => void) } ) { this.dialog = dialog; this.openButton = openButton; this.onOpen = onOpen; document.addEventListener( "click", event => { if (!(event.target instanceof Node)) return; console.log("close"); if (event.target !== openButton && !this.dialog.contains(event.target) || this.dialog === event.target) this.close(); } ); document.addEventListener( "keydown", event => { if (event.key === "Escape" && this.isOpen()) this.close(); } ); openButton?.addEventListener( "click", event => { event.preventDefault(); this.open(); } ); closeButton?.addEventListener( "click", event => { event.preventDefault(); this.close(); } ); form?.addEventListener( "submit", event => { event.preventDefault(); onSubmit?.(); } ); submitButton?.addEventListener( "click", event => { event.preventDefault(); onSubmit?.(); } ); } /** * Opens the dialog. */ open(): void { console.log("opening"); blurActiveElement(); setTimeout(() => $("[autofocus]", this.dialog)?.focus(), 100); this.dialog.setAttribute("open", "true"); this.onOpen?.(); } /** * Closes the dialog. */ close(): void { if (this.isOpen()) { this.dialog.removeAttribute("open"); setTimeout(() => this.openButton?.focus(), 100); } } /** * Returns `true` if and only if this dialog is currently open. */ isOpen(): boolean { return this.dialog.hasAttribute("open"); } }