tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 9258f6d1c54d46a1e438ee19fd72a4abc53cf1c9
parent 962c89e13f9ba9417128957bc24c31f49dc0b91a
Author: Nicolas Chevobbe <nchevobbe@mozilla.com>
Date:   Fri, 19 Dec 2025 16:42:26 +0000

Bug 2005582 - [devtools] Fix copying from markup view HTML editor. r=devtools-reviewers,ochameau.

With the migration to CodeMirror 6, the copy event listener callback that
is set in the Markup view would not see the element as being an editor (it
used to have a textarea for the CodeMirror editor, but not anymore), and
so proceeds to copy the outerHTML of the selected node instead.

This is fixed by checking if the event target is in a CodeMirror instance,
on top of checking if it's an input or a textarea.

A test case is added to cover the fix.

Differential Revision: https://phabricator.services.mozilla.com/D277026

Diffstat:
Mdevtools/client/inspector/markup/markup.js | 18+++++++++++++-----
Mdevtools/client/inspector/markup/test/browser_markup_html_edit_03.js | 30++++++++++++++++++++++++++++++
Mdevtools/client/inspector/markup/views/markup-container.js | 2+-
3 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/devtools/client/inspector/markup/markup.js b/devtools/client/inspector/markup/markup.js @@ -1311,7 +1311,7 @@ class MarkupView extends EventEmitter { _onCopy(evt) { // Ignore copy events from editors - if (this._isInputOrTextarea(evt.target)) { + if (this.isInputOrTextareaOrInCodeMirrorEditor(evt.target)) { return; } @@ -1453,7 +1453,7 @@ class MarkupView extends EventEmitter { * Key shortcut listener. */ _onShortcut(name, event) { - if (this._isInputOrTextarea(event.target)) { + if (this.isInputOrTextareaOrInCodeMirrorEditor(event.target)) { return; } @@ -1477,11 +1477,19 @@ class MarkupView extends EventEmitter { } /** - * Check if a node is an input or textarea + * Check if a node is used to type text (i.e. an input or textarea, or in a CodeMirror editor) */ - _isInputOrTextarea(element) { + isInputOrTextareaOrInCodeMirrorEditor(element) { const name = element.tagName.toLowerCase(); - return name === "input" || name === "textarea"; + if (name === "input" || name === "textarea") { + return true; + } + + if (element.closest(".cm-editor")) { + return true; + } + + return false; } /** diff --git a/devtools/client/inspector/markup/test/browser_markup_html_edit_03.js b/devtools/client/inspector/markup/test/browser_markup_html_edit_03.js @@ -28,6 +28,9 @@ add_task(async function () { info("Check that pressing escape cancels edits"); await testEscapeCancels(inspector); + info("Check that copying seletected text in editor works as expected"); + await testCopyTextSelection(inspector); + info("Check that pressing F2 commits edits"); await testF2Commits(inspector); @@ -58,6 +61,7 @@ async function testEscapeCancels(inspector) { "The node is starting with old HTML." ); + info("Check that copying from the editor does work as expected"); inspector.markup.htmlEditor.editor.setText(NEW_HTML); const onEditorHiddem = once(inspector.markup.htmlEditor, "popuphidden"); @@ -72,6 +76,32 @@ async function testEscapeCancels(inspector) { ); } +async function testCopyTextSelection(inspector) { + await selectNode(SELECTOR, inspector); + + const onHtmlEditorCreated = once(inspector.markup, "begin-editing"); + EventUtils.sendKey("F2", inspector.markup._frame.contentWindow); + await onHtmlEditorCreated; + ok(inspector.markup.htmlEditor.isVisible, "HTML Editor is visible"); + + info("Check that copying from the editor does work as expected"); + inspector.markup.htmlEditor.editor.setText(NEW_HTML); + // Select the "div" word in the editor + inspector.markup.htmlEditor.editor.setSelectionAt( + { line: 1, column: 1 }, + { line: 1, column: 4 } + ); + await waitForClipboardPromise(() => { + EventUtils.synthesizeKey("c", { accelKey: true }); + }, `div`); + ok(true, "Expected text was copied to clipboard"); + + // Close the editor + const onEditorHiddem = once(inspector.markup.htmlEditor, "popuphidden"); + EventUtils.sendKey("ESCAPE", inspector.markup.htmlEditor.doc.defaultView); + await onEditorHiddem; +} + async function testF2Commits(inspector) { const onEditorShown = once(inspector.markup.htmlEditor, "popupshown"); inspector.markup._frame.contentDocument.documentElement.focus(); diff --git a/devtools/client/inspector/markup/views/markup-container.js b/devtools/client/inspector/markup/views/markup-container.js @@ -480,7 +480,7 @@ class MarkupContainer { _onKeyDown(event) { const { target, keyCode, shiftKey } = event; - const isInput = this.markup._isInputOrTextarea(target); + const isInput = this.markup.isInputOrTextareaOrInCodeMirrorEditor(target); // Ignore all keystrokes that originated in editors except for when 'Tab' is // pressed.