From 04f9a4d6a28ad1f515f36c89245ea3e45ecca590 Mon Sep 17 00:00:00 2001 From: mwiegand Date: Sat, 16 May 2026 19:35:47 +0200 Subject: [PATCH] fix(editor): narrow findFilenameInput scope + dispatch input from setValue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses two Minor follow-ups from the Task 4 code review: - findFilenameInput previously included `body` in its closest() selector, meaning any "auto" textarea outside a modal would walk all the way up and pick up the files-editor modal's filename input from elsewhere in the document. Drop `body` so out-of-modal "auto" usage degrades cleanly to "plain". - setValue now dispatches an `input` event on the textarea after writing, matching the onUpdate mirror. Task 10 wires the files-editor modal to call setValue when loading file content — without this fix, textarea-listening code (e.g. unsaved-changes indicators) wouldn't see programmatic loads. Now setValue and user typing produce the same observable side effects. Plan source block updated to match. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../plans/2026-05-16-textarea-code-editor.md | 19 ++++++++++++++----- l4d2web/l4d2web/static/js/editor.js | 19 ++++++++++++++----- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/docs/superpowers/plans/2026-05-16-textarea-code-editor.md b/docs/superpowers/plans/2026-05-16-textarea-code-editor.md index 7c27be4..edc1bd9 100644 --- a/docs/superpowers/plans/2026-05-16-textarea-code-editor.md +++ b/docs/superpowers/plans/2026-05-16-textarea-code-editor.md @@ -440,12 +440,15 @@ Key design decisions baked into the final file (both the initial skeleton and th }; } - // For "auto" language: look for a filename input near the textarea - // (the files-editor modal). Returns the or null. + // For "auto" language: look for a filename input inside the nearest + // enclosing dialog or .modal. Returns the or null. + // Intentionally does NOT walk up to : an "auto" textarea + // outside a modal scope degrades to "plain" rather than picking up + // some unrelated .files-editor-filename elsewhere in the document. function findFilenameInput(textarea) { - const modal = textarea.closest("dialog, .modal, body"); - if (!modal) return null; - return modal.querySelector(".files-editor-filename"); + const scope = textarea.closest("dialog, .modal"); + if (!scope) return null; + return scope.querySelector(".files-editor-filename"); } function mount(textarea) { @@ -491,8 +494,14 @@ Key design decisions baked into the final file (both the initial skeleton and th jar, language, setValue: function (text) { + // updateCode does not invoke the onUpdate mirror, so fire the + // same textarea sync + input event here for consistency. Any + // listener watching the textarea sees external setValue calls + // (e.g. files-overlay loading a file into the modal) the same + // way it sees user typing. instance.jar.updateCode(text); textarea.value = text; + textarea.dispatchEvent(new Event("input", { bubbles: true })); }, getValue: function () { return instance.jar.toString(); diff --git a/l4d2web/l4d2web/static/js/editor.js b/l4d2web/l4d2web/static/js/editor.js index 9b9ee63..7424fbb 100644 --- a/l4d2web/l4d2web/static/js/editor.js +++ b/l4d2web/l4d2web/static/js/editor.js @@ -37,12 +37,15 @@ }; } - // For "auto" language: look for a filename input near the textarea - // (the files-editor modal). Returns the or null. + // For "auto" language: look for a filename input inside the nearest + // enclosing dialog or .modal. Returns the or null. + // Intentionally does NOT walk up to : an "auto" textarea + // outside a modal scope degrades to "plain" rather than picking up + // some unrelated .files-editor-filename elsewhere in the document. function findFilenameInput(textarea) { - const modal = textarea.closest("dialog, .modal, body"); - if (!modal) return null; - return modal.querySelector(".files-editor-filename"); + const scope = textarea.closest("dialog, .modal"); + if (!scope) return null; + return scope.querySelector(".files-editor-filename"); } function mount(textarea) { @@ -88,8 +91,14 @@ jar, language, setValue: function (text) { + // updateCode does not invoke the onUpdate mirror, so fire the + // same textarea sync + input event here for consistency. Any + // listener watching the textarea sees external setValue calls + // (e.g. files-overlay loading a file into the modal) the same + // way it sees user typing. instance.jar.updateCode(text); textarea.value = text; + textarea.dispatchEvent(new Event("input", { bubbles: true })); }, getValue: function () { return instance.jar.toString();