diff --git a/frontend/src/ts/modals/quote-report.ts b/frontend/src/ts/modals/quote-report.ts index 425ae56b5..fd2b4a806 100644 --- a/frontend/src/ts/modals/quote-report.ts +++ b/frontend/src/ts/modals/quote-report.ts @@ -60,11 +60,6 @@ export async function show( async function hide(clearChain = false): Promise { void modal.hide({ clearModalChain: clearChain, - afterAnimation: async () => { - CaptchaController.reset("quoteReportModal"); - state.reasonSelect?.destroy(); - state.reasonSelect = undefined; - }, }); } @@ -131,7 +126,14 @@ async function setup(modalEl: HTMLElement): Promise { }); } +async function cleanup(): Promise { + CaptchaController.reset("quoteReportModal"); + state.reasonSelect?.destroy(); + state.reasonSelect = undefined; +} + const modal = new AnimatedModal({ dialogId: "quoteReportModal", setup, + cleanup, }); diff --git a/frontend/src/ts/modals/quote-search.ts b/frontend/src/ts/modals/quote-search.ts index ffc0be97b..0d89c02c9 100644 --- a/frontend/src/ts/modals/quote-search.ts +++ b/frontend/src/ts/modals/quote-search.ts @@ -312,10 +312,6 @@ export async function show(showOptions?: ShowOptions): Promise { function hide(clearChain = false): void { void modal.hide({ clearModalChain: clearChain, - afterAnimation: async () => { - lengthSelect?.destroy(); - lengthSelect = undefined; - }, }); } @@ -456,7 +452,13 @@ async function setup(modalEl: HTMLElement): Promise { }); } +async function cleanup(): Promise { + lengthSelect?.destroy(); + lengthSelect = undefined; +} + const modal = new AnimatedModal({ dialogId: "quoteSearchModal", setup, + cleanup, }); diff --git a/frontend/src/ts/modals/quote-submit.ts b/frontend/src/ts/modals/quote-submit.ts index 7f8248c0e..05201b719 100644 --- a/frontend/src/ts/modals/quote-submit.ts +++ b/frontend/src/ts/modals/quote-submit.ts @@ -82,11 +82,6 @@ export async function show(showOptions: ShowOptions): Promise { function hide(clearModalChain: boolean): void { void modal.hide({ clearModalChain, - afterAnimation: async () => { - CaptchaController.reset("submitQuote"); - select?.destroy(); - select = undefined; - }, }); } @@ -97,7 +92,14 @@ async function setup(modalEl: HTMLElement): Promise { }); } +async function cleanup(): Promise { + CaptchaController.reset("submitQuote"); + select?.destroy(); + select = undefined; +} + const modal = new AnimatedModal({ dialogId: "quoteSubmitModal", setup, + cleanup, }); diff --git a/frontend/src/ts/modals/user-report.ts b/frontend/src/ts/modals/user-report.ts index 9e8f606a1..83bfc254f 100644 --- a/frontend/src/ts/modals/user-report.ts +++ b/frontend/src/ts/modals/user-report.ts @@ -64,13 +64,7 @@ export async function show(options: ShowOptions): Promise { } async function hide(): Promise { - void modal.hide({ - afterAnimation: async () => { - select?.destroy(); - select = undefined; - CaptchaController.reset("userReportModal"); - }, - }); + void modal.hide(); } async function submitReport(): Promise { @@ -140,4 +134,9 @@ const modal = new AnimatedModal({ void submitReport(); }); }, + cleanup: async (): Promise => { + select?.destroy(); + select = undefined; + CaptchaController.reset("userReportModal"); + }, }); diff --git a/frontend/src/ts/modals/word-filter.ts b/frontend/src/ts/modals/word-filter.ts index 6bc20fe2c..c7b7e9f93 100644 --- a/frontend/src/ts/modals/word-filter.ts +++ b/frontend/src/ts/modals/word-filter.ts @@ -185,14 +185,6 @@ export async function show(showOptions?: ShowOptions): Promise { function hide(hideOptions?: HideOptions): void { void modal.hide({ ...hideOptions, - afterAnimation: async () => { - languageSelect?.destroy(); - layoutSelect?.destroy(); - presetSelect?.destroy(); - languageSelect = undefined; - layoutSelect = undefined; - presetSelect = undefined; - }, }); } @@ -326,6 +318,15 @@ async function setup(): Promise { }); } +async function cleanup(): Promise { + languageSelect?.destroy(); + layoutSelect?.destroy(); + presetSelect?.destroy(); + languageSelect = undefined; + layoutSelect = undefined; + presetSelect = undefined; +} + type OutgoingData = { text: string; set: boolean; @@ -334,4 +335,5 @@ type OutgoingData = { const modal = new AnimatedModal({ dialogId: "wordFilterModal", setup, + cleanup, }); diff --git a/frontend/src/ts/utils/animated-modal.ts b/frontend/src/ts/utils/animated-modal.ts index 0677a6f34..c0a866f46 100644 --- a/frontend/src/ts/utils/animated-modal.ts +++ b/frontend/src/ts/utils/animated-modal.ts @@ -48,6 +48,7 @@ type ConstructorParams = { customEscapeHandler?: (e: KeyboardEvent) => void; customWrapperClickHandler?: (e: MouseEvent) => void; setup?: (modal: HTMLElement) => Promise; + cleanup?: () => Promise; }; const DEFAULT_ANIMATION_DURATION = 125; @@ -73,6 +74,7 @@ export default class AnimatedModal< private customEscapeHandler: ((e: KeyboardEvent) => void) | undefined; private customWrapperClickHandler: ((e: MouseEvent) => void) | undefined; private setup: ((modal: HTMLElement) => Promise) | undefined; + private cleanup: (() => Promise) | undefined; constructor(constructorParams: ConstructorParams) { if (constructorParams.dialogId.startsWith("#")) { @@ -123,6 +125,7 @@ export default class AnimatedModal< this.customWrapperClickHandler = constructorParams?.customWrapperClickHandler; this.setup = constructorParams?.setup; + this.cleanup = constructorParams?.cleanup; Skeleton.save(this.dialogId); } @@ -132,24 +135,26 @@ export default class AnimatedModal< } async runSetup(): Promise { - this.wrapperEl.addEventListener("keydown", (e) => { + this.wrapperEl.addEventListener("keydown", async (e) => { if (e.key === "Escape" && isPopupVisible(this.dialogId)) { e.preventDefault(); e.stopPropagation(); if (this.customEscapeHandler !== undefined) { this.customEscapeHandler(e); + void this.cleanup?.(); } else { - void this.hide(); + await this.hide(); } } }); - this.wrapperEl.addEventListener("mousedown", (e) => { + this.wrapperEl.addEventListener("mousedown", async (e) => { if (e.target === this.wrapperEl) { if (this.customWrapperClickHandler !== undefined) { this.customWrapperClickHandler(e); + void this.cleanup?.(); } else { - void this.hide(); + await this.hide(); } } }); @@ -392,6 +397,7 @@ export default class AnimatedModal< Skeleton.remove(this.dialogId); this.open = false; await options?.afterAnimation?.(this.modalEl); + void this.cleanup?.(); if ( this.previousModalInChain !== undefined && @@ -428,6 +434,7 @@ export default class AnimatedModal< Skeleton.remove(this.dialogId); this.open = false; await options?.afterAnimation?.(this.modalEl); + void this.cleanup?.(); if ( this.previousModalInChain !== undefined && @@ -453,6 +460,7 @@ export default class AnimatedModal< destroy(): void { this.wrapperEl.close(); this.wrapperEl.classList.add("hidden"); + void this.cleanup?.(); Skeleton.remove(this.dialogId); this.open = false; }