Files
ethanfel-ComfyUI-LoRA-Optim…/js/lora_stack_dynamic.js
T
EthanfelandClaude Opus 4.6 d0cc763713 feat: change lora_name slots to STRING inputs for text node connections
Replace COMBO dropdowns with STRING text inputs so users can type
short LoRA names (e.g. "Milena_20260216180133") or connect text nodes
directly. Names are resolved to full paths via _resolve_lora_name.
Remove base_model_filter (no longer applicable without COMBO widgets).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 19:57:47 +01:00

111 lines
3.3 KiB
JavaScript

import { app } from "/scripts/app.js";
const HIDDEN_TAG = "loraopt_hidden";
const origProps = {};
function toggleWidget(node, widget, show, suffix = "") {
if (!widget) return;
if (!origProps[widget.name]) {
origProps[widget.name] = {
origType: widget.type,
origComputeSize: widget.computeSize,
};
}
widget.hidden = !show;
widget.type = show ? origProps[widget.name].origType : HIDDEN_TAG + suffix;
widget.computeSize = show
? origProps[widget.name].origComputeSize
: () => [0, -4];
if (widget.linkedWidgets) {
for (const w of widget.linkedWidgets) {
toggleWidget(node, w, show, ":" + widget.name);
}
}
}
function findWidget(node, name) {
return node.widgets ? node.widgets.find((w) => w.name === name) : null;
}
function interceptWidgetValue(widget, onChange) {
let widgetValue = widget.value;
const desc =
Object.getOwnPropertyDescriptor(widget, "value") ||
Object.getOwnPropertyDescriptor(
Object.getPrototypeOf(widget),
"value"
);
Object.defineProperty(widget, "value", {
configurable: true,
enumerable: true,
get() {
return desc?.get ? desc.get.call(widget) : widgetValue;
},
set(newVal) {
if (desc?.set) {
desc.set.call(widget, newVal);
} else {
widgetValue = newVal;
}
onChange(newVal);
},
});
}
function updateVisibility(node) {
const modeWidget = findWidget(node, "mode");
const countWidget = findWidget(node, "lora_count");
if (!modeWidget || !countWidget) return;
const isSimple = modeWidget.value === "simple";
const count = countWidget.value;
const MAX = 10;
for (let i = 1; i <= MAX; i++) {
const visible = i <= count;
toggleWidget(node, findWidget(node, `lora_name_${i}`), visible);
toggleWidget(node, findWidget(node, `strength_${i}`), visible && isSimple);
toggleWidget(node, findWidget(node, `model_strength_${i}`), visible && !isSimple);
toggleWidget(node, findWidget(node, `clip_strength_${i}`), visible && !isSimple);
toggleWidget(node, findWidget(node, `conflict_mode_${i}`), visible);
}
const newHeight = node.computeSize()[1];
node.setSize([node.size[0], newHeight]);
app.canvas?.setDirty?.(true, true);
}
// --- Node Registration ---
app.registerExtension({
name: "LoRAOptimizer.LoRAStackDynamic",
nodeCreated(node) {
if (node.comfyClass !== "LoRAStackDynamic") return;
// Intercept mode and lora_count changes to update visibility
for (const w of node.widgets || []) {
if (w.name !== "mode" && w.name !== "lora_count") continue;
interceptWidgetValue(w, () => updateVisibility(node));
}
// Initial visibility update — delay to ensure widgets are fully initialized
setTimeout(() => {
updateVisibility(node);
}, 100);
},
});
app.registerExtension({
name: "LoRAOptimizer.LoRAConflictEditor",
nodeCreated(node) {
if (node.comfyClass !== "LoRAConflictEditor") return;
// All 10 conflict_mode slots are always visible.
// Unused slots (beyond the stack size) default to "auto" and are ignored.
},
});