tor-browser

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

commit ef9bbcbf3bf4fb7f33b7b34cc18ffba4e10fb864
parent 6b674e258cdcfc04dfcb9031dc7ce390e33fdc3e
Author: Hubert Boma Manilla <hmanilla@mozilla.com>
Date:   Wed,  1 Oct 2025 18:48:26 +0000

Bug 1978284 - [devtools] Migrate Source preview to Cm6 r=devtools-reviewers,nchevobbe,perftest-reviewers,tschuster,afinder

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

Diffstat:
Mdevtools/client/debugger/src/components/Editor/Editor.css | 20--------------------
Mdevtools/client/netmonitor/index.html | 2+-
Mdevtools/client/netmonitor/src/components/Toolbar.js | 2+-
Mdevtools/client/netmonitor/src/components/previews/SourcePreview.js | 123+++++++++++++++++++++++++++++++++----------------------------------------------
Mdevtools/client/netmonitor/src/components/request-details/RequestPanel.js | 5++++-
Mdevtools/client/netmonitor/src/components/request-details/ResponsePanel.js | 3+++
Mdevtools/client/netmonitor/test/browser_net_brotli.js | 2+-
Mdevtools/client/netmonitor/test/browser_net_chunked-response.js | 2+-
Mdevtools/client/netmonitor/test/browser_net_complex-params.js | 15++++++---------
Mdevtools/client/netmonitor/test/browser_net_content-type.js | 2+-
Mdevtools/client/netmonitor/test/browser_net_cyrillic-01.js | 2+-
Mdevtools/client/netmonitor/test/browser_net_cyrillic-02.js | 4++--
Mdevtools/client/netmonitor/test/browser_net_delayed-response.js | 5+----
Mdevtools/client/netmonitor/test/browser_net_json-b64.js | 4++--
Mdevtools/client/netmonitor/test/browser_net_json-empty.js | 7++-----
Mdevtools/client/netmonitor/test/browser_net_json-long.js | 4++--
Mdevtools/client/netmonitor/test/browser_net_json-malformed.js | 4++--
Mdevtools/client/netmonitor/test/browser_net_json-null.js | 14++++----------
Mdevtools/client/netmonitor/test/browser_net_json-numbers.js | 7++-----
Mdevtools/client/netmonitor/test/browser_net_json-xssi-protection.js | 22++++++++++------------
Mdevtools/client/netmonitor/test/browser_net_json_custom_mime.js | 4++--
Mdevtools/client/netmonitor/test/browser_net_json_text_mime.js | 4++--
Mdevtools/client/netmonitor/test/browser_net_jsonp.js | 6+++---
Mdevtools/client/netmonitor/test/browser_net_large-response.js | 6+++---
Mdevtools/client/netmonitor/test/browser_net_post-data-json-payloads.js | 6+++---
Mdevtools/client/netmonitor/test/browser_net_post-data-raw-payloads-with-upload-stream-headers.js | 4++--
Mdevtools/client/netmonitor/test/browser_net_post-data.js | 4++--
Mdevtools/client/netmonitor/test/browser_net_raw_response.js | 2+-
Mdevtools/client/netmonitor/test/browser_net_search-results.js | 8++++----
Mdevtools/client/netmonitor/test/browser_net_truncate-post-data.js | 8+++-----
Mdevtools/client/netmonitor/test/browser_net_zstd.js | 2+-
Mdevtools/client/netmonitor/test/head.js | 13++++++++-----
Mdevtools/client/shared/sourceeditor/codemirror/mozilla.css | 24+++++++++++++++++++++++-
Mdevtools/client/webconsole/index.html | 2+-
Mdevtools/client/webconsole/test/browser/browser_webconsole_network_messages_expand.js | 6+++---
Mdevtools/client/webconsole/test/browser/browser_webconsole_network_messages_expand_before_updates.js | 6+++---
Mdevtools/client/webconsole/test/browser/browser_webconsole_network_messages_html_preview.js | 2+-
Mdom/security/nsContentSecurityUtils.cpp | 2++
Mtesting/talos/talos/tests/devtools/addon/content/tests/netmonitor/netmonitor-helpers.js | 2+-
39 files changed, 165 insertions(+), 195 deletions(-)

