Files
DemonGatanjieuandClaude Opus 5.5 72d3ca12ea Fix saves: run each save, not the canvas; keep Ctrl+Z after going back
ComfyUI-Manager wraps app.graphToPrompt and drops the graph, so every run and
the check before it compiled the canvas: same seeds, nothing of the later marks.
A result that is not the copy's is now made by ComfyUI's own method.

Going back is one of ComfyUI's undo steps, so Ctrl+Z returns to the state left
behind. A save can also open on a new tab, the empty canvas's menu and a + on
the bar keep one, and marks show as saves, runs counted as runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 15:46:27 +08:00

98 lines
3.5 KiB
JavaScript

/**
* What the canvas's right-click menus offer from AMB, as the user set it (Settings -> Canvas):
* the entries of a node's menu and of the empty canvas's menu, each on or off, in the user's
* order, and whether they sit in one "Anomalous" submenu or right in the menu. A per-viewer
* convenience in localStorage; entries added in a later version join at their default place.
* No DOM.
*/
const KEY = 'anomalous_canvas_menu';
// Each list in its default order, with whether an entry is on at first.
export const NODE_ENTRIES = Object.freeze([
{ id: 'open', on: true },
{ id: 'replaceModel', on: true },
{ id: 'loraBefore', on: true },
{ id: 'loraAfter', on: true },
{ id: 'parameters', on: true },
{ id: 'modelOutputs', on: true },
{ id: 'modelDetails', on: false },
{ id: 'saveParameters', on: false },
{ id: 'saveCombo', on: true },
{ id: 'snapshotMark', on: true },
]);
export const CANVAS_ENTRIES = Object.freeze([
{ id: 'quickSearch', on: true },
{ id: 'openPage', on: true },
{ id: 'snapshotMark', on: true },
]);
export const PLACEMENTS = Object.freeze(['submenu', 'top']);
function storage() {
try {
return globalThis.localStorage || null;
} catch {
return null;
}
}
/** The saved `list` in its order, entries it does not know dropped and new ones added at their place. */
function merged(saved, defaults) {
const known = new Map(defaults.map(entry => [entry.id, entry]));
const kept = (Array.isArray(saved) ? saved : [])
.filter(entry => known.has(entry?.id))
.filter((entry, index, all) => all.findIndex(other => other.id === entry.id) === index)
.map(entry => ({ id: entry.id, on: entry.on !== false }));
defaults.forEach((entry, index) => {
if (kept.some(other => other.id === entry.id)) return;
// After the entry that comes before it by default, else first.
const before = defaults.slice(0, index).reverse().find(other => kept.some(item => item.id === other.id));
const at = before ? kept.findIndex(item => item.id === before.id) + 1 : 0;
kept.splice(at, 0, { ...entry });
});
return kept;
}
/** { placement, node: [{ id, on }], canvas: [{ id, on }] }. */
export function menuSettings(store = storage()) {
let saved = {};
try {
saved = JSON.parse(store?.getItem(KEY) || '{}') || {};
} catch {
saved = {};
}
return {
placement: PLACEMENTS.includes(saved.placement) ? saved.placement : 'submenu',
node: merged(saved.node, NODE_ENTRIES),
canvas: merged(saved.canvas, CANVAS_ENTRIES),
};
}
/** Keeps `settings` (as menuSettings returns them); false when the browser would not keep it. */
export function saveMenuSettings(settings, store = storage()) {
try {
store.setItem(KEY, JSON.stringify({ placement: settings.placement, node: settings.node, canvas: settings.canvas }));
return true;
} catch {
return false;
}
}
/** Back to the defaults. */
export function resetMenuSettings(store = storage()) {
try {
store?.removeItem(KEY);
} catch { /* the defaults show anyway */ }
return menuSettings(store);
}
/** `list` with the entry `id` moved by `step` (-1 up, +1 down), or as it was at an end. */
export function moveEntry(list, id, step) {
const from = list.findIndex(entry => entry.id === id);
const to = from + step;
if (from < 0 || to < 0 || to >= list.length) return list;
const next = [...list];
[next[from], next[to]] = [next[to], next[from]];
return next;
}