Files
CentralFloridaAttorney-Comf…/js/app.js
T
2026-04-02 20:46:29 -04:00

169 lines
5.6 KiB
JavaScript

import { app } from "../../scripts/app.js";
function findWidget(node, name) {
return node.widgets?.find((w) => w.name === name);
}
async function fetchFlattenedFields(collectionName) {
if (!collectionName || String(collectionName).startsWith("<")) {
return [];
}
const response = await fetch(
`/zmongo/flattened_fields?collection_name=${encodeURIComponent(collectionName)}`
);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
if (!data.success || !Array.isArray(data.fields)) {
return [];
}
return data.fields;
}
function setComboValues(widget, values, preferredValue = null) {
const safeValues = values.length ? values : ["<no_fields_found>"];
widget.options = widget.options || {};
widget.options.values = safeValues;
if (preferredValue && safeValues.includes(preferredValue)) {
widget.value = preferredValue;
} else if (!safeValues.includes(widget.value)) {
widget.value = safeValues[0];
}
}
function clampIndex(idx, len) {
if (!len || len <= 0) return 0;
if (Number.isNaN(idx)) return 0;
return Math.max(0, Math.min(idx, len - 1));
}
app.registerExtension({
name: "ZMongo.FlattenedFieldDropdown",
async nodeCreated(node) {
if (node.comfyClass !== "ZMongoFlattenedFieldDropdownNode") {
return;
}
const collectionWidget = findWidget(node, "collection_name");
const fieldWidget = findWidget(node, "field_name");
const indexWidget = findWidget(node, "field_index");
if (!collectionWidget || !fieldWidget || !indexWidget) {
return;
}
let isUpdating = false;
const syncIndexFromField = () => {
const values = fieldWidget.options?.values || [];
const idx = values.indexOf(fieldWidget.value);
indexWidget.value = idx >= 0 ? idx : 0;
node.setDirtyCanvas(true, true);
};
const syncFieldFromIndex = () => {
const values = fieldWidget.options?.values || [];
if (!values.length) {
fieldWidget.value = "<no_fields_found>";
indexWidget.value = 0;
node.setDirtyCanvas(true, true);
return;
}
let idx = Number(indexWidget.value ?? 0);
idx = clampIndex(idx, values.length);
indexWidget.value = idx;
fieldWidget.value = values[idx];
node.setDirtyCanvas(true, true);
};
const refreshFields = async ({ preserveField = true } = {}) => {
if (isUpdating) return;
isUpdating = true;
try {
const collectionName = collectionWidget.value;
const oldFieldValue = fieldWidget.value;
const fields = await fetchFlattenedFields(collectionName);
let preferredValue = null;
if (
preserveField &&
oldFieldValue &&
!String(oldFieldValue).startsWith("<") &&
fields.includes(oldFieldValue)
) {
preferredValue = oldFieldValue;
}
setComboValues(fieldWidget, fields, preferredValue);
const values = fieldWidget.options?.values || [];
let idx = Number(indexWidget.value ?? 0);
idx = clampIndex(idx, values.length);
indexWidget.value = idx;
if (!preferredValue) {
fieldWidget.value = values[idx] ?? "<no_fields_found>";
}
syncIndexFromField();
node.setDirtyCanvas(true, true);
} catch (err) {
console.error("ZMongo flattened field dropdown refresh failed:", err);
setComboValues(fieldWidget, ["<error_loading_fields>"]);
fieldWidget.value = "<error_loading_fields>";
indexWidget.value = 0;
node.setDirtyCanvas(true, true);
} finally {
isUpdating = false;
}
};
const originalCollectionCallback = collectionWidget.callback;
collectionWidget.callback = async (...args) => {
if (originalCollectionCallback) {
originalCollectionCallback.apply(collectionWidget, args);
}
await refreshFields({ preserveField: false });
};
const originalFieldCallback = fieldWidget.callback;
fieldWidget.callback = (...args) => {
if (originalFieldCallback) {
originalFieldCallback.apply(fieldWidget, args);
}
syncIndexFromField();
};
const originalIndexCallback = indexWidget.callback;
indexWidget.callback = (...args) => {
if (originalIndexCallback) {
originalIndexCallback.apply(indexWidget, args);
}
syncFieldFromIndex();
};
// Initial population from the default selected collection.
await refreshFields({ preserveField: false });
// Run again on next tick because ComfyUI sometimes finishes widget restoration
// after nodeCreated, which can otherwise leave the placeholder stuck.
setTimeout(async () => {
await refreshFields({ preserveField: false });
}, 0);
// One more delayed refresh for restored workflows / startup timing issues.
setTimeout(async () => {
await refreshFields({ preserveField: false });
}, 150);
},
});