Files
Maxed-Out-99-ComfyUI-MaxedOut/web/lib/mxd_base_node.js
T
Maxed-Out-99andClaude Fable 5 4cb19be2e0 Restructure web/ into lib+nodes+vendor; merge power lora loader forks
- web/lib/: the shared rgthree-derived layer (mxd_* utils, dialogs, api,
  runtime) + its CSS, moved as a unit.
- web/nodes/: one extension file per node/feature, _mxd suffix dropped.
- web/vendor/zip_loader/: vendored zip import addon.
- index.js explicitly imports every module; loraloader_mxd_entry.js
  folded into it and deleted.

Power Lora Loader merge: new web/nodes/power_lora_base.js holds the
shared node machinery, header row, and single-strength lora row widget.
power_lora_loader.js (dual model/clip strengths) and
ltx2_power_lora_loader.js (per-layer strength rows) are now thin
subclasses (~450 duplicated lines removed). Serialization formats,
widget names, extension names, and node targets unchanged.

better_combos.js scoped to MXD latent loaders only: removed the
pysssss CheckpointLoader/LoraLoader patching (already disabled behind
ENABLE_PYSSSS_NODE_ENHANCEMENTS=false, so provably inert), the dead
' MXD' alias config entries, and the no-op refreshComboInNodes wrapper.

scripts/check_web.py clean; node schema unchanged (68 identical).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 06:41:35 -07:00

218 lines
6.5 KiB
JavaScript

