From bcf3a39de797b897081caa7dd0e392dd6952ec7c Mon Sep 17 00:00:00 2001 From: Chenlei Hu Date: Fri, 14 Jun 2024 14:28:39 -0400 Subject: [PATCH] Migreate ui.js (#8) * Rename js to ts * Migrate ui.js --- src/scripts/app.js | 2 +- src/scripts/logging.ts | 2 +- src/scripts/{ui.js => ui.ts} | 164 ++++++++++++++++++-------------- src/scripts/ui/dialog.js | 2 +- src/scripts/ui/draggableList.js | 2 +- src/scripts/ui/imagePreview.js | 2 +- src/scripts/ui/settings.ts | 24 ++++- src/scripts/ui/toggleSwitch.js | 2 +- src/scripts/ui/userSelection.js | 2 +- src/scripts/utils.js | 2 +- 10 files changed, 120 insertions(+), 84 deletions(-) rename src/scripts/{ui.js => ui.ts} (81%) diff --git a/src/scripts/app.js b/src/scripts/app.js index 9d3774b9a..4b22a8265 100644 --- a/src/scripts/app.js +++ b/src/scripts/app.js @@ -1,6 +1,6 @@ import { ComfyLogging } from "./logging"; import { ComfyWidgets, initWidgets } from "./widgets"; -import { ComfyUI, $el } from "./ui.js"; +import { ComfyUI, $el } from "./ui"; import { api } from "./api.js"; import { defaultGraph } from "./defaultGraph.js"; import { getPngMetadata, getWebpMetadata, importA1111, getLatentMetadata } from "./pnginfo.js"; diff --git a/src/scripts/logging.ts b/src/scripts/logging.ts index 70f650651..386b55aae 100644 --- a/src/scripts/logging.ts +++ b/src/scripts/logging.ts @@ -1,4 +1,4 @@ -import { $el, ComfyDialog } from "./ui.js"; +import { $el, ComfyDialog } from "./ui"; import { api } from "./api.js"; import type { ComfyApp } from "./app.js"; diff --git a/src/scripts/ui.js b/src/scripts/ui.ts similarity index 81% rename from src/scripts/ui.js rename to src/scripts/ui.ts index 4efdefa8c..14cd9187d 100644 --- a/src/scripts/ui.js +++ b/src/scripts/ui.ts @@ -1,73 +1,71 @@ import { api } from "./api.js"; import { ComfyDialog as _ComfyDialog } from "./ui/dialog.js"; import { toggleSwitch } from "./ui/toggleSwitch.js"; -import { ComfySettingsDialog } from "./ui/settings"; +import { ComfySettingsDialog } from "./ui/settings.js"; +import { ComfyApp, app } from "./app.js"; export const ComfyDialog = _ComfyDialog; -/** - * - * @param { string } tag HTML Element Tag and optional classes e.g. div.class1.class2 - * @param { string | Element | Element[] | { - * parent?: Element, - * $?: (el: Element) => void, - * dataset?: DOMStringMap, - * style?: CSSStyleDeclaration, - * for?: string - * ...any - * } | undefined } [propsOrChildren] - * @param { Element[] | Element | undefined } [children] - * @returns - */ -export function $el(tag, propsOrChildren, children) { - const split = tag.split("."); - const element = document.createElement(split.shift()); - if (split.length > 0) { - element.classList.add(...split); - } +type Position2D = { + x: number, + y: number +}; - if (propsOrChildren) { - if (typeof propsOrChildren === "string") { - propsOrChildren = { textContent: propsOrChildren }; - } else if (propsOrChildren instanceof Element) { - propsOrChildren = [propsOrChildren]; - } - if (Array.isArray(propsOrChildren)) { - element.append(...propsOrChildren); - } else { - const { parent, $: cb, dataset, style } = propsOrChildren; - delete propsOrChildren.parent; - delete propsOrChildren.$; - delete propsOrChildren.dataset; - delete propsOrChildren.style; +type Props = { + parent?: HTMLElement, + $?: (el: HTMLElement) => void, + dataset?: DOMStringMap, + style?: Partial, + for?: string, + textContent?: string, + [key: string]: any +}; - if (Object.hasOwn(propsOrChildren, "for")) { - element.setAttribute("for", propsOrChildren.for) - } +export function $el(tag: string, propsOrChildren?: string | Element | Element[] | Props, children?: Element[] | Element): HTMLElement { + const split = tag.split("."); + const element = document.createElement(split.shift() as string); + if (split.length > 0) { + element.classList.add(...split); + } - if (style) { - Object.assign(element.style, style); - } + if (propsOrChildren) { + if (typeof propsOrChildren === "string") { + propsOrChildren = { textContent: propsOrChildren }; + } else if (propsOrChildren instanceof Element) { + propsOrChildren = [propsOrChildren]; + } + if (Array.isArray(propsOrChildren)) { + element.append(...propsOrChildren); + } else { + const { parent, $: cb, dataset, style, ...rest } = propsOrChildren as Props; - if (dataset) { - Object.assign(element.dataset, dataset); - } + if (rest.for) { + element.setAttribute("for", rest.for) + } - Object.assign(element, propsOrChildren); - if (children) { - element.append(...(children instanceof Array ? children : [children])); - } + if (style) { + Object.assign(element.style, style); + } - if (parent) { - parent.append(element); - } + if (dataset) { + Object.assign(element.dataset, dataset); + } - if (cb) { - cb(element); - } - } - } - return element; + Object.assign(element, rest); + if (children) { + element.append(...(Array.isArray(children) ? children : [children])); + } + + if (parent) { + parent.append(element); + } + + if (cb) { + cb(element); + } + } + } + return element; } function dragElement(dragEl, settings) { @@ -130,9 +128,9 @@ function dragElement(dragEl, settings) { } function restorePos() { - let pos = localStorage.getItem("Comfy.MenuPosition"); - if (pos) { - pos = JSON.parse(pos); + let posString = localStorage.getItem("Comfy.MenuPosition"); + if (posString) { + const pos = JSON.parse(posString) as Position2D; newPosX = pos.x; newPosY = pos.y; positionElement(); @@ -198,12 +196,14 @@ class ComfyList { #type; #text; #reverse; + element: HTMLDivElement; + button?: HTMLButtonElement; - constructor(text, type, reverse) { + constructor(text, type?, reverse?) { this.#text = text; this.#type = type || text.toLowerCase(); this.#reverse = reverse || false; - this.element = $el("div.comfy-list"); + this.element = $el("div.comfy-list") as HTMLDivElement; this.element.style.display = "none"; } @@ -289,6 +289,20 @@ class ComfyList { } export class ComfyUI { + app: ComfyApp; + dialog: _ComfyDialog; + settings: ComfySettingsDialog; + batchCount: number; + lastQueueSize: number; + queue: ComfyList; + history: ComfyList; + autoQueueMode: string; + graphHasChanged: boolean; + autoQueueEnabled: boolean; + menuHamburger: HTMLDivElement; + menuContainer: HTMLDivElement; + queueSize: Element; + constructor(app) { this.app = app; this.dialog = new ComfyDialog(); @@ -371,7 +385,7 @@ export class ComfyUI { onchange: () => { app.handleFile(fileInput.files[0]); }, - }); + }) as HTMLInputElement; const autoQueueModeEl = toggleSwitch( "autoQueueMode", @@ -408,7 +422,7 @@ export class ComfyUI { }, }, [$el("div"), $el("div"), $el("div")] - ); + ) as HTMLDivElement; this.menuContainer = $el("div.comfy-menu", { parent: document.body }, [ $el("div.drag-handle.comfy-menu-header", { @@ -446,8 +460,9 @@ export class ComfyUI { type: "checkbox", onchange: (i) => { document.getElementById("extraOptions").style.display = i.srcElement.checked ? "block" : "none"; - this.batchCount = i.srcElement.checked ? document.getElementById("batchCountInputRange").value : 1; - document.getElementById("autoQueueCheckbox").checked = false; + this.batchCount = i.srcElement.checked ? + Number.parseInt((document.getElementById("batchCountInputRange") as HTMLInputElement).value) : 1; + (document.getElementById("autoQueueCheckbox") as HTMLInputElement).checked = false; this.autoQueueEnabled = false; }, }), @@ -462,10 +477,14 @@ export class ComfyUI { type: "number", value: this.batchCount, min: "1", - style: { width: "35%", "margin-left": "0.4em" }, + style: { width: "35%", "marginLeft": "0.4em" }, oninput: (i) => { this.batchCount = i.target.value; - document.getElementById("batchCountInputRange").value = this.batchCount; + /* Even though an element with a type of range logically represents a number (since + it's used for numeric input), the value it holds is still treated as a string in HTML and + JavaScript. This behavior is consistent across all elements regardless of their type + (like text, number, or range), where the .value property is always a string. */ + (document.getElementById("batchCountInputRange") as HTMLInputElement).value = this.batchCount.toString(); }, }), $el("input", { @@ -476,7 +495,8 @@ export class ComfyUI { value: this.batchCount, oninput: (i) => { this.batchCount = i.srcElement.value; - document.getElementById("batchCountInputNumber").value = i.srcElement.value; + // Note + (document.getElementById("batchCountInputNumber") as HTMLInputElement).value = i.srcElement.value; }, }), ]), @@ -505,7 +525,7 @@ export class ComfyUI { onclick: () => app.queuePrompt(-1, this.batchCount) }), $el("button", { - $: (b) => (this.queue.button = b), + $: (b) => (this.queue.button = b as HTMLButtonElement), id: "comfy-view-queue-button", textContent: "View Queue", onclick: () => { @@ -514,7 +534,7 @@ export class ComfyUI { }, }), $el("button", { - $: (b) => (this.history.button = b), + $: (b) => (this.history.button = b as HTMLButtonElement), id: "comfy-view-history-button", textContent: "View History", onclick: () => { @@ -615,7 +635,7 @@ export class ComfyUI { app.resetView(); } }), - ]); + ]) as HTMLDivElement; const devMode = this.settings.addSetting({ id: "Comfy.DevMode", diff --git a/src/scripts/ui/dialog.js b/src/scripts/ui/dialog.js index aee93b3c8..f3407c7e6 100644 --- a/src/scripts/ui/dialog.js +++ b/src/scripts/ui/dialog.js @@ -1,4 +1,4 @@ -import { $el } from "../ui.js"; +import { $el } from "../ui"; export class ComfyDialog { constructor() { diff --git a/src/scripts/ui/draggableList.js b/src/scripts/ui/draggableList.js index d53594886..39e71030d 100644 --- a/src/scripts/ui/draggableList.js +++ b/src/scripts/ui/draggableList.js @@ -25,7 +25,7 @@ SOFTWARE. */ -import { $el } from "../ui.js"; +import { $el } from "../ui"; $el("style", { parent: document.head, diff --git a/src/scripts/ui/imagePreview.js b/src/scripts/ui/imagePreview.js index 2a7f66b8f..45345603c 100644 --- a/src/scripts/ui/imagePreview.js +++ b/src/scripts/ui/imagePreview.js @@ -1,4 +1,4 @@ -import { $el } from "../ui.js"; +import { $el } from "../ui"; export function calculateImageGrid(imgs, dw, dh) { let best = 0; diff --git a/src/scripts/ui/settings.ts b/src/scripts/ui/settings.ts index 450b9e652..570bec7ff 100644 --- a/src/scripts/ui/settings.ts +++ b/src/scripts/ui/settings.ts @@ -1,8 +1,9 @@ -import { $el } from "../ui.js"; +import { $el } from "../ui"; import { api } from "../api.js"; import { ComfyDialog } from "./dialog.js"; import type { ComfyApp } from "../app.js"; +/* The Setting entry stored in `ComfySettingsDialog` */ interface Setting { id: string; onChange?: (value: any, oldValue?: any) => void; @@ -10,6 +11,22 @@ interface Setting { render: () => HTMLElement; } +interface SettingOption { + text: string; + value?: string; +} + +interface SettingParams { + id: string; + name: string; + type: string | ((name: string, setter: (v: any) => void, value: any, attrs: any) => HTMLElement); + defaultValue: any; + onChange?: (newValue: any, oldValue?: any) => void; + attrs?: any; + tooltip?: string; + options?: SettingOption[] | ((value: any) => SettingOption[]); +} + export class ComfySettingsDialog extends ComfyDialog { app: ComfyApp; settingsValues: any; @@ -114,7 +131,8 @@ export class ComfySettingsDialog extends ComfyDialog { }); } - addSetting({ id, name, type, defaultValue, onChange, attrs = {}, tooltip = "", options = undefined }) { + addSetting(params: SettingParams) { + const { id, name, type, defaultValue, onChange, attrs = {}, tooltip = "", options = undefined } = params; if (!id) { throw new Error("Settings must have an ID"); } @@ -321,8 +339,6 @@ export class ComfySettingsDialog extends ComfyDialog { { style: { display: "none" }, }, - // TODO remove this once ui.js is migrated. - // @ts-ignore [$el("th"), $el("th", { style: { width: "33%" } })] ), ...this.settings.sort((a, b) => a.name.localeCompare(b.name)).map((s) => s.render()) diff --git a/src/scripts/ui/toggleSwitch.js b/src/scripts/ui/toggleSwitch.js index 59597ef90..be174dbf8 100644 --- a/src/scripts/ui/toggleSwitch.js +++ b/src/scripts/ui/toggleSwitch.js @@ -1,4 +1,4 @@ -import { $el } from "../ui.js"; +import { $el } from "../ui"; /** * @typedef { { text: string, value?: string, tooltip?: string } } ToggleSwitchItem diff --git a/src/scripts/ui/userSelection.js b/src/scripts/ui/userSelection.js index f9f1ca807..273809191 100644 --- a/src/scripts/ui/userSelection.js +++ b/src/scripts/ui/userSelection.js @@ -1,5 +1,5 @@ import { api } from "../api.js"; -import { $el } from "../ui.js"; +import { $el } from "../ui"; import { addStylesheet } from "../utils.js"; import { createSpinner } from "./spinner.js"; diff --git a/src/scripts/utils.js b/src/scripts/utils.js index 01b988462..91bc9a28e 100644 --- a/src/scripts/utils.js +++ b/src/scripts/utils.js @@ -1,4 +1,4 @@ -import { $el } from "./ui.js"; +import { $el } from "./ui"; // Simple date formatter const parts = {