Loading a workflow does not re-fetch extension JS, and aiohttp serves
web/*.js with only Last-Modified (no no-store), so an open tab can keep
running a cached old text_gate.js. Log a build tag on setup so we can
tell from the devtools console whether the persistence/weighting build
is actually loaded.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ComfyUI's "edit attention" (wrap selection in (token:weight)) is a global
window keydown listener that acts when a <textarea> is focused. The text
gate editor is a textarea, but its keydown handler called stopPropagation
on EVERY key, so the event never bubbled to window and weighting never
fired — notably when using the node as a prompt text node in protected mode.
Now stopPropagation is skipped for the weighting shortcut (Ctrl/Cmd + ↑/↓)
so it reaches the global handler; all other keys are still stopped so
typing/space can't trigger litegraph canvas shortcuts. The weighting edit
goes through execCommand, which fires our oninput -> stored_text stays synced.
Verified against the verbatim editAttention from the shipped frontend:
whole-word weighting, existing-weight decrement, and no-selection word
expansion all round-trip; plain keys stay stopped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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 <noreply@anthropic.com>
computeSize alone left the collapsed pill visible in the 1.47 frontend.
Set widget.hidden=true (what getVisibleWidgets filters on), matching the
pool node's hideWidget. Value still serializes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a '🔒 Protected (text node)' toggle. When on, the DOM editor is a free text
box whose value mirrors into the hidden stored_text widget; the node outputs that
text and ignores upstream (no pause, socket events ignored). Persists via the
protected + stored_text widgets; restored on configure. stored_text is single-line
so it hides cleanly (pool_id trick).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A bare app.queuePrompt(0,1) enqueues but skips the command-level run setup in
the 1.47 frontend, so the prompt never kicked off — you had to press Run
manually. Execute the Comfy.QueuePrompt command (same path as the Run button /
Ctrl+Enter) instead, with app.queuePrompt as a legacy fallback.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Run-from-here now preserves the edited text via an explicit _tgKeepEdit flag
set when the button is pressed, instead of comparing incoming vs last text.
A non-deterministic upstream (random/seeded prompt) regenerates text on every
re-queue, which made the old comparison clobber the edit. Normal toolbar Queue
still shows fresh upstream text.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>