746 lines
32 KiB
JavaScript
746 lines
32 KiB
JavaScript
import { app } from "../../scripts/app.js";
|
|
import { IoDirection, PassThroughFollowing, followConnectionUntilType, getConnectedInputNodes, getConnectedInputNodesAndFilterPassThroughs, getConnectedNodesInfo, getConnectedOutputNodesAndFilterPassThroughs, shouldPassThrough, } from "./utils.js";
|
|
import { rgthree } from "./rgthree.js";
|
|
import { BaseContextNode } from "./context.js";
|
|
class ContextDynamicNodeBase extends BaseContextNode {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.hasShadowInputs = false;
|
|
}
|
|
getContextInputsList() {
|
|
return this.inputs;
|
|
}
|
|
onConnectionsChainChange(arg) {
|
|
console.log("ContextDynamicNodeBase: onConnectionsChainChange", this.id, arg);
|
|
}
|
|
onNodeCreated() {
|
|
const inputs = this.getContextInputsList();
|
|
if (inputs[inputs.length - 1].type === "*") {
|
|
this.removeOutput(inputs.length - 1);
|
|
}
|
|
else {
|
|
this.addInput("+", "*");
|
|
}
|
|
}
|
|
getWidgets() {
|
|
return Object.assign({}, super.getWidgets(), {
|
|
DYNAMIC_CONTEXT_OUTPUTS: (node, inputName, inputData, app) => {
|
|
node.addCustomWidget({
|
|
name: inputName,
|
|
value: "",
|
|
draw(ctx, node, width, posY, height) {
|
|
return;
|
|
},
|
|
computeSize(width) {
|
|
return [0, 0];
|
|
},
|
|
serializeValue() {
|
|
const value = (node.outputs || [])
|
|
.map((o, i) => i > 0 && o.name)
|
|
.filter((n) => n !== false)
|
|
.join(",");
|
|
return value;
|
|
},
|
|
});
|
|
},
|
|
});
|
|
}
|
|
stripOwnedPrefix(name) {
|
|
return name.replace(/^\+\s*/, "");
|
|
}
|
|
addOwnedPrefix(name) {
|
|
return `+ ${this.stripOwnedPrefix(name)}`;
|
|
}
|
|
isOwnedInput(inputOrName) {
|
|
const name = typeof inputOrName == "string" ? inputOrName : (inputOrName === null || inputOrName === void 0 ? void 0 : inputOrName.name) || "";
|
|
return name.startsWith("+ ") || name === "+";
|
|
}
|
|
getNextUniqueNameForThisNode(desiredName) {
|
|
const inputs = this.getContextInputsList();
|
|
const allExistingKeys = inputs.map((i) => this.stripOwnedPrefix(i.name).toLocaleUpperCase());
|
|
desiredName = this.stripOwnedPrefix(desiredName);
|
|
let newName = desiredName;
|
|
let n = 0;
|
|
while (allExistingKeys.includes(newName.toLocaleUpperCase())) {
|
|
newName = `${desiredName}.${++n}`;
|
|
}
|
|
return newName;
|
|
}
|
|
onConnectionsChange(type, slotIndex, isConnected, linkInfo, ioSlot) {
|
|
var _a;
|
|
(_a = super.onConnectionsChange) === null || _a === void 0 ? void 0 : _a.call(this, type, slotIndex, isConnected, linkInfo, ioSlot);
|
|
if (this.configuring) {
|
|
return;
|
|
}
|
|
if (type === LiteGraph.INPUT) {
|
|
if (isConnected) {
|
|
this.handleInputConnected(slotIndex);
|
|
}
|
|
else {
|
|
this.handleInputDisconnected(slotIndex);
|
|
}
|
|
}
|
|
}
|
|
handleInputConnected(slotIndex) {
|
|
}
|
|
handleInputDisconnected(slotIndex) {
|
|
}
|
|
updateFromUpstream(update, node, updatedSlotData) {
|
|
}
|
|
provideInputsData() {
|
|
const inputs = this.getContextInputsList();
|
|
return inputs
|
|
.map((input, index) => ({
|
|
name: this.stripOwnedPrefix(input.name),
|
|
type: String(input.type),
|
|
index,
|
|
}))
|
|
.filter((i) => i.type !== "*");
|
|
}
|
|
updateDownstream(update, updatedSlotData) {
|
|
var _a;
|
|
const nodes = getConnectedOutputNodesAndFilterPassThroughs(this, this, 0);
|
|
for (const node of nodes) {
|
|
(_a = node === null || node === void 0 ? void 0 : node.updateFromUpstream) === null || _a === void 0 ? void 0 : _a.call(node, update, this, updatedSlotData);
|
|
}
|
|
}
|
|
addContextInput(name, type, slot = -1) {
|
|
const inputs = this.getContextInputsList();
|
|
if (this.hasShadowInputs) {
|
|
inputs.push({ name, type });
|
|
}
|
|
else {
|
|
this.addInput(name, type);
|
|
}
|
|
if (slot > -1) {
|
|
inputs.splice(slot, 0, inputs.splice(inputs.length - 1, 1)[0]);
|
|
}
|
|
else {
|
|
slot = inputs.length - 1;
|
|
}
|
|
if (type !== "*") {
|
|
const output = this.addOutput(name.toUpperCase(), type);
|
|
if (type === "COMBO" || String(type).includes(",") || Array.isArray(type)) {
|
|
output.widget = true;
|
|
}
|
|
if (slot > -1) {
|
|
this.outputs.splice(slot, 0, this.outputs.splice(this.outputs.length - 1, 1)[0]);
|
|
}
|
|
this.fixInputsOutputsLinkSlots();
|
|
this.updateDownstream("connect", { index: slot, name });
|
|
}
|
|
}
|
|
removeContextInput(slot) {
|
|
if (this.hasShadowInputs) {
|
|
const inputs = this.getContextInputsList();
|
|
const input = inputs.splice(slot, 1)[0];
|
|
if (this.outputs[slot]) {
|
|
this.removeOutput(slot);
|
|
}
|
|
this.updateDownstream("disconnect", { index: slot, name: input.name });
|
|
this.fixInputsOutputsLinkSlots();
|
|
}
|
|
else {
|
|
this.removeInput(slot);
|
|
}
|
|
}
|
|
moveContextInput(slotFrom, slotTo) {
|
|
const inputs = this.getContextInputsList();
|
|
if (slotTo === 'bottom') {
|
|
slotTo = inputs.length - 1;
|
|
}
|
|
if (slotFrom === slotTo) {
|
|
return;
|
|
}
|
|
let newIndex = slotTo + (slotFrom < slotTo ? -1 : 0);
|
|
const input = inputs.splice(slotFrom, 1)[0];
|
|
inputs.splice(newIndex, 0, input);
|
|
this.outputs.splice(newIndex, 0, ...this.outputs.splice(slotFrom, 1));
|
|
this.fixInputsOutputsLinkSlots();
|
|
this.updateDownstream("move", { index: slotTo, from: slotFrom, name: input.name });
|
|
}
|
|
renameContextInput(index, newName, forceOwnBool = null) {
|
|
const inputs = this.getContextInputsList();
|
|
const input = inputs[index];
|
|
const oldName = input.name;
|
|
newName = this.stripOwnedPrefix(newName.trim() || this.getSlotDefaultInputLabel(index));
|
|
if (forceOwnBool === true || (this.isOwnedInput(oldName) && forceOwnBool !== false)) {
|
|
newName = this.addOwnedPrefix(newName);
|
|
}
|
|
input.name = newName;
|
|
this.outputs[index].name = this.stripOwnedPrefix(inputs[index].name).toUpperCase();
|
|
this.updateDownstream("update", { index, name: newName });
|
|
}
|
|
fixInputsOutputsLinkSlots() {
|
|
if (!this.hasShadowInputs) {
|
|
const inputs = this.inputs;
|
|
for (let index = inputs.length - 1; index > 0; index--) {
|
|
const input = inputs[index];
|
|
if ((input === null || input === void 0 ? void 0 : input.link) != null) {
|
|
app.graph.links[input.link].target_slot = index;
|
|
}
|
|
}
|
|
}
|
|
const outputs = this.outputs;
|
|
for (let index = outputs.length - 1; index > 0; index--) {
|
|
const output = outputs[index];
|
|
for (const link of (output === null || output === void 0 ? void 0 : output.links) || []) {
|
|
app.graph.links[link].origin_slot = index;
|
|
}
|
|
}
|
|
}
|
|
getSlotDefaultInputLabel(slot) {
|
|
const inputs = this.getContextInputsList();
|
|
const input = inputs[slot];
|
|
let defaultLabel = this.stripOwnedPrefix(input.name).toLowerCase();
|
|
return defaultLabel.toLocaleLowerCase();
|
|
}
|
|
}
|
|
ContextDynamicNodeBase.logger = rgthree.newLogSession("[Dynamic Context]");
|
|
class ContextDynamicNode extends ContextDynamicNodeBase {
|
|
static setUp(comfyClass) {
|
|
BaseContextNode.setUp(comfyClass, ContextDynamicNode);
|
|
}
|
|
constructor(title = ContextDynamicNode.title) {
|
|
super(title);
|
|
}
|
|
clone() {
|
|
const cloned = super.clone();
|
|
while (cloned.inputs.length > 1) {
|
|
cloned.removeInput(cloned.inputs.length - 1);
|
|
}
|
|
cloned.addInput("+", "*");
|
|
return cloned;
|
|
}
|
|
removeInput(slot) {
|
|
const input = this.inputs[slot];
|
|
super.removeInput(slot);
|
|
if (this.outputs[slot]) {
|
|
this.removeOutput(slot);
|
|
}
|
|
this.fixInputsOutputsLinkSlots();
|
|
this.updateDownstream("disconnect", { index: slot, name: input.name });
|
|
this.stabilizeNames();
|
|
}
|
|
handleInputConnected(slotIndex) {
|
|
const inputs = this.getContextInputsList();
|
|
const ioSlot = inputs[slotIndex];
|
|
if (slotIndex === 0) {
|
|
const baseNodes = getConnectedInputNodesAndFilterPassThroughs(this, this, 0);
|
|
const baseNodesDynamicCtx = baseNodes[0];
|
|
if (baseNodesDynamicCtx === null || baseNodesDynamicCtx === void 0 ? void 0 : baseNodesDynamicCtx.provideInputsData) {
|
|
for (const input of baseNodesDynamicCtx.provideInputsData()) {
|
|
const inputs = this.getContextInputsList();
|
|
if (input.name === "base_ctx" || input.name === "+") {
|
|
continue;
|
|
}
|
|
const foundIndex = inputs.findIndex(i => this.stripOwnedPrefix(i.name) === input.name);
|
|
if (foundIndex > -1) {
|
|
this.moveContextInput(foundIndex, input.index);
|
|
this.renameContextInput(input.index, input.name, false);
|
|
}
|
|
else {
|
|
this.addContextInput(input.name, input.type, input.index);
|
|
this.stabilizeNames();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (ioSlot.type === "*") {
|
|
let cxn = null;
|
|
if (ioSlot.link) {
|
|
cxn = followConnectionUntilType(this, IoDirection.INPUT, slotIndex, true);
|
|
}
|
|
if (cxn === null || cxn === void 0 ? void 0 : cxn.type) {
|
|
let name = cxn.name;
|
|
if (name.match(/^(\+\s*)?[A-Z_]+$/)) {
|
|
name = name.toLowerCase();
|
|
}
|
|
name = this.getNextUniqueNameForThisNode(name);
|
|
if (!this.outputs[slotIndex]) {
|
|
this.addOutput("*", "*");
|
|
}
|
|
inputs[slotIndex].type = cxn.type;
|
|
inputs[slotIndex].removable = true;
|
|
this.outputs[slotIndex].type = cxn.type;
|
|
this.updateDownstream("connect", { index: slotIndex, name: this.stripOwnedPrefix(name) });
|
|
this.renameContextInput(slotIndex, name, true);
|
|
if (cxn.type === "COMBO" || cxn.type.includes(",") || Array.isArray(cxn.type)) {
|
|
this.outputs[slotIndex].widget = true;
|
|
}
|
|
this.addInput("+", "*");
|
|
}
|
|
}
|
|
}
|
|
handleInputDisconnected(slotIndex) {
|
|
var _a, _b;
|
|
const inputs = this.getContextInputsList();
|
|
if (slotIndex === 0) {
|
|
for (let index = inputs.length - 1; index > 0; index--) {
|
|
if (index === 0 || index === inputs.length - 1) {
|
|
continue;
|
|
}
|
|
const input = inputs[index];
|
|
if (!this.isOwnedInput(input.name)) {
|
|
if (input.link || ((_b = (_a = this.outputs[index]) === null || _a === void 0 ? void 0 : _a.links) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
this.renameContextInput(index, input.name, true);
|
|
}
|
|
else {
|
|
this.removeContextInput(index);
|
|
}
|
|
}
|
|
}
|
|
this.setSize(this.computeSize());
|
|
this.setDirtyCanvas(true, true);
|
|
}
|
|
}
|
|
updateFromUpstream(update, node, updatedSlotData) {
|
|
var _a, _b;
|
|
console.log("----- ContextDynamicNode :: updateFromUpstream", arguments);
|
|
const inputs = this.getContextInputsList();
|
|
if (update == "connect") {
|
|
const baseInputsData = node.provideInputsData();
|
|
const baseIndex = updatedSlotData.index;
|
|
const baseInputData = baseInputsData[baseIndex];
|
|
const name = this.getNextUniqueNameForThisNode(baseInputData.name);
|
|
const foundIndex = inputs.findIndex(i => this.stripOwnedPrefix(i.name) === baseInputData.name);
|
|
if (foundIndex > -1) {
|
|
this.moveContextInput(foundIndex, baseIndex);
|
|
this.renameContextInput(baseIndex, baseInputData.name, false);
|
|
}
|
|
else {
|
|
this.addContextInput(baseInputData.name, baseInputData.type, baseInputData.index);
|
|
this.stabilizeNames();
|
|
}
|
|
}
|
|
else if (update == "disconnect") {
|
|
if ((_b = (_a = this.outputs[updatedSlotData.index]) === null || _a === void 0 ? void 0 : _a.links) === null || _b === void 0 ? void 0 : _b.length) {
|
|
this.renameContextInput(updatedSlotData.index, updatedSlotData.name, true);
|
|
this.moveContextInput(updatedSlotData.index, 'bottom');
|
|
}
|
|
else {
|
|
this.removeContextInput(updatedSlotData.index);
|
|
}
|
|
}
|
|
else if (update === "move") {
|
|
this.moveContextInput(updatedSlotData.from, updatedSlotData.index);
|
|
}
|
|
else if (update == "update") {
|
|
const baseInputsData = node.provideInputsData();
|
|
const baseIndex = updatedSlotData.index;
|
|
const baseInput = baseInputsData[baseIndex];
|
|
this.renameContextInput(baseIndex, baseInput.name);
|
|
this.stabilizeNames();
|
|
}
|
|
this.setSize(this.computeSize());
|
|
this.setDirtyCanvas(true, true);
|
|
}
|
|
stabilizeNames() {
|
|
const inputs = this.getContextInputsList();
|
|
const names = [];
|
|
for (const [index, input] of inputs.entries()) {
|
|
if (index === 0 || index === inputs.length - 1) {
|
|
continue;
|
|
}
|
|
input.label = undefined;
|
|
this.outputs[index].label = undefined;
|
|
let origName = this.stripOwnedPrefix(input.name).replace(/\.\d+$/, "");
|
|
let name = input.name;
|
|
if (!this.isOwnedInput(name)) {
|
|
names.push(name.toLocaleUpperCase());
|
|
}
|
|
else {
|
|
let n = 0;
|
|
name = this.addOwnedPrefix(origName);
|
|
while (names.includes(this.stripOwnedPrefix(name).toLocaleUpperCase())) {
|
|
name = `${this.addOwnedPrefix(origName)}.${++n}`;
|
|
}
|
|
names.push(this.stripOwnedPrefix(name).toLocaleUpperCase());
|
|
if (input.name !== name) {
|
|
this.renameContextInput(index, name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
onConnectInput(inputIdx, outputType, outputSlot, outputNode, outputIndex) {
|
|
let canConnect = true;
|
|
if (super.onConnectInput) {
|
|
canConnect = super.onConnectInput(inputIdx, outputType, outputSlot, outputNode, outputIndex);
|
|
}
|
|
if (canConnect && outputNode instanceof ContextDynamicNode && outputIndex === 0 && inputIdx !== 0) {
|
|
ContextDynamicNodeBase.logger.error("Currently, you can only connect a context node in the first slot.");
|
|
canConnect = false;
|
|
}
|
|
return canConnect;
|
|
}
|
|
getSlotMenuOptions(info) {
|
|
const opts = [];
|
|
if (info.input) {
|
|
if (this.isOwnedInput(info.input.name) && info.input.type !== '*') {
|
|
opts.push({
|
|
content: "✏️ Rename Input",
|
|
callback: () => {
|
|
var dialog = app.canvas.createDialog("<span class='name'>Name</span><input autofocus type='text'/><button>OK</button>", {});
|
|
var dialogInput = dialog.querySelector("input");
|
|
if (dialogInput) {
|
|
dialogInput.value = this.stripOwnedPrefix(info.input.name || "");
|
|
}
|
|
var inner = () => {
|
|
app.graph.beforeChange();
|
|
this.renameContextInput(info.slot, dialogInput.value);
|
|
this.stabilizeNames();
|
|
this.setDirtyCanvas(true, true);
|
|
dialog.close();
|
|
app.graph.afterChange();
|
|
};
|
|
dialog.querySelector("button").addEventListener("click", inner);
|
|
dialogInput.addEventListener("keydown", (e) => {
|
|
var _a;
|
|
dialog.is_modified = true;
|
|
if (e.keyCode == 27) {
|
|
dialog.close();
|
|
}
|
|
else if (e.keyCode == 13) {
|
|
inner();
|
|
}
|
|
else if (e.keyCode != 13 && ((_a = e.target) === null || _a === void 0 ? void 0 : _a.localName) != "textarea") {
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
});
|
|
dialogInput.focus();
|
|
},
|
|
});
|
|
opts.push({
|
|
content: "🗑️ Delete Input",
|
|
callback: () => {
|
|
this.removeInput(info.slot);
|
|
},
|
|
});
|
|
}
|
|
}
|
|
return opts;
|
|
}
|
|
}
|
|
ContextDynamicNode.title = "Dynamic Context (rgthree)";
|
|
ContextDynamicNode.type = "Dynamic Context (rgthree)";
|
|
ContextDynamicNode.comfyClass = "Dynamic Context (rgthree)";
|
|
class ContextDynamicSwitchNode extends ContextDynamicNodeBase {
|
|
constructor(title = ContextDynamicSwitchNode.title) {
|
|
super(title);
|
|
this.hasShadowInputs = true;
|
|
this.lastInputsList = [];
|
|
this.shadowInputs = [
|
|
{ name: "base_ctx", type: "DYNAMIC_CONTEXT" },
|
|
{ name: "+", type: "*" },
|
|
];
|
|
let alerted = false;
|
|
setInterval(() => {
|
|
const plusIndex = this.shadowInputs.findIndex((i) => i.name === "+");
|
|
if (plusIndex === -1) {
|
|
!alerted && console.error("ERROR, no plus in shadow inputs", [...this.shadowInputs]);
|
|
alerted = true;
|
|
}
|
|
else if (plusIndex !== this.shadowInputs.length - 1) {
|
|
!alerted &&
|
|
console.error("ERROR, plus is not last in shadow inputs", [...this.shadowInputs]);
|
|
alerted = true;
|
|
}
|
|
else {
|
|
alerted && console.error("BACK TO NOREMAL", [...this.shadowInputs]);
|
|
alerted = false;
|
|
}
|
|
});
|
|
}
|
|
static setUp(comfyClass) {
|
|
BaseContextNode.setUp(comfyClass, ContextDynamicSwitchNode);
|
|
}
|
|
clone() {
|
|
const cloned = super.clone();
|
|
while (cloned.outputs.length > 1) {
|
|
cloned.removeOutput(cloned.outputs.length - 1);
|
|
}
|
|
return cloned;
|
|
}
|
|
getContextInputsList() {
|
|
return this.shadowInputs;
|
|
}
|
|
onNodeCreated() {
|
|
}
|
|
onConnectInput(inputIndex, outputType, outputSlot, outputNode, outputIndex) {
|
|
let canConnect = true;
|
|
if (super.onConnectInput) {
|
|
canConnect = super.onConnectInput(inputIndex, outputType, outputSlot, outputNode, outputIndex);
|
|
}
|
|
const allConnectedNodes = getConnectedInputNodes(this);
|
|
if (canConnect && allConnectedNodes.includes(outputNode)) {
|
|
rgthree.showMessage({
|
|
id: "dynamic-context-looped",
|
|
type: "warn",
|
|
message: "You may not connect the same context node to a switch.",
|
|
timeout: 5000,
|
|
});
|
|
canConnect = false;
|
|
}
|
|
if (canConnect && shouldPassThrough(outputNode, PassThroughFollowing.REROUTE_ONLY)) {
|
|
const connectedNodes = getConnectedInputNodesAndFilterPassThroughs(outputNode, undefined, undefined, PassThroughFollowing.REROUTE_ONLY);
|
|
if (connectedNodes.length && allConnectedNodes.find((n) => connectedNodes.includes(n))) {
|
|
rgthree.showMessage({
|
|
id: "dynamic-context-looped",
|
|
type: "warn",
|
|
message: "You may not connect the same context node to a switch, even through a reroute.",
|
|
timeout: 5000,
|
|
});
|
|
canConnect = false;
|
|
}
|
|
}
|
|
return canConnect;
|
|
}
|
|
configure(info) {
|
|
super.configure(info);
|
|
setTimeout(() => {
|
|
this.shadowInputs = this.getAllShadowInputs();
|
|
this.shadowInputs.push({ name: "+", type: "*" });
|
|
this.updateLastInputsList();
|
|
console.log(this.shadowInputs);
|
|
}, 100);
|
|
}
|
|
moveContextInput(slotFrom, slotTo) {
|
|
super.moveContextInput(slotFrom, slotTo);
|
|
this.updateLastInputsList();
|
|
}
|
|
removeContextInput(slot) {
|
|
super.removeContextInput(slot);
|
|
this.updateLastInputsList();
|
|
}
|
|
addContextInput(name, type, slot = -1) {
|
|
super.addContextInput(name, type, slot);
|
|
this.updateLastInputsList();
|
|
}
|
|
updateLastInputsList() {
|
|
this.lastInputsList = this.getAllInputsList();
|
|
}
|
|
connectSlotFromUpdateOrInput(data) {
|
|
console.log(`connectSlotFromUpdateOrInput: ${data.name}`, data);
|
|
if (data.duplicatesBefore.length) {
|
|
console.log(`[Do Nothing] It has duplicatesBefore (${data.duplicatesBefore.join(",")}).`);
|
|
this.updateLastInputsList();
|
|
}
|
|
else if (data.duplicatesAfter.length) {
|
|
const from = this.shadowInputs.findIndex((i) => i.name.toLocaleUpperCase() === data.key);
|
|
console.log(`[Move] Has duplicates after. ${from} -> ${data.shadowIndex}`);
|
|
this.moveContextInput(from, data.shadowIndex);
|
|
}
|
|
else {
|
|
console.log(`[Add] No dupes, so we can add it at ${data.shadowIndex}.`);
|
|
this.addContextInput(data.name, data.type, data.shadowIndex);
|
|
}
|
|
}
|
|
handleInputConnected(slotIndex) {
|
|
var _a;
|
|
console.log("--- handleInputConnected", slotIndex);
|
|
const postInputsList = [...this.getAllInputsList()];
|
|
const node = (_a = postInputsList.find((i) => i.slot === slotIndex)) === null || _a === void 0 ? void 0 : _a.node;
|
|
if (!node) {
|
|
console.error("hmmm... no node foun to handle connect.");
|
|
return;
|
|
}
|
|
const inputsDataLists = postInputsList.filter((d) => d.slot == slotIndex && d.nodeIndex > 0 && d.type !== '*');
|
|
for (const data of inputsDataLists) {
|
|
this.connectSlotFromUpdateOrInput(data);
|
|
}
|
|
}
|
|
handleInputDisconnected(slotIndex) {
|
|
var _a;
|
|
console.log("--- handleInputDisconnected", slotIndex);
|
|
const preInputsList = [...this.lastInputsList];
|
|
const node = (_a = preInputsList.find((i) => i.slot === slotIndex)) === null || _a === void 0 ? void 0 : _a.node;
|
|
if (!node) {
|
|
console.error("hmmmm... no node found to handle disconnect.");
|
|
return;
|
|
}
|
|
const postInputsList = [...this.getAllInputsList()];
|
|
const inputs = [...this.shadowInputs];
|
|
console.log("postInputsList", postInputsList);
|
|
let lastIndex = 0;
|
|
for (let [index, data] of postInputsList.entries()) {
|
|
data = this.getAllInputsList()[index];
|
|
if (data.shadowIndex === -1 || data.nodeIndex === 0) {
|
|
continue;
|
|
}
|
|
lastIndex++;
|
|
const foundIndex = this.shadowInputs.findIndex((i) => i.name.toLocaleUpperCase() === data.key);
|
|
console.log(data.name, foundIndex, data.shadowIndex);
|
|
if (foundIndex !== data.shadowIndex) {
|
|
this.moveContextInput(foundIndex, data.shadowIndex);
|
|
}
|
|
}
|
|
for (let index = inputs.length - 1; index > lastIndex; index--) {
|
|
const input = this.shadowInputs[index];
|
|
if (input.type !== '*') {
|
|
this.removeContextInput(index);
|
|
}
|
|
}
|
|
console.log([...this.shadowInputs]);
|
|
}
|
|
updateFromUpstream(update, node, updatedSlotData) {
|
|
var _a;
|
|
console.log("----- ContextDynamicSwitchNode :: updateFromUpstream", update, updatedSlotData);
|
|
const preInputsList = [...this.lastInputsList];
|
|
const postInputsList = [...this.getAllInputsList()];
|
|
if (shouldPassThrough(node)) {
|
|
const connectedNodes = getConnectedNodesInfo(this, IoDirection.INPUT);
|
|
const foundRerouteInfo = connectedNodes.find((n) => n.node === node);
|
|
if (update == "connect") {
|
|
this.handleInputConnected(foundRerouteInfo.originTravelFromSlot);
|
|
}
|
|
else if (update == "disconnect") {
|
|
this.handleInputDisconnected(foundRerouteInfo.originTravelFromSlot);
|
|
}
|
|
else {
|
|
throw new Error("Unexpected update type from pass through node: " + update);
|
|
}
|
|
return;
|
|
}
|
|
switch (update) {
|
|
case "connect": {
|
|
const data = postInputsList.find((d) => {
|
|
return d.node == node && d.nodeIndex === updatedSlotData.index;
|
|
});
|
|
if (!data) {
|
|
throw new Error("Hmmm.. unfound input slot when connecting upstream.");
|
|
}
|
|
this.connectSlotFromUpdateOrInput(data);
|
|
break;
|
|
}
|
|
case "disconnect":
|
|
const preInputData = preInputsList.find((i) => {
|
|
return i.node === node && i.nodeIndex == updatedSlotData.index;
|
|
});
|
|
if (!preInputData) {
|
|
throw new Error("Hmmm... no matching input found in existing input list for disconnect.");
|
|
}
|
|
if (preInputData.duplicatesBefore.length) {
|
|
console.log(`[Do Nothing] It was already duplicated before.`);
|
|
this.updateLastInputsList();
|
|
}
|
|
else if (((_a = preInputData === null || preInputData === void 0 ? void 0 : preInputData.duplicatesAfter) === null || _a === void 0 ? void 0 : _a[0]) != null) {
|
|
console.log(`[Move after] Not duplicated before, but is after.`);
|
|
this.moveContextInput(preInputData.shadowIndex, preInputData.duplicatesAfter[0]);
|
|
}
|
|
else {
|
|
console.log(`[Remove] ${preInputData.shadowIndex}.`, preInputData);
|
|
this.removeContextInput(preInputData.shadowIndex);
|
|
}
|
|
break;
|
|
case "move":
|
|
break;
|
|
case "update":
|
|
const index = postInputsList.findIndex((d) => {
|
|
return d.node == node && d.nodeIndex === updatedSlotData.index;
|
|
});
|
|
const pre = preInputsList[index];
|
|
const post = postInputsList[index];
|
|
console.log("preData", { ...pre });
|
|
console.log("postData", { ...post });
|
|
if (pre.shadowIndex == -1 && post.shadowIndex !== -1) {
|
|
console.log(`[Add] Old name wasn't shown, but new is.`, post.name, post.shadowIndex);
|
|
this.addContextInput(post.name, post.type, post.shadowIndex);
|
|
}
|
|
else if (pre.shadowIndex !== -1 && post.shadowIndex === -1) {
|
|
console.log(`[Remove] Old name was shown, but new isn;t.`, post.name, post.shadowIndex);
|
|
this.removeContextInput(pre.shadowIndex);
|
|
}
|
|
else if (post.shadowIndex > -1) {
|
|
console.log(`[Rename] It's shown and has a new name.`, post.name, post.shadowIndex);
|
|
this.renameContextInput(post.shadowIndex, post.name);
|
|
}
|
|
else {
|
|
console.log(`[Do Nothing] It's shown and has a new name.`, post.name, post.shadowIndex);
|
|
this.updateLastInputsList();
|
|
}
|
|
break;
|
|
}
|
|
console.log(this.shadowInputs);
|
|
}
|
|
getAllInputsList(indexToNodeOverride = {}) {
|
|
var _a, _b, _c;
|
|
const allConnectedInputsDataByName = {};
|
|
const allConnectedInputsData = [];
|
|
let currentShadowIndex = 0;
|
|
for (const [slot, input] of (this.inputs || []).entries()) {
|
|
const connectedNode = (_a = indexToNodeOverride[slot]) !== null && _a !== void 0 ? _a : (_b = getConnectedInputNodesAndFilterPassThroughs(this, this, slot)) === null || _b === void 0 ? void 0 : _b[0];
|
|
if (connectedNode) {
|
|
for (const inputData of connectedNode.provideInputsData()) {
|
|
const key = inputData.name.toLocaleUpperCase();
|
|
allConnectedInputsDataByName[key] = allConnectedInputsDataByName[key] || [];
|
|
const existings = allConnectedInputsDataByName[key];
|
|
let data = {
|
|
node: connectedNode,
|
|
slot,
|
|
shadowIndexFull: allConnectedInputsData.length,
|
|
shadowIndex: !existings.length ? currentShadowIndex : -1,
|
|
shadowIndexIfShownSingularly: currentShadowIndex,
|
|
nodeIndex: inputData.index,
|
|
type: inputData.type,
|
|
name: inputData.name,
|
|
key,
|
|
duplicatesBefore: allConnectedInputsDataByName[key].map((d) => d.shadowIndexFull),
|
|
duplicatesAfter: [],
|
|
};
|
|
if (data.shadowIndex > -1) {
|
|
currentShadowIndex++;
|
|
}
|
|
for (const existing of existings) {
|
|
existing.duplicatesAfter.push(data.shadowIndexFull);
|
|
}
|
|
allConnectedInputsData.push(data);
|
|
(_c = allConnectedInputsDataByName[key]) === null || _c === void 0 ? void 0 : _c.push(data);
|
|
}
|
|
}
|
|
}
|
|
return allConnectedInputsData;
|
|
}
|
|
getAllShadowInputs() {
|
|
const inputsDataMap = {
|
|
BASE_CTX: { name: "base_ctx", type: "DYNAMIC_CONTEXT", index: 0 },
|
|
};
|
|
const baseNodes = getConnectedInputNodesAndFilterPassThroughs(this, this);
|
|
for (const inputNode of baseNodes) {
|
|
for (const inputData of inputNode.provideInputsData()) {
|
|
const dataKey = inputData.name.toLocaleUpperCase();
|
|
const existingData = inputsDataMap[dataKey];
|
|
if (!existingData) {
|
|
inputsDataMap[dataKey] = inputData;
|
|
}
|
|
else if (existingData.name !== inputData.name) {
|
|
throw new Error(`Conflicting data for ${dataKey}. ${existingData.name} !== ${inputData.name}`);
|
|
}
|
|
else if (existingData.type !== inputData.type) {
|
|
throw new Error(`Conflicting data for ${dataKey}. ${existingData.type} !== ${inputData.type}`);
|
|
}
|
|
}
|
|
}
|
|
return Object.values(inputsDataMap).map((v, index) => Object.assign({ ...v }, { index }));
|
|
}
|
|
}
|
|
ContextDynamicSwitchNode.title = "Dynamic Context Switch (rgthree)";
|
|
ContextDynamicSwitchNode.type = "Dynamic Context Switch (rgthree)";
|
|
ContextDynamicSwitchNode.comfyClass = "Dynamic Context Switch (rgthree)";
|
|
const contextDynamicNodes = [ContextDynamicNode, ContextDynamicSwitchNode];
|
|
app.registerExtension({
|
|
name: "rgthree.ContextDynamic",
|
|
async beforeRegisterNodeDef(nodeType, nodeData) {
|
|
for (const ctxClass of contextDynamicNodes) {
|
|
if (nodeData.name === ctxClass.type) {
|
|
console.log(nodeData.name);
|
|
ctxClass.nodeData = nodeData;
|
|
ctxClass.nodeType = nodeType;
|
|
ctxClass.setUp(nodeType);
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
});
|