Rewrite AddInstanceDialog

Object oriented it is
This commit is contained in:
CenTdemeern1 2025-02-03 03:15:14 +01:00
parent 5534bc3942
commit 2be0658ed9
4 changed files with 101 additions and 35 deletions

View file

@ -1,5 +1,6 @@
// This file handles the "Add an instance" dialog // This file handles the "Add an instance" dialog
import { FormDialog, ONCE } from "./dialog.mjs";
import { findButtonOrFail, findFormOrFail, findInputOrFail } from "./dom.mjs"; import { findButtonOrFail, findFormOrFail, findInputOrFail } from "./dom.mjs";
export function parseHost(host: string): { host: string, secure: boolean } | null { export function parseHost(host: string): { host: string, secure: boolean } | null {
@ -13,43 +14,66 @@ export function parseHost(host: string): { host: string, secure: boolean } | nul
}; };
} }
export function initializeAddInstanceDialog( type AddInstanceDialogData = {
dialog: HTMLDialogElement,
callback: (
host: string, host: string,
secure: boolean, secure: boolean,
autoQueryMetadata: boolean, autoQueryMetadata: boolean,
) => void };
): {
showAddInstanceDialog: () => void,
hideAddInstanceDialog: () => void,
} {
const showAddInstanceDialog = () => dialog.showModal();
const hideAddInstanceDialog = () => dialog.close();
const form = findFormOrFail(dialog, ".addInstanceForm"); export class AddInstanceDialog extends FormDialog {
const instanceHost = findInputOrFail(form, "#instanceHost"); protected instanceHost: HTMLInputElement;
const autoQueryMetadata = findInputOrFail(form, "#autoQueryMetadata"); protected autoQueryMetadata: HTMLInputElement;
const closeButton = findButtonOrFail(form, ".close"); protected closeButton: HTMLButtonElement;
instanceHost.addEventListener("input", e => { constructor(dialog: HTMLDialogElement, initializeDOM: boolean = true) {
if (parseHost(instanceHost.value) === null) super(dialog, findFormOrFail(dialog, ".addInstanceForm"));
instanceHost.setCustomValidity("Invalid instance hostname or URL"); this.instanceHost = findInputOrFail(this.form, "#instanceHost");
else this.autoQueryMetadata = findInputOrFail(this.form, "#autoQueryMetadata");
instanceHost.setCustomValidity(""); this.closeButton = findButtonOrFail(this.form, ".close");
});
form.addEventListener("submit", e => { if (initializeDOM) this.initializeDOM();
// A sane browser doesn't allow for submitting the form if the above validation fails }
const { host, secure } = parseHost(instanceHost.value)!;
callback(host, secure, autoQueryMetadata.checked);
form.reset();
});
closeButton.addEventListener("click", e => hideAddInstanceDialog());
#getDataIfValid(): AddInstanceDialogData | null {
const parsedHost = parseHost(this.instanceHost.value);
if (parsedHost === null) {
this.instanceHost.setCustomValidity("Invalid instance hostname or URL");
return null;
}
this.instanceHost.setCustomValidity("");
return { return {
showAddInstanceDialog, host: parsedHost.host,
hideAddInstanceDialog secure: parsedHost.secure,
autoQueryMetadata: this.autoQueryMetadata.checked
}; };
} }
#handleSubmit(resolve: (data: AddInstanceDialogData) => void) {
this.form.addEventListener("submit", e => {
const data = this.#getDataIfValid();
if (data === null) {
// Prevent the user from submitting the form if it's invalid and let them try again
e.preventDefault();
this.#handleSubmit(resolve);
return;
}
resolve(data);
this.close();
}, ONCE);
}
protected override initializeDOM() {
super.initializeDOM();
this.instanceHost.addEventListener("input", e => this.#getDataIfValid());
this.closeButton.addEventListener("click", e => this.close());
}
async prompt(): Promise<AddInstanceDialogData> {
return new Promise((resolve, reject) => {
this.dialog.addEventListener("close", e => reject(), ONCE);
this.#handleSubmit(resolve);
this.open();
});
}
}

View file

@ -1,4 +1,4 @@
import { initializeAddInstanceDialog } from "./add_an_instance.mjs"; import { AddInstanceDialog } from "./add_an_instance.mjs";
import { initializeInstanceDetailsDialog } from "./confirm_instance_details.mjs"; import { initializeInstanceDetailsDialog } from "./confirm_instance_details.mjs";
import storageManager, { Instance } from "./storage_manager.mjs"; import storageManager, { Instance } from "./storage_manager.mjs";

41
static/dialog.mts Normal file
View file

@ -0,0 +1,41 @@
export const ONCE = { once: true };
export class Dialog {
protected dialog: HTMLDialogElement;
constructor(dialog: HTMLDialogElement) {
this.dialog = dialog;
}
/**
* A function that should only be called once that has permanent effects on the DOM
*/
protected initializeDOM() { }
protected open() {
this.dialog.showModal();
}
close() {
this.dialog.close();
}
};
export class FormDialog extends Dialog {
protected form: HTMLFormElement;
constructor(dialog: HTMLDialogElement, form: HTMLFormElement) {
super(dialog);
this.form = form;
}
protected override initializeDOM() {
super.initializeDOM();
this.dialog.addEventListener("close", e => this.reset());
}
reset() {
this.form.reset();
}
}

View file

@ -4,6 +4,7 @@
"allowJs": true, "allowJs": true,
"checkJs": true, "checkJs": true,
"strictNullChecks": true, "strictNullChecks": true,
"noImplicitOverride": true,
}, },
"include": [ "include": [
"static/**.mts", "static/**.mts",