145 lines
4.2 KiB
JavaScript
145 lines
4.2 KiB
JavaScript
import { api } from "../../../scripts/api.js";
|
|
import { app } from "../../../scripts/app.js";
|
|
import { allow_debug } from "./js_shared.js";
|
|
|
|
/* this node is compatible with ComfyUI Node.2.
|
|
I use this node as a perfect simple example for an AI agent
|
|
to understand how to create a DOM widget.
|
|
*/
|
|
app.registerExtension({
|
|
name: "iTools.domNode",
|
|
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
|
if (nodeData.name !== "iToolsDomNode") {
|
|
return;
|
|
}
|
|
|
|
// must set 'OUTPUT_NODE = True' on python side
|
|
const originalOnExecuted = nodeType.prototype.onExecuted;
|
|
nodeType.prototype.onExecuted = function (message) {
|
|
originalOnExecuted?.apply(this, arguments);
|
|
if(allow_debug) console.log('iToolsDomNode executed',);
|
|
};
|
|
|
|
},
|
|
|
|
async nodeCreated(node) {
|
|
if (node.comfyClass !== "iToolsDomNode") {
|
|
return;
|
|
}
|
|
|
|
// Set initial node size if needed
|
|
node.size = [200, 230];
|
|
// if(allow_debug) console.log('node',node);
|
|
|
|
// Create container div
|
|
const container = document.createElement("div");
|
|
container.className = "counter-widget";
|
|
container.style.cssText = `
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center; /* Centers items horizontally */
|
|
justify-content: center; /* Centers items vertically */
|
|
gap: 10px;
|
|
padding: 10px;
|
|
background-color: #2a2a2a;
|
|
border-radius: 4px;
|
|
width: 100%;
|
|
`;
|
|
|
|
// Create controls
|
|
const label = document.createElement("label");
|
|
label.textContent = "Counter";
|
|
label.style.color = "#fff";
|
|
|
|
const controlsDiv = document.createElement("div");
|
|
controlsDiv.style.cssText = `
|
|
display: flex;
|
|
gap: 10px;
|
|
align-items: center;
|
|
`;
|
|
|
|
const minusButton = document.createElement("button");
|
|
minusButton.textContent = "-";
|
|
minusButton.style.minWidth = "30px";
|
|
minusButton.className = "comfy-button";
|
|
|
|
const counterValue = document.createElement("span");
|
|
counterValue.textContent = "0";
|
|
counterValue.style.color = "#fff";
|
|
|
|
const plusButton = document.createElement("button");
|
|
plusButton.textContent = "+";
|
|
plusButton.style.minWidth = "30px";
|
|
plusButton.className = "comfy-button";
|
|
|
|
// Add textarea
|
|
const textarea = document.createElement("textarea");
|
|
textarea.className = "comfy-multiline-input";
|
|
textarea.value = "Notes here...";
|
|
textarea.style.width = "100%";
|
|
textarea.style.minHeight = "80px";
|
|
textarea.style.margin = "10px 0";
|
|
|
|
// Assemble the widget
|
|
controlsDiv.appendChild(minusButton);
|
|
controlsDiv.appendChild(counterValue);
|
|
controlsDiv.appendChild(plusButton);
|
|
|
|
container.appendChild(label);
|
|
container.appendChild(controlsDiv);
|
|
container.appendChild(textarea);
|
|
|
|
// Add event handlers
|
|
const updateCounter = (delta) => {
|
|
const newValue = parseInt(counterValue.textContent) + delta;
|
|
counterValue.textContent = newValue.toString();
|
|
widget.value = {
|
|
count: newValue,
|
|
text: textarea.value
|
|
};
|
|
};
|
|
|
|
minusButton.onclick = () => updateCounter(-1);
|
|
plusButton.onclick = () => updateCounter(1);
|
|
textarea.oninput = () => {
|
|
widget.value = {
|
|
count: parseInt(counterValue.textContent),
|
|
text: textarea.value
|
|
};
|
|
};
|
|
|
|
// Create the widget
|
|
const widget = node.addDOMWidget("CounterWidget", "custom", container, {
|
|
tooltip: 'Counter Widget',
|
|
getValue: () => ({
|
|
count: parseInt(counterValue.textContent),
|
|
text: textarea.value
|
|
}),
|
|
setValue: (v) => {
|
|
if (v && typeof v === 'object') {
|
|
counterValue.textContent = v.count?.toString() || "0";
|
|
textarea.value = v.text || "";
|
|
}
|
|
},
|
|
getMinHeight: () => 200,
|
|
getMaxHeight: () => 400,
|
|
margin: 5,
|
|
onDraw: (ctx) => {
|
|
}
|
|
});
|
|
widget.tooltip = 'Counter Widget'
|
|
// Apply margin directly to the container
|
|
container.style.marginTop = "0px";
|
|
|
|
// Clean up on node removal
|
|
const origOnRemoved = node.onRemoved;
|
|
node.onRemoved = function() {
|
|
origOnRemoved?.apply(this, arguments);
|
|
if (allow_debug) console.log("Cleaning up widget");
|
|
};
|
|
|
|
// Force canvas update
|
|
node.setDirtyCanvas(true, true);
|
|
}
|
|
});
|