interactive

This commit is contained in:
Shaun Johnston
2025-12-16 09:47:20 +10:00
parent 7def12c44f
commit 7ba7721558
+109 -119
View File
@@ -10,99 +10,114 @@ const MAX_PAIRS = 80;
app.registerExtension({
name: "comfyui-multi-replace",
async nodeCreated(node) {
if (node.comfyClass !== "FindReplacePairs") return;
node.pairCount = 1;
// Find all the find/replace widgets and store references
const pairWidgets = [];
if (node.widgets) {
for (const widget of node.widgets) {
const match = widget.name?.match(/^(find|replace)_(\d+)$/);
if (match) {
pairWidgets.push(widget);
}
}
}
// Function to update visibility
node.updatePairVisibility = function() {
if (!this.widgets) return;
for (const widget of this.widgets) {
const match = widget.name?.match(/^(find|replace)_(\d+)$/);
if (match) {
const pairIndex = parseInt(match[2]);
const shouldShow = pairIndex <= this.pairCount;
if (shouldShow) {
widget.type = widget._originalType || widget.type || "STRING";
if (widget._originalComputeSize) {
widget.computeSize = widget._originalComputeSize;
} else {
delete widget.computeSize;
}
} else {
if (!widget._originalType && widget.type !== "hidden") {
widget._originalType = widget.type;
widget._originalComputeSize = widget.computeSize;
}
widget.type = "hidden";
widget.computeSize = () => [0, -4];
}
}
}
this.setSize(this.computeSize());
app.graph.setDirtyCanvas(true, true);
};
// Add pair function
node.addNewPair = function() {
if (this.pairCount >= MAX_PAIRS) return;
this.pairCount++;
this.updatePairVisibility();
};
// Remove pair function
node.removeLastPair = function() {
if (this.pairCount <= 1) return;
// Clear the values
const findWidget = this.widgets?.find(w => w.name === `find_${this.pairCount}`);
const replaceWidget = this.widgets?.find(w => w.name === `replace_${this.pairCount}`);
if (findWidget) findWidget.value = "";
if (replaceWidget) replaceWidget.value = "";
this.pairCount--;
this.updatePairVisibility();
};
// Add buttons AFTER all the pair widgets
// First, do initial hide of extra pairs
node.updatePairVisibility();
// Now add the buttons at the end
const addBtn = node.addWidget("button", "add_pair_btn", "➕ Add Pair", () => {
node.addNewPair();
});
addBtn.serializeValue = () => undefined; // Don't serialize button
const removeBtn = node.addWidget("button", "remove_pair_btn", "➖ Remove Last Pair", () => {
node.removeLastPair();
});
removeBtn.serializeValue = () => undefined; // Don't serialize button
// Override serialize to save pair count
const origSerialize = node.serialize;
node.serialize = function() {
const data = origSerialize ? origSerialize.call(this) : {};
data.pairCount = this.pairCount;
return data;
};
// Handle loading saved pair count
const origConfigure = node.configure;
node.configure = function(data) {
if (origConfigure) {
origConfigure.call(this, data);
}
if (data.pairCount) {
this.pairCount = data.pairCount;
setTimeout(() => this.updatePairVisibility(), 10);
}
};
},
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeData.name === "FindReplacePairs") {
const origOnNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function() {
if (origOnNodeCreated) {
origOnNodeCreated.apply(this, arguments);
}
this.pairCount = 1;
// Add the "Add Pair" button at the end
this.addWidget("button", "➕ Add Pair", null, () => {
this.addNewPair();
});
// Add the "Remove Last Pair" button
this.addWidget("button", "➖ Remove Last Pair", null, () => {
this.removeLastPair();
});
// Initial visibility update
setTimeout(() => {
this.updatePairVisibility();
}, 50);
};
// Show the next pair
nodeType.prototype.addNewPair = function() {
if (this.pairCount >= MAX_PAIRS) return;
this.pairCount++;
this.updatePairVisibility();
};
// Hide the last pair
nodeType.prototype.removeLastPair = function() {
if (this.pairCount <= 1) return;
// Clear the values of the pair being removed
const findWidget = this.widgets?.find(w => w.name === `find_${this.pairCount}`);
const replaceWidget = this.widgets?.find(w => w.name === `replace_${this.pairCount}`);
if (findWidget) findWidget.value = "";
if (replaceWidget) replaceWidget.value = "";
this.pairCount--;
this.updatePairVisibility();
};
// Update visibility of pair widgets
nodeType.prototype.updatePairVisibility = function() {
if (!this.widgets) return;
for (const widget of this.widgets) {
const match = widget.name?.match(/^(find|replace)_(\d+)$/);
if (match) {
const pairIndex = parseInt(match[2]);
const shouldShow = pairIndex <= this.pairCount;
if (shouldShow) {
// Show widget
widget.type = widget._originalType || widget.type;
if (widget._originalComputeSize) {
widget.computeSize = widget._originalComputeSize;
}
} else {
// Hide widget
if (widget.type !== "hidden") {
widget._originalType = widget.type;
widget._originalComputeSize = widget.computeSize;
}
widget.type = "hidden";
widget.computeSize = () => [0, -4];
}
}
}
// Also hide/show the corresponding inputs
if (this.inputs) {
for (const input of this.inputs) {
const match = input.name?.match(/^(find|replace)_(\d+)$/);
if (match) {
const pairIndex = parseInt(match[2]);
// We can't truly hide inputs, but we can mark them
input._hidden = pairIndex > this.pairCount;
}
}
}
this.setSize(this.computeSize());
app.graph.setDirtyCanvas(true, true);
};
// Override getExtraMenuOptions to add right-click options
// Add right-click menu options
const origGetExtraMenuOptions = nodeType.prototype.getExtraMenuOptions;
nodeType.prototype.getExtraMenuOptions = function(_, options) {
if (origGetExtraMenuOptions) {
@@ -113,41 +128,16 @@ app.registerExtension({
{
content: "Add Find/Replace Pair",
disabled: this.pairCount >= MAX_PAIRS,
callback: () => this.addNewPair()
callback: () => this.addNewPair?.()
},
{
content: "Remove Last Pair",
disabled: this.pairCount <= 1,
callback: () => this.removeLastPair()
callback: () => this.removeLastPair?.()
},
null // separator
null
);
};
// Save pair count
const origOnSerialize = nodeType.prototype.onSerialize;
nodeType.prototype.onSerialize = function(info) {
if (origOnSerialize) {
origOnSerialize.apply(this, arguments);
}
info.pairCount = this.pairCount;
};
// Restore pair count and visibility
const origOnConfigure = nodeType.prototype.onConfigure;
nodeType.prototype.onConfigure = function(info) {
if (origOnConfigure) {
origOnConfigure.apply(this, arguments);
}
if (info.pairCount) {
this.pairCount = info.pairCount;
}
setTimeout(() => {
this.updatePairVisibility();
}, 50);
};
}
}
});