mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-04 23:20:07 +00:00
Format all code / Add pre-commit format hook (#81)
* Add format-guard * Format code
This commit is contained in:
@@ -2,63 +2,63 @@ import { ComfyDialog } from "../dialog";
|
||||
import { $el } from "../../ui";
|
||||
|
||||
export class ComfyAsyncDialog extends ComfyDialog {
|
||||
#resolve;
|
||||
#resolve;
|
||||
|
||||
constructor(actions) {
|
||||
super(
|
||||
"dialog.comfy-dialog.comfyui-dialog",
|
||||
actions?.map((opt) => {
|
||||
if (typeof opt === "string") {
|
||||
opt = { text: opt };
|
||||
}
|
||||
return $el("button.comfyui-button", {
|
||||
type: "button",
|
||||
textContent: opt.text,
|
||||
onclick: () => this.close(opt.value ?? opt.text),
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
constructor(actions) {
|
||||
super(
|
||||
"dialog.comfy-dialog.comfyui-dialog",
|
||||
actions?.map((opt) => {
|
||||
if (typeof opt === "string") {
|
||||
opt = { text: opt };
|
||||
}
|
||||
return $el("button.comfyui-button", {
|
||||
type: "button",
|
||||
textContent: opt.text,
|
||||
onclick: () => this.close(opt.value ?? opt.text),
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
show(html) {
|
||||
this.element.addEventListener("close", () => {
|
||||
this.close();
|
||||
});
|
||||
show(html) {
|
||||
this.element.addEventListener("close", () => {
|
||||
this.close();
|
||||
});
|
||||
|
||||
super.show(html);
|
||||
super.show(html);
|
||||
|
||||
return new Promise((resolve) => {
|
||||
this.#resolve = resolve;
|
||||
});
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
this.#resolve = resolve;
|
||||
});
|
||||
}
|
||||
|
||||
showModal(html) {
|
||||
this.element.addEventListener("close", () => {
|
||||
this.close();
|
||||
});
|
||||
showModal(html) {
|
||||
this.element.addEventListener("close", () => {
|
||||
this.close();
|
||||
});
|
||||
|
||||
super.show(html);
|
||||
this.element.showModal();
|
||||
super.show(html);
|
||||
this.element.showModal();
|
||||
|
||||
return new Promise((resolve) => {
|
||||
this.#resolve = resolve;
|
||||
});
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
this.#resolve = resolve;
|
||||
});
|
||||
}
|
||||
|
||||
close(result = null) {
|
||||
this.#resolve(result);
|
||||
this.element.close();
|
||||
super.close();
|
||||
}
|
||||
close(result = null) {
|
||||
this.#resolve(result);
|
||||
this.element.close();
|
||||
super.close();
|
||||
}
|
||||
|
||||
static async prompt({ title = null, message, actions }) {
|
||||
const dialog = new ComfyAsyncDialog(actions);
|
||||
const content = [$el("span", message)];
|
||||
if (title) {
|
||||
content.unshift($el("h3", title));
|
||||
}
|
||||
const res = await dialog.showModal(content);
|
||||
dialog.element.remove();
|
||||
return res;
|
||||
}
|
||||
static async prompt({ title = null, message, actions }) {
|
||||
const dialog = new ComfyAsyncDialog(actions);
|
||||
const content = [$el("span", message)];
|
||||
if (title) {
|
||||
content.unshift($el("h3", title));
|
||||
}
|
||||
const res = await dialog.showModal(content);
|
||||
dialog.element.remove();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,145 +19,159 @@ import { prop } from "../../utils";
|
||||
* }} ComfyButtonProps
|
||||
*/
|
||||
export class ComfyButton {
|
||||
#over = 0;
|
||||
#popupOpen = false;
|
||||
isOver = false;
|
||||
iconElement = $el("i.mdi");
|
||||
contentElement = $el("span");
|
||||
/**
|
||||
* @type {import("./popup").ComfyPopup}
|
||||
*/
|
||||
popup;
|
||||
#over = 0;
|
||||
#popupOpen = false;
|
||||
isOver = false;
|
||||
iconElement = $el("i.mdi");
|
||||
contentElement = $el("span");
|
||||
/**
|
||||
* @type {import("./popup").ComfyPopup}
|
||||
*/
|
||||
popup;
|
||||
|
||||
/**
|
||||
* @param {ComfyButtonProps} opts
|
||||
*/
|
||||
constructor({
|
||||
icon,
|
||||
overIcon,
|
||||
iconSize,
|
||||
content,
|
||||
tooltip,
|
||||
action,
|
||||
classList = "comfyui-button",
|
||||
visibilitySetting,
|
||||
app,
|
||||
enabled = true,
|
||||
}) {
|
||||
this.element = $el("button", {
|
||||
onmouseenter: () => {
|
||||
this.isOver = true;
|
||||
if(this.overIcon) {
|
||||
this.updateIcon();
|
||||
}
|
||||
},
|
||||
onmouseleave: () => {
|
||||
this.isOver = false;
|
||||
if(this.overIcon) {
|
||||
this.updateIcon();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {ComfyButtonProps} opts
|
||||
*/
|
||||
constructor({
|
||||
icon,
|
||||
overIcon,
|
||||
iconSize,
|
||||
content,
|
||||
tooltip,
|
||||
action,
|
||||
classList = "comfyui-button",
|
||||
visibilitySetting,
|
||||
app,
|
||||
enabled = true,
|
||||
}) {
|
||||
this.element = $el(
|
||||
"button",
|
||||
{
|
||||
onmouseenter: () => {
|
||||
this.isOver = true;
|
||||
if (this.overIcon) {
|
||||
this.updateIcon();
|
||||
}
|
||||
},
|
||||
onmouseleave: () => {
|
||||
this.isOver = false;
|
||||
if (this.overIcon) {
|
||||
this.updateIcon();
|
||||
}
|
||||
},
|
||||
},
|
||||
[this.iconElement, this.contentElement]
|
||||
);
|
||||
|
||||
}, [this.iconElement, this.contentElement]);
|
||||
this.icon = prop(
|
||||
this,
|
||||
"icon",
|
||||
icon,
|
||||
toggleElement(this.iconElement, { onShow: this.updateIcon })
|
||||
);
|
||||
this.overIcon = prop(this, "overIcon", overIcon, () => {
|
||||
if (this.isOver) {
|
||||
this.updateIcon();
|
||||
}
|
||||
});
|
||||
this.iconSize = prop(this, "iconSize", iconSize, this.updateIcon);
|
||||
this.content = prop(
|
||||
this,
|
||||
"content",
|
||||
content,
|
||||
toggleElement(this.contentElement, {
|
||||
onShow: (el, v) => {
|
||||
if (typeof v === "string") {
|
||||
el.textContent = v;
|
||||
} else {
|
||||
el.replaceChildren(v);
|
||||
}
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
this.icon = prop(this, "icon", icon, toggleElement(this.iconElement, { onShow: this.updateIcon }));
|
||||
this.overIcon = prop(this, "overIcon", overIcon, () => {
|
||||
if(this.isOver) {
|
||||
this.updateIcon();
|
||||
}
|
||||
});
|
||||
this.iconSize = prop(this, "iconSize", iconSize, this.updateIcon);
|
||||
this.content = prop(
|
||||
this,
|
||||
"content",
|
||||
content,
|
||||
toggleElement(this.contentElement, {
|
||||
onShow: (el, v) => {
|
||||
if (typeof v === "string") {
|
||||
el.textContent = v;
|
||||
} else {
|
||||
el.replaceChildren(v);
|
||||
}
|
||||
},
|
||||
})
|
||||
);
|
||||
this.tooltip = prop(this, "tooltip", tooltip, (v) => {
|
||||
if (v) {
|
||||
this.element.title = v;
|
||||
} else {
|
||||
this.element.removeAttribute("title");
|
||||
}
|
||||
});
|
||||
this.classList = prop(this, "classList", classList, this.updateClasses);
|
||||
this.hidden = prop(this, "hidden", false, this.updateClasses);
|
||||
this.enabled = prop(this, "enabled", enabled, () => {
|
||||
this.updateClasses();
|
||||
this.element.disabled = !this.enabled;
|
||||
});
|
||||
this.action = prop(this, "action", action);
|
||||
this.element.addEventListener("click", (e) => {
|
||||
if (this.popup) {
|
||||
// we are either a touch device or triggered by click not hover
|
||||
if (!this.#over) {
|
||||
this.popup.toggle();
|
||||
}
|
||||
}
|
||||
this.action?.(e, this);
|
||||
});
|
||||
|
||||
this.tooltip = prop(this, "tooltip", tooltip, (v) => {
|
||||
if (v) {
|
||||
this.element.title = v;
|
||||
} else {
|
||||
this.element.removeAttribute("title");
|
||||
}
|
||||
});
|
||||
this.classList = prop(this, "classList", classList, this.updateClasses);
|
||||
this.hidden = prop(this, "hidden", false, this.updateClasses);
|
||||
this.enabled = prop(this, "enabled", enabled, () => {
|
||||
this.updateClasses();
|
||||
this.element.disabled = !this.enabled;
|
||||
});
|
||||
this.action = prop(this, "action", action);
|
||||
this.element.addEventListener("click", (e) => {
|
||||
if (this.popup) {
|
||||
// we are either a touch device or triggered by click not hover
|
||||
if (!this.#over) {
|
||||
this.popup.toggle();
|
||||
}
|
||||
}
|
||||
this.action?.(e, this);
|
||||
});
|
||||
if (visibilitySetting?.id) {
|
||||
const settingUpdated = () => {
|
||||
this.hidden =
|
||||
app.ui.settings.getSettingValue(visibilitySetting.id) !==
|
||||
visibilitySetting.showValue;
|
||||
};
|
||||
app.ui.settings.addEventListener(
|
||||
visibilitySetting.id + ".change",
|
||||
settingUpdated
|
||||
);
|
||||
settingUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
if (visibilitySetting?.id) {
|
||||
const settingUpdated = () => {
|
||||
this.hidden = app.ui.settings.getSettingValue(visibilitySetting.id) !== visibilitySetting.showValue;
|
||||
};
|
||||
app.ui.settings.addEventListener(visibilitySetting.id + ".change", settingUpdated);
|
||||
settingUpdated();
|
||||
}
|
||||
}
|
||||
updateIcon = () =>
|
||||
(this.iconElement.className = `mdi mdi-${(this.isOver && this.overIcon) || this.icon}${this.iconSize ? " mdi-" + this.iconSize + "px" : ""}`);
|
||||
updateClasses = () => {
|
||||
const internalClasses = [];
|
||||
if (this.hidden) {
|
||||
internalClasses.push("hidden");
|
||||
}
|
||||
if (!this.enabled) {
|
||||
internalClasses.push("disabled");
|
||||
}
|
||||
if (this.popup) {
|
||||
if (this.#popupOpen) {
|
||||
internalClasses.push("popup-open");
|
||||
} else {
|
||||
internalClasses.push("popup-closed");
|
||||
}
|
||||
}
|
||||
applyClasses(this.element, this.classList, ...internalClasses);
|
||||
};
|
||||
|
||||
updateIcon = () => (this.iconElement.className = `mdi mdi-${(this.isOver && this.overIcon) || this.icon}${this.iconSize ? " mdi-" + this.iconSize + "px" : ""}`);
|
||||
updateClasses = () => {
|
||||
const internalClasses = [];
|
||||
if (this.hidden) {
|
||||
internalClasses.push("hidden");
|
||||
}
|
||||
if (!this.enabled) {
|
||||
internalClasses.push("disabled");
|
||||
}
|
||||
if (this.popup) {
|
||||
if (this.#popupOpen) {
|
||||
internalClasses.push("popup-open");
|
||||
} else {
|
||||
internalClasses.push("popup-closed");
|
||||
}
|
||||
}
|
||||
applyClasses(this.element, this.classList, ...internalClasses);
|
||||
};
|
||||
/**
|
||||
*
|
||||
* @param { import("./popup").ComfyPopup } popup
|
||||
* @param { "click" | "hover" } mode
|
||||
*/
|
||||
withPopup(popup, mode = "click") {
|
||||
this.popup = popup;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param { import("./popup").ComfyPopup } popup
|
||||
* @param { "click" | "hover" } mode
|
||||
*/
|
||||
withPopup(popup, mode = "click") {
|
||||
this.popup = popup;
|
||||
if (mode === "hover") {
|
||||
for (const el of [this.element, this.popup.element]) {
|
||||
el.addEventListener("mouseenter", () => {
|
||||
this.popup.open = !!++this.#over;
|
||||
});
|
||||
el.addEventListener("mouseleave", () => {
|
||||
this.popup.open = !!--this.#over;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (mode === "hover") {
|
||||
for (const el of [this.element, this.popup.element]) {
|
||||
el.addEventListener("mouseenter", () => {
|
||||
this.popup.open = !!++this.#over;
|
||||
});
|
||||
el.addEventListener("mouseleave", () => {
|
||||
this.popup.open = !!--this.#over;
|
||||
});
|
||||
}
|
||||
}
|
||||
popup.addEventListener("change", () => {
|
||||
this.#popupOpen = popup.open;
|
||||
this.updateClasses();
|
||||
});
|
||||
|
||||
popup.addEventListener("change", () => {
|
||||
this.#popupOpen = popup.open;
|
||||
this.updateClasses();
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,41 +5,41 @@ import { ComfyButton } from "./button";
|
||||
import { prop } from "../../utils";
|
||||
|
||||
export class ComfyButtonGroup {
|
||||
element = $el("div.comfyui-button-group");
|
||||
element = $el("div.comfyui-button-group");
|
||||
|
||||
/** @param {Array<ComfyButton | HTMLElement>} buttons */
|
||||
constructor(...buttons) {
|
||||
this.buttons = prop(this, "buttons", buttons, () => this.update());
|
||||
}
|
||||
/** @param {Array<ComfyButton | HTMLElement>} buttons */
|
||||
constructor(...buttons) {
|
||||
this.buttons = prop(this, "buttons", buttons, () => this.update());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ComfyButton} button
|
||||
* @param {number} index
|
||||
*/
|
||||
insert(button, index) {
|
||||
this.buttons.splice(index, 0, button);
|
||||
this.update();
|
||||
}
|
||||
/**
|
||||
* @param {ComfyButton} button
|
||||
* @param {number} index
|
||||
*/
|
||||
insert(button, index) {
|
||||
this.buttons.splice(index, 0, button);
|
||||
this.update();
|
||||
}
|
||||
|
||||
/** @param {ComfyButton} button */
|
||||
append(button) {
|
||||
this.buttons.push(button);
|
||||
this.update();
|
||||
}
|
||||
/** @param {ComfyButton} button */
|
||||
append(button) {
|
||||
this.buttons.push(button);
|
||||
this.update();
|
||||
}
|
||||
|
||||
/** @param {ComfyButton|number} indexOrButton */
|
||||
remove(indexOrButton) {
|
||||
if (typeof indexOrButton !== "number") {
|
||||
indexOrButton = this.buttons.indexOf(indexOrButton);
|
||||
}
|
||||
if (indexOrButton > -1) {
|
||||
const r = this.buttons.splice(indexOrButton, 1);
|
||||
this.update();
|
||||
return r;
|
||||
}
|
||||
}
|
||||
/** @param {ComfyButton|number} indexOrButton */
|
||||
remove(indexOrButton) {
|
||||
if (typeof indexOrButton !== "number") {
|
||||
indexOrButton = this.buttons.indexOf(indexOrButton);
|
||||
}
|
||||
if (indexOrButton > -1) {
|
||||
const r = this.buttons.splice(indexOrButton, 1);
|
||||
this.update();
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
this.element.replaceChildren(...this.buttons.map((b) => b["element"] ?? b));
|
||||
}
|
||||
update() {
|
||||
this.element.replaceChildren(...this.buttons.map((b) => b["element"] ?? b));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,124 +5,133 @@ import { $el } from "../../ui";
|
||||
import { applyClasses } from "../utils";
|
||||
|
||||
export class ComfyPopup extends EventTarget {
|
||||
element = $el("div.comfyui-popup");
|
||||
element = $el("div.comfyui-popup");
|
||||
|
||||
/**
|
||||
* @param {{
|
||||
* target: HTMLElement,
|
||||
* container?: HTMLElement,
|
||||
* classList?: import("../utils").ClassList,
|
||||
* ignoreTarget?: boolean,
|
||||
* closeOnEscape?: boolean,
|
||||
* position?: "absolute" | "relative",
|
||||
* horizontal?: "left" | "right"
|
||||
* }} param0
|
||||
* @param {...HTMLElement} children
|
||||
*/
|
||||
constructor(
|
||||
{
|
||||
target,
|
||||
container = document.body,
|
||||
classList = "",
|
||||
ignoreTarget = true,
|
||||
closeOnEscape = true,
|
||||
position = "absolute",
|
||||
horizontal = "left",
|
||||
},
|
||||
...children
|
||||
) {
|
||||
super();
|
||||
this.target = target;
|
||||
this.ignoreTarget = ignoreTarget;
|
||||
this.container = container;
|
||||
this.position = position;
|
||||
this.closeOnEscape = closeOnEscape;
|
||||
this.horizontal = horizontal;
|
||||
/**
|
||||
* @param {{
|
||||
* target: HTMLElement,
|
||||
* container?: HTMLElement,
|
||||
* classList?: import("../utils").ClassList,
|
||||
* ignoreTarget?: boolean,
|
||||
* closeOnEscape?: boolean,
|
||||
* position?: "absolute" | "relative",
|
||||
* horizontal?: "left" | "right"
|
||||
* }} param0
|
||||
* @param {...HTMLElement} children
|
||||
*/
|
||||
constructor(
|
||||
{
|
||||
target,
|
||||
container = document.body,
|
||||
classList = "",
|
||||
ignoreTarget = true,
|
||||
closeOnEscape = true,
|
||||
position = "absolute",
|
||||
horizontal = "left",
|
||||
},
|
||||
...children
|
||||
) {
|
||||
super();
|
||||
this.target = target;
|
||||
this.ignoreTarget = ignoreTarget;
|
||||
this.container = container;
|
||||
this.position = position;
|
||||
this.closeOnEscape = closeOnEscape;
|
||||
this.horizontal = horizontal;
|
||||
|
||||
container.append(this.element);
|
||||
container.append(this.element);
|
||||
|
||||
this.children = prop(this, "children", children, () => {
|
||||
this.element.replaceChildren(...this.children);
|
||||
this.update();
|
||||
});
|
||||
this.classList = prop(this, "classList", classList, () => applyClasses(this.element, this.classList, "comfyui-popup", horizontal));
|
||||
this.open = prop(this, "open", false, (v, o) => {
|
||||
if (v === o) return;
|
||||
if (v) {
|
||||
this.#show();
|
||||
} else {
|
||||
this.#hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
this.children = prop(this, "children", children, () => {
|
||||
this.element.replaceChildren(...this.children);
|
||||
this.update();
|
||||
});
|
||||
this.classList = prop(this, "classList", classList, () =>
|
||||
applyClasses(this.element, this.classList, "comfyui-popup", horizontal)
|
||||
);
|
||||
this.open = prop(this, "open", false, (v, o) => {
|
||||
if (v === o) return;
|
||||
if (v) {
|
||||
this.#show();
|
||||
} else {
|
||||
this.#hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
toggle() {
|
||||
this.open = !this.open;
|
||||
}
|
||||
toggle() {
|
||||
this.open = !this.open;
|
||||
}
|
||||
|
||||
#hide() {
|
||||
this.element.classList.remove("open");
|
||||
window.removeEventListener("resize", this.update);
|
||||
window.removeEventListener("click", this.#clickHandler, { capture: true });
|
||||
window.removeEventListener("keydown", this.#escHandler, { capture: true });
|
||||
#hide() {
|
||||
this.element.classList.remove("open");
|
||||
window.removeEventListener("resize", this.update);
|
||||
window.removeEventListener("click", this.#clickHandler, { capture: true });
|
||||
window.removeEventListener("keydown", this.#escHandler, { capture: true });
|
||||
|
||||
this.dispatchEvent(new CustomEvent("close"));
|
||||
this.dispatchEvent(new CustomEvent("change"));
|
||||
}
|
||||
this.dispatchEvent(new CustomEvent("close"));
|
||||
this.dispatchEvent(new CustomEvent("change"));
|
||||
}
|
||||
|
||||
#show() {
|
||||
this.element.classList.add("open");
|
||||
this.update();
|
||||
#show() {
|
||||
this.element.classList.add("open");
|
||||
this.update();
|
||||
|
||||
window.addEventListener("resize", this.update);
|
||||
window.addEventListener("click", this.#clickHandler, { capture: true });
|
||||
if (this.closeOnEscape) {
|
||||
window.addEventListener("keydown", this.#escHandler, { capture: true });
|
||||
}
|
||||
window.addEventListener("resize", this.update);
|
||||
window.addEventListener("click", this.#clickHandler, { capture: true });
|
||||
if (this.closeOnEscape) {
|
||||
window.addEventListener("keydown", this.#escHandler, { capture: true });
|
||||
}
|
||||
|
||||
this.dispatchEvent(new CustomEvent("open"));
|
||||
this.dispatchEvent(new CustomEvent("change"));
|
||||
}
|
||||
this.dispatchEvent(new CustomEvent("open"));
|
||||
this.dispatchEvent(new CustomEvent("change"));
|
||||
}
|
||||
|
||||
#escHandler = (e) => {
|
||||
if (e.key === "Escape") {
|
||||
this.open = false;
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
};
|
||||
#escHandler = (e) => {
|
||||
if (e.key === "Escape") {
|
||||
this.open = false;
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
};
|
||||
|
||||
#clickHandler = (e) => {
|
||||
/** @type {any} */
|
||||
const target = e.target;
|
||||
if (!this.element.contains(target) && this.ignoreTarget && !this.target.contains(target)) {
|
||||
this.open = false;
|
||||
}
|
||||
};
|
||||
#clickHandler = (e) => {
|
||||
/** @type {any} */
|
||||
const target = e.target;
|
||||
if (
|
||||
!this.element.contains(target) &&
|
||||
this.ignoreTarget &&
|
||||
!this.target.contains(target)
|
||||
) {
|
||||
this.open = false;
|
||||
}
|
||||
};
|
||||
|
||||
update = () => {
|
||||
const rect = this.target.getBoundingClientRect();
|
||||
this.element.style.setProperty("--bottom", "unset");
|
||||
if (this.position === "absolute") {
|
||||
if (this.horizontal === "left") {
|
||||
this.element.style.setProperty("--left", rect.left + "px");
|
||||
} else {
|
||||
this.element.style.setProperty("--left", rect.right - this.element.clientWidth + "px");
|
||||
}
|
||||
this.element.style.setProperty("--top", rect.bottom + "px");
|
||||
this.element.style.setProperty("--limit", rect.bottom + "px");
|
||||
} else {
|
||||
this.element.style.setProperty("--left", 0 + "px");
|
||||
this.element.style.setProperty("--top", rect.height + "px");
|
||||
this.element.style.setProperty("--limit", rect.height + "px");
|
||||
}
|
||||
update = () => {
|
||||
const rect = this.target.getBoundingClientRect();
|
||||
this.element.style.setProperty("--bottom", "unset");
|
||||
if (this.position === "absolute") {
|
||||
if (this.horizontal === "left") {
|
||||
this.element.style.setProperty("--left", rect.left + "px");
|
||||
} else {
|
||||
this.element.style.setProperty(
|
||||
"--left",
|
||||
rect.right - this.element.clientWidth + "px"
|
||||
);
|
||||
}
|
||||
this.element.style.setProperty("--top", rect.bottom + "px");
|
||||
this.element.style.setProperty("--limit", rect.bottom + "px");
|
||||
} else {
|
||||
this.element.style.setProperty("--left", 0 + "px");
|
||||
this.element.style.setProperty("--top", rect.height + "px");
|
||||
this.element.style.setProperty("--limit", rect.height + "px");
|
||||
}
|
||||
|
||||
const thisRect = this.element.getBoundingClientRect();
|
||||
if (thisRect.height < 30) {
|
||||
// Move up instead
|
||||
this.element.style.setProperty("--top", "unset");
|
||||
this.element.style.setProperty("--bottom", rect.height + 5 + "px");
|
||||
this.element.style.setProperty("--limit", rect.height + 5 + "px");
|
||||
}
|
||||
};
|
||||
const thisRect = this.element.getBoundingClientRect();
|
||||
if (thisRect.height < 30) {
|
||||
// Move up instead
|
||||
this.element.style.setProperty("--top", "unset");
|
||||
this.element.style.setProperty("--bottom", rect.height + 5 + "px");
|
||||
this.element.style.setProperty("--limit", rect.height + 5 + "px");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,38 +6,47 @@ import { prop } from "../../utils";
|
||||
import { ComfyPopup } from "./popup";
|
||||
|
||||
export class ComfySplitButton {
|
||||
/**
|
||||
* @param {{
|
||||
* primary: ComfyButton,
|
||||
* mode?: "hover" | "click",
|
||||
* horizontal?: "left" | "right",
|
||||
* position?: "relative" | "absolute"
|
||||
* }} param0
|
||||
* @param {Array<ComfyButton> | Array<HTMLElement>} items
|
||||
*/
|
||||
constructor({ primary, mode, horizontal = "left", position = "relative" }, ...items) {
|
||||
this.arrow = new ComfyButton({
|
||||
icon: "chevron-down",
|
||||
});
|
||||
this.element = $el("div.comfyui-split-button" + (mode === "hover" ? ".hover" : ""), [
|
||||
$el("div.comfyui-split-primary", primary.element),
|
||||
$el("div.comfyui-split-arrow", this.arrow.element),
|
||||
]);
|
||||
this.popup = new ComfyPopup({
|
||||
target: this.element,
|
||||
container: position === "relative" ? this.element : document.body,
|
||||
classList: "comfyui-split-button-popup" + (mode === "hover" ? " hover" : ""),
|
||||
closeOnEscape: mode === "click",
|
||||
position,
|
||||
horizontal,
|
||||
});
|
||||
/**
|
||||
* @param {{
|
||||
* primary: ComfyButton,
|
||||
* mode?: "hover" | "click",
|
||||
* horizontal?: "left" | "right",
|
||||
* position?: "relative" | "absolute"
|
||||
* }} param0
|
||||
* @param {Array<ComfyButton> | Array<HTMLElement>} items
|
||||
*/
|
||||
constructor(
|
||||
{ primary, mode, horizontal = "left", position = "relative" },
|
||||
...items
|
||||
) {
|
||||
this.arrow = new ComfyButton({
|
||||
icon: "chevron-down",
|
||||
});
|
||||
this.element = $el(
|
||||
"div.comfyui-split-button" + (mode === "hover" ? ".hover" : ""),
|
||||
[
|
||||
$el("div.comfyui-split-primary", primary.element),
|
||||
$el("div.comfyui-split-arrow", this.arrow.element),
|
||||
]
|
||||
);
|
||||
this.popup = new ComfyPopup({
|
||||
target: this.element,
|
||||
container: position === "relative" ? this.element : document.body,
|
||||
classList:
|
||||
"comfyui-split-button-popup" + (mode === "hover" ? " hover" : ""),
|
||||
closeOnEscape: mode === "click",
|
||||
position,
|
||||
horizontal,
|
||||
});
|
||||
|
||||
this.arrow.withPopup(this.popup, mode);
|
||||
this.arrow.withPopup(this.popup, mode);
|
||||
|
||||
this.items = prop(this, "items", items, () => this.update());
|
||||
}
|
||||
this.items = prop(this, "items", items, () => this.update());
|
||||
}
|
||||
|
||||
update() {
|
||||
this.popup.element.replaceChildren(...this.items.map((b) => b.element ?? b));
|
||||
}
|
||||
update() {
|
||||
this.popup.element.replaceChildren(
|
||||
...this.items.map((b) => b.element ?? b)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { $el } from "../ui";
|
||||
|
||||
export class ComfyDialog<T extends HTMLElement = HTMLElement> extends EventTarget {
|
||||
export class ComfyDialog<
|
||||
T extends HTMLElement = HTMLElement,
|
||||
> extends EventTarget {
|
||||
element: T;
|
||||
textElement: HTMLElement;
|
||||
#buttons: HTMLButtonElement[] | null;
|
||||
@@ -9,7 +11,10 @@ export class ComfyDialog<T extends HTMLElement = HTMLElement> extends EventTarge
|
||||
super();
|
||||
this.#buttons = buttons;
|
||||
this.element = $el(type + ".comfy-modal", { parent: document.body }, [
|
||||
$el("div.comfy-modal-content", [$el("p", { $: (p) => (this.textElement = p) }), ...this.createButtons()]),
|
||||
$el("div.comfy-modal-content", [
|
||||
$el("p", { $: (p) => (this.textElement = p) }),
|
||||
...this.createButtons(),
|
||||
]),
|
||||
]) as T;
|
||||
}
|
||||
|
||||
@@ -33,7 +38,9 @@ export class ComfyDialog<T extends HTMLElement = HTMLElement> extends EventTarge
|
||||
if (typeof html === "string") {
|
||||
this.textElement.innerHTML = html;
|
||||
} else {
|
||||
this.textElement.replaceChildren(...(html instanceof Array ? html : [html]));
|
||||
this.textElement.replaceChildren(
|
||||
...(html instanceof Array ? html : [html])
|
||||
);
|
||||
}
|
||||
this.element.style.display = "flex";
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
import { $el } from "../ui";
|
||||
|
||||
$el("style", {
|
||||
parent: document.head,
|
||||
textContent: `
|
||||
parent: document.head,
|
||||
textContent: `
|
||||
.draggable-item {
|
||||
position: relative;
|
||||
will-change: transform;
|
||||
@@ -40,7 +40,7 @@ $el("style", {
|
||||
.draggable-item.is-draggable {
|
||||
z-index: 10;
|
||||
}
|
||||
`
|
||||
`,
|
||||
});
|
||||
|
||||
export class DraggableList extends EventTarget {
|
||||
@@ -57,9 +57,9 @@ export class DraggableList extends EventTarget {
|
||||
offDrag = [];
|
||||
|
||||
constructor(element, itemSelector) {
|
||||
super();
|
||||
super();
|
||||
this.listContainer = element;
|
||||
this.itemSelector = itemSelector;
|
||||
this.itemSelector = itemSelector;
|
||||
|
||||
if (!this.listContainer) return;
|
||||
|
||||
@@ -71,7 +71,9 @@ export class DraggableList extends EventTarget {
|
||||
|
||||
getAllItems() {
|
||||
if (!this.items?.length) {
|
||||
this.items = Array.from(this.listContainer.querySelectorAll(this.itemSelector));
|
||||
this.items = Array.from(
|
||||
this.listContainer.querySelectorAll(this.itemSelector)
|
||||
);
|
||||
this.items.forEach((element) => {
|
||||
element.classList.add("is-idle");
|
||||
});
|
||||
@@ -80,7 +82,9 @@ export class DraggableList extends EventTarget {
|
||||
}
|
||||
|
||||
getIdleItems() {
|
||||
return this.getAllItems().filter((item) => item.classList.contains("is-idle"));
|
||||
return this.getAllItems().filter((item) =>
|
||||
item.classList.contains("is-idle")
|
||||
);
|
||||
}
|
||||
|
||||
isItemAbove(item) {
|
||||
@@ -106,18 +110,24 @@ export class DraggableList extends EventTarget {
|
||||
|
||||
this.pointerStartX = e.clientX || e.touches[0].clientX;
|
||||
this.pointerStartY = e.clientY || e.touches[0].clientY;
|
||||
this.scrollYMax = this.listContainer.scrollHeight - this.listContainer.clientHeight;
|
||||
this.scrollYMax =
|
||||
this.listContainer.scrollHeight - this.listContainer.clientHeight;
|
||||
|
||||
this.setItemsGap();
|
||||
this.initDraggableItem();
|
||||
this.initItemsState();
|
||||
|
||||
this.offDrag.push(this.on(document, "mousemove", this.drag));
|
||||
this.offDrag.push(this.on(document, "touchmove", this.drag, { passive: false }));
|
||||
this.offDrag.push(
|
||||
this.on(document, "touchmove", this.drag, { passive: false })
|
||||
);
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("dragstart", {
|
||||
detail: { element: this.draggableItem, position: this.getAllItems().indexOf(this.draggableItem) },
|
||||
detail: {
|
||||
element: this.draggableItem,
|
||||
position: this.getAllItems().indexOf(this.draggableItem),
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -250,7 +260,11 @@ export class DraggableList extends EventTarget {
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("dragend", {
|
||||
detail: { element: this.draggableItem, oldPosition, newPosition: reorderedItems.indexOf(this.draggableItem) },
|
||||
detail: {
|
||||
element: this.draggableItem,
|
||||
oldPosition,
|
||||
newPosition: reorderedItems.indexOf(this.draggableItem),
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -57,7 +57,11 @@ export function createImageHost(node) {
|
||||
}
|
||||
|
||||
const nw = node.size[0];
|
||||
({ cellWidth: w, cellHeight: h } = calculateImageGrid(currentImgs, nw - 20, elH));
|
||||
({ cellWidth: w, cellHeight: h } = calculateImageGrid(
|
||||
currentImgs,
|
||||
nw - 20,
|
||||
elH
|
||||
));
|
||||
w += "px";
|
||||
h += "px";
|
||||
|
||||
@@ -86,10 +90,13 @@ export function createImageHost(node) {
|
||||
onDraw() {
|
||||
// Element from point uses a hittest find elements so we need to toggle pointer events
|
||||
el.style.pointerEvents = "all";
|
||||
const over = document.elementFromPoint(app.canvas.mouse[0], app.canvas.mouse[1]);
|
||||
const over = document.elementFromPoint(
|
||||
app.canvas.mouse[0],
|
||||
app.canvas.mouse[1]
|
||||
);
|
||||
el.style.pointerEvents = "none";
|
||||
|
||||
if(!over) return;
|
||||
if (!over) return;
|
||||
// Set the overIndex so Open Image etc work
|
||||
const idx = currentImgs.indexOf(over);
|
||||
node.overIndex = idx;
|
||||
|
||||
@@ -48,7 +48,11 @@ export class ComfyAppMenu {
|
||||
content: t,
|
||||
});
|
||||
|
||||
this.logo = $el("h1.comfyui-logo.nlg-hide", { title: "ComfyUI" }, "ComfyUI");
|
||||
this.logo = $el(
|
||||
"h1.comfyui-logo.nlg-hide",
|
||||
{ title: "ComfyUI" },
|
||||
"ComfyUI"
|
||||
);
|
||||
this.saveButton = new ComfySplitButton(
|
||||
{
|
||||
primary: getSaveButton(),
|
||||
@@ -71,7 +75,8 @@ export class ComfyAppMenu {
|
||||
new ComfyButton({
|
||||
icon: "api",
|
||||
content: "Export (API Format)",
|
||||
tooltip: "Export the current workflow as JSON for use with the ComfyUI API",
|
||||
tooltip:
|
||||
"Export the current workflow as JSON for use with the ComfyUI API",
|
||||
action: () => this.exportWorkflow("workflow_api", "output"),
|
||||
visibilitySetting: { id: "Comfy.DevMode", showValue: true },
|
||||
app,
|
||||
@@ -101,7 +106,10 @@ export class ComfyAppMenu {
|
||||
content: "Clear",
|
||||
tooltip: "Clears current workflow",
|
||||
action: () => {
|
||||
if (!app.ui.settings.getSettingValue("Comfy.ConfirmClear", true) || confirm("Clear workflow?")) {
|
||||
if (
|
||||
!app.ui.settings.getSettingValue("Comfy.ConfirmClear", true) ||
|
||||
confirm("Clear workflow?")
|
||||
) {
|
||||
app.clean();
|
||||
app.graph.clear();
|
||||
}
|
||||
@@ -126,7 +134,9 @@ export class ComfyAppMenu {
|
||||
this.mobileMenuButton = new ComfyButton({
|
||||
icon: "menu",
|
||||
action: (_, btn) => {
|
||||
btn.icon = this.element.classList.toggle("expanded") ? "menu-open" : "menu";
|
||||
btn.icon = this.element.classList.toggle("expanded")
|
||||
? "menu-open"
|
||||
: "menu";
|
||||
window.dispatchEvent(new Event("resize"));
|
||||
},
|
||||
classList: "comfyui-button comfyui-menu-button",
|
||||
@@ -239,7 +249,10 @@ export class ComfyAppMenu {
|
||||
idx--;
|
||||
}
|
||||
} else if (innerSize > this.element.clientWidth) {
|
||||
this.#lastSizeBreaks[this.#sizeBreak] = Math.max(window.innerWidth, innerSize);
|
||||
this.#lastSizeBreaks[this.#sizeBreak] = Math.max(
|
||||
window.innerWidth,
|
||||
innerSize
|
||||
);
|
||||
// We need to shrink
|
||||
if (idx < this.#sizeBreaks.length - 1) {
|
||||
idx++;
|
||||
@@ -254,19 +267,26 @@ export class ComfyAppMenu {
|
||||
clearTimeout(this.#cacheTimeout);
|
||||
if (this.#cachedInnerSize) {
|
||||
// Extend cache time
|
||||
this.#cacheTimeout = setTimeout(() => (this.#cachedInnerSize = null), 100);
|
||||
this.#cacheTimeout = setTimeout(
|
||||
() => (this.#cachedInnerSize = null),
|
||||
100
|
||||
);
|
||||
} else {
|
||||
let innerSize = 0;
|
||||
let count = 1;
|
||||
for (const c of this.element.children) {
|
||||
if (c.classList.contains("comfyui-menu-push")) continue; // ignore right push
|
||||
if (idx && c.classList.contains("comfyui-menu-mobile-collapse")) continue; // ignore collapse items
|
||||
if (idx && c.classList.contains("comfyui-menu-mobile-collapse"))
|
||||
continue; // ignore collapse items
|
||||
innerSize += c.clientWidth;
|
||||
count++;
|
||||
}
|
||||
innerSize += 8 * count;
|
||||
this.#cachedInnerSize = innerSize;
|
||||
this.#cacheTimeout = setTimeout(() => (this.#cachedInnerSize = null), 100);
|
||||
this.#cacheTimeout = setTimeout(
|
||||
() => (this.#cachedInnerSize = null),
|
||||
100
|
||||
);
|
||||
}
|
||||
return this.#cachedInnerSize;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,10 @@ export class ComfyQueueButton {
|
||||
queuePrompt = async (e) => {
|
||||
this.#internalQueueSize += this.queueOptions.batchCount;
|
||||
// Hold shift to queue front, event is undefined when auto-queue is enabled
|
||||
await this.app.queuePrompt(e?.shiftKey ? -1 : 0, this.queueOptions.batchCount);
|
||||
await this.app.queuePrompt(
|
||||
e?.shiftKey ? -1 : 0,
|
||||
this.queueOptions.batchCount
|
||||
);
|
||||
};
|
||||
|
||||
constructor(app) {
|
||||
@@ -63,7 +66,10 @@ export class ComfyQueueButton {
|
||||
}
|
||||
});
|
||||
|
||||
this.queueOptions.addEventListener("autoQueueMode", (e) => (this.autoQueueMode = e["detail"]));
|
||||
this.queueOptions.addEventListener(
|
||||
"autoQueueMode",
|
||||
(e) => (this.autoQueueMode = e["detail"])
|
||||
);
|
||||
|
||||
api.addEventListener("graphChanged", () => {
|
||||
if (this.autoQueueMode === "change") {
|
||||
@@ -79,10 +85,14 @@ export class ComfyQueueButton {
|
||||
api.addEventListener("status", ({ detail }) => {
|
||||
this.#internalQueueSize = detail?.exec_info?.queue_remaining;
|
||||
if (this.#internalQueueSize != null) {
|
||||
this.queueSizeElement.textContent = this.#internalQueueSize > 99 ? "99+" : this.#internalQueueSize + "";
|
||||
this.queueSizeElement.textContent =
|
||||
this.#internalQueueSize > 99 ? "99+" : this.#internalQueueSize + "";
|
||||
this.queueSizeElement.title = `${this.#internalQueueSize} prompts in queue`;
|
||||
if (!this.#internalQueueSize && !app.lastExecutionError) {
|
||||
if (this.autoQueueMode === "instant" || (this.autoQueueMode === "change" && this.graphHasChanged)) {
|
||||
if (
|
||||
this.autoQueueMode === "instant" ||
|
||||
(this.autoQueueMode === "change" && this.graphHasChanged)
|
||||
) {
|
||||
this.graphHasChanged = false;
|
||||
this.queuePrompt();
|
||||
}
|
||||
|
||||
@@ -69,11 +69,14 @@ export class ComfyViewList {
|
||||
},
|
||||
});
|
||||
|
||||
this.element = $el(`div.comfyui-${this.type}-popup.comfyui-view-list-popup`, [
|
||||
$el("h3", mode),
|
||||
$el("header", [this.clear.element, this.refresh.element]),
|
||||
this.items,
|
||||
]);
|
||||
this.element = $el(
|
||||
`div.comfyui-${this.type}-popup.comfyui-view-list-popup`,
|
||||
[
|
||||
$el("h3", mode),
|
||||
$el("header", [this.clear.element, this.refresh.element]),
|
||||
this.items,
|
||||
]
|
||||
);
|
||||
|
||||
api.addEventListener("status", () => {
|
||||
if (this.popup.open) {
|
||||
@@ -155,7 +158,9 @@ export class ComfyViewList {
|
||||
text: "Load",
|
||||
action: async () => {
|
||||
try {
|
||||
await this.app.loadGraphData(item.prompt[3].extra_pnginfo.workflow);
|
||||
await this.app.loadGraphData(
|
||||
item.prompt[3].extra_pnginfo.workflow
|
||||
);
|
||||
if (item.outputs) {
|
||||
this.app.nodeOutputs = item.outputs;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,9 @@ export class ComfyViewQueueList extends ComfyViewList {
|
||||
text: "Load",
|
||||
action: async () => {
|
||||
try {
|
||||
await this.app.loadGraphData(item.prompt[3].extra_pnginfo.workflow);
|
||||
await this.app.loadGraphData(
|
||||
item.prompt[3].extra_pnginfo.workflow
|
||||
);
|
||||
if (item.outputs) {
|
||||
this.app.nodeOutputs = item.outputs;
|
||||
}
|
||||
@@ -51,5 +53,5 @@ export class ComfyViewQueueList extends ComfyViewList {
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -37,14 +37,21 @@ export class ComfyWorkflowsMenu {
|
||||
this.buttonProgress = $el("div.comfyui-workflows-button-progress");
|
||||
this.workflowLabel = $el("span.comfyui-workflows-label", "");
|
||||
this.button = new ComfyButton({
|
||||
content: $el("div.comfyui-workflows-button-inner", [$el("i.mdi.mdi-graph"), this.workflowLabel, this.buttonProgress]),
|
||||
content: $el("div.comfyui-workflows-button-inner", [
|
||||
$el("i.mdi.mdi-graph"),
|
||||
this.workflowLabel,
|
||||
this.buttonProgress,
|
||||
]),
|
||||
icon: "chevron-down",
|
||||
classList,
|
||||
});
|
||||
|
||||
this.element.append(this.button.element);
|
||||
|
||||
this.popup = new ComfyPopup({ target: this.element, classList: "comfyui-workflows-popup" });
|
||||
this.popup = new ComfyPopup({
|
||||
target: this.element,
|
||||
classList: "comfyui-workflows-popup",
|
||||
});
|
||||
this.content = new ComfyWorkflowsContent(app, this.popup);
|
||||
this.popup.children = [this.content.element];
|
||||
this.popup.addEventListener("change", () => {
|
||||
@@ -85,7 +92,10 @@ export class ComfyWorkflowsMenu {
|
||||
};
|
||||
|
||||
#bindEvents() {
|
||||
this.app.workflowManager.addEventListener("changeWorkflow", this.#updateActive);
|
||||
this.app.workflowManager.addEventListener(
|
||||
"changeWorkflow",
|
||||
this.#updateActive
|
||||
);
|
||||
this.app.workflowManager.addEventListener("rename", this.#updateActive);
|
||||
this.app.workflowManager.addEventListener("delete", this.#updateActive);
|
||||
|
||||
@@ -157,10 +167,15 @@ export class ComfyWorkflowsMenu {
|
||||
name: "Comfy.Workflows",
|
||||
async beforeRegisterNodeDef(nodeType) {
|
||||
function getImageWidget(node) {
|
||||
const inputs = { ...node.constructor?.nodeData?.input?.required, ...node.constructor?.nodeData?.input?.optional };
|
||||
const inputs = {
|
||||
...node.constructor?.nodeData?.input?.required,
|
||||
...node.constructor?.nodeData?.input?.optional,
|
||||
};
|
||||
for (const input in inputs) {
|
||||
if (inputs[input][0] === "IMAGEUPLOAD") {
|
||||
const imageWidget = node.widgets.find((w) => w.name === (inputs[input]?.[1]?.widget ?? "image"));
|
||||
const imageWidget = node.widgets.find(
|
||||
(w) => w.name === (inputs[input]?.[1]?.widget ?? "image")
|
||||
);
|
||||
if (imageWidget) return imageWidget;
|
||||
}
|
||||
}
|
||||
@@ -213,8 +228,13 @@ export class ComfyWorkflowsMenu {
|
||||
const getExtraMenuOptions = nodeType.prototype["getExtraMenuOptions"];
|
||||
nodeType.prototype["getExtraMenuOptions"] = function (_, options) {
|
||||
const r = getExtraMenuOptions?.apply?.(this, arguments);
|
||||
if (app.ui.settings.getSettingValue("Comfy.UseNewMenu", false) === true) {
|
||||
const t = /** @type { {imageIndex?: number, overIndex?: number, imgs: string[]} } */ /** @type {any} */ (this);
|
||||
if (
|
||||
app.ui.settings.getSettingValue("Comfy.UseNewMenu", false) === true
|
||||
) {
|
||||
const t =
|
||||
/** @type { {imageIndex?: number, overIndex?: number, imgs: string[]} } */ /** @type {any} */ (
|
||||
this
|
||||
);
|
||||
let img;
|
||||
if (t.imageIndex != null) {
|
||||
// An image is selected so select that
|
||||
@@ -238,10 +258,13 @@ export class ComfyWorkflowsMenu {
|
||||
submenu: {
|
||||
options: [
|
||||
{
|
||||
callback: () => sendToWorkflow(img, app.workflowManager.activeWorkflow),
|
||||
callback: () =>
|
||||
sendToWorkflow(img, app.workflowManager.activeWorkflow),
|
||||
title: "[Current workflow]",
|
||||
},
|
||||
...self.#getFavoriteMenuOptions(sendToWorkflow.bind(null, img)),
|
||||
...self.#getFavoriteMenuOptions(
|
||||
sendToWorkflow.bind(null, img)
|
||||
),
|
||||
null,
|
||||
...self.#getMenuOptions(sendToWorkflow.bind(null, img)),
|
||||
],
|
||||
@@ -315,7 +338,9 @@ export class ComfyWorkflowsContent {
|
||||
this.element.replaceChildren(this.actions, this.spinner);
|
||||
|
||||
this.popup.addEventListener("open", () => this.load());
|
||||
this.popup.addEventListener("close", () => this.element.replaceChildren(this.actions, this.spinner));
|
||||
this.popup.addEventListener("close", () =>
|
||||
this.element.replaceChildren(this.actions, this.spinner)
|
||||
);
|
||||
|
||||
this.app.workflowManager.addEventListener("favorite", (e) => {
|
||||
const workflow = e["detail"];
|
||||
@@ -331,7 +356,9 @@ export class ComfyWorkflowsContent {
|
||||
app.workflowManager.addEventListener(e, () => this.updateOpen());
|
||||
}
|
||||
this.app.workflowManager.addEventListener("rename", () => this.load());
|
||||
this.app.workflowManager.addEventListener("execute", (e) => this.#updateActive());
|
||||
this.app.workflowManager.addEventListener("execute", (e) =>
|
||||
this.#updateActive()
|
||||
);
|
||||
}
|
||||
|
||||
async load() {
|
||||
@@ -339,7 +366,12 @@ export class ComfyWorkflowsContent {
|
||||
this.updateTree();
|
||||
this.updateFavorites();
|
||||
this.updateOpen();
|
||||
this.element.replaceChildren(this.actions, this.openElement, this.favoritesElement, this.treeElement);
|
||||
this.element.replaceChildren(
|
||||
this.actions,
|
||||
this.openElement,
|
||||
this.favoritesElement,
|
||||
this.treeElement
|
||||
);
|
||||
}
|
||||
|
||||
updateOpen() {
|
||||
@@ -368,7 +400,7 @@ export class ComfyWorkflowsContent {
|
||||
if (w.unsaved) {
|
||||
wrapper.element.classList.add("unsaved");
|
||||
}
|
||||
if(w === this.app.workflowManager.activeWorkflow) {
|
||||
if (w === this.app.workflowManager.activeWorkflow) {
|
||||
wrapper.element.classList.add("active");
|
||||
}
|
||||
|
||||
@@ -383,7 +415,9 @@ export class ComfyWorkflowsContent {
|
||||
|
||||
updateFavorites() {
|
||||
const current = this.favoritesElement;
|
||||
const favorites = [...this.app.workflowManager.workflows.filter((w) => w.isFavorite)];
|
||||
const favorites = [
|
||||
...this.app.workflowManager.workflows.filter((w) => w.isFavorite),
|
||||
];
|
||||
|
||||
this.favoritesElement = $el("div.comfyui-workflows-favorites", [
|
||||
$el("h3", "Favorites"),
|
||||
@@ -437,7 +471,10 @@ export class ComfyWorkflowsContent {
|
||||
|
||||
hideTreeParents(element) {
|
||||
// Hide all parents if no children are visible
|
||||
if (element.parentElement?.classList.contains("comfyui-workflows-tree") === false) {
|
||||
if (
|
||||
element.parentElement?.classList.contains("comfyui-workflows-tree") ===
|
||||
false
|
||||
) {
|
||||
for (let i = 1; i < element.parentElement.children.length; i++) {
|
||||
const c = element.parentElement.children[i];
|
||||
if (c.style.display !== "none") {
|
||||
@@ -450,7 +487,10 @@ export class ComfyWorkflowsContent {
|
||||
}
|
||||
|
||||
showTreeParents(element) {
|
||||
if (element.parentElement?.classList.contains("comfyui-workflows-tree") === false) {
|
||||
if (
|
||||
element.parentElement?.classList.contains("comfyui-workflows-tree") ===
|
||||
false
|
||||
) {
|
||||
element.parentElement.style.removeProperty("display");
|
||||
this.showTreeParents(element.parentElement);
|
||||
}
|
||||
@@ -490,7 +530,9 @@ export class ComfyWorkflowsContent {
|
||||
|
||||
for (let i = 0; i < workflow.pathParts.length; i++) {
|
||||
currentPath += (currentPath ? "\\" : "") + workflow.pathParts[i];
|
||||
const parentNode = nodes[currentPath] ?? this.#createNode(currentPath, workflow, i, currentRoot);
|
||||
const parentNode =
|
||||
nodes[currentPath] ??
|
||||
this.#createNode(currentPath, workflow, i, currentRoot);
|
||||
|
||||
nodes[currentPath] = parentNode;
|
||||
currentRoot = parentNode;
|
||||
@@ -559,7 +601,9 @@ export class ComfyWorkflowsContent {
|
||||
|
||||
/** @param {ComfyWorkflow} workflow */
|
||||
#getFavoriteTooltip(workflow) {
|
||||
return workflow.isFavorite ? "Remove this workflow from your favorites" : "Add this workflow to your favorites";
|
||||
return workflow.isFavorite
|
||||
? "Remove this workflow from your favorites"
|
||||
: "Add this workflow to your favorites";
|
||||
}
|
||||
|
||||
/** @param {ComfyWorkflow} workflow */
|
||||
@@ -568,7 +612,9 @@ export class ComfyWorkflowsContent {
|
||||
icon: this.#getFavoriteIcon(workflow),
|
||||
overIcon: this.#getFavoriteOverIcon(workflow),
|
||||
iconSize: 18,
|
||||
classList: "comfyui-button comfyui-workflows-file-action-favorite" + (primary ? " comfyui-workflows-file-action-primary" : ""),
|
||||
classList:
|
||||
"comfyui-button comfyui-workflows-file-action-favorite" +
|
||||
(primary ? " comfyui-workflows-file-action-primary" : ""),
|
||||
tooltip: this.#getFavoriteTooltip(workflow),
|
||||
action: (e) => {
|
||||
e.stopImmediatePropagation();
|
||||
@@ -628,7 +674,9 @@ export class ComfyWorkflowsContent {
|
||||
#getRenameButton(workflow) {
|
||||
return new ComfyButton({
|
||||
icon: "pencil",
|
||||
tooltip: workflow.path ? "Rename this workflow" : "This workflow can't be renamed as it hasn't been saved.",
|
||||
tooltip: workflow.path
|
||||
? "Rename this workflow"
|
||||
: "This workflow can't be renamed as it hasn't been saved.",
|
||||
classList: "comfyui-button comfyui-workflows-file-action",
|
||||
iconSize: 18,
|
||||
enabled: !!workflow.path,
|
||||
@@ -646,7 +694,11 @@ export class ComfyWorkflowsContent {
|
||||
#getWorkflowElement(workflow) {
|
||||
return new WorkflowElement(this, workflow, {
|
||||
primary: this.#getFavoriteButton(workflow, true),
|
||||
buttons: [this.#getInsertButton(workflow), this.#getRenameButton(workflow), this.#getDeleteButton(workflow)],
|
||||
buttons: [
|
||||
this.#getInsertButton(workflow),
|
||||
this.#getRenameButton(workflow),
|
||||
this.#getDeleteButton(workflow),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -660,14 +712,17 @@ export class ComfyWorkflowsContent {
|
||||
#createNode(currentPath, workflow, i, currentRoot) {
|
||||
const part = workflow.pathParts[i];
|
||||
|
||||
const parentNode = $el("ul" + (this.treeState[currentPath] ? "" : ".closed"), {
|
||||
$: (el) => {
|
||||
el.onclick = (e) => {
|
||||
this.#expandNode(el, workflow, currentPath, i);
|
||||
e.stopImmediatePropagation();
|
||||
};
|
||||
},
|
||||
});
|
||||
const parentNode = $el(
|
||||
"ul" + (this.treeState[currentPath] ? "" : ".closed"),
|
||||
{
|
||||
$: (el) => {
|
||||
el.onclick = (e) => {
|
||||
this.#expandNode(el, workflow, currentPath, i);
|
||||
e.stopImmediatePropagation();
|
||||
};
|
||||
},
|
||||
}
|
||||
);
|
||||
currentRoot.append(parentNode);
|
||||
|
||||
// Create a node for the current part and an inner UL for its children if it isnt a leaf node
|
||||
@@ -676,7 +731,10 @@ export class ComfyWorkflowsContent {
|
||||
if (leaf) {
|
||||
nodeElement = this.#createLeafNode(workflow).element;
|
||||
} else {
|
||||
nodeElement = $el("li", [$el("i.mdi.mdi-18px.mdi-folder"), $el("span", part)]);
|
||||
nodeElement = $el("li", [
|
||||
$el("i.mdi.mdi-18px.mdi-folder"),
|
||||
$el("span", part),
|
||||
]);
|
||||
}
|
||||
parentNode.append(nodeElement);
|
||||
return parentNode;
|
||||
@@ -703,7 +761,11 @@ class WorkflowElement {
|
||||
},
|
||||
title: this.workflow.path,
|
||||
},
|
||||
[this.primary?.element, $el("span", workflow.name), ...buttons.map((b) => b.element)]
|
||||
[
|
||||
this.primary?.element,
|
||||
$el("span", workflow.name),
|
||||
...buttons.map((b) => b.element),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -732,7 +794,11 @@ class WidgetSelectionDialog extends ComfyAsyncDialog {
|
||||
"section",
|
||||
this.#options.map((opt) => {
|
||||
return $el("div.comfy-widget-selection-item", [
|
||||
$el("span", { dataset: { id: opt.node.id } }, `${opt.node.title ?? opt.node.type} ${opt.widget.name}`),
|
||||
$el(
|
||||
"span",
|
||||
{ dataset: { id: opt.node.id } },
|
||||
`${opt.node.title ?? opt.node.type} ${opt.widget.name}`
|
||||
),
|
||||
$el(
|
||||
"button.comfyui-button",
|
||||
{
|
||||
@@ -760,4 +826,4 @@ class WidgetSelectionDialog extends ComfyAsyncDialog {
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,14 @@ interface SettingOption {
|
||||
interface SettingParams {
|
||||
id: string;
|
||||
name: string;
|
||||
type: string | ((name: string, setter: (v: any) => void, value: any, attrs: any) => HTMLElement);
|
||||
type:
|
||||
| string
|
||||
| ((
|
||||
name: string,
|
||||
setter: (v: any) => void,
|
||||
value: any,
|
||||
attrs: any
|
||||
) => HTMLElement);
|
||||
defaultValue: any;
|
||||
onChange?: (newValue: any, oldValue?: any) => void;
|
||||
attrs?: any;
|
||||
@@ -81,7 +88,7 @@ export class ComfySettingsDialog extends ComfyDialog<HTMLDialogElement> {
|
||||
new CustomEvent(id + ".change", {
|
||||
detail: {
|
||||
value,
|
||||
oldValue
|
||||
oldValue,
|
||||
},
|
||||
})
|
||||
);
|
||||
@@ -115,8 +122,7 @@ export class ComfySettingsDialog extends ComfyDialog<HTMLDialogElement> {
|
||||
if (this.app.storageLocation === "browser") {
|
||||
try {
|
||||
value = JSON.parse(value);
|
||||
} catch (error) {
|
||||
}
|
||||
} catch (error) {}
|
||||
}
|
||||
}
|
||||
return value ?? defaultValue;
|
||||
@@ -145,7 +151,16 @@ export class ComfySettingsDialog extends ComfyDialog<HTMLDialogElement> {
|
||||
}
|
||||
|
||||
addSetting(params: SettingParams) {
|
||||
const { id, name, type, defaultValue, onChange, attrs = {}, tooltip = "", options = undefined } = params;
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
type,
|
||||
defaultValue,
|
||||
onChange,
|
||||
attrs = {},
|
||||
tooltip = "",
|
||||
options = undefined,
|
||||
} = params;
|
||||
if (!id) {
|
||||
throw new Error("Settings must have an ID");
|
||||
}
|
||||
@@ -272,7 +287,8 @@ export class ComfySettingsDialog extends ComfyDialog<HTMLDialogElement> {
|
||||
style: { maxWidth: "4rem" },
|
||||
oninput: (e) => {
|
||||
setter(e.target.value);
|
||||
e.target.previousElementSibling.value = e.target.value;
|
||||
e.target.previousElementSibling.value =
|
||||
e.target.value;
|
||||
},
|
||||
}),
|
||||
]
|
||||
@@ -291,7 +307,10 @@ export class ComfySettingsDialog extends ComfyDialog<HTMLDialogElement> {
|
||||
setter(e.target.value);
|
||||
},
|
||||
},
|
||||
(typeof options === "function" ? options(value) : options || []).map((opt) => {
|
||||
(typeof options === "function"
|
||||
? options(value)
|
||||
: options || []
|
||||
).map((opt) => {
|
||||
if (typeof opt === "string") {
|
||||
opt = { text: opt };
|
||||
}
|
||||
@@ -309,7 +328,9 @@ export class ComfySettingsDialog extends ComfyDialog<HTMLDialogElement> {
|
||||
case "text":
|
||||
default:
|
||||
if (type !== "text") {
|
||||
console.warn(`Unsupported setting type '${type}, defaulting to text`);
|
||||
console.warn(
|
||||
`Unsupported setting type '${type}, defaulting to text`
|
||||
);
|
||||
}
|
||||
|
||||
element = $el("tr", [
|
||||
@@ -356,7 +377,10 @@ export class ComfySettingsDialog extends ComfyDialog<HTMLDialogElement> {
|
||||
},
|
||||
[$el("th"), $el("th", { style: { width: "33%" } })]
|
||||
),
|
||||
...this.settings.sort((a, b) => a.name.localeCompare(b.name)).map((s) => s.render()).filter(Boolean)
|
||||
...this.settings
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
.map((s) => s.render())
|
||||
.filter(Boolean)
|
||||
);
|
||||
this.element.showModal();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import "./spinner.css";
|
||||
|
||||
|
||||
export function createSpinner() {
|
||||
const div = document.createElement("div");
|
||||
div.innerHTML = `<div class="lds-ring"><div></div><div></div><div></div><div></div></div>`;
|
||||
|
||||
@@ -20,7 +20,10 @@ export function toggleSwitch(name, items, e?) {
|
||||
if (selectedIndex != null) {
|
||||
elements[selectedIndex].classList.remove("comfy-toggle-selected");
|
||||
}
|
||||
onChange?.({ item: items[index], prev: selectedIndex == null ? undefined : items[selectedIndex] });
|
||||
onChange?.({
|
||||
item: items[index],
|
||||
prev: selectedIndex == null ? undefined : items[selectedIndex],
|
||||
});
|
||||
selectedIndex = index;
|
||||
elements[selectedIndex].classList.add("comfy-toggle-selected");
|
||||
}
|
||||
|
||||
@@ -3,16 +3,14 @@ import { $el } from "../ui";
|
||||
import { createSpinner } from "./spinner";
|
||||
import "./userSelection.css";
|
||||
|
||||
|
||||
interface SelectedUser {
|
||||
username: string;
|
||||
userId: string;
|
||||
created: boolean;
|
||||
}
|
||||
|
||||
|
||||
export class UserSelectionScreen {
|
||||
async show(users, user): Promise<SelectedUser>{
|
||||
async show(users, user): Promise<SelectedUser> {
|
||||
const userSelection = document.getElementById("comfy-user-selection");
|
||||
userSelection.style.display = "";
|
||||
return new Promise((resolve) => {
|
||||
@@ -22,7 +20,9 @@ export class UserSelectionScreen {
|
||||
const selectSection = select.closest("section");
|
||||
const form = userSelection.getElementsByTagName("form")[0];
|
||||
const error = userSelection.getElementsByClassName("comfy-user-error")[0];
|
||||
const button = userSelection.getElementsByClassName("comfy-user-button-next")[0];
|
||||
const button = userSelection.getElementsByClassName(
|
||||
"comfy-user-button-next"
|
||||
)[0];
|
||||
|
||||
let inputActive = null;
|
||||
input.addEventListener("focus", () => {
|
||||
@@ -45,7 +45,8 @@ export class UserSelectionScreen {
|
||||
form.addEventListener("submit", async (e) => {
|
||||
e.preventDefault();
|
||||
if (inputActive == null) {
|
||||
error.textContent = "Please enter a username or select an existing user.";
|
||||
error.textContent =
|
||||
"Please enter a username or select an existing user.";
|
||||
} else if (inputActive) {
|
||||
const username = input.value.trim();
|
||||
if (!username) {
|
||||
@@ -54,41 +55,59 @@ export class UserSelectionScreen {
|
||||
}
|
||||
|
||||
// Create new user
|
||||
// @ts-ignore
|
||||
// Property 'readonly' does not exist on type 'HTMLSelectElement'.ts(2339)
|
||||
// Property 'readonly' does not exist on type 'HTMLInputElement'. Did you mean 'readOnly'?ts(2551)
|
||||
input.disabled = select.disabled = input.readonly = select.readonly = true;
|
||||
input.disabled =
|
||||
select.disabled =
|
||||
// @ts-ignore
|
||||
input.readonly =
|
||||
// @ts-ignore
|
||||
select.readonly =
|
||||
true;
|
||||
const spinner = createSpinner();
|
||||
button.prepend(spinner);
|
||||
try {
|
||||
const resp = await api.createUser(username);
|
||||
if (resp.status >= 300) {
|
||||
let message = "Error creating user: " + resp.status + " " + resp.statusText;
|
||||
let message =
|
||||
"Error creating user: " + resp.status + " " + resp.statusText;
|
||||
try {
|
||||
const res = await resp.json();
|
||||
if(res.error) {
|
||||
if (res.error) {
|
||||
message = res.error;
|
||||
}
|
||||
} catch (error) {
|
||||
}
|
||||
} catch (error) {}
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
resolve({ username, userId: await resp.json(), created: true });
|
||||
} catch (err) {
|
||||
spinner.remove();
|
||||
error.textContent = err.message ?? err.statusText ?? err ?? "An unknown error occurred.";
|
||||
// @ts-ignore
|
||||
error.textContent =
|
||||
err.message ??
|
||||
err.statusText ??
|
||||
err ??
|
||||
"An unknown error occurred.";
|
||||
// Property 'readonly' does not exist on type 'HTMLSelectElement'.ts(2339)
|
||||
// Property 'readonly' does not exist on type 'HTMLInputElement'. Did you mean 'readOnly'?ts(2551)
|
||||
input.disabled = select.disabled = input.readonly = select.readonly = false;
|
||||
input.disabled =
|
||||
select.disabled =
|
||||
// @ts-ignore
|
||||
input.readonly =
|
||||
// @ts-ignore
|
||||
select.readonly =
|
||||
false;
|
||||
return;
|
||||
}
|
||||
} else if (!select.value) {
|
||||
error.textContent = "Please select an existing user.";
|
||||
return;
|
||||
} else {
|
||||
resolve({ username: users[select.value], userId: select.value, created: false });
|
||||
resolve({
|
||||
username: users[select.value],
|
||||
userId: select.value,
|
||||
created: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user