154 lines
5.7 KiB
JavaScript
154 lines
5.7 KiB
JavaScript
import { app } from "../../scripts/app.js";
|
||
|
||
/**
|
||
* ComfyUI Multi-Replace Extension
|
||
* Handles dynamic visibility of find/replace pair widgets
|
||
*/
|
||
|
||
const MAX_PAIRS = 80;
|
||
|
||
app.registerExtension({
|
||
name: "comfyui-multi-replace",
|
||
|
||
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
|
||
const origGetExtraMenuOptions = nodeType.prototype.getExtraMenuOptions;
|
||
nodeType.prototype.getExtraMenuOptions = function(_, options) {
|
||
if (origGetExtraMenuOptions) {
|
||
origGetExtraMenuOptions.apply(this, arguments);
|
||
}
|
||
|
||
options.unshift(
|
||
{
|
||
content: "Add Find/Replace Pair",
|
||
disabled: this.pairCount >= MAX_PAIRS,
|
||
callback: () => this.addNewPair()
|
||
},
|
||
{
|
||
content: "Remove Last Pair",
|
||
disabled: this.pairCount <= 1,
|
||
callback: () => this.removeLastPair()
|
||
},
|
||
null // separator
|
||
);
|
||
};
|
||
|
||
// 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);
|
||
};
|
||
}
|
||
}
|
||
});
|