- Replace hide/show visibility approach with dynamic addOutput/removeOutput and addInput/removeInput for proper pin management - On node creation, remove all default pins and add only selected ones - On workflow load (onConfigure), clear all dynamic pins and rebuild from saved properties - Remove OUTPUT_NODE from FlakeDataSplitSelect (not an output node) - Add pin selector UI with +/- buttons that dynamically adds/removes pins - Export DEFAULT_SPLIT_PINS and DEFAULT_INTO_PINS for use in onConfigure Closes #139
210 lines
9.0 KiB
JavaScript
210 lines
9.0 KiB
JavaScript
import { app } from "../../scripts/app.js";
|
|
import { setupFlakeWidget } from "./widgets/flake-stack.js";
|
|
import { setupFlakeComboWidget } from "./widgets/flake-combo.js";
|
|
import { setupFlakeModelPresetWidget } from "./widgets/flake-model-preset.js";
|
|
import { setupFlakeModelComboWidget } from "./widgets/flake-model-combo.js";
|
|
import { setupFlakeDataSplitSelect, setupIntoFlakeDataSelect, DEFAULT_SPLIT_PINS, DEFAULT_INTO_PINS } from "./widgets/flake-data-select.js";
|
|
import { setupPreviewFlakeDataWidget } from "./widgets/flake-preview.js";
|
|
import "./queue.js";
|
|
|
|
function removeHiddenInputs(node, names) {
|
|
for (let i = node.inputs.length - 1; i >= 0; i--) {
|
|
if (names.includes(node.inputs[i].name)) {
|
|
node.inputs.splice(i, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
function setDefaultSize(node, minWidth) {
|
|
const size = node.computeSize();
|
|
if (size[0] < minWidth) {
|
|
node.setSize([minWidth, size[1]]);
|
|
} else {
|
|
node.setSize(size);
|
|
}
|
|
}
|
|
|
|
app.registerExtension({
|
|
name: "comfyui-flakes.FlakeStack",
|
|
async beforeRegisterNodeDef(nodeType, nodeData) {
|
|
if (nodeData.name === "FlakeStack") {
|
|
const origOnNodeCreated = nodeType.prototype.onNodeCreated;
|
|
nodeType.prototype.onNodeCreated = function () {
|
|
const r = origOnNodeCreated?.apply(this, arguments);
|
|
setupFlakeWidget(this);
|
|
removeHiddenInputs(this, ["model_family", "flakes_json"]);
|
|
if (!this._configured) {
|
|
setDefaultSize(this, 340);
|
|
}
|
|
return r;
|
|
};
|
|
|
|
const origOnConfigure = nodeType.prototype.onConfigure;
|
|
nodeType.prototype.onConfigure = function () {
|
|
const r = origOnConfigure?.apply(this, arguments);
|
|
this._configured = true;
|
|
removeHiddenInputs(this, ["model_family", "flakes_json"]);
|
|
this._flakes_render?.();
|
|
return r;
|
|
};
|
|
}
|
|
if (nodeData.name === "FlakeModelPreset") {
|
|
const origOnNodeCreated = nodeType.prototype.onNodeCreated;
|
|
nodeType.prototype.onNodeCreated = function () {
|
|
const r = origOnNodeCreated?.apply(this, arguments);
|
|
setupFlakeModelPresetWidget(this);
|
|
removeHiddenInputs(this, ["model_family", "preset"]);
|
|
if (!this._configured) {
|
|
setDefaultSize(this, 300);
|
|
}
|
|
return r;
|
|
};
|
|
|
|
const origOnConfigure = nodeType.prototype.onConfigure;
|
|
nodeType.prototype.onConfigure = function () {
|
|
const r = origOnConfigure?.apply(this, arguments);
|
|
this._configured = true;
|
|
removeHiddenInputs(this, ["model_family", "preset"]);
|
|
this._preset_render?.();
|
|
return r;
|
|
};
|
|
}
|
|
if (nodeData.name === "FlakeCombo") {
|
|
const origOnNodeCreated = nodeType.prototype.onNodeCreated;
|
|
nodeType.prototype.onNodeCreated = function () {
|
|
const r = origOnNodeCreated?.apply(this, arguments);
|
|
setupFlakeComboWidget(this);
|
|
removeHiddenInputs(this, ["model_family", "flakes_json"]);
|
|
if (!this._configured) {
|
|
setDefaultSize(this, 340);
|
|
}
|
|
return r;
|
|
};
|
|
|
|
const origOnConfigure = nodeType.prototype.onConfigure;
|
|
nodeType.prototype.onConfigure = function () {
|
|
const r = origOnConfigure?.apply(this, arguments);
|
|
this._configured = true;
|
|
removeHiddenInputs(this, ["model_family", "flakes_json"]);
|
|
this._combo_render?.();
|
|
return r;
|
|
};
|
|
}
|
|
if (nodeData.name === "FlakeModelCombo") {
|
|
const origOnNodeCreated = nodeType.prototype.onNodeCreated;
|
|
nodeType.prototype.onNodeCreated = function () {
|
|
const r = origOnNodeCreated?.apply(this, arguments);
|
|
setupFlakeModelComboWidget(this);
|
|
removeHiddenInputs(this, ["model_family", "preset"]);
|
|
if (!this._configured) {
|
|
setDefaultSize(this, 300);
|
|
}
|
|
return r;
|
|
};
|
|
|
|
const origOnConfigure = nodeType.prototype.onConfigure;
|
|
nodeType.prototype.onConfigure = function () {
|
|
const r = origOnConfigure?.apply(this, arguments);
|
|
this._configured = true;
|
|
removeHiddenInputs(this, ["model_family", "preset"]);
|
|
this._model_combo_render?.();
|
|
return r;
|
|
};
|
|
}
|
|
if (nodeData.name === "FlakeDataSplitSelect") {
|
|
const origOnNodeCreated = nodeType.prototype.onNodeCreated;
|
|
nodeType.prototype.onNodeCreated = function () {
|
|
const r = origOnNodeCreated?.apply(this, arguments);
|
|
setupFlakeDataSplitSelect(this);
|
|
removeHiddenInputs(this, ["selected_pins"]);
|
|
if (!this._configured) {
|
|
setDefaultSize(this, 260);
|
|
}
|
|
return r;
|
|
};
|
|
|
|
const origOnConfigure = nodeType.prototype.onConfigure;
|
|
nodeType.prototype.onConfigure = function () {
|
|
const r = origOnConfigure?.apply(this, arguments);
|
|
this._configured = true;
|
|
removeHiddenInputs(this, ["selected_pins"]);
|
|
if (!this.properties) this.properties = {};
|
|
let savedPins;
|
|
try {
|
|
const raw = this.properties._selected_split_pins;
|
|
savedPins = raw ? (typeof raw === "string" ? JSON.parse(raw) : raw) : null;
|
|
} catch { savedPins = null; }
|
|
if (!Array.isArray(savedPins)) {
|
|
const w = this.widgets?.find(w => w.name === "selected_pins");
|
|
try {
|
|
savedPins = w && w.value ? JSON.parse(w.value) : null;
|
|
} catch { savedPins = null; }
|
|
}
|
|
if (!Array.isArray(savedPins)) savedPins = [...DEFAULT_SPLIT_PINS];
|
|
for (let i = this.outputs.length - 1; i >= 0; i--) {
|
|
this.disconnectOutputs(i);
|
|
this.removeOutput(i);
|
|
}
|
|
this.properties._selected_split_pins = [...savedPins];
|
|
this._splitPinUpdate?.();
|
|
return r;
|
|
};
|
|
}
|
|
if (nodeData.name === "IntoFlakeDataSelect") {
|
|
const origOnNodeCreated = nodeType.prototype.onNodeCreated;
|
|
nodeType.prototype.onNodeCreated = function () {
|
|
const r = origOnNodeCreated?.apply(this, arguments);
|
|
setupIntoFlakeDataSelect(this);
|
|
removeHiddenInputs(this, ["active_pins"]);
|
|
if (!this._configured) {
|
|
setDefaultSize(this, 260);
|
|
}
|
|
return r;
|
|
};
|
|
|
|
const origOnConfigure = nodeType.prototype.onConfigure;
|
|
nodeType.prototype.onConfigure = function () {
|
|
const r = origOnConfigure?.apply(this, arguments);
|
|
this._configured = true;
|
|
removeHiddenInputs(this, ["active_pins"]);
|
|
if (!this.properties) this.properties = {};
|
|
let savedPins;
|
|
try {
|
|
const raw = this.properties._selected_into_pins;
|
|
savedPins = raw ? (typeof raw === "string" ? JSON.parse(raw) : raw) : null;
|
|
} catch { savedPins = null; }
|
|
if (!Array.isArray(savedPins)) {
|
|
const w = this.widgets?.find(w => w.name === "active_pins");
|
|
try {
|
|
savedPins = w && w.value ? JSON.parse(w.value) : null;
|
|
} catch { savedPins = null; }
|
|
}
|
|
if (!Array.isArray(savedPins)) savedPins = [...DEFAULT_INTO_PINS];
|
|
const fixedNames = new Set(["flake_data", "active_pins"]);
|
|
for (let i = this.inputs.length - 1; i >= 0; i--) {
|
|
if (!fixedNames.has(this.inputs[i].name)) {
|
|
if (this.inputs[i].link != null) {
|
|
this.disconnectInput(i);
|
|
}
|
|
this.removeInput(i);
|
|
}
|
|
}
|
|
this.properties._selected_into_pins = [...savedPins];
|
|
this._intoPinUpdate?.();
|
|
return r;
|
|
};
|
|
}
|
|
if (nodeData.name === "PreviewFlakeData") {
|
|
const origOnNodeCreated = nodeType.prototype.onNodeCreated;
|
|
nodeType.prototype.onNodeCreated = function () {
|
|
const r = origOnNodeCreated?.apply(this, arguments);
|
|
setupPreviewFlakeDataWidget(this);
|
|
if (!this._configured) {
|
|
setDefaultSize(this, 260);
|
|
}
|
|
return r;
|
|
};
|
|
}
|
|
},
|
|
});
|