133 lines
4.3 KiB
JavaScript
133 lines
4.3 KiB
JavaScript
import { app } from "/scripts/app.js";
|
|
import { api } from "/scripts/api.js";
|
|
import { ComfyWidgets } from "/scripts/widgets.js";
|
|
import { showToast } from "./frontend_helper.js";
|
|
|
|
const NODE_NAME = "PrimerePathSelector";
|
|
const PATH_ENDPOINT = "/primere_select_path";
|
|
const DEFAULT_DISPLAY = "No path selected";
|
|
|
|
function getNodeIdentifier(node) {
|
|
if (!node || typeof node.id === "undefined" || node.id === null) {
|
|
return "";
|
|
}
|
|
return String(node.id);
|
|
}
|
|
|
|
function normalizeDisplay(pathValue) {
|
|
return pathValue && String(pathValue).trim().length > 0 ? String(pathValue) : DEFAULT_DISPLAY;
|
|
}
|
|
|
|
function setNodePathDisplay(node, pathValue) {
|
|
if (!node?._primerePathDisplayWidget) {
|
|
return;
|
|
}
|
|
node._primerePathDisplayWidget.value = normalizeDisplay(pathValue);
|
|
app.graph?.setDirtyCanvas(true, true);
|
|
}
|
|
|
|
async function clearNodePath(node) {
|
|
const nodeId = getNodeIdentifier(node);
|
|
if (!nodeId) {
|
|
setNodePathDisplay(node, "");
|
|
return;
|
|
}
|
|
|
|
const body = new FormData();
|
|
body.append("node_id", nodeId);
|
|
body.append("clear", "1");
|
|
|
|
try {
|
|
const response = await api.fetchApi(PATH_ENDPOINT, {method: "POST", body});
|
|
const payload = await response.json();
|
|
if (!response.ok || payload?.error) {
|
|
throw new Error(payload?.error ?? "Failed to clear selected path");
|
|
}
|
|
setNodePathDisplay(node, payload?.path ?? "");
|
|
} catch (error) {
|
|
showToast("error", error?.message ?? "Failed to clear selected path");
|
|
setNodePathDisplay(node, "");
|
|
}
|
|
}
|
|
|
|
async function openPathDialog(node) {
|
|
const nodeId = getNodeIdentifier(node);
|
|
if (!nodeId) {
|
|
showToast("error", "Node identifier is missing");
|
|
return;
|
|
}
|
|
|
|
const selectWidget = node.widgets?.find((w) => w.name === "select_file");
|
|
const selectFile = Boolean(selectWidget?.value ?? true);
|
|
|
|
const body = new FormData();
|
|
body.append("node_id", nodeId);
|
|
body.append("select_file", selectFile ? "1" : "0");
|
|
|
|
let response;
|
|
try {
|
|
response = await api.fetchApi(PATH_ENDPOINT, {method: "POST", body});
|
|
} catch (error) {
|
|
showToast("error", error?.message ?? "Failed to open path dialog");
|
|
return;
|
|
}
|
|
|
|
let payload;
|
|
try {
|
|
payload = await response.json();
|
|
} catch (_error) {
|
|
showToast("error", "Invalid response from path dialog");
|
|
return;
|
|
}
|
|
|
|
if (!response.ok || payload?.error) {
|
|
showToast("error", payload?.error ?? "Failed to open path dialog");
|
|
return;
|
|
}
|
|
setNodePathDisplay(node, payload?.path ?? "");
|
|
}
|
|
|
|
app.registerExtension({
|
|
name: "Primere.PrimerePathSelector",
|
|
|
|
async beforeRegisterNodeDef(nodeType, nodeData) {
|
|
if (nodeData.name !== NODE_NAME) return;
|
|
|
|
const onNodeCreated = nodeType.prototype.onNodeCreated;
|
|
nodeType.prototype.onNodeCreated = function () {
|
|
onNodeCreated?.apply(this, arguments);
|
|
|
|
const fileModeWidget = this.widgets?.find((w) => w.name === "select_file");
|
|
if (fileModeWidget) {
|
|
const originalCallback = fileModeWidget.callback;
|
|
fileModeWidget.callback = (...args) => {
|
|
originalCallback?.apply(fileModeWidget, args);
|
|
void clearNodePath(this);
|
|
};
|
|
}
|
|
|
|
this.addWidget("button", "Select path", null, () => openPathDialog(this), { serialize: false });
|
|
|
|
this._primerePathDisplayWidget = ComfyWidgets["STRING"](
|
|
this,
|
|
"selected_path",
|
|
["STRING", { multiline: true }],
|
|
app
|
|
).widget;
|
|
this._primerePathDisplayWidget.inputEl.readOnly = true;
|
|
this._primerePathDisplayWidget.options = {
|
|
...(this._primerePathDisplayWidget.options ?? {}),
|
|
serialize: false,
|
|
};
|
|
this._primerePathDisplayWidget.serializeValue = async () => "";
|
|
setNodePathDisplay(this, "");
|
|
};
|
|
const onExecuted = nodeType.prototype.onExecuted;
|
|
nodeType.prototype.onExecuted = function (message) {
|
|
onExecuted?.apply(this, [message]);
|
|
const display = message?.path_display?.[0] ?? message?.text?.[0] ?? "";
|
|
setNodePathDisplay(this, display);
|
|
};
|
|
},
|
|
});
|