Files
JeyzerMC-comfyui-flakes/web/flake_stack.js
T
Mehdi Chaid ad2929a80c fix: redesign FlakeDataSplitSelect and IntoFlakeDataSelect pin management
FlakeDataSplitSelect could not be added to workflow because removeInitialPins
called node.removeOutput/addOutput which could fail during node creation.
Switch to applyPinVisibility (hide/show existing pin slots) instead of
dynamically removing/adding pins, which is safer and avoids the crash.

IntoFlakeDataSelect: hide widget-type fields (filename_prefex, width, height,
steps, cfg, sampler_name, scheduler) by default; show them as label + widget
rows only when added via dropdown. Redesign [+] button with neutral Load Image
style styling and add hover effect. Remove dedicated [-] button since chips
have individual delete (x) buttons. For widget-type pins, display inline
label + input widget instead of a square input pin.

Fixes #152, Fixes #153
2026-05-14 14:17:52 -04:00

216 lines
9.2 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 { setupFlakeGenerateWidget } from "./widgets/flake-generate.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];
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];
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;
};
}
if (nodeData.name === "FlakeGenerate") {
const origOnNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function () {
const r = origOnNodeCreated?.apply(this, arguments);
setupFlakeGenerateWidget(this);
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;
return r;
};
}
},
});