From 1881aa727faa72feacfaa9092b0b25da307569a1 Mon Sep 17 00:00:00 2001 From: Ethanfel Date: Fri, 3 Jul 2026 00:22:28 +0200 Subject: [PATCH] fix: text gate persists editor text across refresh/reload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The editor content was only restored on reload in protected mode, and stored_text was only synced on keystroke (oninput). So in the default pause mode edited text came back empty after refresh/reload-workflow, and upstream text passed without a keystroke was never captured. Now applyPersistedMode restores the editor from stored_text in BOTH modes, and syncStored also fires when upstream text arrives (socket) and on Pass — so whatever text is shown/edited survives a reload. Verified against the shipped litegraph serialize()/configure() widget semantics: default-mode + pass-without-typing round-trips now restore. Co-Authored-By: Claude Opus 4.8 --- web/text_gate.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/web/text_gate.js b/web/text_gate.js index 80fb1a1..57379d9 100644 --- a/web/text_gate.js +++ b/web/text_gate.js @@ -32,7 +32,9 @@ const MARGIN = 10; // ComfyUI DOM-widget inset, matches the other nodes // `protected` (BOOLEAN toggle) + `stored_text` (hidden STRING) are real backend // widgets. When protected, the node acts as a plain text node: it outputs // stored_text and ignores upstream (no pause). The DOM textarea is the visible -// editor and mirrors its value into stored_text so it persists and reaches run(). +// editor and mirrors its value into stored_text on EVERY change (typing, upstream +// arrival, Pass) — so the editor content survives refresh / workflow reload in +// BOTH modes (stored_text also reaches run() when protected). function widgetByName(node, name) { return node.widgets?.find((w) => w.name === name); @@ -59,15 +61,13 @@ function hideStoredWidget(node) { w.computeSize = () => [0, -4]; } -// reflect the persisted protected/stored_text state into the editor + UI +// reflect the persisted stored_text + mode into the editor + UI. The editor text +// is restored in BOTH modes so it survives a refresh / workflow reload; the mode +// only selects the UI state (protected vs idle waiting-for-a-run). function applyPersistedMode(node) { if (!node._tg) return; - if (isProtected(node)) { - node._tg.area.value = widgetByName(node, "stored_text")?.value ?? ""; - setState(node, "protected"); - } else { - setState(node, "idle"); - } + node._tg.area.value = widgetByName(node, "stored_text")?.value ?? ""; + setState(node, isProtected(node) ? "protected" : "idle"); } // ---- server call ------------------------------------------------------------ @@ -182,6 +182,7 @@ function setupTextGateNode(node) { pass.className = "tgate-pass"; pass.textContent = "▶ Pass"; pass.onclick = async () => { + syncStored(node); // persist the passed text so a reload keeps it await postPass(node, area.value); setState(node, "passed"); }; @@ -265,6 +266,7 @@ app.registerExtension({ } else { node._tg.area.value = d.text || ""; } + syncStored(node); // persist the shown text so a refresh/reload keeps it setState(node, "paused"); try { node._tg.area.focus(); } catch (err) { /* ignore */ } });