import { app } from "../../../scripts/app.js";
import { ComfyWidgets } from "../../../scripts/widgets.js";
import { defineProperty, moveArrayItem } from "./mxd_shared_utils.js";
export class MxdBaseNode extends LGraphNode {
static title = "__NEED_CLASS_TITLE__";
static type = "__NEED_CLASS_TYPE__";
static category = "mxd";
static _category = "mxd";
static exposedActions = [];
constructor(title = MxdBaseNode.title) {
super(title);
this.comfyClass = "__NEED_COMFY_CLASS__";
this.isVirtualNode = false;
this.isDropEnabled = false;
this.removed = false;
this.configuring = false;
this._tempWidth = 0;
this.__constructed__ = false;
this.widgets = this.widgets || [];
this.properties = this.properties || {};
defineProperty(this, "mode", {
get: () => this._mxd_mode,
set: (mode) => {
if (this._mxd_mode !== mode) {
const oldMode = this._mxd_mode;
this._mxd_mode = mode;
this.onModeChange(oldMode, mode);
}
},
});
setTimeout(() => this.checkAndRunOnConstructed());
}
checkAndRunOnConstructed() {
if (!this.__constructed__) {
this.onConstructed();
}
return this.__constructed__;
}
onConstructed() {
if (this.__constructed__) return false;
this.type = this.type ?? undefined;
this.__constructed__ = true;
return true;
}
configure(info) {
this.configuring = true;
super.configure(info);
for (const w of this.widgets || []) {
w.last_y = w.last_y || 0;
}
this.configuring = false;
}
clone() {
const cloned = super.clone();
if (cloned?.properties && window.structuredClone) {
cloned.properties = structuredClone(cloned.properties);
}
return cloned;
}
onModeChange(from, to) {}
removeWidget(widget) {
if (typeof widget === "number") {
widget = this.widgets[widget];
}
if (!widget) return;
const index = this.widgets.indexOf(widget);
if (index > -1) {
this.widgets.splice(index, 1);
}
widget.onRemove?.();
}
replaceWidget(widgetOrSlot, newWidget) {
let index = null;
if (widgetOrSlot != null) {
index = typeof widgetOrSlot === "number" ? widgetOrSlot : this.widgets.indexOf(widgetOrSlot);
this.removeWidget(this.widgets[index]);
}
index = index != null ? index : this.widgets.length - 1;
if (this.widgets.includes(newWidget)) {
moveArrayItem(this.widgets, newWidget, index);
} else {
this.widgets.splice(index, 0, newWidget);
}
}
defaultGetSlotMenuOptions(slot) {
const menuInfo = [];
if (slot?.output?.links?.length) {
menuInfo.push({ content: "Disconnect Links", slot });
}
const inputOrOutput = slot.input || slot.output;
if (inputOrOutput) {
if (inputOrOutput.removable) {
menuInfo.push(inputOrOutput.locked ? { content: "Cannot remove" } : { content: "Remove Slot", slot });
}
if (!inputOrOutput.nameLocked) {
menuInfo.push({ content: "Rename Slot", slot });
}
}
return menuInfo;
}
onRemoved() {
super.onRemoved?.();
this.removed = true;
}
static setUp() {}
}
export class MxdBaseServerNode extends MxdBaseNode {
static nodeType = null;
static nodeData = null;
static __registeredForOverride__ = false;
constructor(title) {
super(title);
this.isDropEnabled = true;
this.serialize_widgets = true;
this.setupFromServerNodeData();
this.onConstructed();
}
getWidgets() {
return ComfyWidgets;
}
async setupFromServerNodeData() {
const nodeData = this.constructor.nodeData;
if (!nodeData) throw Error("No node data");
this.comfyClass = nodeData.name;
let inputs = nodeData.input.required;
if (nodeData.input.optional != undefined) {
inputs = Object.assign({}, inputs, nodeData.input.optional);
}
const WIDGETS = this.getWidgets();
const config = { minWidth: 1, minHeight: 1, widget: null };
for (const inputName in inputs) {
const inputData = inputs[inputName];
const type = inputData[0];
if (inputData[1]?.forceInput) {
this.addInput(inputName, type);
} else {
let widgetCreated = true;
if (Array.isArray(type)) {
Object.assign(config, WIDGETS.COMBO(this, inputName, inputData, app) || {});
} else if (`${type}:${inputName}` in WIDGETS) {
Object.assign(config, WIDGETS[`${type}:${inputName}`](this, inputName, inputData, app) || {});
} else if (type in WIDGETS) {
Object.assign(config, WIDGETS[type](this, inputName, inputData, app) || {});
} else {
this.addInput(inputName, type);
widgetCreated = false;
}
if (widgetCreated && inputData[1]?.forceInput && config?.widget) {
if (!config.widget.options) config.widget.options = {};
config.widget.options.forceInput = inputData[1].forceInput;
}
if (widgetCreated && inputData[1]?.defaultInput && config?.widget) {
if (!config.widget.options) config.widget.options = {};
config.widget.options.defaultInput = inputData[1].defaultInput;
}
}
}
for (const o in nodeData.output) {
let output = nodeData.output[o];
if (output instanceof Array) output = "COMBO";
const outputName = nodeData.output_name[o] || output;
const outputShape = nodeData.output_is_list[o] ? LiteGraph.GRID_SHAPE : LiteGraph.CIRCLE_SHAPE;
this.addOutput(outputName, output, { shape: outputShape });
}
const s = this.computeSize();
s[0] = Math.max(config.minWidth ?? 1, s[0] * 1.5);
s[1] = Math.max(config.minHeight ?? 1, s[1]);
this.size = s;
this.serialize_widgets = true;
}
static registerForOverride(comfyClass, nodeData, mxdClass) {
if (OVERRIDDEN_SERVER_NODES.has(comfyClass)) {
throw Error(`Already have a class to override ${comfyClass.type || comfyClass.name || comfyClass.title}`);
}
OVERRIDDEN_SERVER_NODES.set(comfyClass, mxdClass);
if (!mxdClass.__registeredForOverride__) {
mxdClass.__registeredForOverride__ = true;
mxdClass.nodeType = comfyClass;
mxdClass.nodeData = nodeData;
mxdClass.onRegisteredForOverride(comfyClass, mxdClass);
}
}
static onRegisteredForOverride(comfyClass, mxdClass) {}
}
const OVERRIDDEN_SERVER_NODES = new Map();
const oldRegisterNodeType = LiteGraph.registerNodeType;
LiteGraph.registerNodeType = async function (nodeId, baseClass) {
const clazz = OVERRIDDEN_SERVER_NODES.get(baseClass) || baseClass;
return oldRegisterNodeType.call(LiteGraph, nodeId, clazz);
};