vidfom's picture
Upload folder using huggingface_hub (part 6)
f2b53cf verified
Raw
History Blame Contribute Delete
5.86 kB
const { app } = window.comfyAPI.app;
function addNode(name, nextTo, options) {
options = { side: "left", select: true, shiftY: 0, shiftX: 0, ...(options || {}) };
const node = LiteGraph.createNode(name);
const graph = app.canvas?.graph || app.graph;
graph.add(node);
node.pos = [
options.side === "left" ? nextTo.pos[0] - (node.size[0] + options.offset): nextTo.pos[0] + nextTo.size[0] + options.offset,
nextTo.pos[1] + options.shiftY,
];
// Automatically connect nodes
if (options.side === "left") {
// New node on left: connect new node's first output to nextTo's first free input
if (node.outputs && node.outputs.length > 0 && nextTo.inputs && nextTo.inputs.length > 0) {
for (let i = 0; i < nextTo.inputs.length; i++) {
if (!nextTo.inputs[i].link) {
node.pos[1] += i * (node.size[1] + 32);
node.connect(0, nextTo, i);
break;
}
}
}
} else {
// New node on right: connect nextTo's first free output to new node's first free input
if (nextTo.outputs && nextTo.outputs.length > 0 && node.inputs && node.inputs.length > 0) {
for (let o = 0; o < nextTo.outputs.length; o++) {
if (!nextTo.outputs[o].links || nextTo.outputs[o].links.length === 0) {
// Offset vertically by slot index so multiple Set nodes don't overlap
node.pos[1] += o * (node.size[1] + 32);
for (let i = 0; i < node.inputs.length; i++) {
if (!node.inputs[i].link) {
nextTo.connect(o, node, i);
break;
}
}
break;
}
}
}
}
if (options.select) {
app.canvas.selectNode(node, false);
}
return node;
}
// Expose addNode for use in setgetnodes.js
window.kjNodes = window.kjNodes || {};
window.kjNodes.addNode = addNode;
app.registerExtension({
name: "KJNodes.Contextmenu",
settings: [
{
id: "KJNodes.helpPopup",
name: "Help popups",
category: ["KJNodes", "General", "Help popups"],
tooltip: "Show help popups when hovering over KJNodes",
defaultValue: true,
type: "boolean",
},
{
id: "KJNodes.showSetGetInConnectionMenu",
name: "Show Set/Get in connection menu",
category: ["KJNodes", "Set & Get", "Show Set/Get in connection menu"],
tooltip: "Add Set/Get entries to the slot connection menu (next to Add Reroute)",
type: "boolean",
defaultValue: true,
},
],
getNodeMenuItems(node) {
try {
const items = [];
if (node.inputs && node.inputs.length > 0) {
const selectedForConvert = window.kjNodes.snapshotSelectedNodes(node);
items.push(
{
content: "Add GetNode",
callback: () => { addNode("GetNode", node, { side: "left", offset: 30 }); }
},
{
content: "Add SetNode",
callback: () => { addNode("SetNode", node, { side: "right", offset: 30 }); }
},
{
content: "Add PreviewAsTextNode",
callback: () => { addNode("PreviewAny", node, { side: "right", offset: 30 }); }
},
{
content: "Convert all outputs to Set/Get",
callback: () => {
for (const n of selectedForConvert) window.kjNodes.convertOutputsToSetGet(node.graph, n);
}
},
);
}
const cls = node.constructor?.comfyClass || node.comfyClass;
if (cls && window.kjNodes?.recreateNode) {
items.push({
content: "Recreate node",
has_submenu: true,
submenu: {
options: [
{ content: "Keep widget values", callback: () => window.kjNodes.recreateNode(node, cls, { resetValues: false }) },
{ content: "Reset widget values", callback: () => window.kjNodes.recreateNode(node, cls, { resetValues: true }) },
],
},
});
}
return items;
} catch (err) {
console.error("[KJNodes.Contextmenu] getNodeMenuItems failed:", err);
return [];
}
},
async setup(app) {
const origShowConnectionMenu = app.canvas.showConnectionMenu.bind(app.canvas);
// Inject "Add SetNode" / "Add GetNode" into the slot connection dropdown menu.
app.canvas.showConnectionMenu = function(optPass) {
const showSetGet = app.ui.settings.getSettingValue("KJNodes.showSetGetInConnectionMenu") ?? true;
if (!showSetGet) return origShowConnectionMenu(optPass);
const isFrom = optPass.nodeFrom && optPass.slotFrom != null;
const nodeType = isFrom ? "SetNode" : "GetNode";
const label = isFrom ? "Add SetNode" : "Add GetNode";
const OrigCM = LiteGraph.ContextMenu;
let interceptActive = true;
LiteGraph.ContextMenu = function(options, menuOpts) {
LiteGraph.ContextMenu = OrigCM;
if (!interceptActive) return new OrigCM(options, menuOpts);
interceptActive = false;
const idx = options.indexOf("Add Reroute");
if (idx !== -1) options.splice(idx + 1, 0, label);
const origCb = menuOpts.callback;
menuOpts.callback = function(v, cbOpts, e) {
if (v === label) {
const node = LiteGraph.createNode(nodeType);
if (node) {
const graph = app.canvas?.graph || app.graph;
node.pos = [optPass.e?.canvasX ?? 0, optPass.e?.canvasY ?? 0];
graph.add(node);
if (isFrom && optPass.nodeFrom) {
const slotIdx = typeof optPass.slotFrom === 'number'
? optPass.slotFrom
: optPass.nodeFrom.findOutputSlot(optPass.slotFrom.name);
optPass.nodeFrom.connect(slotIdx, node, 0);
} else if (optPass.nodeTo) {
const slotIdx = typeof optPass.slotTo === 'number'
? optPass.slotTo
: optPass.nodeTo.findInputSlot(optPass.slotTo.name);
node.connect(0, optPass.nodeTo, slotIdx);
}
graph.change();
app.canvas.setDirty(true, true);
}
return;
}
return origCb?.call(this, v, cbOpts, e);
};
return new OrigCM(options, menuOpts);
};
LiteGraph.ContextMenu.prototype = OrigCM.prototype;
const result = origShowConnectionMenu(optPass);
LiteGraph.ContextMenu = OrigCM;
interceptActive = false;
return result;
};
}
});