From 91e6150be4b9021f7fda9652f8d0a8a9a626ad9b Mon Sep 17 00:00:00 2001 From: CenTdemeern1 Date: Tue, 14 Jan 2025 14:52:31 +0100 Subject: [PATCH] A little spring cleaning --- static/add_an_instance.mts | 21 +++++----------- static/confirm_instance_details.mts | 35 +++++++-------------------- static/dom.mts | 37 +++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 42 deletions(-) create mode 100644 static/dom.mts diff --git a/static/add_an_instance.mts b/static/add_an_instance.mts index 44af221..c8130fc 100644 --- a/static/add_an_instance.mts +++ b/static/add_an_instance.mts @@ -1,5 +1,7 @@ // This file handles the "Add an instance" dialog +import { findButtonOrFail, findFormOrFail, findInputOrFail } from "./dom.mjs"; + export function parseHost(host: string): { host: string, secure: boolean } | null { let parsedInstance = URL.parse(host); parsedInstance ??= URL.parse("https://" + host); @@ -25,13 +27,10 @@ export function initializeAddInstanceDialog( const showAddInstanceDialog = () => dialog.showModal(); const hideAddInstanceDialog = () => dialog.close(); - const form = dialog.querySelector(".addInstanceForm"); - if (!(form instanceof HTMLFormElement)) - throw new Error(".addInstanceForm isn't a form"); - - const instanceHost = form.querySelector("#instanceHost"); - if (!(instanceHost instanceof HTMLInputElement)) - throw new Error("#instanceHost isn't an input"); + const form = findFormOrFail(dialog, ".addInstanceForm"); + const instanceHost = findInputOrFail(form, "#instanceHost"); + const autoQueryMetadata = findInputOrFail(form, "#autoQueryMetadata"); + const closeButton = findButtonOrFail(form, ".close"); instanceHost.addEventListener("input", e => { if (parseHost(instanceHost.value) === null) @@ -40,10 +39,6 @@ export function initializeAddInstanceDialog( instanceHost.setCustomValidity(""); }); - const autoQueryMetadata = form.querySelector("#autoQueryMetadata"); - if (!(autoQueryMetadata instanceof HTMLInputElement)) - throw new Error("#autoQueryMetadata isn't an input"); - form.addEventListener("submit", e => { // A sane browser doesn't allow for submitting the form if the above validation fails const { host, secure } = parseHost(instanceHost.value)!; @@ -51,10 +46,6 @@ export function initializeAddInstanceDialog( form.reset(); }); - const closeButton = form.querySelector(".close"); - if (!(closeButton instanceof HTMLButtonElement)) - throw new Error(".close isn't a button"); - closeButton.addEventListener("click", e => hideAddInstanceDialog()); return { diff --git a/static/confirm_instance_details.mts b/static/confirm_instance_details.mts index 4a4c808..f175a4a 100644 --- a/static/confirm_instance_details.mts +++ b/static/confirm_instance_details.mts @@ -1,5 +1,6 @@ // This file handles the "Confirm instance details" dialog +import { findButtonOrFail, findFormOrFail, findImageOrFail, findInputOrFail, findSelectOrFail } from "./dom.mjs"; import { resize } from "./image.mjs"; import knownSoftware from "./known_software.mjs"; @@ -28,35 +29,19 @@ export function initializeInstanceDetailsDialog( const showInstanceDetailsDialog = () => dialog.showModal(); const hideInstanceDetailsDialog = () => dialog.close(); - const form = dialog.querySelector(".instanceDetailsForm"); - if (!(form instanceof HTMLFormElement)) - throw new Error(".instanceDetailsForm isn't a form"); - - const instanceName = form.querySelector("#instanceName"); - if (!(instanceName instanceof HTMLInputElement)) - throw new Error("#instanceName isn't an input"); - - const instanceHost = form.querySelector("#instanceHost"); - if (!(instanceHost instanceof HTMLInputElement)) - throw new Error("#instanceHost isn't an input"); - - const instanceHostSecure = form.querySelector("#instanceHostSecure"); - if (!(instanceHostSecure instanceof HTMLInputElement)) - throw new Error("#instanceHostSecure isn't an input"); - - const instanceSoftware = form.querySelector("#instanceSoftware"); - if (!(instanceSoftware instanceof HTMLSelectElement)) - throw new Error("#instanceSoftware isn't a select"); + const form = findFormOrFail(dialog, ".instanceDetailsForm"); + const instanceName = findInputOrFail(form, "#instanceName"); + const instanceHost = findInputOrFail(form, "#instanceHost"); + const instanceHostSecure = findInputOrFail(form, "#instanceHostSecure"); + const instanceSoftware = findSelectOrFail(form, "#instanceSoftware"); + const instanceIcon = findImageOrFail(form, "#instanceIcon"); + const closeButton = findButtonOrFail(form, ".close"); for (const [name, software] of Object.entries(knownSoftware.software)) { const option = new Option(software.name, name); instanceSoftware.appendChild(option); } - const instanceIcon = form.querySelector("#instanceIcon"); - if (!(instanceIcon instanceof HTMLImageElement)) - throw new Error("#instanceIcon isn't an image"); - instanceIcon.src = blankImage; const populateInstanceDetailsDialog = ( @@ -84,10 +69,6 @@ export function initializeInstanceDetailsDialog( form.reset(); }); - const closeButton = form.querySelector(".close"); - if (!(closeButton instanceof HTMLButtonElement)) - throw new Error(".close isn't a button"); - closeButton.addEventListener("click", e => { instanceIcon.src = blankImage; hideInstanceDetailsDialog(); diff --git a/static/dom.mts b/static/dom.mts new file mode 100644 index 0000000..0d013fa --- /dev/null +++ b/static/dom.mts @@ -0,0 +1,37 @@ +// I would've LOVED to use generics for this but unfortunately that's not possible. +// Type safety, but at what cost... >~< thanks TypeScript + +export function findFormOrFail(on: Element, selector: string): HTMLFormElement { + const element = on.querySelector(selector); + if (!(element instanceof HTMLFormElement)) + throw new Error(`${selector} isn't a form`); + return element; +} + +export function findInputOrFail(on: Element, selector: string): HTMLInputElement { + const element = on.querySelector(selector); + if (!(element instanceof HTMLInputElement)) + throw new Error(`${selector} isn't an input`); + return element; +} + +export function findButtonOrFail(on: Element, selector: string): HTMLButtonElement { + const element = on.querySelector(selector); + if (!(element instanceof HTMLButtonElement)) + throw new Error(`${selector} isn't a button`); + return element; +} + +export function findSelectOrFail(on: Element, selector: string): HTMLSelectElement { + const element = on.querySelector(selector); + if (!(element instanceof HTMLSelectElement)) + throw new Error(`${selector} isn't a select`); + return element; +} + +export function findImageOrFail(on: Element, selector: string): HTMLImageElement { + const element = on.querySelector(selector); + if (!(element instanceof HTMLImageElement)) + throw new Error(`${selector} isn't an image`); + return element; +} \ No newline at end of file