Files
2025-08-08 17:52:52 +03:00

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);
};
}
},
});