diff --git a/devtools/client/debugger/src/components/Editor/Editor.css b/devtools/client/debugger/src/components/Editor/Editor.css @@ -7,7 +7,6 @@ --debug-line-error-border: rgb(255, 0, 0); --debug-expression-error-background: rgba(231, 116, 113, 0.3); --line-exception-background: hsl(344, 73%, 97%); - --highlight-line-duration: 5000ms; } .theme-dark .editor-wrapper { @@ -178,25 +177,6 @@ html[dir="rtl"] .editor-mount { .new-debug-line-error .CodeMirror-activeline-background { display: none; } -.highlight-line .CodeMirror-line, -/* For CM6 */ -.cm-editor .cm-line.highlight-line { - animation-name: fade-highlight-out; - animation-duration: var(--highlight-line-duration); - animation-timing-function: ease-out; - animation-fill-mode: forwards; -} - -@keyframes fade-highlight-out { - 0%, - 30% { - /* We want to use a color with some transparency so text selection is visible through it */ - background-color: var(--theme-contrast-background-alpha); - } - 100% { - background-color: transparent; - } -} .visible { visibility: visible; diff --git a/devtools/client/netmonitor/index.html b/devtools/client/netmonitor/index.html @@ -6,7 +6,7 @@ <head> <meta http-equiv="Content-Security-Policy" - content="default-src chrome: resource:; img-src chrome: resource: data:;" + content="default-src chrome: resource:; img-src chrome: resource: data:; style-src chrome: 'unsafe-inline';" /> <link rel="stylesheet" diff --git a/devtools/client/netmonitor/src/components/Toolbar.js b/devtools/client/netmonitor/src/components/Toolbar.js @@ -294,7 +294,7 @@ class Toolbar extends Component { onSearchBoxFocusKeyboardShortcut(event) { // Don't take focus when the keyboard shortcut is triggered in a CodeMirror instance, // so the CodeMirror search UI is displayed. - return !!event.target.closest(".CodeMirror"); + return !!event.target.closest(".cm-editor"); } onSearchBoxFocus() { diff --git a/devtools/client/netmonitor/src/components/previews/SourcePreview.js b/devtools/client/netmonitor/src/components/previews/SourcePreview.js @@ -31,12 +31,13 @@ class SourcePreview extends Component { // Reset target search result that has been used for navigation in this panel. // This is done to avoid second navigation the next time. resetTargetSearchResult: PropTypes.func, + url: PropTypes.string, }; } componentDidMount() { - const { mimeType, text } = this.props; - this.loadEditor(mimeType, text); + this.loadEditor(); + this.updateEditor(); } shouldComponentUpdate(nextProps) { @@ -48,11 +49,10 @@ class SourcePreview extends Component { } componentDidUpdate(prevProps) { - const { mimeType, targetSearchResult, text } = this.props; - + const { targetSearchResult, text } = this.props; if (prevProps.text !== text) { // When updating from editor to editor - this.updateEditor(mimeType, text); + this.updateEditor(); } else if (prevProps.targetSearchResult !== targetSearchResult) { this.findSearchResult(); } @@ -67,102 +67,88 @@ class SourcePreview extends Component { return Editor.modes[lang]; } - loadEditor(mimeType, text) { + loadEditor() { this.editor = new Editor({ + cm6: true, lineNumbers: true, lineWrapping: false, - mode: null, // Disable auto syntax detection, but then we set mode asynchronously + mode: null, // Disable auto syntax detection, but then we set the mode later readOnly: true, theme: "mozilla", - value: text, + value: "", }); - // Delay to CodeMirror initialization content to prevent UI freezing - this.editorTimeout = setTimeout(() => { - this.editorTimeout = null; - this.editor.appendToLocalElement(this.refs.editorElement); - - // CodeMirror's setMode() (syntax highlight) is the performance bottleneck when - // processing large content, so we enable it asynchronously within the setTimeout - // to avoid UI blocking. (rendering source code -> drawing syntax highlight) - this.editorSetModeTimeout = setTimeout(() => { - this.editorSetModeTimeout = null; - const mode = this.getSourceEditorModeForMimetype(mimeType); - this.editor.setMode(mode); - this.findSearchResult(); - }); - }); + this.editor.appendToLocalElement(this.refs.editorElement); + // Used for netmonitor tests + window.codeMirrorSourceEditorTestInstance = this.editor; } - updateEditor(mimeType, text) { - // Reset the existed 'mode' attribute in order to make setText() process faster - // to prevent drawing unnecessary syntax highlight. + async updateEditor() { + const { mimeType, text, url } = this.props; if (this?.editor?.hasCodeMirror) { - this.editor.setMode(null); - this.editor.setText(text); - } - - if (this.editorSetModeTimeout) { - clearTimeout(this.editorSetModeTimeout); - } - - // CodeMirror's setMode() (syntax highlight) is the performance bottleneck when - // processing large content, so we enable it asynchronously within the setTimeout - // to avoid UI blocking. (rendering source code -> drawing syntax highlight) - this.editorSetModeTimeout = setTimeout(() => { - this.editorSetModeTimeout = null; const mode = this.getSourceEditorModeForMimetype(mimeType); - this.editor.setMode(mode); - this.findSearchResult(); - }); + await this.editor.setMode(mode); + await this.editor.setText(text, url); + // When navigating from the netmonitor search, find and highlight the + // the current search result. + await this.findSearchResult(); + } } unloadEditor() { - clearTimeout(this.editorTimeout); - clearTimeout(this.editorSetModeTimeout); if (this.editor) { this.editor.destroy(); this.editor = null; } } - findSearchResult() { + async findSearchResult() { const { targetSearchResult, resetTargetSearchResult } = this.props; - if (targetSearchResult?.line) { const { line } = targetSearchResult; // scroll the editor to center the line // with the target search result if (this.editor) { - this.editor.setCursor({ line: line - 1 }, "center"); + await this.editor.scrollTo(line, 0); + await this.editor.setCursorAt(line - 1, 0); + + // Highlight line + this.editor.setLineContentMarker({ + id: this.editor.markerTypes.HIGHLIGHT_LINE_MARKER, + lineClassName: "highlight-line", + lines: [{ line }], + }); + this.clearHighlightLineAfterDuration(); } } resetTargetSearchResult(); } - // Scroll to specified line if the user clicks on search results. - scrollToLine(element) { - const { targetSearchResult, resetTargetSearchResult } = this.props; + clearHighlightLineAfterDuration() { + const editorContainer = document.querySelector(".editor-row-container"); - // The following code is responsible for scrolling given line - // to visible view-port. - // It gets the <div> child element representing the target - // line (by index) and uses `scrollIntoView` API to make sure - // it's visible to the user. - if (element && targetSearchResult && targetSearchResult.line) { - const child = element.children[targetSearchResult.line - 1]; - if (child) { - const range = document.createRange(); - range.selectNode(child); - document.getSelection().addRange(range); - child.scrollIntoView({ block: "center" }); - } - resetTargetSearchResult(); + if (editorContainer === null) { + return; } + + const duration = parseInt( + getComputedStyle(editorContainer).getPropertyValue( + "--highlight-line-duration" + ), + 10 + ); + + const highlightTimeout = setTimeout(() => { + if (!this.editor) { + return; + } + clearTimeout(highlightTimeout); + this.editor.removeLineContentMarker("highlight-line-marker"); + }, duration); } - renderEditor() { + render() { return div( { className: "editor-row-container" }, div({ @@ -171,13 +157,6 @@ class SourcePreview extends Component { }) ); } - - render() { - return div( - { key: "EDITOR_CONFIG", className: "editor-row-container" }, - this.renderEditor() - ); - } } module.exports = connect(null, dispatch => ({ diff --git a/devtools/client/netmonitor/src/components/request-details/RequestPanel.js b/devtools/client/netmonitor/src/components/request-details/RequestPanel.js @@ -189,7 +189,7 @@ class RequestPanel extends Component { render() { const { request, targetSearchResult } = this.props; const { filterText, rawRequestPayloadDisplayed } = this.state; - const { formDataSections, mimeType, requestPostData } = request; + const { formDataSections, mimeType, requestPostData, url } = request; const postData = requestPostData ? requestPostData.postData?.text : null; if ((!formDataSections || formDataSections.length === 0) && !postData) { @@ -212,6 +212,7 @@ class RequestPanel extends Component { filterText, targetSearchResult, defaultSelectFirstNode: false, + url, }; requestPayloadLabel = REQUEST_FORM_DATA; hasFormattedDisplay = true; @@ -242,6 +243,7 @@ class RequestPanel extends Component { filterText, targetSearchResult, defaultSelectFirstNode: false, + url, }; requestPayloadLabel = JSON_SCOPE_NAME; hasFormattedDisplay = true; @@ -258,6 +260,7 @@ class RequestPanel extends Component { text: postData, mimeType: mimeType?.replace(/;.+/, ""), targetSearchResult, + url, }; requestPayloadLabel = REQUEST_POST_PAYLOAD; } diff --git a/devtools/client/netmonitor/src/components/request-details/ResponsePanel.js b/devtools/client/netmonitor/src/components/request-details/ResponsePanel.js @@ -319,6 +319,7 @@ class ResponsePanel extends Component { defaultSelectFirstNode: false, mode: MODE.LONG, useBaseTreeViewExpand: true, + url, }; hasFormattedDisplay = true; } else if (Filters.html(this.props.request)) { @@ -334,6 +335,7 @@ class ResponsePanel extends Component { text, mimeType: json ? "application/json" : mimeType.replace(/;.+/, ""), targetSearchResult, + url, }; } return { @@ -344,6 +346,7 @@ class ResponsePanel extends Component { json, responsePayloadLabel, xssiStrippedCharsInfoBox, + url, }; } diff --git a/devtools/client/netmonitor/test/browser_net_brotli.js b/devtools/client/netmonitor/test/browser_net_brotli.js @@ -55,7 +55,7 @@ add_task(async function () { } ); - const wait = waitForDOM(document, ".CodeMirror-code"); + const wait = waitForDOM(document, ".cm-content"); const onResponseContent = monitor.panelWin.api.once( TEST_EVENTS.RECEIVED_RESPONSE_CONTENT ); diff --git a/devtools/client/netmonitor/test/browser_net_chunked-response.js b/devtools/client/netmonitor/test/browser_net_chunked-response.js @@ -85,7 +85,7 @@ add_task(async function () { info("Open the response panel and wait for initial chunk of the data"); const waitForResponsePanel = waitForDOM( document, - "#response-panel .CodeMirror-code" + "#response-panel .cm-content" ); store.dispatch(Actions.toggleNetworkDetails()); clickOnSidebarTab(document, "response"); diff --git a/devtools/client/netmonitor/test/browser_net_complex-params.js b/devtools/client/netmonitor/test/browser_net_complex-params.js @@ -146,7 +146,7 @@ async function testRequestWithFormattedView( "The request params box should be displayed." ); Assert.strictEqual( - tabpanel.querySelector(".CodeMirror-code"), + tabpanel.querySelector(".cm-content"), null, "The request post data editor should not be displayed." ); @@ -172,7 +172,7 @@ async function testRequestWithFormattedView( ); // Toggle the raw data display. This should hide the formatted display. - waitForContent = waitForDOM(document, "#request-panel .CodeMirror-code"); + waitForContent = waitForDOM(document, "#request-panel .cm-content"); let rawDataToggle = document.querySelector( "#request-panel .raw-data-toggle-input .devtools-checkbox-toggle" ); @@ -197,7 +197,7 @@ async function testRequestWithFormattedView( "The formatted display should be hidden." ); is( - tabpanel.querySelector(".CodeMirror-code") !== null, + tabpanel.querySelector(".cm-content") !== null, true, "The raw payload data display is shown." ); @@ -236,10 +236,7 @@ async function testRequestWithOnlyRawDataView( // Wait for header and CodeMirror editor to be displayed const wait = waitForDOM(document, "#request-panel .data-header"); - const waitForContent = waitForDOM( - document, - "#request-panel .CodeMirror-code" - ); + const waitForContent = waitForDOM(document, "#request-panel .cm-content"); EventUtils.sendMouseEvent({ type: "mousedown" }, requestListItem); await Promise.all([wait, waitForContent]); @@ -262,7 +259,7 @@ async function testRequestWithOnlyRawDataView( "The formatted display should be hidden." ); is( - tabpanel.querySelector(".CodeMirror-code") !== null, + tabpanel.querySelector(".cm-content") !== null, true, "The raw payload data display is shown." ); @@ -301,7 +298,7 @@ async function testRequestWithoutRequestData(monitor, requestListItem) { "The formatted display should be hidden." ); is( - tabpanel.querySelector(".CodeMirror-code") === null, + tabpanel.querySelector(".cm-content") === null, true, "The raw payload data display should be hidden." ); diff --git a/devtools/client/netmonitor/test/browser_net_content-type.js b/devtools/client/netmonitor/test/browser_net_content-type.js @@ -181,7 +181,7 @@ add_task(async function () { "The response json view doesn't display" ); is( - tabpanel.querySelector(".CodeMirror-code") === null, + tabpanel.querySelector(".cm-content") === null, box !== "textarea", "The response editor doesn't display" ); diff --git a/devtools/client/netmonitor/test/browser_net_cyrillic-01.js b/devtools/client/netmonitor/test/browser_net_cyrillic-01.js @@ -49,7 +49,7 @@ add_task(async function () { document.querySelectorAll(".request-list-item")[0] ); await wait; - wait = waitForDOM(document, "#response-panel .CodeMirror-code"); + wait = waitForDOM(document, "#response-panel .cm-content"); clickOnSidebarTab(document, "response"); await wait; diff --git a/devtools/client/netmonitor/test/browser_net_cyrillic-02.js b/devtools/client/netmonitor/test/browser_net_cyrillic-02.js @@ -56,7 +56,7 @@ add_task(async function () { clickOnSidebarTab(document, "response"); await wait; - wait = waitForDOM(document, "#response-panel .CodeMirror-code"); + wait = waitForDOM(document, "#response-panel .cm-content"); const header = document.querySelector( "#response-panel .raw-data-toggle-input .devtools-checkbox-toggle" ); @@ -65,7 +65,7 @@ add_task(async function () { // CodeMirror will only load lines currently in view to the DOM. getValue() // retrieves all lines pending render after a user begins scrolling. - const text = document.querySelector(".CodeMirror").CodeMirror.getValue(); + const text = getCodeMirrorValue(monitor); ok( text.includes("\u0411\u0440\u0430\u0442\u0430\u043d"), diff --git a/devtools/client/netmonitor/test/browser_net_delayed-response.js b/devtools/client/netmonitor/test/browser_net_delayed-response.js @@ -155,10 +155,7 @@ add_task(async function () { ); info("Open the response panel and wait for the response content"); - waitForResponsePanel = waitForDOM( - document, - "#response-panel .CodeMirror-code" - ); + waitForResponsePanel = waitForDOM(document, "#response-panel .cm-content"); clickOnSidebarTab(document, "response"); await waitForResponsePanel; diff --git a/devtools/client/netmonitor/test/browser_net_json-b64.js b/devtools/client/netmonitor/test/browser_net_json-b64.js @@ -59,7 +59,7 @@ add_task(async function () { ); // Open the response payload section, it should hide the json section - wait = waitForDOM(document, "#response-panel .CodeMirror-code"); + wait = waitForDOM(document, "#response-panel .cm-content"); const header = document.querySelector( "#response-panel .raw-data-toggle-input .devtools-checkbox-toggle" ); @@ -84,7 +84,7 @@ add_task(async function () { "The raw response toggle should be on." ); is( - tabpanel.querySelector(".CodeMirror-code") === null, + tabpanel.querySelector(".cm-content") === null, false, "The response editor has the intended visibility." ); diff --git a/devtools/client/netmonitor/test/browser_net_json-empty.js b/devtools/client/netmonitor/test/browser_net_json-empty.js @@ -33,10 +33,7 @@ add_task(async function () { await onResponsePanelReady; - const codeMirrorReady = waitForDOM( - document, - "#response-panel .CodeMirror-code" - ); + const codeMirrorReady = waitForDOM(document, "#response-panel .cm-content"); const header = document.querySelector( "#response-panel .raw-data-toggle-input .devtools-checkbox-toggle" @@ -58,7 +55,7 @@ add_task(async function () { "The response error header doesn't have the intended visibility." ); is( - tabpanel.querySelector(".CodeMirror-code") === null, + tabpanel.querySelector(".cm-content") === null, false, "The response editor has the intended visibility." ); diff --git a/devtools/client/netmonitor/test/browser_net_json-long.js b/devtools/client/netmonitor/test/browser_net_json-long.js @@ -78,7 +78,7 @@ add_task(async function () { testJsonInResposeTab(); - wait = waitForDOM(document, "#response-panel .CodeMirror-code"); + wait = waitForDOM(document, "#response-panel .cm-content"); const rawResponseToggle = document.querySelector( "#response-panel .raw-data-toggle-input .devtools-checkbox-toggle" ); @@ -146,7 +146,7 @@ add_task(async function () { "The source editor container has visible height." ); is( - tabpanel.querySelector(".CodeMirror-code") === null, + tabpanel.querySelector(".cm-content") === null, false, "The response editor has the intended visibility." ); diff --git a/devtools/client/netmonitor/test/browser_net_json-malformed.js b/devtools/client/netmonitor/test/browser_net_json-malformed.js @@ -47,7 +47,7 @@ add_task(async function () { } ); - const wait = waitForDOM(document, "#response-panel .CodeMirror-code"); + const wait = waitForDOM(document, "#response-panel .cm-content"); store.dispatch(Actions.toggleNetworkDetails()); clickOnSidebarTab(document, "response"); await wait; @@ -77,7 +77,7 @@ add_task(async function () { "The response json view doesn't have the intended visibility." ); is( - tabpanel.querySelector(".CodeMirror-code") === null, + tabpanel.querySelector(".cm-content") === null, false, "The response editor has the intended visibility." ); diff --git a/devtools/client/netmonitor/test/browser_net_json-null.js b/devtools/client/netmonitor/test/browser_net_json-null.js @@ -66,10 +66,7 @@ add_task(async function () { "The first json property value was incorrect." ); - const onCodeMirrorReady = waitForDOM( - document, - "#response-panel .CodeMirror-code" - ); + const onCodeMirrorReady = waitForDOM(document, "#response-panel .cm-content"); const rawResponseToggle = document.querySelector( "#response-panel .raw-data-toggle-input .devtools-checkbox-toggle" @@ -100,7 +97,7 @@ add_task(async function () { "The response json view has the intended visibility." ); is( - panel.querySelector(".CodeMirror-code") === null, + panel.querySelector(".cm-content") === null, false, "The response editor has the intended visibility." ); @@ -129,16 +126,13 @@ add_task(async function () { // Execute requests. await performRequests(monitor, tab, 1); - const onCodeMirrorReady = waitForDOM( - document, - "#response-panel .CodeMirror-code" - ); + const onCodeMirrorReady = waitForDOM(document, "#response-panel .cm-content"); store.dispatch(Actions.toggleNetworkDetails()); clickOnSidebarTab(document, "response"); const [codeMirrorCodeEl] = await onCodeMirrorReady; is( - codeMirrorCodeEl.querySelector("pre.CodeMirror-line span").textContent, + codeMirrorCodeEl.querySelector(".cm-line").textContent, "null", "root null JSON object is displayed in a CodeMirror editor" ); diff --git a/devtools/client/netmonitor/test/browser_net_json-numbers.js b/devtools/client/netmonitor/test/browser_net_json-numbers.js @@ -144,16 +144,13 @@ add_task(async function testLargeRootInteger() { await performRequests(monitor, tab, 1); - const onCodeMirrorReady = waitForDOM( - document, - "#response-panel .CodeMirror-code" - ); + const onCodeMirrorReady = waitForDOM(document, "#response-panel .cm-content"); store.dispatch(Actions.toggleNetworkDetails()); clickOnSidebarTab(document, "response"); const [codeMirrorCodeEl] = await onCodeMirrorReady; is( - codeMirrorCodeEl.querySelector("pre.CodeMirror-line span").textContent, + codeMirrorCodeEl.querySelector(".cm-line").textContent, "1516340399466235648", "Large number is displayed in a CodeMirror editor" ); diff --git a/devtools/client/netmonitor/test/browser_net_json-xssi-protection.js b/devtools/client/netmonitor/test/browser_net_json-xssi-protection.js @@ -23,45 +23,43 @@ add_task(async function () { await performRequests(monitor, tab, 1); const wait = waitForDOM(document, "#response-panel .data-header"); - const waitForRawView = waitForDOM( - document, - "#response-panel .CodeMirror-code", - 1 + const waitForRawView = waitForDOM(document, "#response-panel .cm-content", 1); + const waitForRawToggleOn = waitUntil( + () => + document.querySelector("#response-panel #raw-response-checkbox")?.checked ); store.dispatch(Actions.toggleNetworkDetails()); info("Opening response panel"); clickOnSidebarTab(document, "response"); - await Promise.all([wait, waitForRawView]); + await Promise.all([wait, waitForRawView, waitForRawToggleOn]); info( "making sure response panel defaults to raw view and correctly displays payload" ); - const codeLines = document.querySelector("#response-panel .CodeMirror-code"); + const codeLines = document.querySelector("#response-panel .cm-content"); const firstLine = codeLines.firstChild; - const firstLineText = firstLine.querySelector("pre.CodeMirror-line span"); is( - firstLineText.textContent, + firstLine.textContent, ")]}'", "XSSI protection sequence should be visibly in raw view" ); + info("making sure XSSI notification box is not present in raw view"); let notification = document.querySelector( '.network-monitor #response-panel .notification[data-key="xssi-string-removed-info-box"]' ); ok(!notification, "notification should not be present in raw view"); + info("switching to props view"); const waitForPropsView = waitForDOM( document, "#response-panel .properties-view", 1 ); - - info("switching to props view"); const tabpanel = document.querySelector("#response-panel"); - const rawResponseToggle = tabpanel.querySelector("#raw-response-checkbox"); - clickElement(rawResponseToggle, monitor); + clickElement(tabpanel.querySelector("#raw-response-checkbox"), monitor); await waitForPropsView; is( diff --git a/devtools/client/netmonitor/test/browser_net_json_custom_mime.js b/devtools/client/netmonitor/test/browser_net_json_custom_mime.js @@ -60,7 +60,7 @@ add_task(async function () { testJsonSectionInResponseTab(); - wait = waitForDOM(document, "#response-panel .CodeMirror-code"); + wait = waitForDOM(document, "#response-panel .cm-content"); const rawResponseToggle = document.querySelector( "#response-panel .raw-data-toggle-input .devtools-checkbox-toggle" ); @@ -115,7 +115,7 @@ add_task(async function () { "The raw response toggle should be on." ); is( - tabpanel.querySelector(".CodeMirror-code") === null, + tabpanel.querySelector(".cm-content") === null, false, "The response editor has the intended visibility." ); diff --git a/devtools/client/netmonitor/test/browser_net_json_text_mime.js b/devtools/client/netmonitor/test/browser_net_json_text_mime.js @@ -63,7 +63,7 @@ add_task(async function () { testJsonSectionInResponseTab(); - wait = waitForDOM(document, "#response-panel .CodeMirror-code"); + wait = waitForDOM(document, "#response-panel .cm-content"); const rawResponseToggle = document.querySelector( "#response-panel .raw-data-toggle-input .devtools-checkbox-toggle" ); @@ -120,7 +120,7 @@ add_task(async function () { "The response json view has the intended visibility." ); is( - tabpanel.querySelector(".CodeMirror-code") === null, + tabpanel.querySelector(".cm-content") === null, false, "The response editor has the intended visibility." ); diff --git a/devtools/client/netmonitor/test/browser_net_jsonp.js b/devtools/client/netmonitor/test/browser_net_jsonp.js @@ -80,7 +80,7 @@ add_task(async function () { testJsonSectionInResponseTab(`"Hello JSONP!"`); - wait = waitForDOM(document, "#response-panel .CodeMirror-code"); + wait = waitForDOM(document, "#response-panel .cm-content"); let rawResponseToggle = document.querySelector( "#response-panel .raw-data-toggle-input .devtools-checkbox-toggle" ); @@ -113,7 +113,7 @@ add_task(async function () { testJsonSectionInResponseTab(`"Hello weird JSONP!"`); - wait = waitForDOM(document, "#response-panel .CodeMirror-code"); + wait = waitForDOM(document, "#response-panel .cm-content"); rawResponseToggle = document.querySelector( "#response-panel .raw-data-toggle-input .devtools-checkbox-toggle" ); @@ -161,7 +161,7 @@ add_task(async function () { "The response json view has the intened visibility and correct title." ); is( - tabpanel.querySelector(".CodeMirror-code") === null, + tabpanel.querySelector(".cm-content") === null, false, "The response editor has the intended visibility." ); diff --git a/devtools/client/netmonitor/test/browser_net_large-response.js b/devtools/client/netmonitor/test/browser_net_large-response.js @@ -61,7 +61,7 @@ add_task(async function () { clickOnSidebarTab(document, "response"); await wait; - wait = waitForDOM(document, "#response-panel .CodeMirror-code"); + wait = waitForDOM(document, "#response-panel .cm-content"); const payloadHeader = document.querySelector( "#response-panel .raw-data-toggle-input .devtools-checkbox-toggle" ); @@ -74,10 +74,10 @@ add_task(async function () { ); info("Check that search input can be displayed"); - document.querySelector(".CodeMirror").CodeMirror.focus(); + getCMEditor(monitor).focus(); synthesizeKeyShortcut("CmdOrCtrl+F"); const searchInput = await waitFor(() => - document.querySelector(".CodeMirror input[type=search]") + document.querySelector(".cm-editor input[type=search]") ); Assert.equal( searchInput.ownerDocument.activeElement, diff --git a/devtools/client/netmonitor/test/browser_net_post-data-json-payloads.js b/devtools/client/netmonitor/test/browser_net_post-data-json-payloads.js @@ -40,7 +40,7 @@ add_task(async function () { "The request params doesn't have the indended visibility." ); is( - tabpanel.querySelector(".CodeMirror-code") === null, + tabpanel.querySelector(".cm-content") === null, true, "The request post data doesn't have the indended visibility." ); @@ -68,7 +68,7 @@ add_task(async function () { is(values[0].textContent, "1", "The JSON var value was incorrect."); // Toggle the raw data display. This should hide the formatted display. - waitForContent = waitForDOM(document, "#request-panel .CodeMirror-code"); + waitForContent = waitForDOM(document, "#request-panel .cm-content"); const rawDataToggle = document.querySelector( "#request-panel .raw-data-toggle-input .devtools-checkbox-toggle" ); @@ -93,7 +93,7 @@ add_task(async function () { ); // Bug 1514750 - Show JSON request in plain text view also ok( - tabpanel.querySelector(".CodeMirror-code"), + tabpanel.querySelector(".cm-content"), "The request post data doesn't have the indended visibility." ); ok( diff --git a/devtools/client/netmonitor/test/browser_net_post-data-raw-payloads-with-upload-stream-headers.js b/devtools/client/netmonitor/test/browser_net_post-data-raw-payloads-with-upload-stream-headers.js @@ -185,14 +185,14 @@ add_task(async function () { tabpanel.querySelector(".data-label").textContent == L10N.getStr("paramsPostPayload") && tabpanel.querySelector( - ".panel-container .editor-row-container .CodeMirror-code" + ".panel-container .editor-row-container .cm-content" ) ); // Check that the expected header lines are included in the codemirror // text. const actualText = tabpanel.querySelector( - ".panel-container .editor-row-container .CodeMirror-code" + ".panel-container .editor-row-container .cm-content" ).textContent; const requestPayloadIsCorrect = expected.requestPanelPayload.every( content => actualText.includes(content) diff --git a/devtools/client/netmonitor/test/browser_net_post-data.js b/devtools/client/netmonitor/test/browser_net_post-data.js @@ -88,7 +88,7 @@ add_task(async function () { const waitForHeader = waitForDOM(document, "#request-panel .data-header"); const waitForSourceEditor = waitForDOM( document, - "#request-panel .CodeMirror-code" + "#request-panel .cm-content" ); EventUtils.sendMouseEvent( { type: "mousedown" }, @@ -104,7 +104,7 @@ add_task(async function () { function checkVisibility(box) { is( - tabpanel.querySelector(".CodeMirror-code") === null, + tabpanel.querySelector(".cm-content") === null, !box.includes("editor"), "The request post data doesn't have the intended visibility." ); diff --git a/devtools/client/netmonitor/test/browser_net_raw_response.js b/devtools/client/netmonitor/test/browser_net_raw_response.js @@ -143,7 +143,7 @@ function getRawResponseToggle(doc) { } function getRawResponseCodeMirrorElement(doc) { - return doc.querySelector("#response-panel .CodeMirror"); + return doc.querySelector("#response-panel .cm-editor"); } function getHtmlPreviewElement(doc) { diff --git a/devtools/client/netmonitor/test/browser_net_search-results.js b/devtools/client/netmonitor/test/browser_net_search-results.js @@ -104,8 +104,8 @@ add_task(async function () { monitor, matches[4], "#response-panel", - ".CodeMirror-code", - ".CodeMirror-activeline", + ".cm-content", + ".cm-line", [SEARCH_STRING] ); await checkSearchResult( @@ -160,8 +160,8 @@ add_task(async function () { monitor, matches[11], "#response-panel", - ".CodeMirror-code", - ".CodeMirror-activeline", + ".cm-content", + ".cm-line", [SEARCH_STRING] ); diff --git a/devtools/client/netmonitor/test/browser_net_truncate-post-data.js b/devtools/client/netmonitor/test/browser_net_truncate-post-data.js @@ -70,10 +70,7 @@ async function checkPostDataRequest(expectErrorDisplay) { // Make sure the header and editor are loaded const waitHeader = waitForDOM(document, "#request-panel .data-header"); - const waitSourceEditor = waitForDOM( - document, - "#request-panel .CodeMirror.cm-s-mozilla" - ); + const waitSourceEditor = waitForDOM(document, "#request-panel .cm-editor"); store.dispatch(Actions.toggleNetworkDetails()); clickOnSidebarTab(document, "request"); @@ -99,8 +96,9 @@ async function checkPostDataRequest(expectErrorDisplay) { false, "The params json view doesn't have the intended visibility." ); + is( - tabpanel.querySelector("PRE") === null, + tabpanel.querySelector(".cm-editor") === null, false, "The Request Payload has the intended visibility." ); diff --git a/devtools/client/netmonitor/test/browser_net_zstd.js b/devtools/client/netmonitor/test/browser_net_zstd.js @@ -55,7 +55,7 @@ add_task(async function () { } ); - const wait = waitForDOM(document, ".CodeMirror-code"); + const wait = waitForDOM(document, ".cm-content"); const onResponseContent = monitor.panelWin.api.once( TEST_EVENTS.RECEIVED_RESPONSE_CONTENT ); diff --git a/devtools/client/netmonitor/test/head.js b/devtools/client/netmonitor/test/head.js @@ -1157,9 +1157,9 @@ async function selectIndexAndWaitForSourceEditor(monitor, index) { document.querySelectorAll(".request-list-item")[index] ); // We may already be on the ResponseTab, so only select it if needed. - const editor = document.querySelector("#response-panel .CodeMirror-code"); + const editor = document.querySelector("#response-panel .cm-content"); if (!editor) { - const waitDOM = waitForDOM(document, "#response-panel .CodeMirror-code"); + const waitDOM = waitForDOM(document, "#response-panel .cm-content"); document.querySelector("#response-tab").click(); await waitDOM; } @@ -1181,12 +1181,15 @@ async function performRequests(monitor, tab, count) { await wait; } +function getCMEditor(monitor) { + return monitor.panelWin.codeMirrorSourceEditorTestInstance; +} + /** - * Helper function for retrieving `.CodeMirror` content + * Helper function for retrieving the editor content */ function getCodeMirrorValue(monitor) { - const { document } = monitor.panelWin; - return document.querySelector(".CodeMirror")?.CodeMirror.getValue(); + return getCMEditor(monitor).getText(); } /** diff --git a/devtools/client/shared/sourceeditor/codemirror/mozilla.css b/devtools/client/shared/sourceeditor/codemirror/mozilla.css @@ -8,7 +8,7 @@ --breakpoint-active-color-hover: light-dark(rgba(44,187,15,.5), rgba(0,255,175,.7);); --gutter-background-color: var(--theme-sidebar-background); --gutter-border-color: light-dark(var(--theme-splitter-color), var(--theme-toolbar-background)); - + --highlight-line-duration: 5000ms; &[forced-colors-active] { /* overriding variable in HCM so the border is actually visible (see Bug 1953376) */ --gutter-border-color: var(--theme-splitter-color); @@ -461,6 +461,7 @@ /* We don't want forced colors on selection so we can adjust the colors as we want. This especially helps for the unfocused selected text */ forced-color-adjust: none; + color: inherit; } .cm-editor .cm-line ::selection { @@ -527,3 +528,24 @@ color: currentColor; } } + +.highlight-line .CodeMirror-line, +/* For CM6 */ +.cm-editor .cm-line.highlight-line { + animation-name: fade-highlight-out; + animation-duration: var(--highlight-line-duration); + animation-timing-function: ease-out; + animation-fill-mode: forwards; +} + +@keyframes fade-highlight-out { + + 0%, + 30% { + /* We want to use a color with some transparency so text selection is visible through it */ + background-color: var(--theme-contrast-background-alpha); + } + 100% { + background-color: transparent; + } +} diff --git a/devtools/client/webconsole/index.html b/devtools/client/webconsole/index.html @@ -14,7 +14,7 @@ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-Security-Policy" - content="default-src chrome: resource:; img-src chrome: resource: data:;" + content="default-src chrome: resource:; img-src chrome: resource: data:; style-src chrome: 'unsafe-inline';" /> <link rel="stylesheet" href="chrome://global/skin/global.css" /> <link rel="stylesheet" href="chrome://devtools/skin/webconsole.css" /> diff --git a/devtools/client/webconsole/test/browser/browser_webconsole_network_messages_expand.js b/devtools/client/webconsole/test/browser/browser_webconsole_network_messages_expand.js @@ -164,7 +164,7 @@ async function testRequest(messageNode) { const requestPanel = messageNode.querySelector("#request-panel"); await waitForSourceEditor(requestPanel); const requestContent = requestPanel.querySelector( - ".panel-container .CodeMirror" + ".panel-container .cm-editor" ); ok(requestContent, "Request content is available"); ok( @@ -184,7 +184,7 @@ async function testResponse(messageNode) { const responsePanel = messageNode.querySelector("#response-panel"); await waitForSourceEditor(responsePanel); const responseContent = messageNode.querySelector( - "#response-panel .editor-row-container .CodeMirror" + "#response-panel .editor-row-container .cm-editor" ); ok(responseContent, "Response content is available"); ok(responseContent.textContent, "Response text is available"); @@ -241,7 +241,7 @@ async function waitForPayloadReady(hud) { async function waitForSourceEditor(panel) { return waitUntil(() => { - return !!panel.querySelector(".CodeMirror"); + return !!panel.querySelector(".cm-editor"); }); } diff --git a/devtools/client/webconsole/test/browser/browser_webconsole_network_messages_expand_before_updates.js b/devtools/client/webconsole/test/browser/browser_webconsole_network_messages_expand_before_updates.js @@ -196,7 +196,7 @@ async function testRequest(messageNode) { const requestPanel = messageNode.querySelector("#request-panel"); await waitForSourceEditor(requestPanel); const requestContent = requestPanel.querySelector( - ".panel-container .CodeMirror" + ".panel-container .cm-content" ); ok(requestContent, "Request content is available"); ok( @@ -232,7 +232,7 @@ async function testResponse(messageNode) { } await waitForSourceEditor(responsePanel); const responseContent = messageNode.querySelector( - "#response-panel .editor-row-container .CodeMirror" + "#response-panel .editor-row-container .cm-content" ); ok(responseContent, "Response content is available"); ok(responseContent.textContent, "Response text is available"); @@ -300,7 +300,7 @@ async function testSecurity(messageNode) { async function waitForSourceEditor(panel) { return waitUntil(() => { - return !!panel.querySelector(".CodeMirror"); + return !!panel.querySelector(".cm-content"); }); } diff --git a/devtools/client/webconsole/test/browser/browser_webconsole_network_messages_html_preview.js b/devtools/client/webconsole/test/browser/browser_webconsole_network_messages_html_preview.js @@ -162,7 +162,7 @@ async function expandNetworkRequestAndWaitForHtmlView({ const rawToggleEl = node.querySelector(".devtools-checkbox-toggle"); ok(!rawToggleEl.checked, "Raw toggle isn't checked by default"); rawToggleEl.click(); - await waitFor(() => node.querySelector(".CodeMirror")); + await waitFor(() => node.querySelector(".cm-editor")); ok(true, "The CodeMirror instance is rendered"); } diff --git a/dom/security/nsContentSecurityUtils.cpp b/dom/security/nsContentSecurityUtils.cpp @@ -1288,8 +1288,10 @@ static nsLiteralCString sStyleSrcUnsafeInlineAllowList[] = { "chrome://devtools/content/framework/toolbox-window.xhtml"_ns, "chrome://devtools/content/inspector/index.xhtml"_ns, "chrome://devtools/content/inspector/markup/markup.xhtml"_ns, + "chrome://devtools/content/netmonitor/index.html"_ns, "chrome://devtools/content/memory/index.xhtml"_ns, "chrome://devtools/content/shared/sourceeditor/codemirror/cmiframe.html"_ns, + "chrome://devtools/content/webconsole/index.html"_ns, "chrome://formautofill/content/manageAddresses.xhtml"_ns, "chrome://formautofill/content/manageCreditCards.xhtml"_ns, "chrome://gfxsanity/content/sanityparent.html"_ns, diff --git a/testing/talos/talos/tests/devtools/addon/content/tests/netmonitor/netmonitor-helpers.js b/testing/talos/talos/tests/devtools/addon/content/tests/netmonitor/netmonitor-helpers.js @@ -218,7 +218,7 @@ exports.openResponseDetailsPanel = async function (label, toolbox) { const request = document.querySelectorAll(".request-list-item")[0]; const waitForEditor = waitForDOMElement( monitor, - "#response-panel .CodeMirror.cm-s-mozilla" + "#response-panel .cm-editor" ); mouseDownElement(request, win); await waitForEditor;