interactive
This commit is contained in:
+109
-119
@@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user