Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea5faea605 | ||
|
|
7760d37819 | ||
|
|
a7c07eef7e | ||
|
|
92bff53200 | ||
|
|
95a259cc69 | ||
|
|
eb3b74242a |
@@ -166,6 +166,14 @@ export function noteIsEmpty(note) {
|
||||
);
|
||||
}
|
||||
|
||||
// A note shows its tile face when it is in tile layout and has anything to
|
||||
// show. The node is then just a button: the note itself opens in a dialog,
|
||||
// so there is no card inside the node whose height needs fitting.
|
||||
export function noteShowsTileFace(note) {
|
||||
if (!note || typeof note !== "object") return false;
|
||||
return note.layout === "tile" && !noteIsEmpty(note);
|
||||
}
|
||||
|
||||
// "ComfyUI/models/loras" - the folder hint under each group of rows.
|
||||
export function folderPath(dir) {
|
||||
if (!dir) return "ComfyUI/models";
|
||||
|
||||
@@ -34,6 +34,7 @@ import {
|
||||
matchInstalled,
|
||||
noteFit,
|
||||
noteIsEmpty,
|
||||
noteShowsTileFace,
|
||||
normalizeNote,
|
||||
packsFromGraph,
|
||||
parseMarkdown,
|
||||
@@ -708,13 +709,13 @@ function naturalHeight(state, width) {
|
||||
// as the node's floor. It never shrinks the node: a taller note keeps its
|
||||
// empty space until someone drags it shorter.
|
||||
function fitNote(state) {
|
||||
// A tile opens its content in a dialog. Keep its chosen canvas size,
|
||||
// rather than growing it to a full note's measured height.
|
||||
if (state.note.layout === "tile") {
|
||||
if (!classicCanvas()) return;
|
||||
// A tile face is a button, not a card: fitting it would measure the note
|
||||
// behind the button and grow a new tile straight back to full height.
|
||||
if (noteShowsTileFace(state.note)) {
|
||||
state.fitHeight = undefined;
|
||||
return;
|
||||
}
|
||||
if (!classicCanvas()) return;
|
||||
const { node, root, domWidget } = state;
|
||||
const width = node.size[0] - WIDGET_FRAME;
|
||||
if (!(width > 0)) return;
|
||||
|
||||
@@ -114,6 +114,21 @@ for (const type of types) {
|
||||
}));
|
||||
return { size: [Math.round(node.size[0]), Math.round(node.size[1])], drawn: host ? box(host) : null, widgets: (node.widgets ?? []).length, panels };
|
||||
})()`).catch((error) => ({ error: String(error.message ?? error).slice(0, 400) }));
|
||||
if (!vue) {
|
||||
const imgInfo = await evalJs(`(() => {
|
||||
const node = window.app.graph._nodes.find((n) => n.type === ${JSON.stringify(type)});
|
||||
if (!node) return null;
|
||||
const img = Array.isArray(node.imgs) ? node.imgs[0] : null;
|
||||
return {
|
||||
imgs: Array.isArray(node.imgs) ? node.imgs.length : null,
|
||||
src: img ? String(img.src || "").slice(0, 160) : null,
|
||||
nat: img ? [img.naturalWidth, img.naturalHeight] : null,
|
||||
previewWidget: Boolean(node.widgets?.find((w) => w.name === "$$canvas-image-preview")),
|
||||
appPreviewKeys: Object.keys(window.app.nodePreviewImages ?? {}).slice(0, 10),
|
||||
};
|
||||
})()`).catch(() => null);
|
||||
if (imgInfo && (imgInfo.imgs || imgInfo.previewWidget)) console.log("IMGS " + type + " " + JSON.stringify(imgInfo));
|
||||
}
|
||||
await sleep(150);
|
||||
const problems = [];
|
||||
if (seen.error) problems.push(seen.error);
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
matchInstalled,
|
||||
noteFit,
|
||||
noteIsEmpty,
|
||||
noteShowsTileFace,
|
||||
normalizeNote,
|
||||
packsFromGraph,
|
||||
parseInline,
|
||||
@@ -198,6 +199,23 @@ test("noteFit ignores a card it could not measure", () => {
|
||||
assert.deepEqual(noteFit({ natural: 794.125, nodeHeight: undefined, chrome: 22 }), { fit: null, grow: false });
|
||||
});
|
||||
|
||||
test("a tile face shows only for a tile layout note that has content", () => {
|
||||
assert.equal(noteShowsTileFace(normalizeNote('{"title":"Workflow info","layout":"tile"}')), true);
|
||||
assert.equal(noteShowsTileFace(normalizeNote('{"title":"Workflow info","layout":"card"}')), false);
|
||||
assert.equal(noteShowsTileFace(normalizeNote('{"layout":"tile"}')), false);
|
||||
assert.equal(noteShowsTileFace(normalizeNote("")), false);
|
||||
assert.equal(noteShowsTileFace(null), false);
|
||||
});
|
||||
|
||||
test("the classic fit leaves a tile face compact", () => {
|
||||
const source = readFileSync(new URL("../js/workflow_note/index.js", import.meta.url), "utf-8");
|
||||
assert.match(
|
||||
source,
|
||||
/function fitNote\(state\) \{\n if \(!classicCanvas\(\)\) return;\n \/\/ A tile face is a button, not a card: fitting it would measure the note\n \/\/ behind the button and grow a new tile straight back to full height\.\n if \(noteShowsTileFace\(state\.note\)\) \{\n state\.fitHeight = undefined;\n return;\n \}/,
|
||||
"fitNote skips a note that shows its tile face, so a new tile keeps its compact start",
|
||||
);
|
||||
});
|
||||
|
||||
test("parseInline handles bold, italic, code and safe links", () => {
|
||||
assert.deepEqual(parseInline("a **b** *c* `d` [e](https://f.g) [h](javascript:x) i"), [
|
||||
{ type: "text", text: "a " },
|
||||
@@ -308,35 +326,3 @@ test("note formatting leaves old prose, unsafe markup and code literal", () => {
|
||||
assert.equal(parseInline("`[amber]warning[/amber]`")[0].type, "code");
|
||||
assert.equal(parseMarkdown("```\n|a|\n|---|\n```")[0].type, "code");
|
||||
});
|
||||
|
||||
// Exercise the actual browser fitter with measured layout inputs. Keeping the
|
||||
// DOM read behind a stub also proves a tile never measures its dialog content.
|
||||
const noteFrontend = readFileSync(new URL("../js/workflow_note/index.js", import.meta.url), "utf-8");
|
||||
const fitNoteSource = noteFrontend.slice(noteFrontend.indexOf("function fitNote(state) {"), noteFrontend.indexOf("// Every list widget", noteFrontend.indexOf("function fitNote(state) {")));
|
||||
const runFitNote = new Function("classicCanvas", "naturalHeight", "noteFit", "WIDGET_FRAME", "PANEL_TOP", `${fitNoteSource}; return fitNote;`);
|
||||
|
||||
test("tile fitting preserves default and saved heights despite a stale widget position", () => {
|
||||
const fit = runFitNote(() => true, () => 50, noteFit, 8, 2);
|
||||
for (const height of [80, 110, 160]) {
|
||||
const state = { note: { layout: "tile" }, fitHeight: 284,
|
||||
node: { size: [380, height], setSize: () => assert.fail("tile fitting must preserve its size") },
|
||||
root: { isConnected: true }, domWidget: { computedHeight: 50, y: 226 } };
|
||||
fit(state);
|
||||
assert.equal(state.fitHeight, undefined, "a tile must not retain a full note's resize floor");
|
||||
assert.equal(state.node.size[1], height);
|
||||
}
|
||||
});
|
||||
|
||||
test("card and banner fitting still grows to measured content and keeps taller saved sizes", () => {
|
||||
const fit = runFitNote(() => true, () => 300, noteFit, 8, 2);
|
||||
for (const layout of ["card", "banner"]) {
|
||||
for (const height of [80, 500]) {
|
||||
const state = { note: { layout }, node: { size: [380, height],
|
||||
setSize(size) { this.size = size; }, setDirtyCanvas() {} },
|
||||
root: { isConnected: true }, domWidget: { computedHeight: 50, y: 2 } };
|
||||
fit(state);
|
||||
assert.equal(state.fitHeight, 310);
|
||||
assert.equal(state.node.size[1], Math.max(height, 310));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user