| import { app } from "../../../scripts/app.js"; |
| import { $el, ComfyDialog } from "../../../scripts/ui.js"; |
|
|
| |
|
|
| const id = "pysssss.WidgetDefaults"; |
| const nodeDataKey = Symbol(); |
|
|
| app.registerExtension({ |
| name: id, |
| beforeRegisterNodeDef(nodeType, nodeData) { |
| nodeType[nodeDataKey] = nodeData; |
| }, |
| setup() { |
| let defaults; |
| let setting; |
|
|
| const applyDefaults = (defaults) => { |
| for (const node of Object.values(LiteGraph.registered_node_types)) { |
| const nodeData = node[nodeDataKey]; |
| if (!nodeData) continue; |
| const nodeDefaults = defaults[node.type]; |
| if (!nodeDefaults) continue; |
| const inputs = { ...(nodeData.input?.required || {}), ...(nodeData.input?.optional || {}) }; |
|
|
| for (const w in nodeDefaults) { |
| const widgetDef = inputs[w]; |
| if (widgetDef) { |
| let v = nodeDefaults[w]; |
| if (widgetDef[0] === "INT" || widgetDef[0] === "FLOAT") { |
| v = +v; |
| } |
| if (widgetDef[1]) { |
| widgetDef[1].default = v; |
| } else { |
| widgetDef[1] = { default: v }; |
| } |
| } |
| } |
| } |
| }; |
|
|
| const getDefaults = () => { |
| let items; |
| try { |
| items = JSON.parse(setting.value); |
| items = items.reduce((p, n) => { |
| if (!p[n.node]) p[n.node] = {}; |
| p[n.node][n.widget] = n.value; |
| return p; |
| }, {}); |
| } catch (error) {} |
| if (!items) { |
| items = {}; |
| } |
| applyDefaults(items); |
| return items; |
| }; |
|
|
| const onNodeAdded = app.graph.onNodeAdded; |
| app.graph.onNodeAdded = function (node) { |
| onNodeAdded?.apply?.(this, arguments); |
|
|
| |
| const nodeDefaults = defaults[node.constructor.type]; |
| if (!nodeDefaults) return; |
|
|
| |
| const stack = new Error().stack; |
| if (stack.includes("pasteFromClipboard") || stack.includes("loadGraphData")) { |
| return; |
| } |
|
|
| for (const k in nodeDefaults) { |
| if (k.startsWith("property.")) { |
| const name = k.substring(9); |
| let v = nodeDefaults[k]; |
| |
| if (name in node || ["color", "bgcolor", "title"].includes(name)) { |
| node[name] = v; |
| } else { |
| |
| if (!node.properties) node.properties = {}; |
| if (typeof node.properties[name] === "number") v = +v; |
| else if (typeof node.properties[name] === "boolean") v = v === "true"; |
| else if (v === "true") v = true; |
|
|
| node.properties[name] = v; |
| } |
| } |
| } |
| }; |
|
|
| class WidgetDefaultsDialog extends ComfyDialog { |
| constructor() { |
| super(); |
| this.element.classList.add("comfy-manage-templates"); |
| this.grid = $el( |
| "div", |
| { |
| style: { |
| display: "grid", |
| gridTemplateColumns: "1fr auto auto auto", |
| gap: "5px", |
| }, |
| className: "pysssss-widget-defaults", |
| }, |
| [ |
| $el("label", { |
| textContent: "Node Class", |
| }), |
| $el("label", { |
| textContent: "Widget Name", |
| }), |
| $el("label", { |
| textContent: "Default Value", |
| }), |
| $el("label"), |
| (this.rows = $el("div", { |
| style: { |
| display: "contents", |
| }, |
| })), |
| ] |
| ); |
| } |
|
|
| createButtons() { |
| const btns = super.createButtons(); |
| btns[0].textContent = "Cancel"; |
| btns.unshift( |
| $el("button", { |
| type: "button", |
| textContent: "Add New", |
| onclick: () => this.addRow(), |
| }), |
| $el("button", { |
| type: "button", |
| textContent: "Save", |
| onclick: () => this.save(), |
| }) |
| ); |
| return btns; |
| } |
|
|
| addRow(node = "", widget = "", value = "") { |
| let nameInput; |
| this.rows.append( |
| $el( |
| "div", |
| { |
| style: { |
| display: "contents", |
| }, |
| className: "pysssss-widget-defaults-row", |
| }, |
| [ |
| $el("input", { |
| placeholder: "e.g. CheckpointLoaderSimple", |
| value: node, |
| }), |
| $el("input", { |
| placeholder: "e.g. ckpt_name", |
| value: widget, |
| $: (el) => (nameInput = el), |
| }), |
| $el("input", { |
| placeholder: "e.g. myBestModel.safetensors", |
| value, |
| }), |
| $el("button", { |
| textContent: "Delete", |
| style: { |
| fontSize: "12px", |
| color: "red", |
| fontWeight: "normal", |
| }, |
| onclick: (e) => { |
| nameInput.value = ""; |
| e.target.parentElement.style.display = "none"; |
| }, |
| }), |
| ] |
| ) |
| ); |
| } |
|
|
| save() { |
| const rows = this.rows.children; |
| const items = []; |
|
|
| for (const row of rows) { |
| const inputs = row.querySelectorAll("input"); |
| const node = inputs[0].value.trim(); |
| const widget = inputs[1].value.trim(); |
| const value = inputs[2].value; |
| if (node && widget) { |
| items.push({ node, widget, value }); |
| } |
| } |
|
|
| setting.value = JSON.stringify(items); |
| defaults = getDefaults(); |
|
|
| this.close(); |
| } |
|
|
| show() { |
| this.rows.replaceChildren(); |
| for (const nodeName in defaults) { |
| const node = defaults[nodeName]; |
| for (const widgetName in node) { |
| this.addRow(nodeName, widgetName, node[widgetName]); |
| } |
| } |
|
|
| this.addRow(); |
| super.show(this.grid); |
| } |
| } |
|
|
| setting = app.ui.settings.addSetting({ |
| id, |
| name: "🐍 Widget Defaults", |
| type: () => { |
| return $el("tr", [ |
| $el("td", [ |
| $el("label", { |
| for: id.replaceAll(".", "-"), |
| textContent: "🐍 Widget & Property Defaults:", |
| }), |
| ]), |
| $el("td", [ |
| $el("button", { |
| textContent: "Manage", |
| onclick: () => { |
| app.ui.settings.element.close(); |
| const dialog = new WidgetDefaultsDialog(); |
| dialog.show(); |
| }, |
| style: { |
| fontSize: "14px", |
| }, |
| }), |
| ]), |
| ]); |
| }, |
| }); |
| defaults = getDefaults(); |
| }, |
| }); |
|
|