160 lines
6.8 KiB
JavaScript
160 lines
6.8 KiB
JavaScript
import { app } from "/scripts/app.js";
|
|
|
|
// Simple debounce function
|
|
function debounce(func, delay) {
|
|
let timeoutId;
|
|
return function(...args) {
|
|
clearTimeout(timeoutId);
|
|
timeoutId = setTimeout(() => {
|
|
func.apply(this, args);
|
|
}, delay);
|
|
};
|
|
}
|
|
|
|
// Use the class name registered in NODE_CLASS_MAPPINGS
|
|
const nodeClassName = "MySwitchIndex";
|
|
|
|
app.registerExtension({
|
|
name: "MultiModel.MySwitchIndex",
|
|
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
|
// Compare with the class name
|
|
if (nodeData.name === nodeClassName) {
|
|
function handleModeSwitch(modeWidget, indexWidget, app, value) {
|
|
const updateVisibility = (modeValue) => {
|
|
if (indexWidget) {
|
|
const shouldBeHidden = (modeValue !== "index");
|
|
indexWidget.hidden = shouldBeHidden;
|
|
if (app.graph) app.graph.setDirtyCanvas(true, false);
|
|
}
|
|
};
|
|
updateVisibility(value ?? modeWidget.value);
|
|
// Перевизначаємо callback
|
|
const originalModeCallback = modeWidget.callback;
|
|
modeWidget.callback = (val) => {
|
|
originalModeCallback?.apply(modeWidget, [val]);
|
|
updateVisibility(val);
|
|
};
|
|
}
|
|
|
|
function updateDynamicInputIndexes(node) {
|
|
const prefix = node._input_prefix || "input_";
|
|
let dynamicInputs = node.inputs ? node.inputs.filter(inp => inp.name !== "mode" && inp.name !== "index") : [];
|
|
for (let i = 0; i < dynamicInputs.length; i++) {
|
|
const expectedName = `${prefix}${i + 1}`;
|
|
if (dynamicInputs[i].name !== expectedName) {
|
|
dynamicInputs[i].name = expectedName;
|
|
}
|
|
}
|
|
let maxIdx = dynamicInputs.length > 0 ? dynamicInputs.length : 1;
|
|
node.last_connected = -1;
|
|
for (let i = 0; i < dynamicInputs.length; i++) {
|
|
const inp = dynamicInputs[i];
|
|
if (inp.link != null) node.last_connected = node.inputs.indexOf(inp);
|
|
}
|
|
node._last_input_index = maxIdx;
|
|
// Останній порожній динамічний вхід
|
|
let lastEmptyIdx = -1;
|
|
for (let i = node.inputs.length - 1; i >= 0; i--) {
|
|
if (node.inputs[i].name !== "mode" && node.inputs[i].name !== "index" && node.inputs[i].name.startsWith(prefix) && node.inputs[i].link == null) {
|
|
lastEmptyIdx = i;
|
|
break;
|
|
}
|
|
}
|
|
node.last_empty = lastEmptyIdx;
|
|
}
|
|
|
|
function updateDynamicInputsOnConnect(node, type, index, connected) {
|
|
if (node._updatingInputs) return;
|
|
node._updatingInputs = true;
|
|
const changedInput = node.inputs[index];
|
|
const inputName = changedInput?.name;
|
|
const isDynamic = inputName && inputName !== "mode" && inputName !== "index";
|
|
if (!isDynamic) {
|
|
node._updatingInputs = false;
|
|
return;
|
|
}
|
|
if (connected) {
|
|
if (index === node.last_empty) {
|
|
const prefix = node._input_prefix || "input_";
|
|
let dynamicInputs = node.inputs.filter(inp => inp.name !== "mode" && inp.name !== "index");
|
|
node.addInput(`${prefix}${dynamicInputs.length + 1}`, "*");
|
|
updateDynamicInputIndexes(node);
|
|
}
|
|
} else {
|
|
let dynamicInputs = node.inputs.filter(inp => inp.name !== "mode" && inp.name !== "index");
|
|
let emptyInputs = dynamicInputs.filter(inp => inp.link == null);
|
|
if (index === node.last_connected && emptyInputs.length > 1) {
|
|
node.removeInput(index);
|
|
updateDynamicInputIndexes(node);
|
|
}
|
|
}
|
|
node._updatingInputs = false;
|
|
}
|
|
|
|
function handleNodeCreation(node, app) {
|
|
// --- Віджети ---
|
|
const modeWidget = node.widgets.find(w => w.name === "mode");
|
|
const indexWidget = node.widgets.find(w => w.name === "index");
|
|
if (!modeWidget || !indexWidget) {
|
|
return;
|
|
}
|
|
handleModeSwitch(modeWidget, indexWidget, app);
|
|
|
|
// --- Динамічні входи (last_empty, last_connected) ---
|
|
node._input_prefix = "input_";
|
|
const prefix = node._input_prefix;
|
|
let dynamicInputs = node.inputs ? node.inputs.filter(inp => inp.name !== "mode" && inp.name !== "index") : [];
|
|
if (dynamicInputs.length === 0) {
|
|
node.addInput(`${prefix}1`, "*");
|
|
dynamicInputs = node.inputs.filter(inp => inp.name !== "mode" && inp.name !== "index");
|
|
}
|
|
|
|
let connectedInputs = dynamicInputs.filter(inp => inp.link != null);
|
|
let emptyInputs = dynamicInputs.filter(inp => inp.link == null);
|
|
if (emptyInputs.length === 0) {
|
|
node.addInput(`${prefix}${connectedInputs.length + 1}`, "*");
|
|
dynamicInputs = node.inputs.filter(inp => inp.name !== "mode" && inp.name !== "index");
|
|
} else if (emptyInputs.length > 1) {
|
|
for (let i = node.inputs.length - 1; i >= 0; i--) {
|
|
if (node.inputs[i].name !== "mode" && node.inputs[i].name !== "index" && node.inputs[i].link == null && emptyInputs.length > 1) {
|
|
node.removeInput(i);
|
|
emptyInputs.pop();
|
|
}
|
|
}
|
|
dynamicInputs = node.inputs.filter(inp => inp.name !== "mode" && inp.name !== "index");
|
|
}
|
|
updateDynamicInputIndexes(node);
|
|
// --- Зберігаємо попередній стан links ---
|
|
node._prevLinks = [];
|
|
for (let i = 0; i < node.inputs.length; i++) {
|
|
node._prevLinks[i] = node.inputs[i].link;
|
|
}
|
|
if (app.graph) app.graph.setDirtyCanvas(true, true);
|
|
}
|
|
|
|
function handleConnectionsChange(node, type, index, connected, link_info, slot, app) {
|
|
updateDynamicInputsOnConnect(node, type, index, connected);
|
|
node._prevLinks = [];
|
|
for (let i = 0; i < node.inputs.length; i++) {
|
|
node._prevLinks[i] = node.inputs[i].link;
|
|
}
|
|
}
|
|
|
|
// --- Патчимо onNodeCreated ---
|
|
const onNodeCreated = nodeType.prototype.onNodeCreated;
|
|
nodeType.prototype.onNodeCreated = function() {
|
|
onNodeCreated?.apply(this, arguments);
|
|
setTimeout(() => {
|
|
handleNodeCreation(this, app);
|
|
}, 500);
|
|
};
|
|
|
|
// --- Патчимо onConnectionsChange ---
|
|
const onConnectionsChange = nodeType.prototype.onConnectionsChange;
|
|
nodeType.prototype.onConnectionsChange = function(type, index, connected, link_info, slot) {
|
|
onConnectionsChange?.apply(this, arguments);
|
|
handleConnectionsChange(this, type, index, connected, link_info, slot, app);
|
|
};
|
|
}
|
|
},
|
|
});
|