Compare commits

...
4 changed files with 48 additions and 0 deletions
+8
View File
@@ -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";
+7
View File
@@ -34,6 +34,7 @@ import {
matchInstalled,
noteFit,
noteIsEmpty,
noteShowsTileFace,
normalizeNote,
packsFromGraph,
parseMarkdown,
@@ -709,6 +710,12 @@ function naturalHeight(state, width) {
// empty space until someone drags it shorter.
function fitNote(state) {
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;
}
const { node, root, domWidget } = state;
const width = node.size[0] - WIDGET_FRAME;
if (!(width > 0)) return;
+15
View File
@@ -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);
+18
View File
@@ -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 " },