|
import { BaseContextNode } from "./context.js"; |
|
import { RgthreeBaseServerNode } from "./base_node.js"; |
|
import { moveArrayItem, wait } from "../../rgthree/common/shared_utils.js"; |
|
import { RgthreeInvisibleWidget } from "./utils_widgets.js"; |
|
import { getContextOutputName, InputMutationOperation, } from "./services/context_service.js"; |
|
import { app } from "../../scripts/app.js"; |
|
import { SERVICE as CONTEXT_SERVICE } from "./services/context_service.js"; |
|
const OWNED_PREFIX = "+"; |
|
const REGEX_OWNED_PREFIX = /^\+\s*/; |
|
const REGEX_EMPTY_INPUT = /^\+\s*$/; |
|
export class DynamicContextNodeBase extends BaseContextNode { |
|
constructor() { |
|
super(...arguments); |
|
this.hasShadowInputs = false; |
|
} |
|
getContextInputsList() { |
|
return this.inputs; |
|
} |
|
provideInputsData() { |
|
const inputs = this.getContextInputsList(); |
|
return inputs |
|
.map((input, index) => ({ |
|
name: this.stripOwnedPrefix(input.name), |
|
type: String(input.type), |
|
index, |
|
})) |
|
.filter((i) => i.type !== "*"); |
|
} |
|
addOwnedPrefix(name) { |
|
return `+ ${this.stripOwnedPrefix(name)}`; |
|
} |
|
isOwnedInput(inputOrName) { |
|
const name = typeof inputOrName == "string" ? inputOrName : (inputOrName === null || inputOrName === void 0 ? void 0 : inputOrName.name) || ""; |
|
return REGEX_OWNED_PREFIX.test(name); |
|
} |
|
stripOwnedPrefix(name) { |
|
return name.replace(REGEX_OWNED_PREFIX, ""); |
|
} |
|
handleUpstreamMutation(mutation) { |
|
console.log(`[node ${this.id}] handleUpstreamMutation`, mutation); |
|
if (mutation.operation === InputMutationOperation.ADDED) { |
|
const slot = mutation.slot; |
|
if (!slot) { |
|
throw new Error("Cannot have an ADDED mutation without a provided slot data."); |
|
} |
|
this.addContextInput(this.stripOwnedPrefix(slot.name), slot.type, mutation.slotIndex); |
|
return; |
|
} |
|
if (mutation.operation === InputMutationOperation.REMOVED) { |
|
const slot = mutation.slot; |
|
if (!slot) { |
|
throw new Error("Cannot have an REMOVED mutation without a provided slot data."); |
|
} |
|
this.removeContextInput(mutation.slotIndex); |
|
return; |
|
} |
|
if (mutation.operation === InputMutationOperation.RENAMED) { |
|
const slot = mutation.slot; |
|
if (!slot) { |
|
throw new Error("Cannot have an RENAMED mutation without a provided slot data."); |
|
} |
|
this.renameContextInput(mutation.slotIndex, slot.name); |
|
return; |
|
} |
|
} |
|
clone() { |
|
const cloned = super.clone(); |
|
while (cloned.inputs.length > 1) { |
|
cloned.removeInput(cloned.inputs.length - 1); |
|
} |
|
while (cloned.widgets.length > 1) { |
|
cloned.removeWidget(cloned.widgets.length - 1); |
|
} |
|
while (cloned.outputs.length > 1) { |
|
cloned.removeOutput(cloned.outputs.length - 1); |
|
} |
|
return cloned; |
|
} |
|
onNodeCreated() { |
|
const node = this; |
|
this.addCustomWidget(new RgthreeInvisibleWidget("output_keys", "RGTHREE_DYNAMIC_CONTEXT_OUTPUTS", "", () => { |
|
return (node.outputs || []) |
|
.map((o, i) => i > 0 && o.name) |
|
.filter((n) => n !== false) |
|
.join(","); |
|
})); |
|
} |
|
addContextInput(name, type, slot = -1) { |
|
const inputs = this.getContextInputsList(); |
|
if (this.hasShadowInputs) { |
|
inputs.push({ name, type, link: null }); |
|
} |
|
else { |
|
this.addInput(name, type); |
|
} |
|
if (slot > -1) { |
|
moveArrayItem(inputs, inputs.length - 1, slot); |
|
} |
|
else { |
|
slot = inputs.length - 1; |
|
} |
|
if (type !== "*") { |
|
const output = this.addOutput(getContextOutputName(name), type); |
|
if (type === "COMBO" || String(type).includes(",") || Array.isArray(type)) { |
|
output.widget = true; |
|
} |
|
if (slot > -1) { |
|
moveArrayItem(this.outputs, this.outputs.length - 1, slot); |
|
} |
|
} |
|
this.fixInputsOutputsLinkSlots(); |
|
this.inputsMutated({ |
|
operation: InputMutationOperation.ADDED, |
|
node: this, |
|
slotIndex: slot, |
|
slot: inputs[slot], |
|
}); |
|
} |
|
removeContextInput(slotIndex) { |
|
if (this.hasShadowInputs) { |
|
const inputs = this.getContextInputsList(); |
|
const input = inputs.splice(slotIndex, 1)[0]; |
|
if (this.outputs[slotIndex]) { |
|
this.removeOutput(slotIndex); |
|
} |
|
} |
|
else { |
|
this.removeInput(slotIndex); |
|
} |
|
} |
|
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); |
|
} |
|
if (oldName !== newName) { |
|
input.name = newName; |
|
input.removable = this.isOwnedInput(newName); |
|
this.outputs[index].name = getContextOutputName(inputs[index].name); |
|
this.inputsMutated({ |
|
node: this, |
|
operation: InputMutationOperation.RENAMED, |
|
slotIndex: index, |
|
slot: input, |
|
}); |
|
} |
|
} |
|
getSlotDefaultInputLabel(slotIndex) { |
|
const inputs = this.getContextInputsList(); |
|
const input = inputs[slotIndex]; |
|
let defaultLabel = this.stripOwnedPrefix(input.name).toLowerCase(); |
|
return defaultLabel.toLocaleLowerCase(); |
|
} |
|
inputsMutated(mutation) { |
|
CONTEXT_SERVICE.onInputChanges(this, mutation); |
|
} |
|
fixInputsOutputsLinkSlots() { |
|
if (!this.hasShadowInputs) { |
|
const inputs = this.getContextInputsList(); |
|
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]; |
|
if (output) { |
|
output.nameLocked = true; |
|
for (const link of output.links || []) { |
|
app.graph.links[link].origin_slot = index; |
|
} |
|
} |
|
} |
|
} |
|
static setUp(comfyClass, nodeData) { |
|
RgthreeBaseServerNode.registerForOverride(comfyClass, nodeData, this); |
|
wait(500).then(() => { |
|
LiteGraph.slot_types_default_out["RGTHREE_DYNAMIC_CONTEXT"] = |
|
LiteGraph.slot_types_default_out["RGTHREE_DYNAMIC_CONTEXT"] || []; |
|
LiteGraph.slot_types_default_out["RGTHREE_DYNAMIC_CONTEXT"].push(comfyClass.comfyClass); |
|
}); |
|
} |
|
} |
|
|