diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:35:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:35:49 +0000 |
commit | d8bbc7858622b6d9c278469aab701ca0b609cddf (patch) | |
tree | eff41dc61d9f714852212739e6b3738b82a2af87 /devtools/client | |
parent | Releasing progress-linux version 125.0.3-1~progress7.99u1. (diff) | |
download | firefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.tar.xz firefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.zip |
Merging upstream version 126.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/client')
140 files changed, 1475 insertions, 494 deletions
diff --git a/devtools/client/aboutdebugging/initializer.js b/devtools/client/aboutdebugging/initializer.js index a541df46b9..46c9b63893 100644 --- a/devtools/client/aboutdebugging/initializer.js +++ b/devtools/client/aboutdebugging/initializer.js @@ -4,8 +4,8 @@ "use strict"; -const { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" +const { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); const { require } = BrowserLoader({ baseURI: "resource://devtools/client/aboutdebugging/", diff --git a/devtools/client/aboutdebugging/src/modules/extensions-helper.js b/devtools/client/aboutdebugging/src/modules/extensions-helper.js index cf6c7641e9..03831939d0 100644 --- a/devtools/client/aboutdebugging/src/modules/extensions-helper.js +++ b/devtools/client/aboutdebugging/src/modules/extensions-helper.js @@ -42,7 +42,7 @@ exports.getExtensionUuid = function (extension) { * The window object where the filepicker should be opened. * Note: We cannot use the global window object here because it is undefined if * this module is loaded from a file outside of devtools/client/aboutdebugging/. - * See browser-loader.js `uri.startsWith(baseURI)` for more details. + * See browser-loader.sys.mjs `uri.startsWith(baseURI)` for more details. * @param {String} message * The help message that should be displayed to the user in the filepicker. * @return {Promise} returns a promise that resolves a File object corresponding to the diff --git a/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_addons_manifest_url.js b/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_addons_manifest_url.js index 6420a076b0..a4da406a6b 100644 --- a/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_addons_manifest_url.js +++ b/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_addons_manifest_url.js @@ -7,7 +7,7 @@ const { adbAddon, } = require("resource://devtools/client/shared/remote-debugging/adb/adb-addon.js"); -const ABD_ADDON_NAME = "ADB binary provider"; +const ABD_ADDON_NAME = "Firefox DevTools ADB Extension"; /* import-globals-from helper-adb.js */ Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "helper-adb.js", this); diff --git a/devtools/client/aboutdebugging/test/browser/resources/test-adb-extension/adb-extension-linux.xpi b/devtools/client/aboutdebugging/test/browser/resources/test-adb-extension/adb-extension-linux.xpi Binary files differindex 56054c341c..2e0b115665 100644 --- a/devtools/client/aboutdebugging/test/browser/resources/test-adb-extension/adb-extension-linux.xpi +++ b/devtools/client/aboutdebugging/test/browser/resources/test-adb-extension/adb-extension-linux.xpi diff --git a/devtools/client/aboutdebugging/test/browser/resources/test-adb-extension/adb-extension-linux64.xpi b/devtools/client/aboutdebugging/test/browser/resources/test-adb-extension/adb-extension-linux64.xpi Binary files differindex 9cd737b017..8065f96de4 100644 --- a/devtools/client/aboutdebugging/test/browser/resources/test-adb-extension/adb-extension-linux64.xpi +++ b/devtools/client/aboutdebugging/test/browser/resources/test-adb-extension/adb-extension-linux64.xpi diff --git a/devtools/client/aboutdebugging/test/browser/resources/test-adb-extension/adb-extension-mac64.xpi b/devtools/client/aboutdebugging/test/browser/resources/test-adb-extension/adb-extension-mac64.xpi Binary files differindex 5af9bc963d..d6ecd43957 100644 --- a/devtools/client/aboutdebugging/test/browser/resources/test-adb-extension/adb-extension-mac64.xpi +++ b/devtools/client/aboutdebugging/test/browser/resources/test-adb-extension/adb-extension-mac64.xpi diff --git a/devtools/client/aboutdebugging/test/browser/resources/test-adb-extension/adb-extension-win32.xpi b/devtools/client/aboutdebugging/test/browser/resources/test-adb-extension/adb-extension-win32.xpi Binary files differindex 0c10c8502c..95d5c6485f 100644 --- a/devtools/client/aboutdebugging/test/browser/resources/test-adb-extension/adb-extension-win32.xpi +++ b/devtools/client/aboutdebugging/test/browser/resources/test-adb-extension/adb-extension-win32.xpi diff --git a/devtools/client/accessibility/main.js b/devtools/client/accessibility/main.js index c658d05825..bbfae3462a 100644 --- a/devtools/client/accessibility/main.js +++ b/devtools/client/accessibility/main.js @@ -3,8 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -const { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" +const { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); // Module Loader diff --git a/devtools/client/accessibility/test/chrome/head.js b/devtools/client/accessibility/test/chrome/head.js index a1a02df8a8..2bd03d53c6 100644 --- a/devtools/client/accessibility/test/chrome/head.js +++ b/devtools/client/accessibility/test/chrome/head.js @@ -8,8 +8,8 @@ var { require } = ChromeUtils.importESModule( "resource://devtools/shared/loader/Loader.sys.mjs" ); -var { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" +var { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); var DevToolsUtils = require("resource://devtools/shared/DevToolsUtils.js"); diff --git a/devtools/client/application/initializer.js b/devtools/client/application/initializer.js index c431945bf0..06caa9d169 100644 --- a/devtools/client/application/initializer.js +++ b/devtools/client/application/initializer.js @@ -4,8 +4,8 @@ "use strict"; -const { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" +const { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); const require = BrowserLoader({ baseURI: "resource://devtools/client/application/", diff --git a/devtools/client/debugger/index.html b/devtools/client/debugger/index.html index 0a7ef58d8e..108fe5a653 100644 --- a/devtools/client/debugger/index.html +++ b/devtools/client/debugger/index.html @@ -55,8 +55,8 @@ ></script> <script> try { - const { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" + const { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); const { require } = BrowserLoader({ baseURI: "resource://devtools/client/debugger", diff --git a/devtools/client/debugger/src/.eslintrc.js b/devtools/client/debugger/src/.eslintrc.js index ec6d77b504..67f317ea28 100644 --- a/devtools/client/debugger/src/.eslintrc.js +++ b/devtools/client/debugger/src/.eslintrc.js @@ -251,8 +251,9 @@ module.exports = { // Disallow unreachable statements after a return, throw, continue, or break // statement. "no-unreachable": 2, - // Disallow global and local variables that arent used, but allow unused function arguments. - "no-unused-vars": [2, { vars: "all", args: "none" }], + // Disallow global and local variables that arent used. Allow unused function arguments + // that are prefixed with `_`. + "no-unused-vars": [2, { vars: "all", argsIgnorePattern: "^_" }], // Allow using variables before they are defined. "no-use-before-define": 0, // We use var-only-at-top-level instead of no-var as we allow top level diff --git a/devtools/client/debugger/src/actions/context-menus/editor.js b/devtools/client/debugger/src/actions/context-menus/editor.js index 1cad1e2131..4785c963cb 100644 --- a/devtools/client/debugger/src/actions/context-menus/editor.js +++ b/devtools/client/debugger/src/actions/context-menus/editor.js @@ -73,7 +73,7 @@ export function showEditorContextMenu(event, editor, location) { }; } -export function showEditorGutterContextMenu(event, editor, location, lineText) { +export function showEditorGutterContextMenu(event, line, location, lineText) { return async ({ dispatch, getState }) => { const { source } = location; const state = getState(); @@ -90,7 +90,7 @@ export function showEditorGutterContextMenu(event, editor, location, lineText) { { type: "separator" }, blackBoxLineMenuItem( source, - editor, + line, blackboxedRanges, isSourceOnIgnoreList, location.line, @@ -178,7 +178,7 @@ const blackBoxMenuItem = ( const blackBoxLineMenuItem = ( selectedSource, - editor, + { from, to }, blackboxedRanges, isSourceOnIgnoreList, // the clickedLine is passed when the context menu @@ -187,10 +187,6 @@ const blackBoxLineMenuItem = ( clickedLine = null, dispatch ) => { - const { codeMirror } = editor; - const from = codeMirror.getCursor("from"); - const to = codeMirror.getCursor("to"); - const startLine = clickedLine ?? toSourceLine(selectedSource.id, from.line); const endLine = clickedLine ?? toSourceLine(selectedSource.id, to.line); @@ -251,16 +247,12 @@ const blackBoxLineMenuItem = ( const blackBoxLinesMenuItem = ( selectedSource, - editor, + { from, to }, blackboxedRanges, isSourceOnIgnoreList, clickedLine, dispatch ) => { - const { codeMirror } = editor; - const from = codeMirror.getCursor("from"); - const to = codeMirror.getCursor("to"); - const startLine = toSourceLine(selectedSource.id, from.line); const endLine = toSourceLine(selectedSource.id, to.line); @@ -408,7 +400,10 @@ function editorMenuItems({ items.push( blackBoxSourceLinesMenuItem( source, - editor, + { + from: editor.codeMirror.getCursor("from"), + to: editor.codeMirror.getCursor("to"), + }, blackboxedRanges, isSourceOnIgnoreList, null, diff --git a/devtools/client/debugger/src/components/Editor/Breakpoint.js b/devtools/client/debugger/src/components/Editor/Breakpoint.js index 4559a20289..40de6d47c7 100644 --- a/devtools/client/debugger/src/components/Editor/Breakpoint.js +++ b/devtools/client/debugger/src/components/Editor/Breakpoint.js @@ -59,7 +59,7 @@ class Breakpoint extends PureComponent { selectedSource, } = this.props; - // ignore right clicks + // ignore ctrl + click and right clicks when clicking on the breakpoint if ((event.ctrlKey && event.button === 0) || event.button === 2) { return; } diff --git a/devtools/client/debugger/src/components/Editor/Breakpoints.css b/devtools/client/debugger/src/components/Editor/Breakpoints.css index 1269f73f82..92121e0f46 100644 --- a/devtools/client/debugger/src/components/Editor/Breakpoints.css +++ b/devtools/client/debugger/src/components/Editor/Breakpoints.css @@ -36,7 +36,7 @@ pointer-events: none; } -.editor-wrapper :not(.empty-line, .new-breakpoint) +.editor-wrapper :not(.empty-line, .new-breakpoint .cm6-gutter-breakpoint) > .CodeMirror-gutter-wrapper > .CodeMirror-linenumber:hover::after { content: ""; @@ -55,6 +55,27 @@ mask-position: right; } +/* Codemirror 6*/ +.cm6-gutter-breakpoint .breakpoint-marker svg { + fill: var(--breakpoint-fill); + stroke: var(--breakpoint-stroke); + height: 14px; + position: absolute; + right: -8px; + z-index: -99; +} + +/* set the linenumber white when there is a breakpoint */ +.editor-wrapper:not(.skip-pausing) .new-breakpoint .CodeMirror-gutter-wrapper .CodeMirror-linenumber, + .editor-wrapper:not(.skip-pausing) .cm6-gutter-breakpoint { + color: white; +} + +/* move the breakpoint below the other gutter elements */ +.new-breakpoint .CodeMirror-gutter-elt:nth-child(2) { + z-index: 0; +} + .editor.new-breakpoint svg { fill: var(--breakpoint-fill); stroke: var(--breakpoint-stroke); @@ -85,7 +106,9 @@ } .editor.new-breakpoint.breakpoint-disabled svg, -.blackboxed-line .editor.new-breakpoint svg { +.blackboxed-line .editor.new-breakpoint svg, +.cm6-gutter-breakpoint .breakpoint-marker.breakpoint-disabled svg, +.cm6-gutter-breakpoint.blackboxed-line .breakpoint-marker svg { fill-opacity: var(--breakpoint-disabled-opacity); stroke-opacity: var(--breakpoint-disabled-opacity); } diff --git a/devtools/client/debugger/src/components/Editor/Breakpoints.js b/devtools/client/debugger/src/components/Editor/Breakpoints.js index 6d1d088f11..ac3fe0890c 100644 --- a/devtools/client/debugger/src/components/Editor/Breakpoints.js +++ b/devtools/client/debugger/src/components/Editor/Breakpoints.js @@ -11,9 +11,31 @@ import { getSelectedSource, getFirstVisibleBreakpoints, } from "../../selectors/index"; +import { getSelectedLocation } from "../../utils/selected-location"; import { makeBreakpointId } from "../../utils/breakpoint/index"; import { connect } from "devtools/client/shared/vendor/react-redux"; +import { fromEditorLine } from "../../utils/editor/index"; import actions from "../../actions/index"; +import { features } from "../../utils/prefs"; +const classnames = require("resource://devtools/client/shared/classnames.js"); + +const isMacOS = Services.appinfo.OS === "Darwin"; + +const breakpointSvg = document.createElement("div"); +const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); +svg.setAttribute("viewBox", "0 0 60 15"); +svg.setAttribute("width", 60); +svg.setAttribute("height", 15); + +const path = document.createElementNS("http://www.w3.org/2000/svg", "path"); +path.setAttributeNS( + null, + "d", + "M53.07.5H1.5c-.54 0-1 .46-1 1v12c0 .54.46 1 1 1h51.57c.58 0 1.15-.26 1.53-.7l4.7-6.3-4.7-6.3c-.38-.44-.95-.7-1.53-.7z" +); + +svg.appendChild(path); +breakpointSvg.appendChild(svg); class Breakpoints extends Component { static get propTypes() { @@ -27,6 +49,93 @@ class Breakpoints extends Component { showEditorEditBreakpointContextMenu: PropTypes.func, }; } + + constructor(props) { + super(props); + } + + componentDidUpdate() { + const { selectedSource, breakpoints, editor } = this.props; + + // Only for codemirror 6 + if (!features.codemirrorNext) { + return; + } + + if (!selectedSource || !breakpoints || !editor) { + return; + } + + const markers = [ + { + id: "gutter-breakpoint-marker", + lineClassName: "cm6-gutter-breakpoint", + condition: line => { + const lineNumber = fromEditorLine(selectedSource.id, line); + return breakpoints.some(bp => bp.location.line === lineNumber); + }, + createLineElementNode: line => { + const lineNumber = fromEditorLine(selectedSource.id, line); + const breakpoint = breakpoints.find( + bp => bp.location.line === lineNumber + ); + + const breakpointNode = breakpointSvg.cloneNode(true); + breakpointNode.appendChild(document.createTextNode(lineNumber)); + breakpointNode.className = classnames("breakpoint-marker", { + "breakpoint-disabled": breakpoint.disabled, + "has-condition": breakpoint?.options.condition, + "has-log": breakpoint?.options.logValue, + }); + breakpointNode.onclick = event => this.onClick(event, breakpoint); + breakpointNode.oncontextmenu = event => + this.onContextMenu(event, breakpoint); + return breakpointNode; + }, + }, + ]; + editor.setLineGutterMarkers(markers); + } + + onClick = (event, breakpoint) => { + const { + continueToHere, + toggleBreakpointsAtLine, + removeBreakpointsAtLine, + selectedSource, + } = this.props; + + event.stopPropagation(); + event.preventDefault(); + + // ignore right clicks when clicking on the breakpoint + if (event.button === 2) { + return; + } + + const selectedLocation = getSelectedLocation(breakpoint, selectedSource); + const ctrlOrCmd = isMacOS ? event.metaKey : event.ctrlKey; + + if (ctrlOrCmd) { + continueToHere(selectedLocation); + return; + } + + if (event.shiftKey) { + toggleBreakpointsAtLine(!breakpoint.disabled, selectedLocation.line); + return; + } + + removeBreakpointsAtLine(selectedLocation.source, selectedLocation.line); + }; + + onContextMenu = (event, breakpoint) => { + event.stopPropagation(); + event.preventDefault(); + + this.props.showEditorEditBreakpointContextMenu(event, breakpoint); + }; + render() { const { breakpoints, @@ -41,6 +150,11 @@ class Breakpoints extends Component { if (!selectedSource || !breakpoints) { return null; } + + if (features.codemirrorNext) { + return null; + } + return div( null, breakpoints.map(breakpoint => { diff --git a/devtools/client/debugger/src/components/Editor/DebugLine.js b/devtools/client/debugger/src/components/Editor/DebugLine.js index 1b8e59ba64..61caae69a5 100644 --- a/devtools/client/debugger/src/components/Editor/DebugLine.js +++ b/devtools/client/debugger/src/components/Editor/DebugLine.js @@ -6,6 +6,7 @@ import { PureComponent } from "devtools/client/shared/vendor/react"; import PropTypes from "devtools/client/shared/vendor/react-prop-types"; import { toEditorPosition, + fromEditorLine, getDocument, hasDocument, startOperation, @@ -21,12 +22,16 @@ import { getSourceTextContent, getCurrentThread, } from "../../selectors/index"; +import { isWasm } from "../../utils/wasm"; +import { features } from "../../utils/prefs"; export class DebugLine extends PureComponent { debugExpression; static get propTypes() { return { + editor: PropTypes.object, + selectedSource: PropTypes.object, location: PropTypes.object, why: PropTypes.object, }; @@ -34,21 +39,62 @@ export class DebugLine extends PureComponent { componentDidMount() { const { why, location } = this.props; + if (features.codemirrorNext) { + return; + } this.setDebugLine(why, location); } componentWillUnmount() { const { why, location } = this.props; + if (features.codemirrorNext) { + return; + } this.clearDebugLine(why, location); } componentDidUpdate(prevProps) { - const { why, location } = this.props; - - startOperation(); - this.clearDebugLine(prevProps.why, prevProps.location); - this.setDebugLine(why, location); - endOperation(); + const { why, location, editor, selectedSource } = this.props; + + if (features.codemirrorNext) { + if (!selectedSource) { + return; + } + + if ( + prevProps.location == this.props.location && + prevProps.selectedSource?.id == selectedSource?.id + ) { + return; + } + + const { lineClass } = this.getTextClasses(why); + // Remove the debug line marker when no longer paused, or the selected source + // is no longer the source where the pause occured. + if (!location || location.source.id !== selectedSource.id) { + editor.removeLineContentMarker("debug-line-marker"); + } else { + const isSourceWasm = isWasm(selectedSource.id); + editor.setLineContentMarker({ + id: "debug-line-marker", + lineClassName: lineClass, + condition(line) { + const lineNumber = fromEditorLine( + selectedSource.id, + line, + isSourceWasm + ); + const editorLocation = toEditorPosition(location); + return editorLocation.line == lineNumber; + }, + }); + } + } else { + startOperation(); + this.clearDebugLine(prevProps.why, prevProps.location); + this.setDebugLine(why, location); + endOperation(); + } } setDebugLine(why, location) { @@ -125,7 +171,10 @@ const mapStateToProps = state => { return {}; } const sourceTextContent = getSourceTextContent(state, location); - if (!isDocumentReady(location, sourceTextContent)) { + if ( + !features.codemirrorNext && + !isDocumentReady(location, sourceTextContent) + ) { return {}; } return { diff --git a/devtools/client/debugger/src/components/Editor/Editor.css b/devtools/client/debugger/src/components/Editor/Editor.css index 0c48da019e..f28833747d 100644 --- a/devtools/client/debugger/src/components/Editor/Editor.css +++ b/devtools/client/debugger/src/components/Editor/Editor.css @@ -80,19 +80,6 @@ html[dir="rtl"] .editor-mount { line-height: var(--theme-code-line-height); } -/* set the linenumber white when there is a breakpoint */ -.editor-wrapper:not(.skip-pausing) - .new-breakpoint - .CodeMirror-gutter-wrapper - .CodeMirror-linenumber { - color: white; -} - -/* move the breakpoint below the other gutter elements */ -.new-breakpoint .CodeMirror-gutter-elt:nth-child(2) { - z-index: 0; -} - .theme-dark .editor-wrapper .CodeMirror-line .cm-comment { color: var(--theme-comment); } @@ -134,7 +121,9 @@ html[dir="rtl"] .editor-mount { background-color: var(--debug-expression-error-background); } -.new-debug-line > .CodeMirror-line { +.new-debug-line > .CodeMirror-line, +/* For CM6 */ +.cm-editor .cm-line.new-debug-line { background-color: transparent !important; outline: var(--debug-line-border) solid 1px; } @@ -145,7 +134,9 @@ html[dir="rtl"] .editor-mount { display: none; } -.new-debug-line-error > .CodeMirror-line { +.new-debug-line-error > .CodeMirror-line, +/* For CM6 */ +.cm-editor .cm-line.new-debug-line-error { background-color: var(--debug-expression-error-background) !important; outline: var(--debug-line-error-border) solid 1px; } @@ -196,10 +187,6 @@ html[dir="rtl"] .editor-mount { border-left: none; } -.editor-wrapper .CodeMirror-foldgutter .CodeMirror-guttermarker-subtle { - visibility: visible; -} - .editor-wrapper .CodeMirror-foldgutter .CodeMirror-linenumber { text-align: left; padding: 0 0 0 2px; diff --git a/devtools/client/debugger/src/components/Editor/Exceptions.js b/devtools/client/debugger/src/components/Editor/Exceptions.js index 2fb183f135..217ec40be6 100644 --- a/devtools/client/debugger/src/components/Editor/Exceptions.js +++ b/devtools/client/debugger/src/components/Editor/Exceptions.js @@ -6,25 +6,72 @@ import React, { Component } from "devtools/client/shared/vendor/react"; import PropTypes from "devtools/client/shared/vendor/react-prop-types"; import { connect } from "devtools/client/shared/vendor/react-redux"; +import { + toEditorPosition, + fromEditorLine, + getDocument, +} from "../../utils/editor/index"; +import { createLocation } from "../../utils/location"; + +import { features } from "../../utils/prefs"; + import Exception from "./Exception"; import { getSelectedSource, getSelectedSourceExceptions, } from "../../selectors/index"; -import { getDocument } from "../../utils/editor/index"; class Exceptions extends Component { static get propTypes() { return { exceptions: PropTypes.array, selectedSource: PropTypes.object, + editor: PropTypes.object, }; } + componentDidUpdate() { + const { exceptions, selectedSource, editor } = this.props; + + if (!features.codemirrorNext) { + return; + } + + if (!selectedSource || !editor || !exceptions.length) { + return; + } + + editor.setLineContentMarker({ + id: "line-exception-marker", + lineClassName: "line-exception", + condition: line => { + const lineNumber = fromEditorLine(selectedSource.id, line); + + const exception = exceptions.find(e => e.lineNumber == lineNumber); + if (!exception) { + return false; + } + const exceptionLocation = createLocation({ + source: selectedSource, + line: exception.lineNumber, + // Exceptions are reported with column being 1-based + // while the frontend uses 0-based column. + column: exception.columnNumber - 1, + }); + const editorLocation = toEditorPosition(exceptionLocation); + return editorLocation.line == lineNumber; + }, + }); + } + render() { const { exceptions, selectedSource } = this.props; + if (features.codemirrorNext) { + return null; + } + if (!selectedSource || !exceptions.length) { return null; } diff --git a/devtools/client/debugger/src/components/Editor/index.js b/devtools/client/debugger/src/components/Editor/index.js index ae9bde7657..e21e05c11a 100644 --- a/devtools/client/debugger/src/components/Editor/index.js +++ b/devtools/client/debugger/src/components/Editor/index.js @@ -12,6 +12,7 @@ import { connect } from "devtools/client/shared/vendor/react-redux"; import { getLineText, isLineBlackboxed } from "./../../utils/source"; import { createLocation } from "./../../utils/location"; import { getIndentation } from "../../utils/indentation"; +import { isWasm } from "../../utils/wasm"; import { features } from "../../utils/prefs"; import { @@ -50,6 +51,7 @@ import Exceptions from "./Exceptions"; import BlackboxLines from "./BlackboxLines"; import { + fromEditorLine, showSourceText, setDocument, resetLineNumberFormat, @@ -68,7 +70,11 @@ import { endOperation, } from "../../utils/editor/index"; -import { resizeToggleButton, resizeBreakpointGutter } from "../../utils/ui"; +import { + resizeToggleButton, + getLineNumberWidth, + resizeBreakpointGutter, +} from "../../utils/ui"; const { debounce } = require("resource://devtools/shared/debounce.js"); const classnames = require("resource://devtools/client/shared/classnames.js"); @@ -169,7 +175,7 @@ class Editor extends PureComponent { if (this.props.selectedSource != nextProps.selectedSource) { this.props.updateViewport(); resizeBreakpointGutter(editor.codeMirror); - resizeToggleButton(editor.codeMirror); + resizeToggleButton(getLineNumberWidth(editor.codeMirror)); } } else { // For codemirror 6 @@ -180,6 +186,12 @@ class Editor extends PureComponent { } } + onEditorUpdated(v) { + if (v.docChanged || v.geometryChanged) { + resizeToggleButton(v.view.dom.querySelector(".cm-gutters").clientWidth); + } + } + setupEditor() { const editor = getEditor(features.codemirrorNext); @@ -216,32 +228,18 @@ class Editor extends PureComponent { codeMirrorWrapper.addEventListener("keydown", e => this.onKeyDown(e)); codeMirrorWrapper.addEventListener("click", e => this.onClick(e)); codeMirrorWrapper.addEventListener("mouseover", onMouseOver(codeMirror)); - - const toggleFoldMarkerVisibility = () => { - if (node instanceof HTMLElement) { - node - .querySelectorAll(".CodeMirror-guttermarker-subtle") - .forEach(elem => { - elem.classList.toggle("visible"); - }); - } - }; - - const codeMirrorGutter = codeMirror.getGutterElement(); - codeMirrorGutter.addEventListener( - "mouseleave", - toggleFoldMarkerVisibility - ); - codeMirrorGutter.addEventListener( - "mouseenter", - toggleFoldMarkerVisibility - ); codeMirrorWrapper.addEventListener("contextmenu", event => this.openMenu(event) ); codeMirror.on("scroll", this.onEditorScroll); this.onEditorScroll(); + } else { + editor.setUpdateListener(this.onEditorUpdated); + editor.setGutterEventListeners({ + click: (event, cm, line) => this.onGutterClick(cm, line, null, event), + contextmenu: (event, cm, line) => this.openMenu(event, line, true), + }); } this.setState({ editor }); return editor; @@ -280,6 +278,69 @@ class Editor extends PureComponent { } }; + componentDidUpdate(prevProps) { + const { + selectedSource, + blackboxedRanges, + isSourceOnIgnoreList, + breakableLines, + } = this.props; + const { editor } = this.state; + + if (!selectedSource || !editor) { + return; + } + + // Sets the breakables lines for codemirror 6 + if (features.codemirrorNext) { + const shouldUpdateBreakableLines = + prevProps.breakableLines.size !== this.props.breakableLines.size || + prevProps.selectedSource?.id !== selectedSource.id; + + const isSourceWasm = isWasm(selectedSource.id); + + if (shouldUpdateBreakableLines) { + editor.setLineGutterMarkers([ + { + id: "empty-line-marker", + lineClassName: "empty-line", + condition: line => { + const lineNumber = fromEditorLine( + selectedSource.id, + line, + isSourceWasm + ); + return !breakableLines.has(lineNumber); + }, + }, + ]); + } + + function condition(line) { + const lineNumber = fromEditorLine(selectedSource.id, line); + + return isLineBlackboxed( + blackboxedRanges[selectedSource.url], + lineNumber, + isSourceOnIgnoreList + ); + } + + editor.setLineGutterMarkers([ + { + id: "blackboxed-line-gutter-marker", + lineClassName: "blackboxed-line", + condition, + }, + ]); + editor.setLineContentMarker({ + id: "blackboxed-line-marker", + lineClassName: "blackboxed-line", + condition, + }); + } + } + componentWillUnmount() { if (!features.codemirrorNext) { const { editor } = this.state; @@ -396,8 +457,9 @@ class Editor extends PureComponent { e.preventDefault(); } }; - - openMenu(event) { + // Note: The line is optional, if not passed (as is likely for codemirror 6) + // it fallsback to lineAtHeight. + openMenu(event, line) { event.stopPropagation(); event.preventDefault(); @@ -421,13 +483,19 @@ class Editor extends PureComponent { const target = event.target; const { id: sourceId } = selectedSource; - const line = lineAtHeight(editor, sourceId, event); + line = line ?? lineAtHeight(editor, sourceId, event); if (typeof line != "number") { return; } - if (target.classList.contains("CodeMirror-linenumber")) { + if ( + // handles codemirror 6 + (target.classList.contains("cm-gutterElement") && + target.closest(".cm-gutter.cm-lineNumbers")) || + // handles codemirror 5 + target.classList.contains("CodeMirror-linenumber") + ) { const location = createLocation({ line, column: undefined, @@ -440,7 +508,14 @@ class Editor extends PureComponent { line ).trim(); - this.props.showEditorGutterContextMenu(event, editor, location, lineText); + const lineObject = { from: { line }, to: { line } }; + + this.props.showEditorGutterContextMenu( + event, + lineObject, + location, + lineText + ); return; } @@ -542,10 +617,6 @@ class Editor extends PureComponent { ); }; - onGutterContextMenu = event => { - this.openMenu(event); - }; - onClick(e) { const { selectedSource, updateCursorPosition, jumpToMappedLocation } = this.props; @@ -717,6 +788,18 @@ class Editor extends PureComponent { } = this.props; const { editor } = this.state; + if (features.codemirrorNext) { + return React.createElement( + React.Fragment, + null, + React.createElement(Breakpoints, { + editor, + }), + React.createElement(DebugLine, { editor, selectedSource }), + React.createElement(Exceptions, { editor }) + ); + } + if (!selectedSource || !editor || !getDocument(selectedSource.id)) { return null; } diff --git a/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/index.js b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/index.js index 1f5e08cd7e..767df21bf6 100644 --- a/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/index.js +++ b/devtools/client/debugger/src/components/SecondaryPanes/Breakpoints/index.js @@ -17,7 +17,6 @@ import { getSelectedLocation } from "../../../utils/selected-location"; import { createHeadlessEditor } from "../../../utils/editor/create-editor"; import { makeBreakpointId } from "../../../utils/breakpoint/index"; -import { features } from "../../../utils/prefs"; import { getSelectedSource, @@ -154,7 +153,7 @@ class Breakpoints extends Component { className: "pane", }, this.renderExceptionsOptions(), - !features.codemirrorNext ? this.renderBreakpoints() : null + this.renderBreakpoints() ); } } diff --git a/devtools/client/debugger/src/components/shared/Button/styles/CommandBarButton.css b/devtools/client/debugger/src/components/shared/Button/styles/CommandBarButton.css index 12e53e6fc5..a04f080291 100644 --- a/devtools/client/debugger/src/components/shared/Button/styles/CommandBarButton.css +++ b/devtools/client/debugger/src/components/shared/Button/styles/CommandBarButton.css @@ -14,6 +14,7 @@ min-width: 30px; /* Adjust outline so it's not clipped */ outline-offset: -3px; + flex-shrink: 0; } .command-bar-button:disabled { diff --git a/devtools/client/debugger/src/utils/editor/index.js b/devtools/client/debugger/src/utils/editor/index.js index d12e2f29f1..e729388acf 100644 --- a/devtools/client/debugger/src/utils/editor/index.js +++ b/devtools/client/debugger/src/utils/editor/index.js @@ -11,6 +11,7 @@ import { createEditor } from "./create-editor"; import { isWasm, lineToWasmOffset, wasmOffsetToLine } from "../wasm"; import { createLocation } from "../location"; +import { features } from "../prefs"; let editor; @@ -65,6 +66,10 @@ export function toEditorLine(sourceId, lineOrOffset) { return wasmOffsetToLine(sourceId, lineOrOffset) || 0; } + if (features.codemirrorNext) { + return lineOrOffset; + } + return lineOrOffset ? lineOrOffset - 1 : 1; } @@ -73,6 +78,10 @@ export function fromEditorLine(sourceId, line, sourceIsWasm) { return lineToWasmOffset(sourceId, line) || 0; } + if (features.codemirrorNext) { + return line; + } + return line + 1; } @@ -88,7 +97,13 @@ export function toEditorPosition(location) { } export function toSourceLine(sourceId, line) { - return isWasm(sourceId) ? lineToWasmOffset(sourceId, line) : line + 1; + if (isWasm(sourceId)) { + return lineToWasmOffset(sourceId, line); + } + if (features.codemirrorNext) { + return line; + } + return line + 1; } export function scrollToPosition(codeMirror, line, column) { diff --git a/devtools/client/debugger/src/utils/editor/source-documents.js b/devtools/client/debugger/src/utils/editor/source-documents.js index 53ee4f2f35..cc9f44d82a 100644 --- a/devtools/client/debugger/src/utils/editor/source-documents.js +++ b/devtools/client/debugger/src/utils/editor/source-documents.js @@ -4,7 +4,11 @@ import { isWasm, getWasmLineNumberFormatter, renderWasmText } from "../wasm"; import { isMinified } from "../isMinified"; -import { resizeBreakpointGutter, resizeToggleButton } from "../ui"; +import { + resizeBreakpointGutter, + resizeToggleButton, + getLineNumberWidth, +} from "../ui"; import { javascriptLikeExtensions } from "../source"; const sourceDocs = new Map(); @@ -39,7 +43,7 @@ export function resetLineNumberFormat(editor) { const cm = editor.codeMirror; cm.setOption("lineNumberFormatter", number => number); resizeBreakpointGutter(cm); - resizeToggleButton(cm); + resizeToggleButton(getLineNumberWidth(cm)); } function updateLineNumberFormat(editor, sourceId) { @@ -51,7 +55,7 @@ function updateLineNumberFormat(editor, sourceId) { const lineNumberFormatter = getWasmLineNumberFormatter(sourceId); cm.setOption("lineNumberFormatter", lineNumberFormatter); resizeBreakpointGutter(cm); - resizeToggleButton(cm); + resizeToggleButton(getLineNumberWidth(cm)); } const contentTypeModeMap = new Map([ diff --git a/devtools/client/debugger/src/utils/editor/tokens.js b/devtools/client/debugger/src/utils/editor/tokens.js index f8783c02fe..3c6875f9cd 100644 --- a/devtools/client/debugger/src/utils/editor/tokens.js +++ b/devtools/client/debugger/src/utils/editor/tokens.js @@ -50,6 +50,8 @@ function _isInvalidTarget(target) { target.closest(".CodeMirror-widget") || // exclude in-line "empty" space, as well as the gutter target.matches(".CodeMirror-line, .CodeMirror-gutter-elt") || + // exclude items that are not in a line + !target.closest(".CodeMirror-line") || target.getBoundingClientRect().top == 0 ) { return true; diff --git a/devtools/client/debugger/src/utils/ui.js b/devtools/client/debugger/src/utils/ui.js index eab5bb1e07..3ad221f465 100644 --- a/devtools/client/debugger/src/utils/ui.js +++ b/devtools/client/debugger/src/utils/ui.js @@ -38,11 +38,11 @@ export function resizeBreakpointGutter(editor) { * Forces the left toggle button in source header to be the same size * as the line numbers gutter. */ -export function resizeToggleButton(editor) { +export function resizeToggleButton(newSize) { const toggleButton = document.querySelector( - ".source-header .toggle-button-start" + ".source-header .toggle-button.start" ); if (toggleButton) { - toggleButton.style.width = `${getLineNumberWidth(editor)}px`; + toggleButton.style.width = `${newSize}px`; } } diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-breakpoints-popup.js b/devtools/client/debugger/test/mochitest/browser_dbg-breakpoints-popup.js index eba02919d3..8a7ac18df4 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-breakpoints-popup.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-breakpoints-popup.js @@ -70,8 +70,7 @@ add_task(async function testPausedByBreakpoint() { info("Open the popup in order to be able to set a breakpoint"); const firstPopupBrowsingContext = await openPopup(POPUP_URL); - await waitForSource(dbg, POPUP_URL); - const source = findSource(dbg, POPUP_URL); + let source = await waitForSource(dbg, POPUP_URL); await selectSource(dbg, source); await addBreakpoint(dbg, source, 4); @@ -88,7 +87,7 @@ add_task(async function testPausedByBreakpoint() { "The popup is really paused" ); - await waitForSource(dbg, POPUP_URL); + source = await waitForSource(dbg, POPUP_URL); assertPausedAtSourceAndLine(dbg, source.id, 4); await resume(dbg); @@ -131,8 +130,7 @@ add_task(async function testPausedInTwoPopups() { const browser = gBrowser.selectedBrowser; const popupBrowsingContext = await openPopup(POPUP_URL); - await waitForSource(dbg, POPUP_URL); - const source = findSource(dbg, POPUP_URL); + const source = await waitForSource(dbg, POPUP_URL); await selectSource(dbg, source); await addBreakpoint(dbg, source, 4); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-call-stack.js b/devtools/client/debugger/test/mochitest/browser_dbg-call-stack.js index d461918d7a..4d8720d395 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-call-stack.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-call-stack.js @@ -19,6 +19,8 @@ add_task(async function () { const button = toggleButton(dbg); ok(!button, "toggle button shouldn't be there"); + + await resume(dbg); }); add_task(async function () { diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-console-async.js b/devtools/client/debugger/test/mochitest/browser_dbg-console-async.js index 4c669766b0..caa122eb24 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-console-async.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-console-async.js @@ -9,7 +9,7 @@ "use strict"; add_task(async function () { - Services.prefs.setBoolPref("devtools.toolbox.splitconsoleEnabled", true); + Services.prefs.setBoolPref("devtools.toolbox.splitconsole.open", true); Services.prefs.setBoolPref( "devtools.debugger.features.map-await-expression", true diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-console-map-bindings.js b/devtools/client/debugger/test/mochitest/browser_dbg-console-map-bindings.js index 26529a75cd..085b048fb6 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-console-map-bindings.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-console-map-bindings.js @@ -5,7 +5,7 @@ "use strict"; add_task(async function () { - Services.prefs.setBoolPref("devtools.toolbox.splitconsoleEnabled", true); + Services.prefs.setBoolPref("devtools.toolbox.splitconsole.open", true); const dbg = await initDebugger("doc-strict.html"); await getSplitConsole(dbg); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-console.js b/devtools/client/debugger/test/mochitest/browser_dbg-console.js index a725f7de43..73a5780cc6 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-console.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-console.js @@ -5,7 +5,7 @@ "use strict"; add_task(async function () { - Services.prefs.setBoolPref("devtools.toolbox.splitconsoleEnabled", true); + Services.prefs.setBoolPref("devtools.toolbox.splitconsole.open", true); const dbg = await initDebugger( "doc-script-switching.html", "script-switching-01.js" diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-dom-mutation-breakpoints.js b/devtools/client/debugger/test/mochitest/browser_dbg-dom-mutation-breakpoints.js index e26ca0493b..de10014069 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-dom-mutation-breakpoints.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-dom-mutation-breakpoints.js @@ -146,9 +146,7 @@ add_task(async function () { await resume(dbg); info("Blackboxing the source prevents debugger pause"); - await waitForSource(dbg, "dom-mutation.original.js"); - - const source = findSource(dbg, "dom-mutation.original.js"); + const source = await waitForSource(dbg, "dom-mutation.original.js"); await selectSource(dbg, source); await clickElement(dbg, "blackbox"); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-es-module-worker.js b/devtools/client/debugger/test/mochitest/browser_dbg-es-module-worker.js index 93123187e1..f9b299991f 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-es-module-worker.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-es-module-worker.js @@ -40,7 +40,7 @@ add_task(async function () { is(threads.length, 1, "Got the page and the worker threads"); is(threads[0].name, WORKER_URL, "Thread name is correct"); - const source = findSource(dbg, "worker.js"); + const source = await waitForSource(dbg, "worker.js"); await selectSource(dbg, source); await addBreakpoint(dbg, source, 3); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-log-events.js b/devtools/client/debugger/test/mochitest/browser_dbg-log-events.js index 6ce0acbc77..e857a38654 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-log-events.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-log-events.js @@ -9,7 +9,7 @@ "use strict"; add_task(async function () { - Services.prefs.setBoolPref("devtools.toolbox.splitconsoleEnabled", true); + Services.prefs.setBoolPref("devtools.toolbox.splitconsole.open", true); const dbg = await initDebugger( "doc-event-breakpoints.html", "event-breakpoints.js" diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-log-point-mapping.js b/devtools/client/debugger/test/mochitest/browser_dbg-log-point-mapping.js index 67886672b6..521e59b270 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-log-point-mapping.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-log-point-mapping.js @@ -9,7 +9,7 @@ "use strict"; add_task(async function () { - Services.prefs.setBoolPref("devtools.toolbox.splitconsoleEnabled", true); + Services.prefs.setBoolPref("devtools.toolbox.splitconsole.open", true); await pushPref("devtools.debugger.map-scopes-enabled", true); const dbg = await initDebugger("doc-sourcemaps3.html", "test.js"); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-log-points-workers.js b/devtools/client/debugger/test/mochitest/browser_dbg-log-points-workers.js index aa52904d31..3475d3f41d 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-log-points-workers.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-log-points-workers.js @@ -9,7 +9,7 @@ "use strict"; add_task(async function () { - Services.prefs.setBoolPref("devtools.toolbox.splitconsoleEnabled", true); + Services.prefs.setBoolPref("devtools.toolbox.splitconsole.open", true); const dbg = await initDebugger("doc-windowless-workers.html"); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-log-points.js b/devtools/client/debugger/test/mochitest/browser_dbg-log-points.js index d265caa0ad..ea3fecf1ec 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-log-points.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-log-points.js @@ -9,7 +9,7 @@ "use strict"; add_task(async function () { - Services.prefs.setBoolPref("devtools.toolbox.splitconsoleEnabled", true); + Services.prefs.setBoolPref("devtools.toolbox.splitconsole.open", true); const dbg = await initDebugger( "doc-script-switching.html", "script-switching-01.js" diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-pretty-print-paused-anonymous.js b/devtools/client/debugger/test/mochitest/browser_dbg-pretty-print-paused-anonymous.js index 8d3771cae9..223f401c73 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-pretty-print-paused-anonymous.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-pretty-print-paused-anonymous.js @@ -22,8 +22,7 @@ add_task(async function () { const prettyEvaluatedSourceFilename = evaluatedSourceId.split("/").at(-1) + ":formatted"; - await waitForSource(dbg, prettyEvaluatedSourceFilename); - const prettySource = findSource(dbg, prettyEvaluatedSourceFilename); + const prettySource = await waitForSource(dbg, prettyEvaluatedSourceFilename); info("Check that the script was pretty-printed as expected"); const { value: prettySourceValue } = findSourceContent(dbg, prettySource); @@ -67,8 +66,7 @@ document.addEventListener('click', e => { const prettyEvalSourceFilename = evalSourceId.split("/").at(-1) + ":formatted"; - await waitForSource(dbg, prettyEvalSourceFilename); - const prettyEvalSource = findSource(dbg, prettyEvalSourceFilename); + const prettyEvalSource = await waitForSource(dbg, prettyEvalSourceFilename); info("Check that the script was pretty-printed as expected"); const { value: prettyEvalSourceValue } = findSourceContent( @@ -113,8 +111,7 @@ setTimeout( const prettyNewFunctionSourceFilename = newFunctionSourceId.split("/").at(-1) + ":formatted"; - await waitForSource(dbg, prettyNewFunctionSourceFilename); - const prettyNewFunctionSource = findSource( + const prettyNewFunctionSource = await waitForSource( dbg, prettyNewFunctionSourceFilename ); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-preview.js b/devtools/client/debugger/test/mochitest/browser_dbg-preview.js index 532854548c..b7bb67c7d8 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-preview.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-preview.js @@ -158,6 +158,46 @@ async function testHoveringInvalidTargetTokens(dbg) { is(raceResult, "TIMEOUT", "No popup was displayed over the inline preview"); await resume(dbg); + + info("Test hovering element not in a line"); + await getDebuggerSplitConsole(dbg); + const { hud } = dbg.toolbox.getPanel("webconsole"); + evaluateExpressionInConsole( + hud, + ` + a = 1; + debugger; + b = 2;` + ); + await waitForPaused(dbg); + await dbg.toolbox.toggleSplitConsole(); + + resetCursorPositionToTopLeftCorner(dbg); + + const racePromiseLines = Promise.any([ + waitForElement(dbg, "previewPopup"), + wait(500).then(() => "TIMEOUT_LINES"), + ]); + // We don't want to use hoverToken, as it synthesize the event at the center of the element, + // which wouldn't reproduce the original issue we want to check + EventUtils.synthesizeMouse( + findElementWithSelector(dbg, ".CodeMirror-lines"), + 0, + 0, + { + type: "mousemove", + }, + dbg.win + ); + is( + await racePromiseLines, + "TIMEOUT_LINES", + "No popup was displayed over the .CodeMirror-lines element" + ); + + // Resume and select back the main JS file that is used by the other assertions + await resume(dbg); + await selectSource(dbg, "preview.js"); } async function assertNoPreviews(dbg, expression, line, column) { diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-source-pragma.js b/devtools/client/debugger/test/mochitest/browser_dbg-source-pragma.js index edca4e2b80..82fbd911ac 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-source-pragma.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-source-pragma.js @@ -13,8 +13,7 @@ add_task(async function () { const dbg = await initDebugger("doc-source-pragma.html"); // The sourceURL pragma didn't rename the source - await waitForSource(dbg, "source-pragma.js"); - const source = findSource(dbg, "source-pragma.js"); + const source = await waitForSource(dbg, "source-pragma.js"); const actors = dbg.selectors.getSourceActorsForSource(source.id); is(actors.length, 1, "have a single actor"); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-state-based-panels.js b/devtools/client/debugger/test/mochitest/browser_dbg-state-based-panels.js index 0dc81605c9..2f07390c48 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-state-based-panels.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-state-based-panels.js @@ -149,8 +149,9 @@ add_task(async function testBreakpointsPanePersistOnPauseToggle() { is(getPaneElements(dbg).length, 1, "Breakpoint pane is closed"); info("Check event listener breakpoints log box"); - + const wait = waitForDispatch(dbg.store, "TOGGLE_EVENT_LISTENERS"); await clickElement(dbg, "logEventsCheckbox"); + await wait; is(getPaneElements(dbg).length, 1, "Breakpoint pane is still closed"); }); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-step-in-navigate.js b/devtools/client/debugger/test/mochitest/browser_dbg-step-in-navigate.js index 53d66c6f12..85dff42104 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-step-in-navigate.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-step-in-navigate.js @@ -24,11 +24,10 @@ add_task(async function () { await addBreakpoint(dbg, "long.js", 1); // Navigation should clear the stepping state - const reloaded = reload(dbg); + const reloaded = reload(dbg, "simple2.js"); await waitForPaused(dbg); assertPausedAtSourceAndLine(dbg, findSource(dbg, "long.js").id, 1); await resume(dbg); await reloaded; - await waitForSource(dbg, "simple3.js"); }); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-windowless-service-workers-reload.js b/devtools/client/debugger/test/mochitest/browser_dbg-windowless-service-workers-reload.js index 1638cb9722..9256f91c2f 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-windowless-service-workers-reload.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-windowless-service-workers-reload.js @@ -17,8 +17,7 @@ add_task(async function () { const dbg = await initDebugger("doc-service-workers.html"); invokeInTab("registerWorker"); - await waitForSource(dbg, "service-worker.sjs"); - const workerSource = findSource(dbg, "service-worker.sjs"); + const workerSource = await waitForSource(dbg, "service-worker.sjs"); await reload(dbg, "service-worker.sjs"); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-windowless-service-workers.js b/devtools/client/debugger/test/mochitest/browser_dbg-windowless-service-workers.js index f2e20f4541..c89541871b 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-windowless-service-workers.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-windowless-service-workers.js @@ -22,8 +22,7 @@ add_task(async function () { ); invokeInTab("registerWorker"); - await waitForSource(dbg, "service-worker.sjs"); - const workerSource = findSource(dbg, "service-worker.sjs"); + const workerSource = await waitForSource(dbg, "service-worker.sjs"); await addBreakpoint(dbg, "service-worker.sjs", 13); @@ -52,8 +51,7 @@ add_task(async function () { // The test page will immediately fetch from the service worker if registered. const onReloaded = reload(dbg); - await waitForSource(dbg, "service-worker.sjs"); - const workerSource = findSource(dbg, "service-worker.sjs"); + const workerSource = await waitForSource(dbg, "service-worker.sjs"); await waitForPaused(dbg); assertPausedAtSourceAndLine(dbg, workerSource.id, 13); @@ -140,8 +138,7 @@ add_task(async function () { invokeInTab("registerWorker"); await checkAdditionalThreadCount(dbg, 1); - await waitForSource(dbg, "service-worker.sjs"); - const workerSource = findSource(dbg, "service-worker.sjs"); + const workerSource = await waitForSource(dbg, "service-worker.sjs"); await waitForBreakpointCount(dbg, 1); await waitForPaused(dbg); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-windowless-workers.js b/devtools/client/debugger/test/mochitest/browser_dbg-windowless-workers.js index ffe362b44f..49decefd1c 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-windowless-workers.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-windowless-workers.js @@ -10,7 +10,10 @@ add_task(async function () { await pushPref("devtools.debugger.threads-visible", true); - const dbg = await initDebugger("doc-windowless-workers.html"); + const dbg = await initDebugger( + "doc-windowless-workers.html", + "simple-worker.js" + ); const mainThread = dbg.toolbox.threadFront.actor; await waitForThreadCount(dbg, 2); @@ -21,8 +24,6 @@ add_task(async function () { const mainThreadSource = findSource(dbg, "doc-windowless-workers.html"); - await waitForSource(dbg, "simple-worker.js"); - info("Pause in the main thread"); assertNotPaused(dbg); await dbg.actions.breakOnNext(); diff --git a/devtools/client/debugger/test/mochitest/shared-head.js b/devtools/client/debugger/test/mochitest/shared-head.js index b2a1c7c3d7..fe3ab0171c 100644 --- a/devtools/client/debugger/test/mochitest/shared-head.js +++ b/devtools/client/debugger/test/mochitest/shared-head.js @@ -68,25 +68,27 @@ const DEBUGGER_L10N = new LocalizationHelper( /** * Waits for `predicate()` to be true. `state` is the redux app state. * - * @memberof mochitest/waits * @param {Object} dbg * @param {Function} predicate + * @param {String} msg * @return {Promise} - * @static */ -function waitForState(dbg, predicate, msg) { +function waitForState(dbg, predicate, msg = "") { return new Promise(resolve => { - info(`Waiting for state change: ${msg || ""}`); - if (predicate(dbg.store.getState())) { - info(`Finished waiting for state change: ${msg || ""}`); - resolve(); + info(`Waiting for state change: ${msg}`); + let result = predicate(dbg.store.getState()); + if (result) { + info( + `--> The state was immediately correct (should rather do an immediate assertion?)` + ); + resolve(result); return; } const unsubscribe = dbg.store.subscribe(() => { - const result = predicate(dbg.store.getState()); + result = predicate(dbg.store.getState()); if (result) { - info(`Finished waiting for state change: ${msg || ""}`); + info(`Finished waiting for state change: ${msg}`); unsubscribe(); resolve(result); } diff --git a/devtools/client/dom/main.js b/devtools/client/dom/main.js index d7fbd5dc5f..b48d7e2739 100644 --- a/devtools/client/dom/main.js +++ b/devtools/client/dom/main.js @@ -6,8 +6,8 @@ const { XPCOMUtils } = ChromeUtils.importESModule( "resource://gre/modules/XPCOMUtils.sys.mjs" ); -const { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" +const { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); // Module Loader diff --git a/devtools/client/framework/components/MeatballMenu.js b/devtools/client/framework/components/MeatballMenu.js index fc694171c8..74d8592723 100644 --- a/devtools/client/framework/components/MeatballMenu.js +++ b/devtools/client/framework/components/MeatballMenu.js @@ -3,6 +3,8 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; +const SPLITCONSOLE_ENABLED_PREF = "devtools.toolbox.splitconsole.enabled"; + const { PureComponent, createFactory, @@ -180,19 +182,27 @@ class MeatballMenu extends PureComponent { // Split console if (this.props.currentToolId !== "webconsole") { - const l10nID = this.props.isSplitConsoleActive - ? "toolbox-meatball-menu-hideconsole-label" - : "toolbox-meatball-menu-splitconsole-label"; - items.push( - MenuItem({ - id: "toolbox-meatball-menu-splitconsole", - key: "splitconsole", - l10nID, - accelerator: "Esc", - onClick: this.props.toggleSplitConsole, - className: "iconic", - }) + const isSplitConsoleEnabled = Services.prefs.getBoolPref( + SPLITCONSOLE_ENABLED_PREF, + true ); + + if (isSplitConsoleEnabled) { + const l10nID = this.props.isSplitConsoleActive + ? "toolbox-meatball-menu-hideconsole-label" + : "toolbox-meatball-menu-splitconsole-label"; + + items.push( + MenuItem({ + id: "toolbox-meatball-menu-splitconsole", + key: "splitconsole", + l10nID, + accelerator: "Esc", + onClick: this.props.toggleSplitConsole, + className: "iconic", + }) + ); + } } // Settings diff --git a/devtools/client/framework/components/ToolboxToolbar.js b/devtools/client/framework/components/ToolboxToolbar.js index f9998db0ab..bd9e3d5071 100644 --- a/devtools/client/framework/components/ToolboxToolbar.js +++ b/devtools/client/framework/components/ToolboxToolbar.js @@ -320,6 +320,10 @@ class ToolboxToolbar extends Component { errorCount = "99+"; } + const errorIconTooltip = this.props.toolbox.isSplitConsoleEnabled() + ? this.props.L10N.getStr("toolbox.errorCountButton.tooltip") + : this.props.L10N.getStr("toolbox.errorCountButtonConsoleTab.tooltip"); + return button( { id, @@ -330,9 +334,7 @@ class ToolboxToolbar extends Component { } }, title: - this.props.currentToolId !== "webconsole" - ? this.props.L10N.getStr("toolbox.errorCountButton.tooltip") - : null, + this.props.currentToolId !== "webconsole" ? errorIconTooltip : null, }, errorCount ); diff --git a/devtools/client/framework/test/browser_dynamic_tool_enabling.js b/devtools/client/framework/test/browser_dynamic_tool_enabling.js index 56313607cf..0caf32b134 100644 --- a/devtools/client/framework/test/browser_dynamic_tool_enabling.js +++ b/devtools/client/framework/test/browser_dynamic_tool_enabling.js @@ -11,7 +11,7 @@ var gItemsToTest = { }; function expectedAttributeValueFromPrefs(prefs) { - return prefs.every(pref => Services.prefs.getBoolPref(pref)) ? "" : "true"; + return prefs.every(pref => Services.prefs.getBoolPref(pref)) ? null : "true"; } function checkItem(el, prefs) { diff --git a/devtools/client/framework/test/browser_toolbox_error_count.js b/devtools/client/framework/test/browser_toolbox_error_count.js index e4dcf0214f..858615f18b 100644 --- a/devtools/client/framework/test/browser_toolbox_error_count.js +++ b/devtools/client/framework/test/browser_toolbox_error_count.js @@ -22,8 +22,14 @@ const TEST_URI = `https://example.com/document-builder.sjs?html=<meta charset=ut const { Toolbox } = require("resource://devtools/client/framework/toolbox.js"); add_task(async function () { - // Make sure we start the test with the split console disabled. - await pushPref("devtools.toolbox.splitconsoleEnabled", false); + // Make sure we start the test with the split console closed, and the split console setting enabled + await pushPref("devtools.toolbox.splitconsole.open", false); + await pushPref("devtools.toolbox.splitconsole.enabled", true); + + registerCleanupFunction(() => { + Services.prefs.clearUserPref("devtools.toolbox.splitconsole.enabled"); + }); + const tab = await addTab(TEST_URI); const toolbox = await openToolboxForTab( @@ -175,6 +181,28 @@ add_task(async function () { "The error is displayed again, with the correct error count, after enabling it from the settings panel" ); + info("Disable the split console from the options panel"); + const splitConsoleButtonToggleEl = + optionsPanel.panelWin.document.querySelector( + "input#devtools-enable-split-console" + ); + splitConsoleButtonToggleEl.click(); + await waitFor( + () => getErrorIcon(toolbox).getAttribute("title") === "Show Console" + ); + ok( + true, + "The error count icon title changed to reflect split console being disabled" + ); + + info( + "Check if with split console being disabled click leads to the console tab" + ); + const onWebConsole = toolbox.once("webconsole-selected"); + getErrorIcon(toolbox).click(); + await onWebConsole; + ok(!toolbox.splitConsole, "Web Console opened instead of split console"); + toolbox.destroy(); }); diff --git a/devtools/client/framework/test/browser_toolbox_error_count_reset_on_navigation.js b/devtools/client/framework/test/browser_toolbox_error_count_reset_on_navigation.js index 53f5068655..ebf862be88 100644 --- a/devtools/client/framework/test/browser_toolbox_error_count_reset_on_navigation.js +++ b/devtools/client/framework/test/browser_toolbox_error_count_reset_on_navigation.js @@ -23,7 +23,7 @@ add_task(async function () { // Make sure we start the test with the split console disabled. // ⚠️ In this test it's important to _not_ enable the console. - await pushPref("devtools.toolbox.splitconsoleEnabled", false); + await pushPref("devtools.toolbox.splitconsole.open", false); const tab = await addTab(TEST_URI); const toolbox = await openToolboxForTab( diff --git a/devtools/client/framework/test/browser_toolbox_remoteness_change.js b/devtools/client/framework/test/browser_toolbox_remoteness_change.js index af5f105214..ff019d1826 100644 --- a/devtools/client/framework/test/browser_toolbox_remoteness_change.js +++ b/devtools/client/framework/test/browser_toolbox_remoteness_change.js @@ -19,7 +19,7 @@ add_task(async function () { ); is( tab.linkedBrowser.getAttribute("remote"), - "", + null, "And running in parent process" ); diff --git a/devtools/client/framework/test/browser_toolbox_screenshot_tool.js b/devtools/client/framework/test/browser_toolbox_screenshot_tool.js index 63c8b9fd58..e87830a940 100644 --- a/devtools/client/framework/test/browser_toolbox_screenshot_tool.js +++ b/devtools/client/framework/test/browser_toolbox_screenshot_tool.js @@ -121,6 +121,6 @@ add_task(async function () { await resetDownloads(); const closePromise = BrowserTestUtils.windowClosed(privateWindow); - privateWindow.BrowserTryToCloseWindow(); + privateWindow.BrowserCommands.tryToCloseWindow(); await closePromise; }); diff --git a/devtools/client/framework/test/browser_toolbox_watchedByDevTools.js b/devtools/client/framework/test/browser_toolbox_watchedByDevTools.js index a58b57885d..7365c43313 100644 --- a/devtools/client/framework/test/browser_toolbox_watchedByDevTools.js +++ b/devtools/client/framework/test/browser_toolbox_watchedByDevTools.js @@ -64,6 +64,11 @@ add_task(async function () { info("Check that the flag is reset when the toolbox is closed"); await gDevTools.closeToolboxForTab(tab); + + // As the destroy sequence of DevTools server is synchronous and we aren't waiting + // for full completion of server cleanups, we have to wait for its full processing. + await waitFor(() => !tab.linkedBrowser.browsingContext.watchedByDevTools); + is( tab.linkedBrowser.browsingContext.watchedByDevTools, false, diff --git a/devtools/client/framework/toolbox-init.js b/devtools/client/framework/toolbox-init.js index de2bce080a..130f94dc0e 100644 --- a/devtools/client/framework/toolbox-init.js +++ b/devtools/client/framework/toolbox-init.js @@ -40,8 +40,8 @@ const onLoad = new Promise(r => { async function showErrorPage(doc, errorMessage) { const win = doc.defaultView; - const { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" + const { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); const browserRequire = BrowserLoader({ window: win, diff --git a/devtools/client/framework/toolbox-options.html b/devtools/client/framework/toolbox-options.html index 2ff33a581f..08c63265f0 100644 --- a/devtools/client/framework/toolbox-options.html +++ b/devtools/client/framework/toolbox-options.html @@ -126,6 +126,18 @@ </label> </fieldset> + <fieldset id="webconsole-options" class="options-groupbox"> + <legend data-l10n-id="options-webconsole-label"></legend> + <label data-l10n-id="options-webconsole-split-console-tooltip"> + <input + type="checkbox" + id="devtools-enable-split-console" + data-pref="devtools.toolbox.splitconsole.enabled" + /> + <span data-l10n-id="options-webconsole-split-console-label"></span> + </label> + </fieldset> + <fieldset id="styleeditor-options" class="options-groupbox"> <legend data-l10n-id="options-styleeditor-label"></legend> <label data-l10n-id="options-stylesheet-autocompletion-tooltip"> diff --git a/devtools/client/framework/toolbox-options.js b/devtools/client/framework/toolbox-options.js index 98b263ad44..809804e2f1 100644 --- a/devtools/client/framework/toolbox-options.js +++ b/devtools/client/framework/toolbox-options.js @@ -106,6 +106,10 @@ OptionsPanel.prototype = { "devtools.source-map.client-service.enabled", this._prefChanged ); + Services.prefs.addObserver( + "devtools.toolbox.splitconsole.enabled", + this._prefChanged + ); gDevTools.on("theme-registered", this._themeRegistered); gDevTools.on("theme-unregistered", this._themeUnregistered); @@ -126,6 +130,10 @@ OptionsPanel.prototype = { "devtools.source-map.client-service.enabled", this._prefChanged ); + Services.prefs.removeObserver( + "devtools.toolbox.splitconsole.enabled", + this._prefChanged + ); this.toolbox.off("tool-registered", this.setupToolsList); this.toolbox.off("tool-unregistered", this.setupToolsList); @@ -145,6 +153,8 @@ OptionsPanel.prototype = { this.updateCurrentTheme(); } else if (prefName === "devtools.source-map.client-service.enabled") { this.updateSourceMapPref(); + } else if (prefName === "devtools.toolbox.splitconsole.enabled") { + this.toolbox.updateIsSplitConsoleEnabled(); } }, diff --git a/devtools/client/framework/toolbox.js b/devtools/client/framework/toolbox.js index a03360aa26..222f928ecf 100644 --- a/devtools/client/framework/toolbox.js +++ b/devtools/client/framework/toolbox.js @@ -5,7 +5,8 @@ "use strict"; const MAX_ORDINAL = 99; -const SPLITCONSOLE_ENABLED_PREF = "devtools.toolbox.splitconsoleEnabled"; +const SPLITCONSOLE_OPEN_PREF = "devtools.toolbox.splitconsole.open"; +const SPLITCONSOLE_ENABLED_PREF = "devtools.toolbox.splitconsole.enabled"; const SPLITCONSOLE_HEIGHT_PREF = "devtools.toolbox.splitconsoleHeight"; const DEVTOOLS_ALWAYS_ON_TOP = "devtools.toolbox.alwaysOnTop"; const DISABLE_AUTOHIDE_PREF = "ui.popup.disable_autohide"; @@ -41,8 +42,8 @@ var Startup = Cc["@mozilla.org/devtools/startup-clh;1"].getService( Ci.nsISupports ).wrappedJSObject; -const { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" +const { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); const { @@ -608,6 +609,18 @@ Toolbox.prototype = { ); }, + /** + * Get the enabled split console setting, and if it's not set, set it with updateIsSplitConsoleEnabled + * @returns {boolean} devtools.toolbox.splitconsole.enabled option + */ + isSplitConsoleEnabled() { + if (typeof this._splitConsoleEnabled !== "boolean") { + this.updateIsSplitConsoleEnabled(); + } + + return this._splitConsoleEnabled; + }, + get isBrowserToolbox() { return this.hostType === Toolbox.HostType.BROWSERTOOLBOX; }, @@ -1038,7 +1051,7 @@ Toolbox.prototype = { // Wait until the original tool is selected so that the split // console input will receive focus. let splitConsolePromise = Promise.resolve(); - if (Services.prefs.getBoolPref(SPLITCONSOLE_ENABLED_PREF)) { + if (Services.prefs.getBoolPref(SPLITCONSOLE_OPEN_PREF)) { splitConsolePromise = this.openSplitConsole(); this.telemetry.addEventProperty( this.topWindow, @@ -1617,7 +1630,7 @@ Toolbox.prototype = { }, _splitConsoleOnKeypress(e) { - if (e.keyCode !== KeyCodes.DOM_VK_ESCAPE) { + if (e.keyCode !== KeyCodes.DOM_VK_ESCAPE || !this.isSplitConsoleEnabled()) { return; } @@ -2351,6 +2364,21 @@ Toolbox.prototype = { }, /** + * Setup the _splitConsoleEnabled, reflecting the enabled/disabled state of the Enable Split + * Console setting, and close the split console if it's open and the setting is turned off + */ + updateIsSplitConsoleEnabled() { + this._splitConsoleEnabled = Services.prefs.getBoolPref( + SPLITCONSOLE_ENABLED_PREF, + true + ); + + if (!this._splitConsoleEnabled && this.splitConsole) { + this.closeSplitConsole(); + } + }, + + /** * Ensure the visibility of each toolbox button matches the preference value. */ _commandIsVisible(button) { @@ -3013,8 +3041,15 @@ Toolbox.prototype = { * loaded and focused. */ openSplitConsole({ focusConsoleInput = true } = {}) { + if (!this.isSplitConsoleEnabled()) { + return this.selectTool( + "webconsole", + "use_in_console_with_disabled_split_console" + ); + } + this._splitConsole = true; - Services.prefs.setBoolPref(SPLITCONSOLE_ENABLED_PREF, true); + Services.prefs.setBoolPref(SPLITCONSOLE_OPEN_PREF, true); this._refreshConsoleDisplay(); // Ensure split console is visible if console was already loaded in background @@ -3044,7 +3079,7 @@ Toolbox.prototype = { */ closeSplitConsole() { this._splitConsole = false; - Services.prefs.setBoolPref(SPLITCONSOLE_ENABLED_PREF, false); + Services.prefs.setBoolPref(SPLITCONSOLE_OPEN_PREF, false); this._refreshConsoleDisplay(); this.component.setIsSplitConsoleActive(false); diff --git a/devtools/client/fronts/targets/target-mixin.js b/devtools/client/fronts/targets/target-mixin.js index 157e83e73a..bef1f5f975 100644 --- a/devtools/client/fronts/targets/target-mixin.js +++ b/devtools/client/fronts/targets/target-mixin.js @@ -10,12 +10,6 @@ loader.lazyRequireGetter( "resource://devtools/shared/protocol.js", true ); -loader.lazyRequireGetter( - this, - "getThreadOptions", - "resource://devtools/client/shared/thread-utils.js", - true -); /** * A Target represents a debuggable context. It can be a browser tab, a tab on @@ -420,39 +414,16 @@ function TargetMixin(parentClass) { return; } - const options = await getThreadOptions(); // If the target is destroyed or soon will be, don't go further if (this.isDestroyedOrBeingDestroyed()) { return; } - await this.attachThread(options); - } - - async attachThread(options = {}) { if (!this.targetForm || !this.targetForm.threadActor) { throw new Error( - "TargetMixin sub class should set targetForm.threadActor before calling " + - "attachThread" + "TargetMixin sub class should set targetForm.threadActor before calling attachAndInitThread" ); } this.threadFront = await this.getFront("thread"); - - // Avoid attaching if the thread actor was already attached on target creation from the server side. - // This doesn't include: - // * targets that aren't yet supported by the Watcher (like web extensions), - // * workers, which still use a unique codepath for thread actor attach - // * all targets when connecting to an older server - // If all targets are supported by watcher actor, and workers no longer use - // its unique attach sequence, we can assume the thread front is always attached. - const isAttached = await this.threadFront.isAttached(); - - const isDestroyed = - this.isDestroyedOrBeingDestroyed() || this.threadFront.isDestroyed(); - if (!isAttached && !isDestroyed) { - await this.threadFront.attach(options); - } - - return this.threadFront; } isDestroyedOrBeingDestroyed() { diff --git a/devtools/client/inspector/changes/test/browser_changes_nested_rules.js b/devtools/client/inspector/changes/test/browser_changes_nested_rules.js index 789d88fdda..d6da1af72d 100644 --- a/devtools/client/inspector/changes/test/browser_changes_nested_rules.js +++ b/devtools/client/inspector/changes/test/browser_changes_nested_rules.js @@ -12,7 +12,7 @@ // --- @container myContainer (width > 10px) { // ----- div { // ------- & > span { … } -// ------- .mySpan { +// ------- & .mySpan { // --------- &:not(:focus) { const spanNotFocusedRule = `&:not(:focus) { @@ -94,7 +94,7 @@ const EXPECTED_AFTER_SPAN_PROP_CHANGES = EXPECTED_AFTER_DIV_PROP_CHANGE.map( }) ).concat([ { - text: ".mySpan {", + text: "& .mySpan {", copyRuleClipboard: applyModificationAfterSpanPropertiesChange(spanClassRule), }, diff --git a/devtools/client/inspector/computed/test/browser_computed_search-filter_context-menu.js b/devtools/client/inspector/computed/test/browser_computed_search-filter_context-menu.js index 0069d644c7..bea344e5f5 100644 --- a/devtools/client/inspector/computed/test/browser_computed_search-filter_context-menu.js +++ b/devtools/client/inspector/computed/test/browser_computed_search-filter_context-menu.js @@ -88,12 +88,12 @@ add_task(async function () { cmdCopy = searchContextMenu.querySelector("#editmenu-copy"); cmdPaste = searchContextMenu.querySelector("#editmenu-paste"); - is(cmdUndo.getAttribute("disabled"), "", "cmdUndo is enabled"); - is(cmdDelete.getAttribute("disabled"), "", "cmdDelete is enabled"); - is(cmdSelectAll.getAttribute("disabled"), "", "cmdSelectAll is enabled"); - is(cmdCut.getAttribute("disabled"), "", "cmdCut is enabled"); - is(cmdCopy.getAttribute("disabled"), "", "cmdCopy is enabled"); - is(cmdPaste.getAttribute("disabled"), "", "cmdPaste is enabled"); + is(cmdUndo.getAttribute("disabled"), null, "cmdUndo is enabled"); + is(cmdDelete.getAttribute("disabled"), null, "cmdDelete is enabled"); + is(cmdSelectAll.getAttribute("disabled"), null, "cmdSelectAll is enabled"); + is(cmdCut.getAttribute("disabled"), null, "cmdCut is enabled"); + is(cmdCopy.getAttribute("disabled"), null, "cmdCopy is enabled"); + is(cmdPaste.getAttribute("disabled"), null, "cmdPaste is enabled"); onContextMenuClose = toolbox.once("menu-close"); searchContextMenu.hidePopup(); diff --git a/devtools/client/inspector/index.xhtml b/devtools/client/inspector/index.xhtml index 75d0a792c3..4cdbea4bee 100644 --- a/devtools/client/inspector/index.xhtml +++ b/devtools/client/inspector/index.xhtml @@ -66,8 +66,8 @@ var { require, loader } = ChromeUtils.importESModule( "resource://devtools/shared/loader/Loader.sys.mjs" ); - var { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" + var { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); } </script> diff --git a/devtools/client/inspector/markup/test/browser_markup_screenshot_node_about_page.js b/devtools/client/inspector/markup/test/browser_markup_screenshot_node_about_page.js index 4d8f4ff6a6..21dcf844b7 100644 --- a/devtools/client/inspector/markup/test/browser_markup_screenshot_node_about_page.js +++ b/devtools/client/inspector/markup/test/browser_markup_screenshot_node_about_page.js @@ -23,12 +23,12 @@ add_task(async function () { info("Select the main content node"); await selectNode(".main-content", inspector); - let inContentPageBackgroundColor = await getComputedStyleProperty( + let pageBackgroundColor = await getComputedStyleProperty( ":root", null, - "--in-content-page-background" + "background-color" ); - inContentPageBackgroundColor = inContentPageBackgroundColor.trim(); + pageBackgroundColor = pageBackgroundColor.trim(); info("Take a screenshot of the element and verify it looks as expected"); const image = await takeNodeScreenshot(inspector); @@ -38,7 +38,7 @@ add_task(async function () { image, x: 0, y: 0, - expectedColor: hexToCSS(inContentPageBackgroundColor), + expectedColor: hexToCSS(pageBackgroundColor), label: "The screenshot was taken", }); diff --git a/devtools/client/inspector/rules/models/element-style.js b/devtools/client/inspector/rules/models/element-style.js index e280a5e4a0..368a8ae953 100644 --- a/devtools/client/inspector/rules/models/element-style.js +++ b/devtools/client/inspector/rules/models/element-style.js @@ -57,7 +57,7 @@ class ElementStyle { this.ruleView = ruleView; this.store = store || {}; this.pageStyle = pageStyle; - this.pseudoElements = []; + this.pseudoElementTypes = new Set(); this.showUserAgentStyles = showUserAgentStyles; this.rules = []; this.cssProperties = this.ruleView.cssProperties; @@ -90,7 +90,7 @@ class ElementStyle { } this.destroyed = true; - this.pseudoElements = []; + this.pseudoElementTypes.clear(); for (const rule of this.rules) { if (rule.editor) { @@ -141,9 +141,12 @@ class ElementStyle { } // Store a list of all pseudo-element types found in the matching rules. - this.pseudoElements = this.rules - .filter(r => r.pseudoElement) - .map(r => r.pseudoElement); + this.pseudoElementTypes = new Set(); + for (const rule of this.rules) { + if (rule.pseudoElement) { + this.pseudoElementTypes.add(rule.pseudoElement); + } + } // Mark overridden computed styles. this.onRuleUpdated(); @@ -275,7 +278,7 @@ class ElementStyle { this.updateDeclarations(); // Update declarations for matching rules for pseudo-elements. - for (const pseudo of this.pseudoElements) { + for (const pseudo of this.pseudoElementTypes) { this.updateDeclarations(pseudo); } } @@ -299,11 +302,6 @@ class ElementStyle { updateDeclarations(pseudo = "") { // Gather all text properties applicable to the selected element or pseudo-element. const textProps = this._getDeclarations(pseudo); - // Gather all the computed properties applied by those text properties. - let computedProps = []; - for (const textProp of textProps) { - computedProps = computedProps.concat(textProp.computed); - } // CSS Variables inherits from the normal element in case of pseudo element. const variables = new Map(pseudo ? this.variablesMap.get("") : null); @@ -332,58 +330,62 @@ class ElementStyle { // _overriddenDirty will be set on each prop, indicating whether its // dirty status changed during this pass. const taken = new Map(); - for (const computedProp of computedProps) { - const earlier = taken.get(computedProp.name); - - // Prevent -webkit-gradient from being selected after unchecking - // linear-gradient in this case: - // -moz-linear-gradient: ...; - // -webkit-linear-gradient: ...; - // linear-gradient: ...; - if (!computedProp.textProp.isValid()) { - computedProp.overridden = true; - continue; - } - - let overridden; - if ( - earlier && - computedProp.priority === "important" && - (earlier.priority !== "important" || - // Even if the earlier property was important, if the current rule is in a layer - // it will take precedence, unless the earlier property rule was in the same layer. - (computedProp.textProp.rule?.isInLayer() && - computedProp.textProp.rule.isInDifferentLayer( - earlier.textProp.rule - ))) && - // For !important only consider rules applying to the same parent node. - computedProp.textProp.rule.inherited == earlier.textProp.rule.inherited - ) { - // New property is higher priority. Mark the earlier property - // overridden (which will reverse its dirty state). - earlier._overriddenDirty = !earlier._overriddenDirty; - earlier.overridden = true; - overridden = false; - } else { - overridden = !!earlier; - } - - computedProp._overriddenDirty = !!computedProp.overridden !== overridden; - computedProp.overridden = overridden; - - if (!computedProp.overridden && computedProp.textProp.enabled) { - taken.set(computedProp.name, computedProp); + for (const textProp of textProps) { + for (const computedProp of textProp.computed) { + const earlier = taken.get(computedProp.name); + + // Prevent -webkit-gradient from being selected after unchecking + // linear-gradient in this case: + // -moz-linear-gradient: ...; + // -webkit-linear-gradient: ...; + // linear-gradient: ...; + if (!computedProp.textProp.isValid()) { + computedProp.overridden = true; + continue; + } - // At this point, we can get CSS variable from "inherited" rules. - // When this is a registered custom property with `inherits` set to false, - // the text prop is "invisible" (i.e. not shown in the rule view). - // In such case, we don't want to get the value in the Map, and we'll rather - // get the initial value from the registered property definition. + let overridden; if ( - isCssVariable(computedProp.name) && - !computedProp.textProp.invisible + earlier && + computedProp.priority === "important" && + (earlier.priority !== "important" || + // Even if the earlier property was important, if the current rule is in a layer + // it will take precedence, unless the earlier property rule was in the same layer. + (computedProp.textProp.rule?.isInLayer() && + computedProp.textProp.rule.isInDifferentLayer( + earlier.textProp.rule + ))) && + // For !important only consider rules applying to the same parent node. + computedProp.textProp.rule.inherited == + earlier.textProp.rule.inherited ) { - variables.set(computedProp.name, computedProp.value); + // New property is higher priority. Mark the earlier property + // overridden (which will reverse its dirty state). + earlier._overriddenDirty = !earlier._overriddenDirty; + earlier.overridden = true; + overridden = false; + } else { + overridden = !!earlier; + } + + computedProp._overriddenDirty = + !!computedProp.overridden !== overridden; + computedProp.overridden = overridden; + + if (!computedProp.overridden && computedProp.textProp.enabled) { + taken.set(computedProp.name, computedProp); + + // At this point, we can get CSS variable from "inherited" rules. + // When this is a registered custom property with `inherits` set to false, + // the text prop is "invisible" (i.e. not shown in the rule view). + // In such case, we don't want to get the value in the Map, and we'll rather + // get the initial value from the registered property definition. + if ( + isCssVariable(computedProp.name) && + !computedProp.textProp.invisible + ) { + variables.set(computedProp.name, computedProp.value); + } } } } diff --git a/devtools/client/inspector/rules/test/browser_rules_content_01.js b/devtools/client/inspector/rules/test/browser_rules_content_01.js index b92ec47db0..1985f07f5f 100644 --- a/devtools/client/inspector/rules/test/browser_rules_content_01.js +++ b/devtools/client/inspector/rules/test/browser_rules_content_01.js @@ -103,7 +103,7 @@ add_task(async function () { matches: true, }, { - selector: ".unmatched", + selector: "& .unmatched", matches: false, }, ]); diff --git a/devtools/client/inspector/rules/test/browser_rules_nested_rules.js b/devtools/client/inspector/rules/test/browser_rules_nested_rules.js index 925f36a0e6..0dc068232b 100644 --- a/devtools/client/inspector/rules/test/browser_rules_nested_rules.js +++ b/devtools/client/inspector/rules/test/browser_rules_nested_rules.js @@ -93,7 +93,7 @@ add_task(async function () { checkRuleViewContent(view, [ { selector: "element", ancestorRulesData: null, declarations: [] }, { - selector: `.foo`, + selector: `& .foo`, // prettier-ignore ancestorRulesData: [ `body {`, @@ -108,7 +108,7 @@ add_task(async function () { checkRuleViewContent(view, [ { selector: "element", ancestorRulesData: null, declarations: [] }, { - selector: `#bar`, + selector: `& #bar`, // prettier-ignore ancestorRulesData: [ `body {`, @@ -138,7 +138,7 @@ add_task(async function () { checkRuleViewContent(view, [ { selector: "element", ancestorRulesData: null, declarations: [] }, { - selector: `[href]`, + selector: `& [href]`, ancestorRulesData: [ `body {`, ` @media screen {`, diff --git a/devtools/client/inspector/rules/test/browser_rules_search-filter_context-menu.js b/devtools/client/inspector/rules/test/browser_rules_search-filter_context-menu.js index 881b5274ee..009c67cd70 100644 --- a/devtools/client/inspector/rules/test/browser_rules_search-filter_context-menu.js +++ b/devtools/client/inspector/rules/test/browser_rules_search-filter_context-menu.js @@ -86,12 +86,12 @@ add_task(async function () { cmdCopy = searchContextMenu.querySelector("#editmenu-copy"); cmdPaste = searchContextMenu.querySelector("#editmenu-paste"); - is(cmdUndo.getAttribute("disabled"), "", "cmdUndo is enabled"); - is(cmdDelete.getAttribute("disabled"), "", "cmdDelete is enabled"); - is(cmdSelectAll.getAttribute("disabled"), "", "cmdSelectAll is enabled"); - is(cmdCut.getAttribute("disabled"), "", "cmdCut is enabled"); - is(cmdCopy.getAttribute("disabled"), "", "cmdCopy is enabled"); - is(cmdPaste.getAttribute("disabled"), "", "cmdPaste is enabled"); + is(cmdUndo.getAttribute("disabled"), null, "cmdUndo is enabled"); + is(cmdDelete.getAttribute("disabled"), null, "cmdDelete is enabled"); + is(cmdSelectAll.getAttribute("disabled"), null, "cmdSelectAll is enabled"); + is(cmdCut.getAttribute("disabled"), null, "cmdCut is enabled"); + is(cmdCopy.getAttribute("disabled"), null, "cmdCopy is enabled"); + is(cmdPaste.getAttribute("disabled"), null, "cmdPaste is enabled"); const onContextMenuHidden = toolbox.once("menu-close"); searchContextMenu.hidePopup(); diff --git a/devtools/client/inspector/rules/test/browser_rules_select-and-copy-styles.js b/devtools/client/inspector/rules/test/browser_rules_select-and-copy-styles.js index f9d245828e..c6d4f29a4d 100644 --- a/devtools/client/inspector/rules/test/browser_rules_select-and-copy-styles.js +++ b/devtools/client/inspector/rules/test/browser_rules_select-and-copy-styles.js @@ -209,9 +209,9 @@ async function checkCopyNestedRule(view) { const copyEvent = new win.Event("copy", { bubbles: true }); const expectedNested = `html { - body { + & body { @container (1px < width) { - #nested { + & #nested { background: tomato; color: gold; } diff --git a/devtools/client/inspector/rules/test/browser_rules_selector-highlighter-nested-rules.js b/devtools/client/inspector/rules/test/browser_rules_selector-highlighter-nested-rules.js index 4a5e8bcd0c..ecf41fb920 100644 --- a/devtools/client/inspector/rules/test/browser_rules_selector-highlighter-nested-rules.js +++ b/devtools/client/inspector/rules/test/browser_rules_selector-highlighter-nested-rules.js @@ -88,8 +88,8 @@ add_task(async function () { ); ok(highlighterData.isShown, "The selector highlighter was shown"); - info(`Clicking on ".title" selector icon`); - highlighterData = await clickSelectorIcon(view, ".title"); + info(`Clicking on "& .title" selector icon`); + highlighterData = await clickSelectorIcon(view, "& .title"); is( highlighterData.nodeFront.nodeName.toLowerCase(), "h1", diff --git a/devtools/client/inspector/rules/test/browser_rules_variables_02.js b/devtools/client/inspector/rules/test/browser_rules_variables_02.js index 4100859fb9..ee37a7b07a 100644 --- a/devtools/client/inspector/rules/test/browser_rules_variables_02.js +++ b/devtools/client/inspector/rules/test/browser_rules_variables_02.js @@ -119,9 +119,14 @@ async function testBorderShorthandAndInheritance(inspector, view) { // var(x) is the next sibling of the parent of M const setVarXParent = setVarMParent.parentNode.nextElementSibling; - // var(r) is the next sibling of var(x), and var(g) is the next sibling of var(r), etc. - const setVarRParent = setVarXParent.nextElementSibling; + // var(x) next sibling is the element that wraps the color + const colorParent = + setVarXParent.nextElementSibling.querySelector(".ruleview-color"); + // var(r) is the first childElement of the ruleview-color element + const setVarRParent = colorParent.firstElementChild; + // var(g) is the next sibling of var(r), const setVarGParent = setVarRParent.nextElementSibling; + // and var(b) is the next sibling of var(g), const setVarBParent = setVarGParent.nextElementSibling; const setVarM = getVarFromParent(setVarMParent); diff --git a/devtools/client/inspector/test/browser_inspector_highlighter-cssshape_offset-path.js b/devtools/client/inspector/test/browser_inspector_highlighter-cssshape_offset-path.js index 004d7e945f..bb187db4f5 100644 --- a/devtools/client/inspector/test/browser_inspector_highlighter-cssshape_offset-path.js +++ b/devtools/client/inspector/test/browser_inspector_highlighter-cssshape_offset-path.js @@ -38,7 +38,6 @@ const TEST_URL = `data:text/html,<meta charset=utf8>${encodeURIComponent(` const HIGHLIGHTER_TYPE = "ShapesHighlighter"; add_task(async function () { - await pushPref("layout.css.motion-path-basic-shapes.enabled", true); const env = await openInspectorForURL(TEST_URL); const { highlighterTestFront, inspector } = env; const view = selectRuleView(inspector); diff --git a/devtools/client/inspector/test/browser_inspector_inspect_loading_document.js b/devtools/client/inspector/test/browser_inspector_inspect_loading_document.js index 6798c85394..11e67ff4cd 100644 --- a/devtools/client/inspector/test/browser_inspector_inspect_loading_document.js +++ b/devtools/client/inspector/test/browser_inspector_inspect_loading_document.js @@ -131,6 +131,10 @@ add_task(async function testSlowLoadingDocument() { // Navigate to about:blank to clean the state. await navigateTo("about:blank"); + const markuploaded = inspector.once("markuploaded"); + const onNewRoot = inspector.once("new-root"); + const onUpdated = inspector.once("inspector-updated"); + await navigateTo(TEST_URL_2, { waitForLoad: false }); info("Wait for the #start div to be available as a markupview container"); await TestUtils.waitForCondition(async () => { @@ -165,4 +169,11 @@ add_task(async function testSlowLoadingDocument() { "body", inspector ); + + info( + "Waiting for inspector to update after having released the document load" + ); + await markuploaded; + await onNewRoot; + await onUpdated; }); diff --git a/devtools/client/inspector/test/browser_inspector_menu-04-use-in-console.js b/devtools/client/inspector/test/browser_inspector_menu-04-use-in-console.js index ac6ae35ad1..bd655a9a96 100644 --- a/devtools/client/inspector/test/browser_inspector_menu-04-use-in-console.js +++ b/devtools/client/inspector/test/browser_inspector_menu-04-use-in-console.js @@ -11,9 +11,17 @@ add_task(async function () { // requests to evaluateJSAsync. await pushPref("devtools.webconsole.input.eagerEvaluation", false); - const { inspector, toolbox } = await openInspectorForURL(TEST_URL); + info("Testing 'Use in Console' menu item with enabled split console."); + await pushPref("devtools.toolbox.splitconsole.enabled", true); + await testConsoleFunctionality({ isSplitConsoleEnabled: true }); + + info("Testing 'Use in Console' menu item with disabled split console."); + await pushPref("devtools.toolbox.splitconsole.enabled", false); + await testConsoleFunctionality({ isSplitConsoleEnabled: false }); +}); - info("Testing 'Use in Console' menu item."); +async function testConsoleFunctionality({ isSplitConsoleEnabled }) { + const { inspector, toolbox } = await openInspectorForURL(TEST_URL); await selectNode("#console-var", inspector); const container = await getContainerForSelector("#console-var", inspector); @@ -27,6 +35,12 @@ add_task(async function () { const hud = toolbox.getPanel("webconsole").hud; + if (isSplitConsoleEnabled) { + ok(toolbox.splitConsole, "The console is split console."); + } else { + ok(!toolbox.splitConsole, "The console is Web Console tab."); + } + const getConsoleResults = () => hud.ui.outputNode.querySelectorAll(".result"); is(hud.getInputValue(), "temp0", "first console variable is named temp0"); @@ -54,4 +68,4 @@ add_task(async function () { ); hud.ui.wrapper.dispatchClearHistory(); -}); +} diff --git a/devtools/client/inspector/test/browser_inspector_search-filter_context-menu.js b/devtools/client/inspector/test/browser_inspector_search-filter_context-menu.js index dad2ffa0b8..e8392b1425 100644 --- a/devtools/client/inspector/test/browser_inspector_search-filter_context-menu.js +++ b/devtools/client/inspector/test/browser_inspector_search-filter_context-menu.js @@ -96,12 +96,12 @@ add_task(async function () { cmdCopy = searchContextMenu.querySelector("#editmenu-copy"); cmdPaste = searchContextMenu.querySelector("#editmenu-paste"); - is(cmdUndo.getAttribute("disabled"), "", "cmdUndo is enabled"); - is(cmdDelete.getAttribute("disabled"), "", "cmdDelete is enabled"); - is(cmdSelectAll.getAttribute("disabled"), "", "cmdSelectAll is enabled"); - is(cmdCut.getAttribute("disabled"), "", "cmdCut is enabled"); - is(cmdCopy.getAttribute("disabled"), "", "cmdCopy is enabled"); - is(cmdPaste.getAttribute("disabled"), "", "cmdPaste is enabled"); + is(cmdUndo.getAttribute("disabled"), null, "cmdUndo is enabled"); + is(cmdDelete.getAttribute("disabled"), null, "cmdDelete is enabled"); + is(cmdSelectAll.getAttribute("disabled"), null, "cmdSelectAll is enabled"); + is(cmdCut.getAttribute("disabled"), null, "cmdCut is enabled"); + is(cmdCopy.getAttribute("disabled"), null, "cmdCopy is enabled"); + is(cmdPaste.getAttribute("disabled"), null, "cmdPaste is enabled"); const onContextMenuHidden = toolbox.once("menu-close"); searchContextMenu.hidePopup(); diff --git a/devtools/client/jar.mn b/devtools/client/jar.mn index a2b1b7bfb7..4975514395 100644 --- a/devtools/client/jar.mn +++ b/devtools/client/jar.mn @@ -116,6 +116,7 @@ devtools.jar: skin/images/import.svg (themes/images/import.svg) skin/images/pane-collapse.svg (themes/images/pane-collapse.svg) skin/images/pane-expand.svg (themes/images/pane-expand.svg) + skin/images/whatsnew.svg (themes/images/whatsnew.svg) skin/images/help.svg (themes/images/help.svg) skin/images/report.svg (themes/images/report.svg) skin/images/reveal.svg (themes/images/reveal.svg) diff --git a/devtools/client/locales/en-US/toolbox-options.ftl b/devtools/client/locales/en-US/toolbox-options.ftl index 28b1d86705..0e711d1a41 100644 --- a/devtools/client/locales/en-US/toolbox-options.ftl +++ b/devtools/client/locales/en-US/toolbox-options.ftl @@ -66,6 +66,16 @@ options-default-color-unit-rgb = RGB(A) options-default-color-unit-hwb = HWB options-default-color-unit-name = Color Names +## Web Console section + +# The heading +options-webconsole-label = Web Console + +# The label for the checkbox that toggle whether the Split console is enabled +options-webconsole-split-console-label = Enable Split Console +options-webconsole-split-console-tooltip = + .title = Open Split Console with the Escape Key + ## Style Editor section # The heading diff --git a/devtools/client/locales/en-US/toolbox.properties b/devtools/client/locales/en-US/toolbox.properties index fc8dd99241..51c5d33658 100644 --- a/devtools/client/locales/en-US/toolbox.properties +++ b/devtools/client/locales/en-US/toolbox.properties @@ -160,9 +160,13 @@ toolbox.meatballMenu.button.tooltip=Customize Developer Tools and Get Help toolbox.closebutton.tooltip=Close Developer Tools # LOCALIZATION NOTE (toolbox.errorCountButton.tooltip): This is the tooltip for -# the error count button displayed in the developer tools toolbox. +# the error count button displayed in the developer tools toolbox if the "Enable Split Console" setting is checked. toolbox.errorCountButton.tooltip=Show Split Console +# LOCALIZATION NOTE (toolbox.errorCountButtonConsoleTab.tooltip): This is the tooltip for +# the error count button displayed in the developer tools toolbox if the "Enable Split Console" setting is unchecked. +toolbox.errorCountButtonConsoleTab.tooltip=Show Console + # LOCALIZATION NOTE (toolbox.errorCountButton.description): This is the description that # will be used for the error count button in the devTools settings panel. toolbox.errorCountButton.description=Show the number of errors on the page diff --git a/devtools/client/memory/panel.js b/devtools/client/memory/panel.js index e6143aafa4..c9d4f82f80 100644 --- a/devtools/client/memory/panel.js +++ b/devtools/client/memory/panel.js @@ -12,8 +12,8 @@ function MemoryPanel(iframeWindow, toolbox, commands) { this._toolbox = toolbox; this._commands = commands; - const { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" + const { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); const browserRequire = BrowserLoader({ baseURI: "resource://devtools/client/memory/", diff --git a/devtools/client/memory/test/chrome/head.js b/devtools/client/memory/test/chrome/head.js index 685fa62928..4061ffa264 100644 --- a/devtools/client/memory/test/chrome/head.js +++ b/devtools/client/memory/test/chrome/head.js @@ -3,8 +3,8 @@ "use strict"; -var { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" +var { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); var { require } = BrowserLoader({ baseURI: "resource://devtools/client/memory/", diff --git a/devtools/client/netmonitor/initializer.js b/devtools/client/netmonitor/initializer.js index c6a8a246f5..24afadf434 100644 --- a/devtools/client/netmonitor/initializer.js +++ b/devtools/client/netmonitor/initializer.js @@ -9,8 +9,8 @@ * This script is the entry point of Network monitor panel. * See README.md for more information. */ -const { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" +const { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); const require = (window.windowRequire = BrowserLoader({ diff --git a/devtools/client/netmonitor/src/har/test/browser_net_har_copy_all_as_har.js b/devtools/client/netmonitor/src/har/test/browser_net_har_copy_all_as_har.js index 2faaf01b73..08dbfbf068 100644 --- a/devtools/client/netmonitor/src/har/test/browser_net_har_copy_all_as_har.js +++ b/devtools/client/netmonitor/src/har/test/browser_net_har_copy_all_as_har.js @@ -7,7 +7,7 @@ * Basic tests for exporting Network panel content into HAR format. */ -const EXPECTED_REQUEST_HEADER_COUNT = 9; +const EXPECTED_REQUEST_HEADER_COUNT = 13; const EXPECTED_RESPONSE_HEADER_COUNT = 6; add_task(async function () { @@ -15,7 +15,7 @@ add_task(async function () { // (bug 1352274). TCP Fast Open is not present on all platforms therefore the // number of response headers will vary depending on the platform. await pushPref("network.tcp.tcp_fastopen_enable", false); - const { tab, monitor, toolbox } = await initNetMonitor(SIMPLE_URL, { + const { tab, monitor, toolbox } = await initNetMonitor(HTTPS_SIMPLE_URL, { requestCount: 1, }); @@ -45,7 +45,7 @@ async function testSimpleReload({ tab, monitor, toolbox }) { const page = har.log.pages[0]; - is(page.title, SIMPLE_URL, "There must be some page title"); + is(page.title, HTTPS_SIMPLE_URL, "There must be some page title"); ok("onContentLoad" in page.pageTimings, "There must be onContentLoad time"); ok("onLoad" in page.pageTimings, "There must be onLoad time"); @@ -98,7 +98,7 @@ async function testManyReloads({ tab, monitor, toolbox }) { if (entry) { ok(entry, "Found the cancelled request"); is(entry.request.method, "GET", "Method is set"); - is(entry.request.url, SIMPLE_URL, "URL is set"); + is(entry.request.url, HTTPS_SIMPLE_URL, "URL is set"); // We always get the following headers: // "Host", "User-agent", "Accept", "Accept-Language", "Accept-Encoding", "Connection" // but are missing the three last headers: @@ -173,7 +173,7 @@ function assertNavigationRequestEntry(entry) { info("Assert that the entry relates to the navigation request"); Assert.greater(entry.time, 0, "Check the total time"); is(entry.request.method, "GET", "Check the method"); - is(entry.request.url, SIMPLE_URL, "Check the URL"); + is(entry.request.url, HTTPS_SIMPLE_URL, "Check the URL"); is( entry.request.headers.length, EXPECTED_REQUEST_HEADER_COUNT, diff --git a/devtools/client/netmonitor/src/har/test/browser_net_har_import.js b/devtools/client/netmonitor/src/har/test/browser_net_har_import.js index 44ae3a8e16..9d66674bd3 100644 --- a/devtools/client/netmonitor/src/har/test/browser_net_har_import.js +++ b/devtools/client/netmonitor/src/har/test/browser_net_har_import.js @@ -65,7 +65,7 @@ add_task(async () => { ); is( har2.log.entries[1]._securityState, - "insecure", + "secure", "There must be expected security state" ); is(har2.log.entries[2].response.status, 304, "There must be expected status"); diff --git a/devtools/client/netmonitor/src/har/test/head.js b/devtools/client/netmonitor/src/har/test/head.js index b41ea580fd..abf34c1ffb 100644 --- a/devtools/client/netmonitor/src/har/test/head.js +++ b/devtools/client/netmonitor/src/har/test/head.js @@ -13,7 +13,7 @@ Services.scriptloader.loadSubScript(netMonitorHead, this); // Directory with HAR related test files. const HAR_EXAMPLE_URL = - "http://example.com/browser/devtools/client/netmonitor/src/har/test/"; + "https://example.com/browser/devtools/client/netmonitor/src/har/test/"; /** * Trigger a "copy all as har" from the context menu of the requests list. diff --git a/devtools/client/netmonitor/test/browser_net_cached-status.js b/devtools/client/netmonitor/test/browser_net_cached-status.js index b41362b398..d6dd5519c5 100644 --- a/devtools/client/netmonitor/test/browser_net_cached-status.js +++ b/devtools/client/netmonitor/test/browser_net_cached-status.js @@ -10,6 +10,9 @@ add_task(async function () { // Disable rcwn to make cache behavior deterministic. await pushPref("network.http.rcwn.enabled", false); + // performing http to https redirects, hence we do not + // want https-first to interfere with that test + await pushPref("dom.security.https_first", false); const { tab, monitor } = await initNetMonitor(STATUS_CODES_URL, { enableCache: true, diff --git a/devtools/client/netmonitor/test/browser_net_copy_as_powershell.js b/devtools/client/netmonitor/test/browser_net_copy_as_powershell.js index 5785b89929..8160b10cfa 100644 --- a/devtools/client/netmonitor/test/browser_net_copy_as_powershell.js +++ b/devtools/client/netmonitor/test/browser_net_copy_as_powershell.js @@ -19,7 +19,7 @@ add_task(async function () { -Headers @{ "Accept" = "*/*" "Accept-Language" = "en-US" - "Accept-Encoding" = "gzip, deflate, br" + "Accept-Encoding" = "gzip, deflate, br, zstd" "X-Custom-Header-1" = "Custom value" "X-Custom-Header-2" = "8.8.8.8" "X-Custom-Header-3" = "Mon, 3 Mar 2014 11:11:11 GMT" @@ -42,7 +42,7 @@ Invoke-WebRequest -UseBasicParsing -Uri "https://example.com/browser/devtools/cl -Headers @{ "Accept" = "*/*" "Accept-Language" = "en-US" - "Accept-Encoding" = "gzip, deflate, br" + "Accept-Encoding" = "gzip, deflate, br, zstd" "X-Custom-Header-1" = "Custom value" "X-Custom-Header-2" = "8.8.8.8" "X-Custom-Header-3" = "Mon, 3 Mar 2014 11:11:11 GMT" @@ -66,7 +66,7 @@ Invoke-WebRequest -UseBasicParsing -Uri "https://example.com/browser/devtools/cl -Headers @{ "Accept" = "*/*" "Accept-Language" = "en-US" - "Accept-Encoding" = "gzip, deflate, br" + "Accept-Encoding" = "gzip, deflate, br, zstd" "X-Custom-Header-1" = "Custom value" "X-Custom-Header-2" = "8.8.8.8" "X-Custom-Header-3" = "Mon, 3 Mar 2014 11:11:11 GMT" @@ -95,7 +95,7 @@ Invoke-WebRequest -UseBasicParsing -Uri "https://example.com/browser/devtools/cl -Headers @{ "Accept" = "*/*" "Accept-Language" = "en-US" - "Accept-Encoding" = "gzip, deflate, br" + "Accept-Encoding" = "gzip, deflate, br, zstd" "X-Custom-Header-1" = "Custom value" "X-Custom-Header-2" = "8.8.8.8" "X-Custom-Header-3" = "Mon, 3 Mar 2014 11:11:11 GMT" diff --git a/devtools/client/netmonitor/test/browser_net_copy_headers.js b/devtools/client/netmonitor/test/browser_net_copy_headers.js index cd6499d93b..458a19af97 100644 --- a/devtools/client/netmonitor/test/browser_net_copy_headers.js +++ b/devtools/client/netmonitor/test/browser_net_copy_headers.js @@ -47,6 +47,7 @@ add_task(async function () { "Accept-Encoding: gzip, deflate", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", + "Priority: u=1", "Pragma: no-cache", "Cache-Control: no-cache", ].join("\n"); diff --git a/devtools/client/netmonitor/test/browser_net_headers_sorted.js b/devtools/client/netmonitor/test/browser_net_headers_sorted.js index 2965ea8d3c..ea12b1c67e 100644 --- a/devtools/client/netmonitor/test/browser_net_headers_sorted.js +++ b/devtools/client/netmonitor/test/browser_net_headers_sorted.js @@ -71,6 +71,7 @@ async function verifyHeaders(monitor) { "Cookie", "Host", "Pragma", + "Priority", "Sec-Fetch-Dest", "Sec-Fetch-Mode", "Sec-Fetch-Site", @@ -144,6 +145,7 @@ async function verifyRawHeaders(monitor) { "Sec-Fetch-Dest", "Sec-Fetch-Mode", "Sec-Fetch-Site", + "Priority", "Pragma", "Cache-Control", ]; diff --git a/devtools/client/netmonitor/test/browser_net_http3_request_details.js b/devtools/client/netmonitor/test/browser_net_http3_request_details.js index 9ceb9dba88..6a6c5973c9 100644 --- a/devtools/client/netmonitor/test/browser_net_http3_request_details.js +++ b/devtools/client/netmonitor/test/browser_net_http3_request_details.js @@ -74,8 +74,8 @@ add_task(async function () { // The Text-Encoding header is not consistently displayed, exclude it from // the assertion. See Bug 1830053. headers.filter(cell => cell.textContent != "TE").length, - 25, - "There should be 25 header values displayed in this tabpanel." + 26, + "There should be 26 header values displayed in this tabpanel." ); const headersTable = tabpanel.querySelector(".accordion"); diff --git a/devtools/client/netmonitor/test/browser_net_resend.js b/devtools/client/netmonitor/test/browser_net_resend.js index cc3c212988..9150bfe3ba 100644 --- a/devtools/client/netmonitor/test/browser_net_resend.js +++ b/devtools/client/netmonitor/test/browser_net_resend.js @@ -60,14 +60,23 @@ async function testResendRequest() { "The resent request has the same url and query parameters and the first request" ); + // The priority header only appears when the urgency and incremental values + // are not both default values (u=3 and i=false). In this case the original + // request has no priority header and the resent request does, hence we subtract one. is( firstResend.originalResource.requestHeaders.headers.length, - firstResend.newResource.requestHeaders.headers.length, + firstResend.newResource.requestHeaders.headers.length - 1, "The no of headers are the same" ); + // Because a resent request has a different purpose and principal it will + // also have a different CoS flag (meaning a different priority header). + // So we can't compare the original and resent request's priority and skip it. firstResend.originalResource.requestHeaders.headers.forEach( ({ name, value }) => { + if (name === "Priority") { + return; + } const foundHeader = firstResend.newResource.requestHeaders.headers.find( header => header.name == name ); diff --git a/devtools/client/netmonitor/test/browser_net_simple-request-details.js b/devtools/client/netmonitor/test/browser_net_simple-request-details.js index e52a0b101a..e7d07f392c 100644 --- a/devtools/client/netmonitor/test/browser_net_simple-request-details.js +++ b/devtools/client/netmonitor/test/browser_net_simple-request-details.js @@ -137,8 +137,8 @@ add_task(async function () { is( tabpanel.querySelectorAll(".accordion .treeLabelCell").length, - 23, - "There should be 23 header values displayed in this tabpanel." + 24, + "There should be 24 header values displayed in this tabpanel." ); const headersTable = tabpanel.querySelector(".accordion"); diff --git a/devtools/client/performance-new/@types/gecko.d.ts b/devtools/client/performance-new/@types/gecko.d.ts index f5da78697e..682db32c13 100644 --- a/devtools/client/performance-new/@types/gecko.d.ts +++ b/devtools/client/performance-new/@types/gecko.d.ts @@ -28,7 +28,7 @@ declare namespace MockedExports { "resource://devtools/shared/loader/Loader.sys.mjs": typeof import("resource://devtools/shared/loader/Loader.sys.mjs"); "resource://devtools/client/performance-new/shared/background.sys.mjs": typeof import("resource://devtools/client/performance-new/shared/background.sys.mjs"); "resource://devtools/client/performance-new/shared/symbolication.sys.mjs": typeof import("resource://devtools/client/performance-new/shared/symbolication.sys.mjs"); - "resource://devtools/shared/loader/browser-loader.js": any; + "resource://devtools/shared/loader/browser-loader.sys.mjs": any; "resource://devtools/client/performance-new/popup/menu-button.sys.mjs": typeof import("resource://devtools/client/performance-new/popup/menu-button.sys.mjs"); "resource://devtools/client/performance-new/shared/typescript-lazy-load.sys.mjs": typeof import("resource://devtools/client/performance-new/shared/typescript-lazy-load.sys.mjs"); "resource://devtools/client/performance-new/popup/logic.sys.mjs": typeof import("resource://devtools/client/performance-new/popup/logic.sys.mjs"); diff --git a/devtools/client/performance-new/aboutprofiling/initializer.js b/devtools/client/performance-new/aboutprofiling/initializer.js index 8dd854007c..2e99ca0a3a 100644 --- a/devtools/client/performance-new/aboutprofiling/initializer.js +++ b/devtools/client/performance-new/aboutprofiling/initializer.js @@ -19,8 +19,8 @@ // TypeScript. See devtools/client/performance-new/typescript.md and // the section on "Do not overload require" for more information. - const { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" + const { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); const browserLoader = BrowserLoader({ baseURI: "resource://devtools/client/performance-new/aboutprofiling", diff --git a/devtools/client/performance-new/panel/initializer.js b/devtools/client/performance-new/panel/initializer.js index 2264e4764f..25a2176a36 100644 --- a/devtools/client/performance-new/panel/initializer.js +++ b/devtools/client/performance-new/panel/initializer.js @@ -23,8 +23,8 @@ // TypeScript. See devtools/client/performance-new/typescript.md and // the section on "Do not overload require" for more information. - const { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" + const { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); const browserLoader = BrowserLoader({ baseURI: "resource://devtools/client/performance-new/", diff --git a/devtools/client/performance-new/shared/#typescript-lazy-load.jsm.js# b/devtools/client/performance-new/shared/#typescript-lazy-load.jsm.js# deleted file mode 100644 index de982cc3ff..0000000000 --- a/devtools/client/performance-new/shared/#typescript-lazy-load.jsm.js# +++ /dev/null @@ -1,55 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -// @ts-check -"use strict"; - -/** - * TypeScript can't understand the lazyRequireGetter mechanism, due to how it defines - * properties as a getter. This function, instead provides lazy loading in a - * TypeScript-friendly manner. It applies the lazy load memoization to each property - * of the provided object. - * - * Example usage: - * - * const lazy = createLazyLoaders({ - * moduleA: () => require("module/a"), - * moduleB: () => require("module/b"), - * }); - * - * Later: - * - * const moduleA = lazy.moduleA(); - * const { objectInModuleB } = lazy.moduleB(); - * - * @template {{ [key: string]: () => any }} T - * @param {T} definition - An object where each property has a function that loads a module. - * @returns {T} - The load memoized version of T. - */ -function createLazyLoaders(definition) { - /** @type {any} */ - const result = {}; - for (const [key, callback] of Object.entries(definition)) { - /** @type {any} */ - let cache; - result[key] = () => { - if (cache === undefined) { - cache = callback(); - } - return cache; - }; - } - return result; -} - -// Provide an exports object for the JSM to be properly read by TypeScript. -/** @type {any} */ -var module = {}; - -module.exports = { - createLazyLoaders, -}; - -// Object.keys() confuses the linting which expects a static array expression. -// eslint-disable-next-line -var EXPORTED_SYMBOLS = Object.keys(module.exports); diff --git a/devtools/client/performance-new/tsconfig.json b/devtools/client/performance-new/tsconfig.json index f98b4b33d4..80bababd37 100644 --- a/devtools/client/performance-new/tsconfig.json +++ b/devtools/client/performance-new/tsconfig.json @@ -14,7 +14,12 @@ "noEmit": true, // Allow esnext syntax. Otherwise the default is ES5 only. "target": "esnext", - "lib": ["esnext", "dom"] + "lib": ["esnext", "dom"], + // Make sure that only this project is taken into account when checking types. + // In the future we'll want to use the same types as in the rest of Gecko, but + // that's not ready yet. + // See Bug 1891209 + "typeRoots": ["./@types", "./node_modules/@types"] }, "files": ["./@types/gecko.d.ts"], // Add a @ts-check comment to a JS file to start type checking it. diff --git a/devtools/client/responsive/index.js b/devtools/client/responsive/index.js index 84bdf16e12..5ee25ab95e 100644 --- a/devtools/client/responsive/index.js +++ b/devtools/client/responsive/index.js @@ -6,8 +6,8 @@ "use strict"; -const { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" +const { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); const { require } = BrowserLoader({ baseURI: "resource://devtools/client/responsive/", diff --git a/devtools/client/responsive/test/browser/browser_device_width.js b/devtools/client/responsive/test/browser/browser_device_width.js index 11dc8fd31c..a7d1dfde30 100644 --- a/devtools/client/responsive/test/browser/browser_device_width.js +++ b/devtools/client/responsive/test/browser/browser_device_width.js @@ -11,9 +11,6 @@ addRDMTask(TEST_URL, async function ({ ui, manager }) { ok(ui, "An instance of the RDM should be attached to the tab."); await setViewportSizeAndAwaitReflow(ui, manager, 110, 500); - info("Checking initial width/height properties."); - await doInitialChecks(ui, 110); - info("Checking initial width/height with meta viewport on"); await setTouchAndMetaViewportSupport(ui, true); await doInitialChecks(ui, 980); diff --git a/devtools/client/responsive/test/browser/browser_toolbox_computed_view.js b/devtools/client/responsive/test/browser/browser_toolbox_computed_view.js index f22ee8d246..d4d9c94c79 100644 --- a/devtools/client/responsive/test/browser/browser_toolbox_computed_view.js +++ b/devtools/client/responsive/test/browser/browser_toolbox_computed_view.js @@ -6,18 +6,22 @@ // Check that when the viewport is resized, the computed-view refreshes. const TEST_URI = - "data:text/html;charset=utf-8,<html><style>" + - "div {" + - " width: 500px;" + - " height: 10px;" + - " background: purple;" + - "} " + - "@media screen and (max-width: 200px) {" + - " div { " + - " width: 100px;" + - " }" + - "};" + - "</style><div></div></html>"; + "data:text/html;charset=utf-8," + + ` + <meta name="viewport" content="width=device-width"> + <style> + div { + width: 500px; + height: 10px; + background: purple; + } + @media screen and (max-width: 200px) { + div { + width: 100px; + } + }; + </style><div></div></html> +`; addRDMTask(TEST_URI, async function ({ ui, manager }) { info("Open the responsive design mode and set its size to 500x500 to start"); diff --git a/devtools/client/responsive/test/browser/browser_viewport_resizing_after_reload.js b/devtools/client/responsive/test/browser/browser_viewport_resizing_after_reload.js index ad750326ae..22dbdff527 100644 --- a/devtools/client/responsive/test/browser/browser_viewport_resizing_after_reload.js +++ b/devtools/client/responsive/test/browser/browser_viewport_resizing_after_reload.js @@ -23,7 +23,7 @@ addRDMTask(TEST_URL, async function ({ ui, manager }) { const expected = [ { metaSupport: false, - before: [1.0, 300, 600], + before: [0.5, 300, 600], after: [1.0, 600, 300], }, { diff --git a/devtools/client/responsive/test/browser/browser_viewport_resizing_fixed_width.js b/devtools/client/responsive/test/browser/browser_viewport_resizing_fixed_width.js index 46a2529b12..5fd38565be 100644 --- a/devtools/client/responsive/test/browser/browser_viewport_resizing_fixed_width.js +++ b/devtools/client/responsive/test/browser/browser_viewport_resizing_fixed_width.js @@ -19,8 +19,8 @@ addRDMTask(TEST_URL, async function ({ ui, manager }) { const expected = [ { metaSupport: false, - before: [1.0, 600, 300], - after: [1.0, 50, 50], // Zoom is unaffected. + before: [2.0, 300, 150], + after: [0.25, 300, 300], // This checks that min-zoom is active. }, { metaSupport: true, diff --git a/devtools/client/responsive/test/browser/doc_toolbox_rule_view.html b/devtools/client/responsive/test/browser/doc_toolbox_rule_view.html index e4a311b7ec..f0cc88ef97 100644 --- a/devtools/client/responsive/test/browser/doc_toolbox_rule_view.html +++ b/devtools/client/responsive/test/browser/doc_toolbox_rule_view.html @@ -1,4 +1,5 @@ <html> + <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" charset="UTF-8" type="text/css" media="screen" href="doc_toolbox_rule_view.css"/> <div></div> </html> diff --git a/devtools/client/shared/components/NotificationBox.css b/devtools/client/shared/components/NotificationBox.css index f2ff550f46..b051c96a2f 100644 --- a/devtools/client/shared/components/NotificationBox.css +++ b/devtools/client/shared/components/NotificationBox.css @@ -87,7 +87,7 @@ } .notificationbox .messageImage[data-type="new"] { - background-image: url("chrome://global/skin/icons/whatsnew.svg"); + background-image: url("chrome://devtools/skin/images/whatsnew.svg"); fill: var(--theme-highlight-blue); } diff --git a/devtools/client/shared/components/test/chrome/head.js b/devtools/client/shared/components/test/chrome/head.js index 7abe54942f..e8260cb774 100644 --- a/devtools/client/shared/components/test/chrome/head.js +++ b/devtools/client/shared/components/test/chrome/head.js @@ -14,8 +14,8 @@ var { Assert } = ChromeUtils.importESModule( "resource://testing-common/Assert.sys.mjs" ); var { gDevTools } = require("resource://devtools/client/framework/devtools.js"); -var { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" +var { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); var { DevToolsServer, diff --git a/devtools/client/shared/output-parser.js b/devtools/client/shared/output-parser.js index fc1afca5a0..bd514096b3 100644 --- a/devtools/client/shared/output-parser.js +++ b/devtools/client/shared/output-parser.js @@ -217,8 +217,13 @@ class OutputParser { options.getVariableValue ) { sawVariable = true; - const { node } = this.#parseVariable(token, text, tokenStream, options); - functionData.push(node); + const { node, value, fallbackValue } = this.#parseVariable( + token, + text, + tokenStream, + options + ); + functionData.push({ node, value, fallbackValue }); } else if (token.tokenType === "function") { ++depth; } @@ -278,6 +283,7 @@ class OutputParser { const secondOpts = {}; let varValue; + let varFallbackValue; // Get the variable value if it is in use. if (tokens && tokens.length === 1) { @@ -324,11 +330,16 @@ class OutputParser { const span = this.#createNode("span", secondOpts); span.appendChild(rest); + varFallbackValue = span.textContent; variableNode.appendChild(span); } variableNode.appendChild(this.#doc.createTextNode(")")); - return { node: variableNode, value: varValue }; + return { + node: variableNode, + value: varValue, + fallbackValue: varFallbackValue, + }; } /** @@ -435,17 +446,43 @@ class OutputParser { ); if (sawVariable) { - // If function contains variable, we need to add both strings - // and nodes. - this.#appendTextNode(functionName); - for (const data of functionData) { - if (typeof data === "string") { - this.#appendTextNode(data); - } else if (data) { - this.#parsed.push(data); + const computedFunctionText = + functionName + + functionData + .map(data => { + if (typeof data === "string") { + return data; + } + return data.value ?? data.fallbackValue; + }) + .join("") + + ")"; + if ( + colorOK() && + InspectorUtils.isValidCSSColor(computedFunctionText) + ) { + this.#appendColor(computedFunctionText, { + ...options, + colorFunction: colorFunctions.at(-1)?.functionName, + valueParts: [ + functionName, + ...functionData.map(data => data.node || data), + ")", + ], + }); + } else { + // If function contains variable, we need to add both strings + // and nodes. + this.#appendTextNode(functionName); + for (const data of functionData) { + if (typeof data === "string") { + this.#appendTextNode(data); + } else if (data) { + this.#parsed.push(data.node); + } } + this.#appendTextNode(")"); } - this.#appendTextNode(")"); } else { // If no variable in function, join the text together and add // to DOM accordingly. @@ -1598,13 +1635,14 @@ class OutputParser { container.appendChild(options.variableContainer); } else { // Otherwise we create a new element with the `color` as textContent. - const value = this.#createNode( - "span", - { - class: options.colorClass, - }, - color - ); + const value = this.#createNode("span", { + class: options.colorClass, + }); + if (options.valueParts) { + value.append(...options.valueParts); + } else { + value.append(this.#doc.createTextNode(color)); + } container.appendChild(value); } diff --git a/devtools/client/shared/remote-debugging/adb/xpcshell/test_prepare-tcp-connection.js b/devtools/client/shared/remote-debugging/adb/xpcshell/test_prepare-tcp-connection.js index 09dad165f2..11df5663f8 100644 --- a/devtools/client/shared/remote-debugging/adb/xpcshell/test_prepare-tcp-connection.js +++ b/devtools/client/shared/remote-debugging/adb/xpcshell/test_prepare-tcp-connection.js @@ -15,8 +15,8 @@ add_task(async function testParseFileUri() { // Mocks are not supported for the regular DevTools loader. info("Create a BrowserLoader to enable mocks in the test"); - const { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" + const { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); const mockedRequire = BrowserLoader({ baseURI: "resource://devtools/client/shared/remote-debugging/adb", diff --git a/devtools/client/shared/sourceeditor/editor.js b/devtools/client/shared/sourceeditor/editor.js index 056914b931..3487acffa4 100644 --- a/devtools/client/shared/sourceeditor/editor.js +++ b/devtools/client/shared/sourceeditor/editor.js @@ -166,6 +166,10 @@ class Editor extends EventEmitter { #ownerDoc; #prefObserver; #win; + #lineGutterMarkers = new Map(); + #lineContentMarkers = new Map(); + + #updateListener = null; constructor(config) { super(); @@ -412,6 +416,12 @@ class Editor extends EventEmitter { } } + // This update listener allows listening to the changes + // to the codemiror editor. + setUpdateListener(listener = null) { + this.#updateListener = listener; + } + /** * Do the actual appending and configuring of the CodeMirror instance. This is * used by both append functions above, and does all the hard work to @@ -614,11 +624,17 @@ class Editor extends EventEmitter { const tabSizeCompartment = new Compartment(); const indentCompartment = new Compartment(); const lineWrapCompartment = new Compartment(); + const lineNumberCompartment = new Compartment(); + const lineNumberMarkersCompartment = new Compartment(); + const lineContentMarkerCompartment = new Compartment(); this.#compartments = { tabSizeCompartment, indentCompartment, lineWrapCompartment, + lineNumberCompartment, + lineNumberMarkersCompartment, + lineContentMarkerCompartment, }; const indentStr = (this.config.indentWithTabs ? "\t" : " ").repeat( @@ -632,6 +648,7 @@ class Editor extends EventEmitter { this.config.lineWrapping ? EditorView.lineWrapping : [] ), EditorState.readOnly.of(this.config.readOnly), + lineNumberCompartment.of(this.config.lineNumbers ? lineNumbers() : []), codemirrorLanguage.codeFolding({ placeholderText: "↔", }), @@ -645,6 +662,21 @@ class Editor extends EventEmitter { }, }), codemirrorLanguage.syntaxHighlighting(lezerHighlight.classHighlighter), + EditorView.updateListener.of(v => { + if (v.viewportChanged || v.docChanged) { + // reset line gutter markers for the new visible ranges + // when the viewport changes(e.g when the page is scrolled). + if (this.#lineGutterMarkers.size > 0) { + this.setLineGutterMarkers(); + } + } + // Any custom defined update listener should be called + if (typeof this.#updateListener == "function") { + this.#updateListener(v); + } + }), + lineNumberMarkersCompartment.of([]), + lineContentMarkerCompartment.of(this.#lineContentMarkersExtension([])), // keep last so other extension take precedence codemirror.minimalSetup, ]; @@ -653,10 +685,6 @@ class Editor extends EventEmitter { extensions.push(codemirrorLangJavascript.javascript()); } - if (this.config.lineNumbers) { - extensions.push(lineNumbers()); - } - const cm = new EditorView({ parent: el, extensions, @@ -666,6 +694,219 @@ class Editor extends EventEmitter { } /** + * This creates the extension used to manage the rendering of markers + * for in editor line content. + * @param {Array} markers - The current list of markers + * @returns {Array<ViewPlugin>} showLineContentDecorations - An extension which is an array containing the view + * which manages the rendering of the line content markers. + */ + #lineContentMarkersExtension(markers) { + const { + codemirrorView: { Decoration, ViewPlugin }, + codemirrorState: { RangeSetBuilder }, + } = this.#CodeMirror6; + + // Build and return the decoration set + function buildDecorations(view) { + const builder = new RangeSetBuilder(); + for (const { from, to } of view.visibleRanges) { + for (let pos = from; pos <= to; ) { + const line = view.state.doc.lineAt(pos); + for (const { lineClassName, condition } of markers) { + if (condition(line.number)) { + builder.add( + line.from, + line.from, + Decoration.line({ class: lineClassName }) + ); + } + } + pos = line.to + 1; + } + } + return builder.finish(); + } + + // The view which handles rendering and updating the + // markers decorations + const showLineContentDecorations = ViewPlugin.fromClass( + class { + decorations; + constructor(view) { + this.decorations = buildDecorations(view); + } + update(update) { + if (update.docChanged || update.viewportChanged) { + this.decorations = buildDecorations(update.view); + } + } + }, + { decorations: v => v.decorations } + ); + + return [showLineContentDecorations]; + } + + /** + * This adds a marker used to add classes to editor line based on a condition. + * @property {object} marker - The rule rendering a marker or class. + * @property {object} marker.id - The unique identifier for this marker + * @property {string} marker.lineClassName - The css class to add to the line + * @property {function} marker.condition - The condition that decides if the marker/class gets added or removed. + * The line is passed as an argument. + */ + setLineContentMarker(marker) { + const cm = editors.get(this); + this.#lineContentMarkers.set(marker.id, marker); + + cm.dispatch({ + effects: this.#compartments.lineContentMarkerCompartment.reconfigure( + this.#lineContentMarkersExtension( + Array.from(this.#lineContentMarkers.values()) + ) + ), + }); + } + + /** + * This removes the marker which has the specified className + * @param {string} markerId - The unique identifier for this marker + */ + removeLineContentMarker(markerId) { + const cm = editors.get(this); + this.#lineContentMarkers.delete(markerId); + + cm.dispatch({ + effects: this.#compartments.lineContentMarkerCompartment.reconfigure( + this.#lineContentMarkersExtension( + Array.from(this.#lineContentMarkers.values()) + ) + ), + }); + } + + /** + * Set event listeners for the line gutter + * @param {Object} domEventHandlers + * + * example usage: + * const domEventHandlers = { click(event) { console.log(event);} } + */ + setGutterEventListeners(domEventHandlers) { + const cm = editors.get(this); + const { + codemirrorView: { lineNumbers }, + } = this.#CodeMirror6; + + for (const eventName in domEventHandlers) { + const handler = domEventHandlers[eventName]; + domEventHandlers[eventName] = (view, line, event) => { + line = view.state.doc.lineAt(line.from); + handler(event, view, line.number); + }; + } + + cm.dispatch({ + effects: this.#compartments.lineWrapCompartment.reconfigure( + lineNumbers({ domEventHandlers }) + ), + }); + } + + /** + * This supports adding/removing of line classes or markers on the + * line number gutter based on the defined conditions. This only supports codemirror 6. + * + * @param {Array<Marker>} markers - The list of marker objects which defines the rules + * for rendering each marker. + * @property {object} marker - The rule rendering a marker or class. This is required. + * @property {string} marker.id - The unique identifier for this marker. + * @property {string} marker.lineClassName - The css class to add to the line. This is required. + * @property {function} marker.condition - The condition that decides if the marker/class gets added or removed. + * @property {function=} marker.createLineElementNode - This gets the line as an argument and should return the DOM element which + * is used for the marker. This is optional. + */ + setLineGutterMarkers(markers) { + const cm = editors.get(this); + + if (markers) { + // Cache the markers for use later. See next comment + for (const marker of markers) { + if (!marker.id) { + throw new Error("Marker has no unique identifier"); + } + this.#lineGutterMarkers.set(marker.id, marker); + } + } + // When no markers are passed, the cached markers are used to update the line gutters. + // This is useful for re-rendering the line gutters when the viewport changes + // (note: the visible ranges will be different) in this case, mainly when the editor is scrolled. + else if (!this.#lineGutterMarkers.size) { + return; + } + markers = Array.from(this.#lineGutterMarkers.values()); + + const { + codemirrorView: { lineNumberMarkers, GutterMarker }, + codemirrorState: { RangeSetBuilder }, + } = this.#CodeMirror6; + + // This creates a new GutterMarker https://codemirror.net/docs/ref/#view.GutterMarker + // to represents how each line gutter is rendered in the view. + // This is set as the value for the Range https://codemirror.net/docs/ref/#state.Range + // which represents the line. + class LineGutterMarker extends GutterMarker { + constructor(className, lineNumber, createElementNode) { + super(); + this.elementClass = className || null; + this.toDOM = createElementNode + ? () => createElementNode(lineNumber) + : null; + } + } + + // Loop through the visible ranges https://codemirror.net/docs/ref/#view.EditorView.visibleRanges + // (representing the lines in the current viewport) and generate a new rangeset for updating the line gutter + // based on the conditions defined in the markers(for each line) provided. + const builder = new RangeSetBuilder(); + for (const { from, to } of cm.visibleRanges) { + for (let pos = from; pos <= to; ) { + const line = cm.state.doc.lineAt(pos); + for (const { + lineClassName, + condition, + createLineElementNode, + } of markers) { + if (typeof condition !== "function") { + throw new Error("The `condition` is not a valid function"); + } + if (condition(line.number)) { + builder.add( + line.from, + line.to, + new LineGutterMarker( + lineClassName, + line.number, + createLineElementNode + ) + ); + } + } + pos = line.to + 1; + } + } + + // To update the state with the newly generated marker range set, a dispatch is called on the view + // with an transaction effect created by the lineNumberMarkersCompartment, which is used to update the + // lineNumberMarkers extension configuration. + cm.dispatch({ + effects: this.#compartments.lineNumberMarkersCompartment.reconfigure( + lineNumberMarkers.of(builder.finish()) + ), + }); + } + + /** * Returns a boolean indicating whether the editor is ready to * use. Use appendTo(el).then(() => {}) for most cases */ @@ -1658,6 +1899,8 @@ class Editor extends EventEmitter { this.config = null; this.version = null; this.#ownerDoc = null; + this.#updateListener = null; + this.#lineGutterMarkers.clear(); if (this.#prefObserver) { this.#prefObserver.off(KEYMAP_PREF, this.setKeyMap); diff --git a/devtools/client/shared/test/browser_browserloader_mocks.js b/devtools/client/shared/test/browser_browserloader_mocks.js index 6cc38259f3..5a67b6fcd2 100644 --- a/devtools/client/shared/test/browser_browserloader_mocks.js +++ b/devtools/client/shared/test/browser_browserloader_mocks.js @@ -3,8 +3,8 @@ "use strict"; -const { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" +const { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); const { diff --git a/devtools/client/shared/test/browser_outputparser.js b/devtools/client/shared/test/browser_outputparser.js index 226e0bb685..7e0c1b7e00 100644 --- a/devtools/client/shared/test/browser_outputparser.js +++ b/devtools/client/shared/test/browser_outputparser.js @@ -6,7 +6,6 @@ add_task(async function () { await pushPref("layout.css.backdrop-filter.enabled", true); await pushPref("layout.css.individual-transform.enabled", true); - await pushPref("layout.css.motion-path-basic-shapes.enabled", true); await addTab("about:blank"); await performTest(); gBrowser.removeCurrentTab(); @@ -671,6 +670,36 @@ function testParseVariable(doc, parser) { `</span>)` + `</span>`, }, + { + text: "rgba(var(--r), 0, 0, var(--a))", + variables: { "--r": "255", "--a": "0.5" }, + expected: + // prettier-ignore + '<span data-color="rgba(255, 0, 0, 0.5)">' + + "<span>rgba("+ + "<span>" + + 'var(<span data-variable="--r = 255">--r</span>)' + + "</span>, 0, 0, " + + "<span>" + + 'var(<span data-variable="--a = 0.5">--a</span>)' + + "</span>" + + ")</span>" + + "</span>", + }, + { + text: "rgb(var(--not-seen, 255), 0, 0)", + variables: {}, + expected: + // prettier-ignore + '<span data-color="rgb( 255, 0, 0)">' + + "<span>rgb("+ + "<span>var(" + + `<span class="unmatched-class" data-variable="--not-seen is not set">--not-seen</span>,` + + `<span> 255</span>` + + ")</span>, 0, 0" + + ")</span>" + + "</span>", + }, ]; for (const test of TESTS) { diff --git a/devtools/client/shared/test/browser_require_raw.js b/devtools/client/shared/test/browser_require_raw.js index bcf4afe98f..64d48f2eb1 100644 --- a/devtools/client/shared/test/browser_require_raw.js +++ b/devtools/client/shared/test/browser_require_raw.js @@ -3,8 +3,8 @@ "use strict"; -const { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" +const { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); const { require: browserRequire } = BrowserLoader({ diff --git a/devtools/client/shared/test/shared-head.js b/devtools/client/shared/test/shared-head.js index aa47b35edd..0657ede75e 100644 --- a/devtools/client/shared/test/shared-head.js +++ b/devtools/client/shared/test/shared-head.js @@ -93,6 +93,30 @@ if (DEBUG_STEP) { }); } +const DEBUG_TRACE_LINE = Services.env.get("DEBUG_TRACE_LINE"); +if (DEBUG_TRACE_LINE) { + // Use a custom loader with `invisibleToDebugger` flag for the allocation tracker + // as it instantiates custom Debugger API instances and has to be running in a distinct + // compartments from DevTools and system scopes (ESMs, XPCOM,...) + const { + useDistinctSystemPrincipalLoader, + releaseDistinctSystemPrincipalLoader, + } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/DistinctSystemPrincipalLoader.sys.mjs" + ); + const requester = {}; + const loader = useDistinctSystemPrincipalLoader(requester); + + const lineTracer = loader.require( + "resource://devtools/shared/test-helpers/test-line-tracer.js" + ); + lineTracer.start(globalThis, gTestPath, DEBUG_TRACE_LINE); + registerCleanupFunction(() => { + lineTracer.stop(); + releaseDistinctSystemPrincipalLoader(requester); + }); +} + const { loader, require } = ChromeUtils.importESModule( "resource://devtools/shared/loader/Loader.sys.mjs" ); @@ -276,7 +300,7 @@ registerCleanupFunction(() => { Services.prefs.clearUserPref("dom.ipc.processPrelaunch.enabled"); Services.prefs.clearUserPref("devtools.toolbox.host"); Services.prefs.clearUserPref("devtools.toolbox.previousHost"); - Services.prefs.clearUserPref("devtools.toolbox.splitconsoleEnabled"); + Services.prefs.clearUserPref("devtools.toolbox.splitconsole.open"); Services.prefs.clearUserPref("devtools.toolbox.splitconsoleHeight"); Services.prefs.clearUserPref( "javascript.options.asyncstack_capture_debuggee_only" diff --git a/devtools/client/shared/thread-utils.js b/devtools/client/shared/thread-utils.js index 9c29681b91..7f3aa4a8ac 100644 --- a/devtools/client/shared/thread-utils.js +++ b/devtools/client/shared/thread-utils.js @@ -4,8 +4,9 @@ "use strict"; const asyncStoreHelper = require("resource://devtools/client/shared/async-store-helper.js"); -const { validateBreakpointLocation } = ChromeUtils.import( - "resource://devtools/shared/validate-breakpoint.jsm" +const { validateBreakpointLocation } = ChromeUtils.importESModule( + "resource://devtools/shared/validate-breakpoint.sys.mjs", + { global: "contextual" } ); const asyncStore = asyncStoreHelper("debugger", { diff --git a/devtools/client/shared/vendor/WASMPARSER_UPGRADING b/devtools/client/shared/vendor/WASMPARSER_UPGRADING index 05a9e8abd3..f756c45dd2 100644 --- a/devtools/client/shared/vendor/WASMPARSER_UPGRADING +++ b/devtools/client/shared/vendor/WASMPARSER_UPGRADING @@ -1,13 +1,13 @@ # wasmparser version -Current version is: 5.9.0 +Current version is: 5.11.0 # Upgrade process 1. Pull latest release from npm and extract WasmDis.js and WasmParser.js, e.g. ``` -curl https://registry.npmjs.org/wasmparser/-/wasmparser-5.9.0.tgz | tar -zx --strip-components 3 package/dist/cjs/{WasmDis,WasmParser}.js +curl https://registry.npmjs.org/wasmparser/-/wasmparser-5.11.0.tgz | tar -zx --strip-components 3 package/dist/cjs/{WasmDis,WasmParser}.js ``` 2. Remove reference to source maps (last line) diff --git a/devtools/client/shared/vendor/WasmDis.js b/devtools/client/shared/vendor/WasmDis.js index a412de6b39..be6849d1c8 100644 --- a/devtools/client/shared/vendor/WasmDis.js +++ b/devtools/client/shared/vendor/WasmDis.js @@ -256,7 +256,7 @@ var DefaultNameResolver = /** @class */ (function () { return "$elem".concat(index); }; DefaultNameResolver.prototype.getTagName = function (index, isRef) { - return "$event".concat(index); + return "$tag".concat(index); }; DefaultNameResolver.prototype.getFunctionName = function (index, isImport, isRef) { return (isImport ? "$import" : "$func") + index; @@ -476,6 +476,8 @@ var WasmDisassembler = /** @class */ (function () { return "eq"; case -20 /* TypeKind.i31ref */: return "i31"; + case -23 /* TypeKind.exnref */: + return "exnref"; case -21 /* TypeKind.structref */: return "struct"; case -22 /* TypeKind.arrayref */: @@ -486,8 +488,13 @@ var WasmDisassembler = /** @class */ (function () { return "noextern"; case -15 /* TypeKind.nullref */: return "none"; + case -12 /* TypeKind.nullexnref */: + return "noexnref"; } }; + WasmDisassembler.prototype.refTypeToString = function (typeIndex, nullable) { + return this.typeToString(new WasmParser_js_1.RefType(nullable ? -29 /* TypeKind.ref_null */ : -28 /* TypeKind.ref */, typeIndex)); + }; WasmDisassembler.prototype.typeToString = function (type) { switch (type.kind) { case -1 /* TypeKind.i32 */: @@ -508,6 +515,8 @@ var WasmDisassembler = /** @class */ (function () { return "funcref"; case -17 /* TypeKind.externref */: return "externref"; + case -23 /* TypeKind.exnref */: + return "exnref"; case -18 /* TypeKind.anyref */: return "anyref"; case -19 /* TypeKind.eqref */: @@ -522,6 +531,8 @@ var WasmDisassembler = /** @class */ (function () { return "nullfuncref"; case -14 /* TypeKind.nullexternref */: return "nullexternref"; + case -12 /* TypeKind.nullexnref */: + return "nullexnref"; case -15 /* TypeKind.nullref */: return "nullref"; case -28 /* TypeKind.ref */: @@ -647,6 +658,7 @@ var WasmDisassembler = /** @class */ (function () { case 3 /* OperatorCode.loop */: case 4 /* OperatorCode.if */: case 6 /* OperatorCode.try */: + case 31 /* OperatorCode.try_table */: if (this._labelMode !== LabelMode.Depth) { var backrefLabel_1 = { line: this._lines.length, @@ -665,6 +677,31 @@ var WasmDisassembler = /** @class */ (function () { this._backrefLabels.push(backrefLabel_1); } this.printBlockType(operator.blockType); + if (operator.tryTable) { + for (var i = 0; i < operator.tryTable.length; i++) { + this.appendBuffer(" ("); + switch (operator.tryTable[i].kind) { + case WasmParser_js_1.CatchHandlerKind.Catch: + this.appendBuffer("catch "); + break; + case WasmParser_js_1.CatchHandlerKind.CatchRef: + this.appendBuffer("catch_ref "); + break; + case WasmParser_js_1.CatchHandlerKind.CatchAll: + this.appendBuffer("catch_all "); + break; + case WasmParser_js_1.CatchHandlerKind.CatchAllRef: + this.appendBuffer("catch_all_ref "); + break; + } + if (operator.tryTable[i].tagIndex != null) { + var tagName = this._nameResolver.getTagName(operator.tryTable[i].tagIndex, true); + this.appendBuffer("".concat(tagName, " ")); + } + this.appendBuffer(this.useLabel(operator.tryTable[i].depth + 1)); + this.appendBuffer(")"); + } + } break; case 11 /* OperatorCode.end */: if (this._labelMode === LabelMode.Depth) { @@ -947,9 +984,17 @@ var WasmDisassembler = /** @class */ (function () { break; } case 64278 /* OperatorCode.ref_cast */: + case 64276 /* OperatorCode.ref_test */: { + var refType = this.refTypeToString(operator.refType, false); + this.appendBuffer(" ".concat(refType)); + break; + } case 64279 /* OperatorCode.ref_cast_null */: - case 64276 /* OperatorCode.ref_test */: - case 64277 /* OperatorCode.ref_test_null */: + case 64277 /* OperatorCode.ref_test_null */: { + var refType = this.refTypeToString(operator.refType, true); + this.appendBuffer(" ".concat(refType)); + break; + } case 64257 /* OperatorCode.struct_new_default */: case 64256 /* OperatorCode.struct_new */: case 64263 /* OperatorCode.array_new_default */: @@ -1496,7 +1541,6 @@ var WasmDisassembler = /** @class */ (function () { case 5 /* OperatorCode.else */: case 7 /* OperatorCode.catch */: case 25 /* OperatorCode.catch_all */: - case 10 /* OperatorCode.unwind */: case 24 /* OperatorCode.delegate */: this.decreaseIndent(); break; @@ -1510,9 +1554,9 @@ var WasmDisassembler = /** @class */ (function () { case 3 /* OperatorCode.loop */: case 5 /* OperatorCode.else */: case 6 /* OperatorCode.try */: + case 31 /* OperatorCode.try_table */: case 7 /* OperatorCode.catch */: case 25 /* OperatorCode.catch_all */: - case 10 /* OperatorCode.unwind */: this.increaseIndent(); break; } diff --git a/devtools/client/shared/vendor/WasmParser.js b/devtools/client/shared/vendor/WasmParser.js index 68397b8eeb..efa5b9a4e6 100644 --- a/devtools/client/shared/vendor/WasmParser.js +++ b/devtools/client/shared/vendor/WasmParser.js @@ -29,7 +29,7 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -exports.bytesToString = exports.BinaryReader = exports.Int64 = exports.TagAttribute = exports.ElementMode = exports.DataMode = exports.BinaryReaderState = exports.NameType = exports.LinkingType = exports.RelocType = exports.RefType = exports.Type = exports.FuncDef = exports.FieldDef = exports.TypeKind = exports.ExternalKind = exports.OperatorCodeNames = exports.OperatorCode = exports.SectionCode = void 0; +exports.bytesToString = exports.BinaryReader = exports.Int64 = exports.TagAttribute = exports.ElementMode = exports.DataMode = exports.BinaryReaderState = exports.NameType = exports.LinkingType = exports.RelocType = exports.CatchHandler = exports.CatchHandlerKind = exports.RefType = exports.Type = exports.FuncDef = exports.FieldDef = exports.TypeKind = exports.ExternalKind = exports.OperatorCodeNames = exports.OperatorCode = exports.SectionCode = void 0; // See https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md var WASM_MAGIC_NUMBER = 0x6d736100; var WASM_SUPPORTED_EXPERIMENTAL_VERSION = 0xd; @@ -64,7 +64,7 @@ var OperatorCode; OperatorCode[OperatorCode["catch"] = 7] = "catch"; OperatorCode[OperatorCode["throw"] = 8] = "throw"; OperatorCode[OperatorCode["rethrow"] = 9] = "rethrow"; - OperatorCode[OperatorCode["unwind"] = 10] = "unwind"; + OperatorCode[OperatorCode["throw_ref"] = 10] = "throw_ref"; OperatorCode[OperatorCode["end"] = 11] = "end"; OperatorCode[OperatorCode["br"] = 12] = "br"; OperatorCode[OperatorCode["br_if"] = 13] = "br_if"; @@ -82,6 +82,7 @@ var OperatorCode; OperatorCode[OperatorCode["drop"] = 26] = "drop"; OperatorCode[OperatorCode["select"] = 27] = "select"; OperatorCode[OperatorCode["select_with_type"] = 28] = "select_with_type"; + OperatorCode[OperatorCode["try_table"] = 31] = "try_table"; OperatorCode[OperatorCode["local_get"] = 32] = "local_get"; OperatorCode[OperatorCode["local_set"] = 33] = "local_set"; OperatorCode[OperatorCode["local_tee"] = 34] = "local_tee"; @@ -597,8 +598,8 @@ var OperatorCode; OperatorCode[OperatorCode["f64x2_relaxed_min"] = 1036559] = "f64x2_relaxed_min"; OperatorCode[OperatorCode["f64x2_relaxed_max"] = 1036560] = "f64x2_relaxed_max"; OperatorCode[OperatorCode["i16x8_relaxed_q15mulr_s"] = 1036561] = "i16x8_relaxed_q15mulr_s"; - OperatorCode[OperatorCode["i16x8_dot_i8x16_i7x16_s"] = 1036562] = "i16x8_dot_i8x16_i7x16_s"; - OperatorCode[OperatorCode["i32x4_dot_i8x16_i7x16_add_s"] = 1036563] = "i32x4_dot_i8x16_i7x16_add_s"; + OperatorCode[OperatorCode["i16x8_relaxed_dot_i8x16_i7x16_s"] = 1036562] = "i16x8_relaxed_dot_i8x16_i7x16_s"; + OperatorCode[OperatorCode["i32x4_relaxed_dot_i8x16_i7x16_add_s"] = 1036563] = "i32x4_relaxed_dot_i8x16_i7x16_add_s"; // GC proposal. OperatorCode[OperatorCode["struct_new"] = 64256] = "struct_new"; OperatorCode[OperatorCode["struct_new_default"] = 64257] = "struct_new_default"; @@ -643,7 +644,7 @@ exports.OperatorCodeNames = [ "catch", "throw", "rethrow", - "unwind", + "throw_ref", "end", "br", "br_if", @@ -664,7 +665,7 @@ exports.OperatorCodeNames = [ "select", undefined, undefined, - undefined, + "try_table", "local.get", "local.set", "local.tee", @@ -1187,8 +1188,8 @@ exports.OperatorCodeNames = [ "f64x2.relaxed_min", "f64x2.relaxed_max", "i16x8.relaxed_q15mulr_s", - "i16x8.dot_i8x16_i7x16_s", - "i32x4.dot_i8x16_i7x16_add_s", + "i16x8.relaxed_dot_i8x16_i7x16_s", + "i32x4.relaxed_dot_i8x16_i7x16_add_s", ].forEach(function (s, i) { exports.OperatorCodeNames[0xfd000 | i] = s; }); @@ -1297,9 +1298,9 @@ exports.OperatorCodeNames = [ "array.init_data", "array.init_elem", "ref.test", - "ref.test null", + "ref.test", + "ref.cast", "ref.cast", - "ref.cast null", "br_on_cast", "br_on_cast_fail", "any.convert_extern", @@ -1328,6 +1329,7 @@ var TypeKind; TypeKind[TypeKind["v128"] = -5] = "v128"; TypeKind[TypeKind["i8"] = -8] = "i8"; TypeKind[TypeKind["i16"] = -9] = "i16"; + TypeKind[TypeKind["nullexnref"] = -12] = "nullexnref"; TypeKind[TypeKind["nullfuncref"] = -13] = "nullfuncref"; TypeKind[TypeKind["nullref"] = -15] = "nullref"; TypeKind[TypeKind["nullexternref"] = -14] = "nullexternref"; @@ -1338,6 +1340,7 @@ var TypeKind; TypeKind[TypeKind["i31ref"] = -20] = "i31ref"; TypeKind[TypeKind["structref"] = -21] = "structref"; TypeKind[TypeKind["arrayref"] = -22] = "arrayref"; + TypeKind[TypeKind["exnref"] = -23] = "exnref"; TypeKind[TypeKind["ref"] = -28] = "ref"; TypeKind[TypeKind["ref_null"] = -29] = "ref_null"; TypeKind[TypeKind["func"] = -32] = "func"; @@ -1388,6 +1391,7 @@ var Type = exports.Type = /** @class */ (function () { // Convenience singletons. Type.funcref = new Type(-16 /* TypeKind.funcref */); Type.externref = new Type(-17 /* TypeKind.externref */); + Type.exnref = new Type(-23 /* TypeKind.exnref */); return Type; }()); var RefType = /** @class */ (function (_super) { @@ -1411,6 +1415,19 @@ var RefType = /** @class */ (function (_super) { return RefType; }(Type)); exports.RefType = RefType; +var CatchHandlerKind; +(function (CatchHandlerKind) { + CatchHandlerKind[CatchHandlerKind["Catch"] = 0] = "Catch"; + CatchHandlerKind[CatchHandlerKind["CatchRef"] = 1] = "CatchRef"; + CatchHandlerKind[CatchHandlerKind["CatchAll"] = 2] = "CatchAll"; + CatchHandlerKind[CatchHandlerKind["CatchAllRef"] = 3] = "CatchAllRef"; +})(CatchHandlerKind = exports.CatchHandlerKind || (exports.CatchHandlerKind = {})); +var CatchHandler = /** @class */ (function () { + function CatchHandler() { + } + return CatchHandler; +}()); +exports.CatchHandler = CatchHandler; var RelocType; (function (RelocType) { RelocType[RelocType["FunctionIndex_LEB"] = 0] = "FunctionIndex_LEB"; @@ -1814,11 +1831,13 @@ var BinaryReader = /** @class */ (function () { case -9 /* TypeKind.i16 */: case -16 /* TypeKind.funcref */: case -17 /* TypeKind.externref */: + case -23 /* TypeKind.exnref */: case -18 /* TypeKind.anyref */: case -19 /* TypeKind.eqref */: case -20 /* TypeKind.i31ref */: case -14 /* TypeKind.nullexternref */: case -13 /* TypeKind.nullfuncref */: + case -12 /* TypeKind.nullexnref */: case -21 /* TypeKind.structref */: case -22 /* TypeKind.arrayref */: case -15 /* TypeKind.nullref */: @@ -1989,6 +2008,7 @@ var BinaryReader = /** @class */ (function () { case -9 /* TypeKind.i16 */: case -16 /* TypeKind.funcref */: case -17 /* TypeKind.externref */: + case -23 /* TypeKind.exnref */: case -18 /* TypeKind.anyref */: case -19 /* TypeKind.eqref */: this.result = { @@ -2936,8 +2956,8 @@ var BinaryReader = /** @class */ (function () { case 1036559 /* OperatorCode.f64x2_relaxed_min */: case 1036560 /* OperatorCode.f64x2_relaxed_max */: case 1036561 /* OperatorCode.i16x8_relaxed_q15mulr_s */: - case 1036562 /* OperatorCode.i16x8_dot_i8x16_i7x16_s */: - case 1036563 /* OperatorCode.i32x4_dot_i8x16_i7x16_add_s */: + case 1036562 /* OperatorCode.i16x8_relaxed_dot_i8x16_i7x16_s */: + case 1036563 /* OperatorCode.i32x4_relaxed_dot_i8x16_i7x16_add_s */: break; default: this.error = new Error("Unknown operator: 0x".concat(code.toString(16).padStart(4, "0"))); @@ -3109,7 +3129,7 @@ var BinaryReader = /** @class */ (function () { } break; } - var code, blockType, selectType, refType, brDepth, brTable, relativeDepth, funcIndex, typeIndex, tableIndex, localIndex, globalIndex, tagIndex, memoryAddress, literal, reserved; + var code, blockType, selectType, refType, brDepth, brTable, tryTable, relativeDepth, funcIndex, typeIndex, tableIndex, localIndex, globalIndex, tagIndex, memoryAddress, literal, reserved; if (this.state === 26 /* BinaryReaderState.INIT_EXPRESSION_OPERATOR */ && this._sectionId === 9 /* SectionCode.Element */ && isExternvalElementSegmentType(this._segmentType)) { @@ -3171,6 +3191,38 @@ var BinaryReader = /** @class */ (function () { case 8 /* OperatorCode.throw */: tagIndex = this.readVarInt32(); break; + case 31 /* OperatorCode.try_table */: + blockType = this.readType(); + var tableCount = this.readVarUint32(); + if (!this.hasBytes(2 * tableCount)) { + // We need at least (2 * tableCount) bytes + this._pos = pos; + return false; + } + tryTable = []; + for (var i = 0; i < tableCount; i++) { + if (!this.hasVarIntBytes()) { + this._pos = pos; + return false; + } + var kind = this.readVarUint32(); + var tagIndex; + if (kind == CatchHandlerKind.Catch || + kind == CatchHandlerKind.CatchRef) { + if (!this.hasVarIntBytes()) { + this._pos = pos; + return false; + } + tagIndex = this.readVarUint32(); + } + if (!this.hasVarIntBytes()) { + this._pos = pos; + return false; + } + var depth = this.readVarUint32(); + tryTable.push({ kind: kind, depth: depth, tagIndex: tagIndex }); + } + break; case 208 /* OperatorCode.ref_null */: refType = this.readHeapType(); break; @@ -3278,7 +3330,6 @@ var BinaryReader = /** @class */ (function () { case 0 /* OperatorCode.unreachable */: case 1 /* OperatorCode.nop */: case 5 /* OperatorCode.else */: - case 10 /* OperatorCode.unwind */: case 11 /* OperatorCode.end */: case 15 /* OperatorCode.return */: case 25 /* OperatorCode.catch_all */: @@ -3415,6 +3466,7 @@ var BinaryReader = /** @class */ (function () { case 209 /* OperatorCode.ref_is_null */: case 212 /* OperatorCode.ref_as_non_null */: case 211 /* OperatorCode.ref_eq */: + case 10 /* OperatorCode.throw_ref */: break; default: this.error = new Error("Unknown operator: ".concat(code)); @@ -3430,6 +3482,7 @@ var BinaryReader = /** @class */ (function () { srcType: undefined, brDepth: brDepth, brTable: brTable, + tryTable: tryTable, relativeDepth: relativeDepth, tableIndex: tableIndex, funcIndex: funcIndex, diff --git a/devtools/client/shared/widgets/tooltip/css-compatibility-tooltip-helper.js b/devtools/client/shared/widgets/tooltip/css-compatibility-tooltip-helper.js index 40755a212b..ee6a62d4e2 100644 --- a/devtools/client/shared/widgets/tooltip/css-compatibility-tooltip-helper.js +++ b/devtools/client/shared/widgets/tooltip/css-compatibility-tooltip-helper.js @@ -4,8 +4,8 @@ "use strict"; -const { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" +const { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); loader.lazyRequireGetter( diff --git a/devtools/client/storage/test/browser_storage_cache_navigation.js b/devtools/client/storage/test/browser_storage_cache_navigation.js index 5421b85028..0a7ed68484 100644 --- a/devtools/client/storage/test/browser_storage_cache_navigation.js +++ b/devtools/client/storage/test/browser_storage_cache_navigation.js @@ -51,7 +51,10 @@ add_task(async function () { // Check second domain await navigateTo(URL2); - // Select the Cache view in order to force updating it + info("Waiting until Cache > example.net is available in the UI"); + await waitUntil(() => gUI.tree.exists(["Cache", "https://example.net"])); + + info("Select the Cache view in order to force updating it"); await selectTreeItem(["Cache", "https://example.net"]); // wait for storage tree refresh, and check host diff --git a/devtools/client/storage/test/browser_storage_cookies_navigation.js b/devtools/client/storage/test/browser_storage_cookies_navigation.js index 3dc1406451..cd4a562a33 100644 --- a/devtools/client/storage/test/browser_storage_cookies_navigation.js +++ b/devtools/client/storage/test/browser_storage_cookies_navigation.js @@ -115,6 +115,12 @@ add_task(async function () { "host of iframe in previous document (example.org) is not in the tree anymore" ); + // indexedDB is slightly more asynchronously fetched than the others + // and is emitted as a Resource to the frontend late. navigateTo isn't waiting for + // the full initialization of the storage panel on reload. + // To avoid exception when navigating back wait for indexed DB to be updated. + await waitUntil(() => isInTree(doc, ["indexedDB", "https://example.com"])); + info("Navigate backward to test bfcache navigation"); gBrowser.goBack(); await waitUntil( diff --git a/devtools/client/styleeditor/StyleEditorUI.sys.mjs b/devtools/client/styleeditor/StyleEditorUI.sys.mjs index e00a88c3ad..e31bd4bcc1 100644 --- a/devtools/client/styleeditor/StyleEditorUI.sys.mjs +++ b/devtools/client/styleeditor/StyleEditorUI.sys.mjs @@ -1400,6 +1400,10 @@ export class StyleEditorUI extends EventEmitter { type.append(this.#panelDoc.createTextNode(`@${rule.type}\u00A0`)); if (rule.type == "layer" && rule.layerName) { type.append(this.#panelDoc.createTextNode(`${rule.layerName}\u00A0`)); + } else if (rule.type === "property") { + type.append( + this.#panelDoc.createTextNode(`${rule.propertyName}\u00A0`) + ); } const cond = this.#panelDoc.createElementNS(HTML_NS, "span"); @@ -1549,6 +1553,7 @@ export class StyleEditorUI extends EventEmitter { this.#loadingStyleSheets = null; this.#root.classList.remove("loading"); + this.emit("reloaded"); } async #handleStyleSheetResource(resource) { diff --git a/devtools/client/styleeditor/panel.js b/devtools/client/styleeditor/panel.js index 5a2772d095..a7f8cf77c7 100644 --- a/devtools/client/styleeditor/panel.js +++ b/devtools/client/styleeditor/panel.js @@ -48,6 +48,7 @@ StyleEditorPanel.prototype = { cssProperties ); this.UI.on("error", this._showError); + this.UI.on("reloaded", () => this.emit("reloaded")); await this.UI.initialize(options); return this; diff --git a/devtools/client/styleeditor/test/browser_styleeditor_at_rules_sidebar.js b/devtools/client/styleeditor/test/browser_styleeditor_at_rules_sidebar.js index a0a9bc93fd..d106d6780e 100644 --- a/devtools/client/styleeditor/test/browser_styleeditor_at_rules_sidebar.js +++ b/devtools/client/styleeditor/test/browser_styleeditor_at_rules_sidebar.js @@ -39,6 +39,8 @@ waitForExplicitFinish(); add_task(async function () { await pushPref("layout.css.container-queries.enabled", true); + // Enable @property rules + await pushPref("layout.css.properties-and-values.enabled", true); const { ui } = await openStyleEditorForURL(TESTCASE_URI); @@ -88,7 +90,7 @@ async function testInlineMediaEditor(ui, editor) { is(sidebar.hidden, false, "sidebar is showing on editor with @media"); const entries = sidebar.querySelectorAll(".at-rule-label"); - is(entries.length, 6, "6 @media rules displayed in sidebar"); + is(entries.length, 7, "7 at-rules displayed in sidebar"); await testRule({ ui, @@ -123,7 +125,6 @@ async function testInlineMediaEditor(ui, editor) { ui, editor, rule: entries[3], - conditionText: "", line: 16, type: "layer", layerName: "myLayer", @@ -146,6 +147,15 @@ async function testInlineMediaEditor(ui, editor) { line: 21, type: "support", }); + + await testRule({ + ui, + editor, + rule: entries[6], + line: 30, + type: "property", + propertyName: "--my-property", + }); } async function testMediaEditor(ui, editor) { @@ -273,27 +283,35 @@ async function testMediaRuleAdded(ui, editor) { * @param {StyleEditorUI} options.ui * @param {StyleSheetEditor} options.editor: The editor the rule is displayed in * @param {Element} options.rule: The rule element in the media sidebar - * @param {String} options.conditionText: media query condition text + * @param {String} options.conditionText: at-rule condition text (for @media, @container, @support) * @param {Boolean} options.matches: Whether or not the document matches the rule * @param {String} options.layerName: Optional name of the @layer + * @param {String} options.propertyName: Name of the @property if type is "property" * @param {Number} options.line: Line of the rule - * @param {String} options.type: The type of the rule (container, layer, media, support ). + * @param {String} options.type: The type of the rule (container, layer, media, support, property ). * Defaults to "media". */ async function testRule({ ui, editor, rule, - conditionText, + conditionText = "", matches, layerName, + propertyName, line, type = "media", }) { const atTypeEl = rule.querySelector(".at-rule-type"); + let name; + if (type === "layer") { + name = layerName; + } else if (type === "property") { + name = propertyName; + } is( atTypeEl.textContent, - `@${type}\u00A0${layerName ? `${layerName}\u00A0` : ""}`, + `@${type}\u00A0${name ? `${name}\u00A0` : ""}`, "label for at-rule type is correct" ); diff --git a/devtools/client/styleeditor/test/media-rules.html b/devtools/client/styleeditor/test/media-rules.html index 76725bfb54..b74d97f6b2 100644 --- a/devtools/client/styleeditor/test/media-rules.html +++ b/devtools/client/styleeditor/test/media-rules.html @@ -2,6 +2,7 @@ <html> <head> <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> <link rel="stylesheet" href="simple.css"/> <link rel="stylesheet" href="media-rules.css"/> <!-- This stylesheet is needed to ensure we cover the fix for Bug 1779043 --> @@ -38,6 +39,12 @@ } } } + + @property --my-property { + syntax: "<color>"; + inherits: true; + initial-value: #f06; + } </style> </head> <body> diff --git a/devtools/client/themes/dark-theme.css b/devtools/client/themes/dark-theme.css index 8433bc75c4..cd1b58e36e 100644 --- a/devtools/client/themes/dark-theme.css +++ b/devtools/client/themes/dark-theme.css @@ -261,12 +261,16 @@ div.CodeMirror span.marked-text { } -.cm-s-mozilla .empty-line .CodeMirror-linenumber { +.cm-s-mozilla .empty-line .CodeMirror-linenumber, +/* Codemirror 6 */ +.cm-editor .cm-gutterElement.empty-line { color: var(--grey-50); } /* Blackboxing lines */ -.CodeMirror-lines .blackboxed-line :is(span, .cm-comment, .CodeMirror-gutter-elt) { +.CodeMirror-lines .blackboxed-line :is(span, .cm-comment, .CodeMirror-gutter-elt), +/* Codemirror 6 */ +.cm-gutterElement.blackboxed-line, .cm-line.blackboxed-line span[class^="tok-"] { color: #806414cc; } diff --git a/devtools/client/themes/images/whatsnew.svg b/devtools/client/themes/images/whatsnew.svg new file mode 100644 index 0000000000..b77d0165a6 --- /dev/null +++ b/devtools/client/themes/images/whatsnew.svg @@ -0,0 +1,10 @@ +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> + <path fill="context-fill" fill-opacity="context-fill-opacity" d="M2 13.76A1.23 1.23 0 0 0 3.24 15H7V9H2z"/> + <path fill="context-fill" fill-opacity="context-fill-opacity" d="M9 9v6h3.76A1.23 1.23 0 0 0 14 13.76V9H9z"/> + <path fill="context-fill" fill-opacity="context-fill-opacity" d="M1 5v3h6V4H2a1 1 0 0 0-1 1z"/> + <path fill="context-fill" fill-opacity="context-fill-opacity" d="M14 4H9v4h6V5a1 1 0 0 0-1-1z"/> + <path fill="context-fill" fill-opacity="context-fill-opacity" d="M10.05.41A1.34 1.34 0 0 0 8 1a1.35 1.35 0 0 0-2-.59C5.2 1.08 4.91 2.48 8 4c3.09-1.52 2.8-2.92 2.05-3.59z"/> +</svg> diff --git a/devtools/client/themes/light-theme.css b/devtools/client/themes/light-theme.css index d54bfffef3..979999bd31 100644 --- a/devtools/client/themes/light-theme.css +++ b/devtools/client/themes/light-theme.css @@ -248,12 +248,16 @@ div.CodeMirror span.marked-text { margin-inline-end: -1px; } -.cm-s-mozilla .empty-line .CodeMirror-linenumber { +.cm-s-mozilla .empty-line .CodeMirror-linenumber, +/* Codemirror 6 */ +.cm-editor .cm-gutterElement.empty-line { color: var(--grey-40); } /* Blackboxing lines */ -.CodeMirror-lines .blackboxed-line :is(span, .cm-comment, .CodeMirror-gutter-elt) { +.CodeMirror-lines .blackboxed-line :is(span, .cm-comment, .CodeMirror-gutter-elt), +/* Codemirror 6 */ +.cm-gutterElement.blackboxed-line, .cm-line.blackboxed-line span[class^="tok-"] { color: #806414cc; } diff --git a/devtools/client/themes/rules.css b/devtools/client/themes/rules.css index 72ca35fff7..c3079e3d62 100644 --- a/devtools/client/themes/rules.css +++ b/devtools/client/themes/rules.css @@ -825,6 +825,10 @@ cursor: text; } +.ruleview-variable { + color: var(--theme-highlight-blue); +} + .ruleview-selector-separator, .ruleview-selector.unmatched, .ruleview-unmatched-variable, diff --git a/devtools/client/webconsole/components/Output/message-types/JSTracerTrace.js b/devtools/client/webconsole/components/Output/message-types/JSTracerTrace.js index 241fa15bd1..ed74728777 100644 --- a/devtools/client/webconsole/components/Output/message-types/JSTracerTrace.js +++ b/devtools/client/webconsole/components/Output/message-types/JSTracerTrace.js @@ -60,7 +60,7 @@ function JSTracerTrace(props) { // Attributes specific to function call returns returnedValue, relatedTraceId, - // See tracer.jsm FRAME_EXIT_REASONS + // See tracer.sys.mjs FRAME_EXIT_REASONS why, // Attributes specific to DOM Mutations diff --git a/devtools/client/webconsole/test/browser/_jsterm.toml b/devtools/client/webconsole/test/browser/_jsterm.toml index c9be46216a..fd23edd9c6 100644 --- a/devtools/client/webconsole/test/browser/_jsterm.toml +++ b/devtools/client/webconsole/test/browser/_jsterm.toml @@ -28,7 +28,7 @@ support-files = [ "!/devtools/client/framework/browser-toolbox/test/helpers-browser-toolbox.js", "!/devtools/client/shared/test/telemetry-test-helpers.js", "!/devtools/client/shared/test/highlighter-test-actor.js", - "../../../../../toolkit/components/reader/test/readerModeArticle.html", + "../../../../../toolkit/components/reader/tests/browser/readerModeArticle.html", ] ["browser_jsterm_add_edited_input_to_history.js"] diff --git a/devtools/client/webconsole/test/browser/browser_console_webconsole_private_browsing.js b/devtools/client/webconsole/test/browser/browser_console_webconsole_private_browsing.js index 0fed8c03c5..96033f84d8 100644 --- a/devtools/client/webconsole/test/browser/browser_console_webconsole_private_browsing.js +++ b/devtools/client/webconsole/test/browser/browser_console_webconsole_private_browsing.js @@ -141,7 +141,7 @@ add_task(async function () { info("close the private window and check if private messages are removed"); const onPrivateMessagesCleared = hud.ui.once("private-messages-cleared"); - privateWindow.BrowserTryToCloseWindow(); + privateWindow.BrowserCommands.tryToCloseWindow(); await onPrivateMessagesCleared; ok( diff --git a/devtools/client/webconsole/test/browser/browser_jsterm_await_paused.js b/devtools/client/webconsole/test/browser/browser_jsterm_await_paused.js index 421837e9eb..f0dbca4dd8 100644 --- a/devtools/client/webconsole/test/browser/browser_jsterm_await_paused.js +++ b/devtools/client/webconsole/test/browser/browser_jsterm_await_paused.js @@ -12,7 +12,7 @@ add_task(async function () { await pushPref("devtools.debugger.features.map-await-expression", true); // Force the split console to be closed. - await pushPref("devtools.toolbox.splitconsoleEnabled", false); + await pushPref("devtools.toolbox.splitconsole.open", false); const hud = await openNewTabAndConsole(TEST_URI); const pauseExpression = `(() => { diff --git a/devtools/client/webconsole/test/browser/browser_jsterm_eager_evaluation.js b/devtools/client/webconsole/test/browser/browser_jsterm_eager_evaluation.js index 194cc64531..dae99c1961 100644 --- a/devtools/client/webconsole/test/browser/browser_jsterm_eager_evaluation.js +++ b/devtools/client/webconsole/test/browser/browser_jsterm_eager_evaluation.js @@ -310,7 +310,7 @@ add_task(async function () { EventUtils.synthesizeKey("KEY_ArrowDown"); // Navigates to the XMLDocument item in the popup - await waitForEagerEvaluationResult(hud, `function ()`); + await waitForEagerEvaluationResult(hud, `function XMLDocument()`); onPopupClose = popup.once("popup-closed"); EventUtils.sendString(" "); diff --git a/devtools/client/webconsole/test/browser/browser_jsterm_editor_reverse_search_keyboard_navigation.js b/devtools/client/webconsole/test/browser/browser_jsterm_editor_reverse_search_keyboard_navigation.js index 0b9b828ce3..bbdc251107 100644 --- a/devtools/client/webconsole/test/browser/browser_jsterm_editor_reverse_search_keyboard_navigation.js +++ b/devtools/client/webconsole/test/browser/browser_jsterm_editor_reverse_search_keyboard_navigation.js @@ -6,7 +6,7 @@ // Ensure keyboard navigation works in editor mode and does // not trigger reader mode (See 1682340). -const TEST_URI = `http://example.com/browser/toolkit/components/reader/test/readerModeArticle.html`; +const TEST_URI = `http://example.com/browser/toolkit/components/reader/tests/browser/readerModeArticle.html`; const isMacOS = AppConstants.platform === "macosx"; add_task(async function () { @@ -42,7 +42,7 @@ add_task(async function () { await wait(1000); is( readerModeButtonEl.getAttribute("readeractive"), - "", + null, "reader mode wasn't activated" ); @@ -72,7 +72,7 @@ add_task(async function () { await wait(1000); is( readerModeButtonEl.getAttribute("readeractive"), - "", + null, "reader mode still wasn't activated" ); diff --git a/devtools/client/webconsole/test/browser/browser_webconsole_console_api_iframe.js b/devtools/client/webconsole/test/browser/browser_webconsole_console_api_iframe.js index 9670312e85..977710b78e 100644 --- a/devtools/client/webconsole/test/browser/browser_webconsole_console_api_iframe.js +++ b/devtools/client/webconsole/test/browser/browser_webconsole_console_api_iframe.js @@ -17,7 +17,7 @@ add_task(async function () { ok(true, "The initial message is displayed in the console"); // Create a promise for the message logged after the reload. const onMessage = waitForMessageByType(hud, loggedString, ".console-api"); - BrowserReload(); + BrowserCommands.reload(); await onMessage; ok(true, "The message is also displayed after a page reload"); }); diff --git a/devtools/client/webconsole/test/browser/browser_webconsole_cors_errors.js b/devtools/client/webconsole/test/browser/browser_webconsole_cors_errors.js index b29da33bab..c20991c1bf 100644 --- a/devtools/client/webconsole/test/browser/browser_webconsole_cors_errors.js +++ b/devtools/client/webconsole/test/browser/browser_webconsole_cors_errors.js @@ -6,6 +6,9 @@ "use strict"; +// The test can take a bit long on slow machines. +requestLongerTimeout(2); + const TEST_URI = "http://example.com/browser/devtools/client/webconsole/test/browser/test-network-request.html"; const BASE_CORS_ERROR_URL = @@ -40,6 +43,7 @@ add_task(async function () { await checkCorsMessage(hud, message, "CORSDisabled"); await pushPref("content.cors.disable", false); + await clearOutput(hud); info("Test CORSPreflightDidNotSucceed"); onCorsMessage = waitForMessageByType( hud, @@ -50,6 +54,7 @@ add_task(async function () { message = await onCorsMessage; await checkCorsMessage(hud, message, "CORSPreflightDidNotSucceed"); + await clearOutput(hud); info("Test CORS did not succeed"); onCorsMessage = waitForMessageByType( hud, @@ -60,6 +65,7 @@ add_task(async function () { message = await onCorsMessage; await checkCorsMessage(hud, message, "CORSDidNotSucceed"); + await clearOutput(hud); info("Test CORSExternalRedirectNotAllowed"); onCorsMessage = waitForMessageByType( hud, @@ -70,6 +76,7 @@ add_task(async function () { message = await onCorsMessage; await checkCorsMessage(hud, message, "CORSExternalRedirectNotAllowed"); + await clearOutput(hud); info("Test CORSMissingAllowOrigin"); onCorsMessage = waitForMessageByType( hud, @@ -82,6 +89,7 @@ add_task(async function () { message = await onCorsMessage; await checkCorsMessage(hud, message, "CORSMissingAllowOrigin"); + await clearOutput(hud); info("Test CORSMultipleAllowOriginNotAllowed"); onCorsMessage = waitForMessageByType( hud, @@ -94,6 +102,7 @@ add_task(async function () { message = await onCorsMessage; await checkCorsMessage(hud, message, "CORSMultipleAllowOriginNotAllowed"); + await clearOutput(hud); info("Test CORSAllowOriginNotMatchingOrigin"); onCorsMessage = waitForMessageByType( hud, @@ -107,6 +116,7 @@ add_task(async function () { message = await onCorsMessage; await checkCorsMessage(hud, message, "CORSAllowOriginNotMatchingOrigin"); + await clearOutput(hud); info("Test CORSNotSupportingCredentials"); onCorsMessage = waitForMessageByType( hud, @@ -118,6 +128,7 @@ add_task(async function () { message = await onCorsMessage; await checkCorsMessage(hud, message, "CORSNotSupportingCredentials"); + await clearOutput(hud); info("Test CORSMethodNotFound"); onCorsMessage = waitForMessageByType( hud, @@ -129,6 +140,7 @@ add_task(async function () { message = await onCorsMessage; await checkCorsMessage(hud, message, "CORSMethodNotFound"); + await clearOutput(hud); info("Test CORSMissingAllowCredentials"); onCorsMessage = waitForMessageByType( hud, @@ -140,6 +152,7 @@ add_task(async function () { message = await onCorsMessage; await checkCorsMessage(hud, message, "CORSMissingAllowCredentials"); + await clearOutput(hud); info("Test CORSInvalidAllowMethod"); onCorsMessage = waitForMessageByType( hud, @@ -151,6 +164,7 @@ add_task(async function () { message = await onCorsMessage; await checkCorsMessage(hud, message, "CORSInvalidAllowMethod"); + await clearOutput(hud); info("Test CORSInvalidAllowHeader"); onCorsMessage = waitForMessageByType( hud, @@ -162,6 +176,7 @@ add_task(async function () { message = await onCorsMessage; await checkCorsMessage(hud, message, "CORSInvalidAllowHeader"); + await clearOutput(hud); info("Test CORSMissingAllowHeaderFromPreflight"); onCorsMessage = waitForMessageByType( hud, diff --git a/devtools/client/webconsole/test/browser/browser_webconsole_split_escape_key.js b/devtools/client/webconsole/test/browser/browser_webconsole_split_escape_key.js index 84c6935510..8127ae1709 100644 --- a/devtools/client/webconsole/test/browser/browser_webconsole_split_escape_key.js +++ b/devtools/client/webconsole/test/browser/browser_webconsole_split_escape_key.js @@ -53,4 +53,27 @@ add_task(async function () { await onSplitConsoleEvent; ok(!toolbox.splitConsole, "Split console is hidden."); + + info("Test if Split console Shortcut stops working when it's disabled."); + + info("Setting the Pref to false and sending ESCAPE key."); + await pushPref("devtools.toolbox.splitconsole.enabled", false); + // pushPref doesn't trigger _prefChanged of toolbox-options.js, so we invoke the toolbox setting update manually + toolbox.updateIsSplitConsoleEnabled(); + const onSplitConsole = toolbox.once("split-console"); + const onTimeout = wait(1000).then(() => "TIMEOUT"); + EventUtils.sendKey("ESCAPE", toolbox.win); + const raceResult = await Promise.race([onSplitConsole, onTimeout]); + is(raceResult, "TIMEOUT", "split-console wasn't emitted"); + + ok(!toolbox.splitConsole, "Split console didn't get Triggered."); + + info("Setting the Pref to true and sending ESCAPE key again."); + await pushPref("devtools.toolbox.splitconsole.enabled", true); + toolbox.updateIsSplitConsoleEnabled(); + const onSplitConsoleReadyAgain = toolbox.once("split-console"); + EventUtils.sendKey("ESCAPE", toolbox.win); + await onSplitConsoleReadyAgain; + + ok(toolbox.splitConsole, "Split console Shortcut is working again."); }); diff --git a/devtools/client/webconsole/test/browser/browser_webconsole_split_persist.js b/devtools/client/webconsole/test/browser/browser_webconsole_split_persist.js index 2442b64b5b..2f037c6ee0 100644 --- a/devtools/client/webconsole/test/browser/browser_webconsole_split_persist.js +++ b/devtools/client/webconsole/test/browser/browser_webconsole_split_persist.js @@ -99,7 +99,7 @@ add_task(async function () { }); function getVisiblePrefValue() { - return Services.prefs.getBoolPref("devtools.toolbox.splitconsoleEnabled"); + return Services.prefs.getBoolPref("devtools.toolbox.splitconsole.open"); } function getHeightPrefValue() { diff --git a/devtools/client/webconsole/test/browser/browser_webconsole_stubs_console_api.js b/devtools/client/webconsole/test/browser/browser_webconsole_stubs_console_api.js index 9718a8efd1..86e62b173d 100644 --- a/devtools/client/webconsole/test/browser/browser_webconsole_stubs_console_api.js +++ b/devtools/client/webconsole/test/browser/browser_webconsole_stubs_console_api.js @@ -68,6 +68,11 @@ async function generateConsoleApiStubs() { await commands.targetCommand.startListening(); const resourceCommand = commands.resourceCommand; + // Ensure waiting for sources in order to populate message.sourceId correctly. + await resourceCommand.watchResources([resourceCommand.TYPES.SOURCE], { + onAvailable() {}, + }); + // The resource-watcher only supports a single call to watch/unwatch per // instance, so we attach a unique watch callback, which will forward the // resource to `handleConsoleMessage`, dynamically updated for each command. diff --git a/devtools/client/webconsole/test/browser/browser_webconsole_stubs_page_error.js b/devtools/client/webconsole/test/browser/browser_webconsole_stubs_page_error.js index d6610b7309..50029a3139 100644 --- a/devtools/client/webconsole/test/browser/browser_webconsole_stubs_page_error.js +++ b/devtools/client/webconsole/test/browser/browser_webconsole_stubs_page_error.js @@ -70,6 +70,11 @@ async function generatePageErrorStubs() { await commands.targetCommand.startListening(); const resourceCommand = commands.resourceCommand; + // Ensure waiting for sources in order to populate message.sourceId correctly. + await resourceCommand.watchResources([resourceCommand.TYPES.SOURCE], { + onAvailable() {}, + }); + // The resource-watcher only supports a single call to watch/unwatch per // instance, so we attach a unique watch callback, which will forward the // resource to `handleErrorMessage`, dynamically updated for each command. diff --git a/devtools/client/webconsole/test/chrome/head.js b/devtools/client/webconsole/test/chrome/head.js index 2f984d564d..3f4988c2d0 100644 --- a/devtools/client/webconsole/test/chrome/head.js +++ b/devtools/client/webconsole/test/chrome/head.js @@ -4,8 +4,8 @@ "use strict"; -var { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" +var { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); var { require: browserRequire } = BrowserLoader({ diff --git a/devtools/client/webconsole/webconsole-ui.js b/devtools/client/webconsole/webconsole-ui.js index a12f1f3983..b562752ccb 100644 --- a/devtools/client/webconsole/webconsole-ui.js +++ b/devtools/client/webconsole/webconsole-ui.js @@ -10,8 +10,8 @@ const { l10n, } = require("resource://devtools/client/webconsole/utils/messages.js"); -const { BrowserLoader } = ChromeUtils.import( - "resource://devtools/shared/loader/browser-loader.js" +const { BrowserLoader } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/browser-loader.sys.mjs" ); const { getAdHocFrontOrPrimitiveGrip, |