diff --git a/browser/config/mozconfigs/linux64/beta b/browser/config/mozconfigs/linux64/beta index 29ceee4f49536..a523db851dc46 100644 --- a/browser/config/mozconfigs/linux64/beta +++ b/browser/config/mozconfigs/linux64/beta @@ -1,4 +1,4 @@ -export MOZ_PGO=1 +. "$topsrcdir/build/mozconfig.pgo" . "$topsrcdir/browser/config/mozconfigs/linux64/common-opt" diff --git a/browser/config/mozconfigs/linux64/release b/browser/config/mozconfigs/linux64/release index bf2af71d3a307..a7a075950161d 100644 --- a/browser/config/mozconfigs/linux64/release +++ b/browser/config/mozconfigs/linux64/release @@ -1,7 +1,7 @@ # This make file should be identical to the beta mozconfig, apart from the # safeguard below -export MOZ_PGO=1 +. "$topsrcdir/build/mozconfig.pgo" . "$topsrcdir/browser/config/mozconfigs/linux64/common-opt" diff --git a/browser/config/mozconfigs/whitelist b/browser/config/mozconfigs/whitelist index d6659f89b5737..d66055cd23705 100644 --- a/browser/config/mozconfigs/whitelist +++ b/browser/config/mozconfigs/whitelist @@ -42,7 +42,7 @@ whitelist['release']['linux32'] += [ whitelist['release']['linux64'] += [ 'export MOZILLA_OFFICIAL=1', 'export MOZ_TELEMETRY_REPORTING=1', - 'export MOZ_PGO=1', + '. "$topsrcdir/build/mozconfig.pgo"', ] if __name__ == '__main__': diff --git a/browser/config/mozconfigs/win32/common-opt b/browser/config/mozconfigs/win32/common-opt index cec7b0b6e75a5..9aa2658aea469 100644 --- a/browser/config/mozconfigs/win32/common-opt +++ b/browser/config/mozconfigs/win32/common-opt @@ -5,7 +5,6 @@ . "$topsrcdir/browser/config/mozconfigs/common" ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} -ac_add_options --enable-jemalloc if [ -f /c/builds/gapi.data ]; then _gapi_keyfile=c:/builds/gapi.data diff --git a/browser/config/mozconfigs/win64-aarch64/common-opt b/browser/config/mozconfigs/win64-aarch64/common-opt index 29484fa32b252..551458d6bff4e 100644 --- a/browser/config/mozconfigs/win64-aarch64/common-opt +++ b/browser/config/mozconfigs/win64-aarch64/common-opt @@ -5,7 +5,7 @@ . "$topsrcdir/browser/config/mozconfigs/common" ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} -ac_add_options --enable-jemalloc + if [ -f /c/builds/gapi.data ]; then _gapi_keyfile=c:/builds/gapi.data else diff --git a/browser/config/mozconfigs/win64/common-opt b/browser/config/mozconfigs/win64/common-opt index 4cd860705eda0..5129a713b4f9e 100644 --- a/browser/config/mozconfigs/win64/common-opt +++ b/browser/config/mozconfigs/win64/common-opt @@ -5,7 +5,7 @@ . "$topsrcdir/browser/config/mozconfigs/common" ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} -ac_add_options --enable-jemalloc + if [ -f /c/builds/gapi.data ]; then _gapi_keyfile=c:/builds/gapi.data else diff --git a/browser/extensions/pdfjs/README.mozilla b/browser/extensions/pdfjs/README.mozilla index 0ce1b62951eef..f652fff1474c8 100644 --- a/browser/extensions/pdfjs/README.mozilla +++ b/browser/extensions/pdfjs/README.mozilla @@ -1,5 +1,5 @@ This is the PDF.js project output, https://github.com/mozilla/pdf.js -Current extension version is: 2.1.266 +Current extension version is: 2.2.15 -Taken from upstream commit: 81f5835c +Taken from upstream commit: ece6a31a diff --git a/browser/extensions/pdfjs/content/PdfJsDefaultPreferences.jsm b/browser/extensions/pdfjs/content/PdfJsDefaultPreferences.jsm index 65439871d34c2..8b83a7b506b86 100644 --- a/browser/extensions/pdfjs/content/PdfJsDefaultPreferences.jsm +++ b/browser/extensions/pdfjs/content/PdfJsDefaultPreferences.jsm @@ -22,25 +22,25 @@ "use strict"; var EXPORTED_SYMBOLS = ["PdfJsDefaultPreferences"]; var PdfJsDefaultPreferences = Object.freeze({ - "viewOnLoad": 0, - "defaultZoomValue": "", - "sidebarViewOnLoad": -1, "cursorToolOnLoad": 0, + "defaultZoomValue": "", + "disablePageLabels": false, + "enablePrintAutoRotate": false, "enableWebGL": false, "eventBusDispatchToDOM": false, - "pdfBugEnabled": false, - "disableRange": false, - "disableStream": false, - "disableAutoFetch": false, - "disableFontFace": false, - "textLayerMode": 1, - "useOnlyCssZoom": false, "externalLinkTarget": 0, + "historyUpdateUrl": false, + "pdfBugEnabled": false, "renderer": "canvas", "renderInteractiveForms": false, - "enablePrintAutoRotate": false, - "disablePageLabels": false, - "historyUpdateUrl": false, + "sidebarViewOnLoad": -1, "scrollModeOnLoad": -1, - "spreadModeOnLoad": -1 + "spreadModeOnLoad": -1, + "textLayerMode": 1, + "useOnlyCssZoom": false, + "viewOnLoad": 0, + "disableAutoFetch": false, + "disableFontFace": false, + "disableRange": false, + "disableStream": false }); diff --git a/browser/extensions/pdfjs/content/build/pdf.js b/browser/extensions/pdfjs/content/build/pdf.js index 24b6b7d7a965c..c9b2748e1a7a1 100644 --- a/browser/extensions/pdfjs/content/build/pdf.js +++ b/browser/extensions/pdfjs/content/build/pdf.js @@ -123,8 +123,8 @@ return /******/ (function(modules) { // webpackBootstrap "use strict"; -var pdfjsVersion = '2.1.266'; -var pdfjsBuild = '81f5835c'; +var pdfjsVersion = '2.2.15'; +var pdfjsBuild = 'ece6a31a'; var pdfjsSharedUtil = __w_pdfjs_require__(1); @@ -1411,7 +1411,7 @@ function _fetchDocument(worker, source, pdfDataRangeTransport, docId) { return worker.messageHandler.sendWithPromise('GetDocRequest', { docId, - apiVersion: '2.1.266', + apiVersion: '2.2.15', source: { data: source.data, url: source.url, @@ -3148,9 +3148,9 @@ const InternalRenderTask = function InternalRenderTaskClosure() { return InternalRenderTask; }(); -const version = '2.1.266'; +const version = '2.2.15'; exports.version = version; -const build = '81f5835c'; +const build = 'ece6a31a'; exports.build = build; /***/ }), diff --git a/browser/extensions/pdfjs/content/build/pdf.worker.js b/browser/extensions/pdfjs/content/build/pdf.worker.js index 2692d980e9bd0..82e90ff8436a3 100644 --- a/browser/extensions/pdfjs/content/build/pdf.worker.js +++ b/browser/extensions/pdfjs/content/build/pdf.worker.js @@ -123,8 +123,8 @@ return /******/ (function(modules) { // webpackBootstrap "use strict"; -const pdfjsVersion = '2.1.266'; -const pdfjsBuild = '81f5835c'; +const pdfjsVersion = '2.2.15'; +const pdfjsBuild = 'ece6a31a'; const pdfjsCoreWorker = __w_pdfjs_require__(1); @@ -375,7 +375,7 @@ var WorkerMessageHandler = { var cancelXHRs = null; var WorkerTasks = []; let apiVersion = docParams.apiVersion; - let workerVersion = '2.1.266'; + let workerVersion = '2.2.15'; if (apiVersion !== workerVersion) { throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`); @@ -3007,7 +3007,7 @@ class PDFDocument { this.xfa = this.acroForm.get('XFA'); const fields = this.acroForm.get('Fields'); - if ((!fields || !Array.isArray(fields) || fields.length === 0) && !this.xfa) { + if ((!Array.isArray(fields) || fields.length === 0) && !this.xfa) { this.acroForm = null; } } @@ -3019,6 +3019,20 @@ class PDFDocument { (0, _util.info)('Cannot fetch AcroForm entry; assuming no AcroForms are present'); this.acroForm = null; } + + try { + const collection = this.catalog.catDict.get('Collection'); + + if ((0, _primitives.isDict)(collection) && collection.getKeys().length > 0) { + this.collection = collection; + } + } catch (ex) { + if (ex instanceof _util.MissingDataException) { + throw ex; + } + + (0, _util.info)('Cannot fetch Collection dictionary.'); + } } get linearization() { @@ -3147,7 +3161,8 @@ class PDFDocument { PDFFormatVersion: this.pdfFormatVersion, IsLinearized: !!this.linearization, IsAcroFormPresent: !!this.acroForm, - IsXFAPresent: !!this.xfa + IsXFAPresent: !!this.xfa, + IsCollectionPresent: !!this.collection }; let infoDict; diff --git a/browser/extensions/pdfjs/content/web/viewer.js b/browser/extensions/pdfjs/content/web/viewer.js index f5af53ad4aa84..c008414998c5b 100644 --- a/browser/extensions/pdfjs/content/web/viewer.js +++ b/browser/extensions/pdfjs/content/web/viewer.js @@ -117,7 +117,7 @@ let pdfjsWebApp, pdfjsWebAppOptions; { pdfjsWebApp = __webpack_require__(1); - pdfjsWebAppOptions = __webpack_require__(8); + pdfjsWebAppOptions = __webpack_require__(3); } { __webpack_require__(33); @@ -278,15 +278,15 @@ exports.PDFPrintServiceFactory = exports.DefaultExternalServices = exports.PDFVi var _ui_utils = __webpack_require__(2); -var _pdfjsLib = __webpack_require__(3); +var _app_options = __webpack_require__(3); -var _pdf_cursor_tools = __webpack_require__(4); +var _pdfjsLib = __webpack_require__(4); -var _pdf_rendering_queue = __webpack_require__(6); +var _pdf_cursor_tools = __webpack_require__(6); -var _pdf_sidebar = __webpack_require__(7); +var _pdf_rendering_queue = __webpack_require__(8); -var _app_options = __webpack_require__(8); +var _pdf_sidebar = __webpack_require__(9); var _overlay_manager = __webpack_require__(10); @@ -808,7 +808,7 @@ let PDFViewerApplication = { await this.close(); } - const workerParameters = _app_options.AppOptions.getAll('worker'); + const workerParameters = _app_options.AppOptions.getAll(_app_options.OptionKind.WORKER); for (let key in workerParameters) { _pdfjsLib.GlobalWorkerOptions[key] = workerParameters[key]; @@ -828,7 +828,7 @@ let PDFViewerApplication = { parameters.docBaseUrl = this.baseUrl; - const apiParameters = _app_options.AppOptions.getAll('api'); + const apiParameters = _app_options.AppOptions.getAll(_app_options.OptionKind.API); for (let key in apiParameters) { parameters[key] = apiParameters[key]; @@ -3103,6 +3103,237 @@ function moveToEndOfArray(arr, condition) { "use strict"; +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.OptionKind = exports.AppOptions = void 0; + +var _pdfjsLib = __webpack_require__(4); + +var _viewer_compatibility = __webpack_require__(5); + +const OptionKind = { + VIEWER: 0x02, + API: 0x04, + WORKER: 0x08, + PREFERENCE: 0x80 +}; +exports.OptionKind = OptionKind; +const defaultOptions = { + cursorToolOnLoad: { + value: 0, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + defaultUrl: { + value: 'compressed.tracemonkey-pldi-09.pdf', + kind: OptionKind.VIEWER + }, + defaultZoomValue: { + value: '', + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + disableHistory: { + value: false, + kind: OptionKind.VIEWER + }, + disablePageLabels: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + enablePrintAutoRotate: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + enableWebGL: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + eventBusDispatchToDOM: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + externalLinkRel: { + value: 'noopener noreferrer nofollow', + kind: OptionKind.VIEWER + }, + externalLinkTarget: { + value: 0, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + historyUpdateUrl: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + imageResourcesPath: { + value: './images/', + kind: OptionKind.VIEWER + }, + maxCanvasPixels: { + value: 16777216, + compatibility: _viewer_compatibility.viewerCompatibilityParams.maxCanvasPixels, + kind: OptionKind.VIEWER + }, + pdfBugEnabled: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + renderer: { + value: 'canvas', + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + renderInteractiveForms: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + sidebarViewOnLoad: { + value: -1, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + scrollModeOnLoad: { + value: -1, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + spreadModeOnLoad: { + value: -1, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + textLayerMode: { + value: 1, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + useOnlyCssZoom: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + viewOnLoad: { + value: 0, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, + cMapPacked: { + value: true, + kind: OptionKind.API + }, + cMapUrl: { + value: '../web/cmaps/', + kind: OptionKind.API + }, + disableAutoFetch: { + value: false, + kind: OptionKind.API + OptionKind.PREFERENCE + }, + disableCreateObjectURL: { + value: false, + compatibility: _pdfjsLib.apiCompatibilityParams.disableCreateObjectURL, + kind: OptionKind.API + }, + disableFontFace: { + value: false, + kind: OptionKind.API + OptionKind.PREFERENCE + }, + disableRange: { + value: false, + kind: OptionKind.API + OptionKind.PREFERENCE + }, + disableStream: { + value: false, + kind: OptionKind.API + OptionKind.PREFERENCE + }, + isEvalSupported: { + value: true, + kind: OptionKind.API + }, + maxImageSize: { + value: -1, + kind: OptionKind.API + }, + pdfBug: { + value: false, + kind: OptionKind.API + }, + postMessageTransfers: { + value: true, + kind: OptionKind.API + }, + verbosity: { + value: 1, + kind: OptionKind.API + }, + workerPort: { + value: null, + kind: OptionKind.WORKER + }, + workerSrc: { + value: '../build/pdf.worker.js', + kind: OptionKind.WORKER + } +}; +; +const userOptions = Object.create(null); + +class AppOptions { + constructor() { + throw new Error('Cannot initialize AppOptions.'); + } + + static get(name) { + const userOption = userOptions[name]; + + if (userOption !== undefined) { + return userOption; + } + + const defaultOption = defaultOptions[name]; + + if (defaultOption !== undefined) { + return defaultOption.compatibility || defaultOption.value; + } + + return undefined; + } + + static getAll(kind = null) { + const options = Object.create(null); + + for (const name in defaultOptions) { + const defaultOption = defaultOptions[name]; + + if (kind) { + if ((kind & defaultOption.kind) === 0) { + continue; + } + + if ((kind & OptionKind.PREFERENCE) !== 0) { + options[name] = defaultOption.value; + continue; + } + } + + const userOption = userOptions[name]; + options[name] = userOption !== undefined ? userOption : defaultOption.compatibility || defaultOption.value; + } + + return options; + } + + static set(name, value) { + userOptions[name] = value; + } + + static remove(name) { + delete userOptions[name]; + } + +} + +exports.AppOptions = AppOptions; + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + let pdfjsLib; if (typeof window !== 'undefined' && window['pdfjs-dist/build/pdf']) { @@ -3114,7 +3345,18 @@ if (typeof window !== 'undefined' && window['pdfjs-dist/build/pdf']) { module.exports = pdfjsLib; /***/ }), -/* 4 */ +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +let compatibilityParams = Object.create(null); +; +exports.viewerCompatibilityParams = Object.freeze(compatibilityParams); + +/***/ }), +/* 6 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -3125,7 +3367,7 @@ Object.defineProperty(exports, "__esModule", { }); exports.PDFCursorTools = exports.CursorTool = void 0; -var _grab_to_pan = __webpack_require__(5); +var _grab_to_pan = __webpack_require__(7); const CursorTool = { SELECT: 0, @@ -3237,7 +3479,7 @@ class PDFCursorTools { exports.PDFCursorTools = PDFCursorTools; /***/ }), -/* 5 */ +/* 7 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -3400,7 +3642,7 @@ function isLeftMouseReleased(event) { } /***/ }), -/* 6 */ +/* 8 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -3537,7 +3779,7 @@ class PDFRenderingQueue { exports.PDFRenderingQueue = PDFRenderingQueue; /***/ }), -/* 7 */ +/* 9 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -3550,7 +3792,7 @@ exports.PDFSidebar = exports.SidebarView = void 0; var _ui_utils = __webpack_require__(2); -var _pdf_rendering_queue = __webpack_require__(6); +var _pdf_rendering_queue = __webpack_require__(8); const UI_NOTIFICATION_CLASS = 'pdfSidebarNotification'; const SidebarView = { @@ -3724,420 +3966,186 @@ class PDFSidebar { close() { if (!this.isOpen) { - return; - } - - this.isOpen = false; - this.toggleButton.classList.remove('toggled'); - this.outerContainer.classList.add('sidebarMoving'); - this.outerContainer.classList.remove('sidebarOpen'); - - this._forceRendering(); - - this._dispatchEvent(); - } - - toggle() { - if (this.isOpen) { - this.close(); - } else { - this.open(); - } - } - - _dispatchEvent() { - this.eventBus.dispatch('sidebarviewchanged', { - source: this, - view: this.visibleView - }); - } - - _forceRendering() { - if (this.onToggled) { - this.onToggled(); - } else { - this.pdfViewer.forceRendering(); - this.pdfThumbnailViewer.forceRendering(); - } - } - - _updateThumbnailViewer() { - let { - pdfViewer, - pdfThumbnailViewer - } = this; - let pagesCount = pdfViewer.pagesCount; - - for (let pageIndex = 0; pageIndex < pagesCount; pageIndex++) { - let pageView = pdfViewer.getPageView(pageIndex); - - if (pageView && pageView.renderingState === _pdf_rendering_queue.RenderingStates.FINISHED) { - let thumbnailView = pdfThumbnailViewer.getThumbnail(pageIndex); - thumbnailView.setImage(pageView); - } - } - - pdfThumbnailViewer.scrollThumbnailIntoView(pdfViewer.currentPageNumber); - } - - _showUINotification(view) { - if (this.disableNotification) { - return; - } - - this.l10n.get('toggle_sidebar_notification.title', null, 'Toggle Sidebar (document contains outline/attachments)').then(msg => { - this.toggleButton.title = msg; - }); - - if (!this.isOpen) { - this.toggleButton.classList.add(UI_NOTIFICATION_CLASS); - } else if (view === this.active) { - return; - } - - switch (view) { - case SidebarView.OUTLINE: - this.outlineButton.classList.add(UI_NOTIFICATION_CLASS); - break; - - case SidebarView.ATTACHMENTS: - this.attachmentsButton.classList.add(UI_NOTIFICATION_CLASS); - break; - } - } - - _hideUINotification(view) { - if (this.disableNotification) { - return; - } - - let removeNotification = view => { - switch (view) { - case SidebarView.OUTLINE: - this.outlineButton.classList.remove(UI_NOTIFICATION_CLASS); - break; - - case SidebarView.ATTACHMENTS: - this.attachmentsButton.classList.remove(UI_NOTIFICATION_CLASS); - break; - } - }; - - if (!this.isOpen && view !== null) { - return; - } - - this.toggleButton.classList.remove(UI_NOTIFICATION_CLASS); - - if (view !== null) { - removeNotification(view); - return; - } - - for (view in SidebarView) { - removeNotification(SidebarView[view]); - } - - this.l10n.get('toggle_sidebar.title', null, 'Toggle Sidebar').then(msg => { - this.toggleButton.title = msg; - }); - } - - _addEventListeners() { - this.viewerContainer.addEventListener('transitionend', evt => { - if (evt.target === this.viewerContainer) { - this.outerContainer.classList.remove('sidebarMoving'); - } - }); - this.thumbnailButton.addEventListener('click', () => { - this.switchView(SidebarView.THUMBS); - }); - this.outlineButton.addEventListener('click', () => { - this.switchView(SidebarView.OUTLINE); - }); - this.outlineButton.addEventListener('dblclick', () => { - this.eventBus.dispatch('toggleoutlinetree', { - source: this - }); - }); - this.attachmentsButton.addEventListener('click', () => { - this.switchView(SidebarView.ATTACHMENTS); - }); - this.eventBus.on('outlineloaded', evt => { - let outlineCount = evt.outlineCount; - this.outlineButton.disabled = !outlineCount; - - if (outlineCount) { - this._showUINotification(SidebarView.OUTLINE); - } else if (this.active === SidebarView.OUTLINE) { - this.switchView(SidebarView.THUMBS); - } - }); - this.eventBus.on('attachmentsloaded', evt => { - if (evt.attachmentsCount) { - this.attachmentsButton.disabled = false; - - this._showUINotification(SidebarView.ATTACHMENTS); - - return; - } - - Promise.resolve().then(() => { - if (this.attachmentsView.hasChildNodes()) { - return; - } - - this.attachmentsButton.disabled = true; - - if (this.active === SidebarView.ATTACHMENTS) { - this.switchView(SidebarView.THUMBS); - } - }); - }); - this.eventBus.on('presentationmodechanged', evt => { - if (!evt.active && !evt.switchInProgress && this.isThumbnailViewVisible) { - this._updateThumbnailViewer(); - } - }); - } - -} - -exports.PDFSidebar = PDFSidebar; - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.OptionKind = exports.AppOptions = void 0; - -var _pdfjsLib = __webpack_require__(3); - -var _viewer_compatibility = __webpack_require__(9); - -const OptionKind = { - VIEWER: 'viewer', - API: 'api', - WORKER: 'worker' -}; -exports.OptionKind = OptionKind; -const defaultOptions = { - cursorToolOnLoad: { - value: 0, - kind: OptionKind.VIEWER - }, - defaultUrl: { - value: 'compressed.tracemonkey-pldi-09.pdf', - kind: OptionKind.VIEWER - }, - defaultZoomValue: { - value: '', - kind: OptionKind.VIEWER - }, - disableHistory: { - value: false, - kind: OptionKind.VIEWER - }, - disablePageLabels: { - value: false, - kind: OptionKind.VIEWER - }, - enablePrintAutoRotate: { - value: false, - kind: OptionKind.VIEWER - }, - enableWebGL: { - value: false, - kind: OptionKind.VIEWER - }, - eventBusDispatchToDOM: { - value: false, - kind: OptionKind.VIEWER - }, - externalLinkRel: { - value: 'noopener noreferrer nofollow', - kind: OptionKind.VIEWER - }, - externalLinkTarget: { - value: 0, - kind: OptionKind.VIEWER - }, - historyUpdateUrl: { - value: false, - kind: OptionKind.VIEWER - }, - imageResourcesPath: { - value: './images/', - kind: OptionKind.VIEWER - }, - maxCanvasPixels: { - value: 16777216, - compatibility: _viewer_compatibility.viewerCompatibilityParams.maxCanvasPixels, - kind: OptionKind.VIEWER - }, - pdfBugEnabled: { - value: false, - kind: OptionKind.VIEWER - }, - renderer: { - value: 'canvas', - kind: OptionKind.VIEWER - }, - renderInteractiveForms: { - value: false, - kind: OptionKind.VIEWER - }, - sidebarViewOnLoad: { - value: -1, - kind: OptionKind.VIEWER - }, - scrollModeOnLoad: { - value: -1, - kind: OptionKind.VIEWER - }, - spreadModeOnLoad: { - value: -1, - kind: OptionKind.VIEWER - }, - textLayerMode: { - value: 1, - kind: OptionKind.VIEWER - }, - useOnlyCssZoom: { - value: false, - kind: OptionKind.VIEWER - }, - viewOnLoad: { - value: 0, - kind: OptionKind.VIEWER - }, - cMapPacked: { - value: true, - kind: OptionKind.API - }, - cMapUrl: { - value: '../web/cmaps/', - kind: OptionKind.API - }, - disableAutoFetch: { - value: false, - kind: OptionKind.API - }, - disableCreateObjectURL: { - value: false, - compatibility: _pdfjsLib.apiCompatibilityParams.disableCreateObjectURL, - kind: OptionKind.API - }, - disableFontFace: { - value: false, - kind: OptionKind.API - }, - disableRange: { - value: false, - kind: OptionKind.API - }, - disableStream: { - value: false, - kind: OptionKind.API - }, - isEvalSupported: { - value: true, - kind: OptionKind.API - }, - maxImageSize: { - value: -1, - kind: OptionKind.API - }, - pdfBug: { - value: false, - kind: OptionKind.API - }, - postMessageTransfers: { - value: true, - kind: OptionKind.API - }, - verbosity: { - value: 1, - kind: OptionKind.API - }, - workerPort: { - value: null, - kind: OptionKind.WORKER - }, - workerSrc: { - value: '../build/pdf.worker.js', - kind: OptionKind.WORKER + return; + } + + this.isOpen = false; + this.toggleButton.classList.remove('toggled'); + this.outerContainer.classList.add('sidebarMoving'); + this.outerContainer.classList.remove('sidebarOpen'); + + this._forceRendering(); + + this._dispatchEvent(); } -}; -; -const userOptions = Object.create(null); -class AppOptions { - constructor() { - throw new Error('Cannot initialize AppOptions.'); + toggle() { + if (this.isOpen) { + this.close(); + } else { + this.open(); + } } - static get(name) { - const userOption = userOptions[name]; + _dispatchEvent() { + this.eventBus.dispatch('sidebarviewchanged', { + source: this, + view: this.visibleView + }); + } - if (userOption !== undefined) { - return userOption; + _forceRendering() { + if (this.onToggled) { + this.onToggled(); + } else { + this.pdfViewer.forceRendering(); + this.pdfThumbnailViewer.forceRendering(); } + } - const defaultOption = defaultOptions[name]; + _updateThumbnailViewer() { + let { + pdfViewer, + pdfThumbnailViewer + } = this; + let pagesCount = pdfViewer.pagesCount; - if (defaultOption !== undefined) { - return defaultOption.compatibility || defaultOption.value; + for (let pageIndex = 0; pageIndex < pagesCount; pageIndex++) { + let pageView = pdfViewer.getPageView(pageIndex); + + if (pageView && pageView.renderingState === _pdf_rendering_queue.RenderingStates.FINISHED) { + let thumbnailView = pdfThumbnailViewer.getThumbnail(pageIndex); + thumbnailView.setImage(pageView); + } } - return undefined; + pdfThumbnailViewer.scrollThumbnailIntoView(pdfViewer.currentPageNumber); } - static getAll(kind = null) { - const options = Object.create(null); + _showUINotification(view) { + if (this.disableNotification) { + return; + } - for (const name in defaultOptions) { - const defaultOption = defaultOptions[name]; + this.l10n.get('toggle_sidebar_notification.title', null, 'Toggle Sidebar (document contains outline/attachments)').then(msg => { + this.toggleButton.title = msg; + }); - if (kind && kind !== defaultOption.kind) { - continue; + if (!this.isOpen) { + this.toggleButton.classList.add(UI_NOTIFICATION_CLASS); + } else if (view === this.active) { + return; + } + + switch (view) { + case SidebarView.OUTLINE: + this.outlineButton.classList.add(UI_NOTIFICATION_CLASS); + break; + + case SidebarView.ATTACHMENTS: + this.attachmentsButton.classList.add(UI_NOTIFICATION_CLASS); + break; + } + } + + _hideUINotification(view) { + if (this.disableNotification) { + return; + } + + let removeNotification = view => { + switch (view) { + case SidebarView.OUTLINE: + this.outlineButton.classList.remove(UI_NOTIFICATION_CLASS); + break; + + case SidebarView.ATTACHMENTS: + this.attachmentsButton.classList.remove(UI_NOTIFICATION_CLASS); + break; } + }; - const userOption = userOptions[name]; - options[name] = userOption !== undefined ? userOption : defaultOption.compatibility || defaultOption.value; + if (!this.isOpen && view !== null) { + return; } - return options; - } + this.toggleButton.classList.remove(UI_NOTIFICATION_CLASS); - static set(name, value) { - userOptions[name] = value; - } + if (view !== null) { + removeNotification(view); + return; + } - static remove(name) { - delete userOptions[name]; + for (view in SidebarView) { + removeNotification(SidebarView[view]); + } + + this.l10n.get('toggle_sidebar.title', null, 'Toggle Sidebar').then(msg => { + this.toggleButton.title = msg; + }); } -} + _addEventListeners() { + this.viewerContainer.addEventListener('transitionend', evt => { + if (evt.target === this.viewerContainer) { + this.outerContainer.classList.remove('sidebarMoving'); + } + }); + this.thumbnailButton.addEventListener('click', () => { + this.switchView(SidebarView.THUMBS); + }); + this.outlineButton.addEventListener('click', () => { + this.switchView(SidebarView.OUTLINE); + }); + this.outlineButton.addEventListener('dblclick', () => { + this.eventBus.dispatch('toggleoutlinetree', { + source: this + }); + }); + this.attachmentsButton.addEventListener('click', () => { + this.switchView(SidebarView.ATTACHMENTS); + }); + this.eventBus.on('outlineloaded', evt => { + let outlineCount = evt.outlineCount; + this.outlineButton.disabled = !outlineCount; -exports.AppOptions = AppOptions; + if (outlineCount) { + this._showUINotification(SidebarView.OUTLINE); + } else if (this.active === SidebarView.OUTLINE) { + this.switchView(SidebarView.THUMBS); + } + }); + this.eventBus.on('attachmentsloaded', evt => { + if (evt.attachmentsCount) { + this.attachmentsButton.disabled = false; -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { + this._showUINotification(SidebarView.ATTACHMENTS); -"use strict"; + return; + } + + Promise.resolve().then(() => { + if (this.attachmentsView.hasChildNodes()) { + return; + } + this.attachmentsButton.disabled = true; -let compatibilityParams = Object.create(null); -; -exports.viewerCompatibilityParams = Object.freeze(compatibilityParams); + if (this.active === SidebarView.ATTACHMENTS) { + this.switchView(SidebarView.THUMBS); + } + }); + }); + this.eventBus.on('presentationmodechanged', evt => { + if (!evt.active && !evt.switchInProgress && this.isThumbnailViewVisible) { + this._updateThumbnailViewer(); + } + }); + } + +} + +exports.PDFSidebar = PDFSidebar; /***/ }), /* 10 */ @@ -4264,7 +4272,7 @@ exports.PasswordPrompt = void 0; var _ui_utils = __webpack_require__(2); -var _pdfjsLib = __webpack_require__(3); +var _pdfjsLib = __webpack_require__(4); class PasswordPrompt { constructor(options, overlayManager, l10n = _ui_utils.NullL10n) { @@ -4341,7 +4349,7 @@ Object.defineProperty(exports, "__esModule", { }); exports.PDFAttachmentViewer = void 0; -var _pdfjsLib = __webpack_require__(3); +var _pdfjsLib = __webpack_require__(4); class PDFAttachmentViewer { constructor({ @@ -4491,7 +4499,7 @@ exports.PDFDocumentProperties = void 0; var _ui_utils = __webpack_require__(2); -var _pdfjsLib = __webpack_require__(3); +var _pdfjsLib = __webpack_require__(4); const DEFAULT_FIELD_CONTENT = '-'; const NON_METRIC_LOCALES = ['en-us', 'en-lr', 'my']; @@ -5025,7 +5033,7 @@ exports.PDFFindController = exports.FindState = void 0; var _ui_utils = __webpack_require__(2); -var _pdfjsLib = __webpack_require__(3); +var _pdfjsLib = __webpack_require__(4); var _pdf_find_utils = __webpack_require__(16); @@ -6776,7 +6784,7 @@ Object.defineProperty(exports, "__esModule", { }); exports.PDFOutlineViewer = void 0; -var _pdfjsLib = __webpack_require__(3); +var _pdfjsLib = __webpack_require__(4); const DEFAULT_TITLE = '\u2013'; @@ -7771,11 +7779,11 @@ Object.defineProperty(exports, "__esModule", { }); exports.PDFThumbnailView = void 0; -var _pdfjsLib = __webpack_require__(3); +var _pdfjsLib = __webpack_require__(4); var _ui_utils = __webpack_require__(2); -var _pdf_rendering_queue = __webpack_require__(6); +var _pdf_rendering_queue = __webpack_require__(8); const MAX_NUM_SCALING_STEPS = 3; const THUMBNAIL_CANVAS_BORDER_WIDTH = 1; @@ -7891,6 +7899,7 @@ class PDFThumbnailView { reset() { this.cancelRendering(); + this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL; this.pageWidth = this.viewport.width; this.pageHeight = this.viewport.height; this.pageRatio = this.pageWidth / this.pageHeight; @@ -7939,7 +7948,6 @@ class PDFThumbnailView { this.renderTask = null; } - this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL; this.resume = null; } @@ -8173,7 +8181,7 @@ exports.PDFViewer = void 0; var _base_viewer = __webpack_require__(25); -var _pdfjsLib = __webpack_require__(3); +var _pdfjsLib = __webpack_require__(4); class PDFViewer extends _base_viewer.BaseViewer { get _setDocumentViewerElement() { @@ -8260,11 +8268,11 @@ exports.BaseViewer = void 0; var _ui_utils = __webpack_require__(2); -var _pdf_rendering_queue = __webpack_require__(6); +var _pdf_rendering_queue = __webpack_require__(8); var _annotation_layer_builder = __webpack_require__(26); -var _pdfjsLib = __webpack_require__(3); +var _pdfjsLib = __webpack_require__(4); var _pdf_page_view = __webpack_require__(27); @@ -9311,7 +9319,7 @@ Object.defineProperty(exports, "__esModule", { }); exports.DefaultAnnotationLayerFactory = exports.AnnotationLayerBuilder = void 0; -var _pdfjsLib = __webpack_require__(3); +var _pdfjsLib = __webpack_require__(4); var _ui_utils = __webpack_require__(2); @@ -9424,11 +9432,11 @@ exports.PDFPageView = void 0; var _ui_utils = __webpack_require__(2); -var _pdfjsLib = __webpack_require__(3); +var _pdfjsLib = __webpack_require__(4); -var _pdf_rendering_queue = __webpack_require__(6); +var _pdf_rendering_queue = __webpack_require__(8); -var _viewer_compatibility = __webpack_require__(9); +var _viewer_compatibility = __webpack_require__(5); const MAX_CANVAS_PIXELS = _viewer_compatibility.viewerCompatibilityParams.maxCanvasPixels || 16777216; @@ -9515,6 +9523,7 @@ class PDFPageView { reset(keepZoomLayer = false, keepAnnotations = false) { this.cancelRendering(keepAnnotations); + this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL; let div = this.div; div.style.width = Math.floor(this.viewport.width) + 'px'; div.style.height = Math.floor(this.viewport.height) + 'px'; @@ -9620,14 +9629,11 @@ class PDFPageView { } cancelRendering(keepAnnotations = false) { - const renderingState = this.renderingState; - if (this.paintTask) { this.paintTask.cancel(); this.paintTask = null; } - this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL; this.resume = null; if (this.textLayer) { @@ -9639,14 +9645,6 @@ class PDFPageView { this.annotationLayer.cancel(); this.annotationLayer = null; } - - if (renderingState !== _pdf_rendering_queue.RenderingStates.INITIAL) { - this.eventBus.dispatch('pagecancelled', { - source: this, - pageNumber: this.id, - renderingState - }); - } } cssTransform(target, redrawAnnotations = false) { @@ -9995,7 +9993,7 @@ exports.DefaultTextLayerFactory = exports.TextLayerBuilder = void 0; var _ui_utils = __webpack_require__(2); -var _pdfjsLib = __webpack_require__(3); +var _pdfjsLib = __webpack_require__(4); const EXPAND_DIVS_TIMEOUT = 300; @@ -10022,9 +10020,7 @@ class TextLayerBuilder { this.findController = findController; this.textLayerRenderTask = null; this.enhanceTextSelection = enhanceTextSelection; - this._boundEvents = Object.create(null); - - this._bindEvents(); + this._onUpdateTextLayerMatches = null; this._bindMouse(); } @@ -10070,6 +10066,16 @@ class TextLayerBuilder { this._updateMatches(); }, function (reason) {}); + + if (!this._onUpdateTextLayerMatches) { + this._onUpdateTextLayerMatches = evt => { + if (evt.pageIndex === this.pageIdx || evt.pageIndex === -1) { + this._updateMatches(); + } + }; + + this.eventBus.on('updatetextlayermatches', this._onUpdateTextLayerMatches); + } } cancel() { @@ -10077,6 +10083,11 @@ class TextLayerBuilder { this.textLayerRenderTask.cancel(); this.textLayerRenderTask = null; } + + if (this._onUpdateTextLayerMatches) { + this.eventBus.off('updatetextlayermatches', this._onUpdateTextLayerMatches); + this._onUpdateTextLayerMatches = null; + } } setTextContentStream(readableStream) { @@ -10279,40 +10290,6 @@ class TextLayerBuilder { this._renderMatches(this.matches); } - _bindEvents() { - const { - eventBus, - _boundEvents - } = this; - - _boundEvents.pageCancelled = evt => { - if (evt.pageNumber !== this.pageNumber) { - return; - } - - if (this.textLayerRenderTask) { - console.error('TextLayerBuilder._bindEvents: `this.cancel()` should ' + 'have been called when the page was reset, or rendering cancelled.'); - return; - } - - for (const name in _boundEvents) { - eventBus.off(name.toLowerCase(), _boundEvents[name]); - delete _boundEvents[name]; - } - }; - - _boundEvents.updateTextLayerMatches = evt => { - if (evt.pageIndex !== this.pageIdx && evt.pageIndex !== -1) { - return; - } - - this._updateMatches(); - }; - - eventBus.on('pagecancelled', _boundEvents.pageCancelled); - eventBus.on('updatetextlayermatches', _boundEvents.updateTextLayerMatches); - } - _bindMouse() { let div = this.textLayerDiv; let expandDivsTimer = null; @@ -10378,7 +10355,7 @@ exports.SecondaryToolbar = void 0; var _ui_utils = __webpack_require__(2); -var _pdf_cursor_tools = __webpack_require__(4); +var _pdf_cursor_tools = __webpack_require__(6); var _pdf_single_page_viewer = __webpack_require__(30); @@ -10694,7 +10671,7 @@ exports.PDFSinglePageViewer = void 0; var _base_viewer = __webpack_require__(25); -var _pdfjsLib = __webpack_require__(3); +var _pdfjsLib = __webpack_require__(4); class PDFSinglePageViewer extends _base_viewer.BaseViewer { constructor(options) { @@ -11150,7 +11127,7 @@ exports.FirefoxCom = exports.DownloadManager = void 0; __webpack_require__(34); -var _pdfjsLib = __webpack_require__(3); +var _pdfjsLib = __webpack_require__(4); var _preferences = __webpack_require__(35); @@ -11589,27 +11566,27 @@ let defaultPreferences = null; function getDefaultPreferences() { if (!defaultPreferences) { defaultPreferences = Promise.resolve({ - "viewOnLoad": 0, - "defaultZoomValue": "", - "sidebarViewOnLoad": -1, "cursorToolOnLoad": 0, + "defaultZoomValue": "", + "disablePageLabels": false, + "enablePrintAutoRotate": false, "enableWebGL": false, "eventBusDispatchToDOM": false, - "pdfBugEnabled": false, - "disableRange": false, - "disableStream": false, - "disableAutoFetch": false, - "disableFontFace": false, - "textLayerMode": 1, - "useOnlyCssZoom": false, "externalLinkTarget": 0, + "historyUpdateUrl": false, + "pdfBugEnabled": false, "renderer": "canvas", "renderInteractiveForms": false, - "enablePrintAutoRotate": false, - "disablePageLabels": false, - "historyUpdateUrl": false, + "sidebarViewOnLoad": -1, "scrollModeOnLoad": -1, - "spreadModeOnLoad": -1 + "spreadModeOnLoad": -1, + "textLayerMode": 1, + "useOnlyCssZoom": false, + "viewOnLoad": 0, + "disableAutoFetch": false, + "disableFontFace": false, + "disableRange": false, + "disableStream": false }); } @@ -11735,7 +11712,7 @@ var _ui_utils = __webpack_require__(2); var _app = __webpack_require__(1); -var _pdfjsLib = __webpack_require__(3); +var _pdfjsLib = __webpack_require__(4); function composePage(pdfDocument, pageNumber, size, printContainer) { let canvas = document.createElement('canvas'); diff --git a/browser/extensions/pdfjs/moz.yaml b/browser/extensions/pdfjs/moz.yaml index 081f851e0bb3e..9d2c716711725 100644 --- a/browser/extensions/pdfjs/moz.yaml +++ b/browser/extensions/pdfjs/moz.yaml @@ -20,7 +20,7 @@ origin: # Human-readable identifier for this version/release # Generally "version NNN", "tag SSS", "bookmark SSS" - release: version 2.1.266 + release: version 2.2.15 # The package's license, where possible using the mnemonic from # https://spdx.org/licenses/ diff --git a/build/moz.configure/init.configure b/build/moz.configure/init.configure index 9f19d4350face..1ee8d267f08ae 100644 --- a/build/moz.configure/init.configure +++ b/build/moz.configure/init.configure @@ -643,7 +643,7 @@ def split_triplet(triplet, allow_unknown=False): elif len(parts) == 2: cpu, os = parts else: - die("Unexpected triplet string: %s" % triplet) + raise ValueError("Unexpected triplet string: %s" % triplet) # Autoconf uses config.sub to validate and canonicalize those triplets, # but the granularity of its results has never been satisfying to our @@ -687,7 +687,7 @@ def split_triplet(triplet, allow_unknown=False): elif allow_unknown: canonical_os = canonical_kernel = os else: - die('Unknown OS: %s' % os) + raise ValueError('Unknown OS: %s' % os) # The CPU granularity is probably not enough. Moving more things from # old-configure will tell us if we need more @@ -737,7 +737,7 @@ def split_triplet(triplet, allow_unknown=False): canonical_cpu = cpu endianness = 'unknown' else: - die('Unknown CPU type: %s' % cpu) + raise ValueError('Unknown CPU type: %s' % cpu) def sanitize(cls, value): try: @@ -796,6 +796,7 @@ def config_sub(shell, triplet): @imports('os') @imports('subprocess') @imports('sys') +@imports(_from='__builtin__', _import='ValueError') def real_host(value, shell): if not value and sys.platform == 'win32': arch = (os.environ.get('PROCESSOR_ARCHITEW6432') or @@ -809,10 +810,19 @@ def real_host(value, shell): config_guess = os.path.join(os.path.dirname(__file__), '..', 'autoconf', 'config.guess') host = subprocess.check_output([shell, config_guess]).strip() + try: + return split_triplet(host) + except ValueError: + pass else: - host = config_sub(shell, value[0]) + host = value[0] + + host = config_sub(shell, host) - return split_triplet(host) + try: + return split_triplet(host) + except ValueError as e: + die(e.message) host = help_host_target | real_host @@ -820,6 +830,7 @@ host = help_host_target | real_host @depends('--target', real_host, shell, '--enable-project', '--enable-application') @checking('for target system type', lambda t: t.alias) +@imports(_from='__builtin__', _import='ValueError') def real_target(value, host, shell, project, application): # Because --enable-project is implied by --enable-application, and # implied options are not currently handled during --help, which is @@ -846,9 +857,16 @@ def real_target(value, host, shell, project, application): rest += 'eabi' else: cpu, rest = host.alias.split('-', 1) - return split_triplet('-'.join((target, rest))) - - return split_triplet(config_sub(shell, target)) + target = '-'.join((target, rest)) + try: + return split_triplet(target) + except ValueError: + pass + + try: + return split_triplet(config_sub(shell, target)) + except ValueError as e: + die(e.message) target = help_host_target | real_target diff --git a/build/mozconfig.pgo b/build/mozconfig.pgo new file mode 100644 index 0000000000000..41444f7445f26 --- /dev/null +++ b/build/mozconfig.pgo @@ -0,0 +1,7 @@ +case "$PERFHERDER_EXTRA_OPTIONS" in +base-toolchains*) + ;; +*) + export MOZ_PGO=1 + ;; +esac diff --git a/configure.py b/configure.py index 9ec2ae24bacbb..913dd35f9aef8 100644 --- a/configure.py +++ b/configure.py @@ -14,7 +14,10 @@ base_dir = os.path.abspath(os.path.dirname(__file__)) sys.path.insert(0, os.path.join(base_dir, 'python', 'mozbuild')) -from mozbuild.configure import ConfigureSandbox +from mozbuild.configure import ( + ConfigureSandbox, + TRACE, +) from mozbuild.pythonutil import iter_modules_in_path from mozbuild.backend.configenvironment import PartialConfigEnvironment from mozbuild.util import ( @@ -26,7 +29,12 @@ def main(argv): config = {} + sandbox = ConfigureSandbox(config, os.environ, argv) + + if os.environ.get('MOZ_CONFIGURE_TRACE'): + sandbox._logger.setLevel(TRACE) + sandbox.run(os.path.join(os.path.dirname(__file__), 'moz.configure')) if sandbox._help: diff --git a/devtools/client/debugger/new/README.mozilla b/devtools/client/debugger/new/README.mozilla index 39cc989138e93..dba0e54b7de35 100644 --- a/devtools/client/debugger/new/README.mozilla +++ b/devtools/client/debugger/new/README.mozilla @@ -1,9 +1,9 @@ This is the debugger.html project output. See https://github.com/devtools-html/debugger.html -Version 125 +Version 126 -Comparison: https://github.com/devtools-html/debugger.html/compare/release-124...release-125 +Comparison: https://github.com/devtools-html/debugger.html/compare/release-125...release-126 Packages: - babel-plugin-transform-es2015-modules-commonjs @6.26.2 diff --git a/devtools/client/debugger/new/dist/debugger.css b/devtools/client/debugger/new/dist/debugger.css index 925a1b33c3b86..610aaed81ca16 100644 --- a/devtools/client/debugger/new/dist/debugger.css +++ b/devtools/client/debugger/new/dist/debugger.css @@ -251,7 +251,7 @@ button.open-inspector { margin: 0 4px; padding: 0; border: none; - background-color: var(--comment-node-color); + background-color: var(--theme-icon-color); cursor: pointer; } @@ -260,7 +260,7 @@ button.open-inspector { .objectBox-textNode:hover .open-inspector, .open-accessibility-inspector:hover, .open-inspector:hover { - background-color: var(--theme-highlight-blue); + background-color: var(--theme-icon-checked-color); } /******************************************************************************/ @@ -269,14 +269,14 @@ button.open-inspector { button.jump-definition { mask: url("resource://devtools/client/shared/components/reps/images/jump-definition.svg") no-repeat; display: inline-block; - background-color: var(--comment-node-color); + background-color: var(--theme-icon-color); height: 16px; margin-left: 0.25em; vertical-align: middle; } .jump-definition:hover { - background-color: var(--theme-highlight-blue); + background-color: var(--theme-icon-checked-color); } /******************************************************************************/ @@ -285,14 +285,14 @@ button.jump-definition { button.invoke-getter { mask: url("resource://devtools/client/shared/components/reps/images/input.svg") no-repeat; display: inline-block; - background-color: var(--comment-node-color); + background-color: var(--theme-icon-color); height: 10px; vertical-align: middle; border:none; } .invoke-getter:hover { - background-color: var(--theme-highlight-blue); + background-color: var(--theme-icon-checked-color); } /******************************************************************************/ @@ -357,30 +357,27 @@ button.invoke-getter { } .tree-node button.arrow { - background:url("resource://devtools/client/debugger/new/images/arrow.svg") no-repeat; - background-size:contain; - background-position:center center; + mask: url("resource://devtools/client/debugger/new/images/arrow.svg") no-repeat center; + mask-size: 10px; + vertical-align: -1px; width: 10px; height: 10px; - border:0; - padding:0; + border: 0; + padding: 0; margin-inline-start: 1px; margin-inline-end: 4px; - transform: rotate(-90deg); transform-origin: center center; - transition: transform 0.125s ease; - align-self: center; - -moz-context-properties: fill; - fill: var(--theme-splitter-color, #9B9B9B); + transition: transform 125ms var(--animation-curve); + background-color: var(--theme-icon-dimmed-color); } -html[dir="rtl"] .tree-node button.arrow { - transform: rotate(90deg); +.tree-node button.arrow:not(.expanded) { + transform: rotate(-90deg); } -.tree-node button.arrow.expanded.expanded { - transform: rotate(0deg); - } +html[dir="rtl"] .tree-node button:not(.expanded) { + transform: rotate(90deg); +} .tree .tree-node.focused { color: white; @@ -388,7 +385,7 @@ html[dir="rtl"] .tree-node button.arrow { } .tree-node.focused button.arrow { - fill: currentColor; + background-color: currentColor; } /* 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 @@ -555,6 +552,8 @@ html[dir="rtl"] .tree-node button.arrow { --editor-footer-height: 25px; /* searchbar height is 24px + 1px for its top border */ --editor-searchbar-height: 25px; + /* Remove once https://bugzilla.mozilla.org/show_bug.cgi?id=1520440 lands */ + --theme-code-line-height: calc(15 / 11); } :root.theme-light, @@ -2318,7 +2317,7 @@ menuseparator { } .source-footer > .commands > .blackboxed > .img.blackBox { - background-color: var(--theme-highlight-blue); + background-color: var(--theme-icon-checked-color); } .source-footer .blackbox-summary, @@ -2670,8 +2669,8 @@ menuseparator { .column-breakpoint { display: inline; - padding: 0; - padding-inline-end: 4px; + padding-inline-start: 1px; + padding-inline-end: 3px; } .column-breakpoint:hover { @@ -2679,10 +2678,10 @@ menuseparator { } .column-breakpoint svg { - display: inline; + display: inline-block; cursor: pointer; - height: 12px; - width: 9px; + height: 13px; + width: 11px; vertical-align: top; } @@ -2787,7 +2786,7 @@ menuseparator { /** * There's a known codemirror flex issue with chrome that this addresses. - * BUG https://github.com/devtools-html/debugger.html/issues/63 + * BUG https://github.com/firefox-devtools/debugger.html/issues/63 */ .editor-wrapper { position: absolute; @@ -2825,20 +2824,6 @@ html[dir="rtl"] .editor-mount { color: var(--grey-50); } -:not(.empty-line):not(.new-breakpoint) - > .CodeMirror-gutter-wrapper:hover - > .CodeMirror-linenumber { - height: 13px; - color: var(--theme-body-color); - /* Add 1px offset to the background to match it - with the actual breakpoint image dimensions */ - background: linear-gradient( - to bottom, - transparent 1px, - var(--gutter-hover-background-color) 0 - ); -} - .new-breakpoint .CodeMirror-linenumber { pointer-events: none; } @@ -2848,12 +2833,16 @@ html[dir="rtl"] .editor-mount { > .CodeMirror-linenumber::after { content: ""; position: absolute; - top: 1px; - height: 12px; - width: 9px; + /* paint below the number */ + z-index: -1; + top: 0; + left: 0; + right: -7px; + bottom: 0; + height: 15px; background-color: var(--gutter-hover-background-color); mask: url("resource://devtools/client/debugger/new/images/breakpoint.svg") no-repeat; - mask-size: auto 12px; + mask-size: auto 15px; mask-position: right; } @@ -2873,7 +2862,7 @@ html[dir="rtl"] .editor-mount { } .editor.hit-marker { - height: 14px; + height: 15px; } .editor-wrapper .highlight-lines { @@ -2884,7 +2873,7 @@ html[dir="rtl"] .editor-mount { fill: var(--breakpoint-fill); stroke: var(--breakpoint-stroke); width: 60px; - height: 14px; + height: 15px; position: absolute; top: 0px; right: -4px; @@ -2929,7 +2918,7 @@ html[dir="rtl"] .editor-mount { fill: var(--theme-selection-background); vertical-align: middle; width: 17px; - height: 14px; + height: 15px; } .editor.column-breakpoint.breakpoint-disabled svg { @@ -2944,11 +2933,8 @@ html[dir="rtl"] .editor-mount { .editor-wrapper .editor-mount { width: 100%; background-color: var(--theme-body-background); -} - -.CodeMirror-linenumber { - font-size: 11px; - line-height: 14px; + font-size: var(--theme-code-font-size); + line-height: var(--theme-code-line-height); } .folding-enabled .CodeMirror-linenumber { @@ -2969,10 +2955,6 @@ html[dir="rtl"] .editor-mount { z-index: 0; } -.editor-wrapper .CodeMirror-line { - font-size: 11px; -} - .theme-dark .editor-wrapper .CodeMirror-line .cm-comment { color: var(--theme-comment); } @@ -3439,8 +3421,8 @@ html[dir="rtl"] .breakpoints-list .breakpoint .breakpoint-line { * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at . */ -.frames ul .frames-group .group, -.frames ul .frames-group .group .location { +.frames [role="list"] .frames-group .group, +.frames [role="list"] .frames-group .group .location { font-weight: 500; cursor: default; /* @@ -3451,21 +3433,21 @@ html[dir="rtl"] .breakpoints-list .breakpoint .breakpoint-line { direction: ltr; } -.frames ul .frames-group.expanded .group, -.frames ul .frames-group.expanded .group .location { +.frames [role="list"] .frames-group.expanded .group, +.frames [role="list"] .frames-group.expanded .group .location { color: var(--theme-highlight-blue); } -.frames ul .frames-group .frames-list li { +.frames [role="list"] .frames-group .frames-list [role="listitem"] { padding-left: 30px; } -.frames ul .frames-group .frames-list { +.frames [role="list"] .frames-group .frames-list { border-top: 1px solid var(--theme-splitter-color); border-bottom: 1px solid var(--theme-splitter-color); } -.frames ul .frames-group.expanded .badge { +.frames [role="list"] .frames-group.expanded .badge { color: var(--theme-highlight-blue); } @@ -3831,7 +3813,7 @@ html[dir="rtl"] .command-bar { } .command-bar .active .disable-pausing { - background-color: var(--theme-highlight-blue); + background-color: var(--theme-icon-checked-color); } .bottom { @@ -3981,7 +3963,10 @@ html[dir="rtl"] .command-bar { * file, You can obtain one at . */ .event-listeners-content { - padding: 4px 20px; + padding-top: 4px; + padding-bottom: 4px; + padding-inline-start: 14px; + padding-inline-end: 20px; } .event-listeners-content ul { @@ -3993,6 +3978,39 @@ html[dir="rtl"] .command-bar { user-select: none; } +.event-listener-header { + display: flex; + align-items: center; +} + +.event-listener-expand { + border: none; + background: none; + padding: 4px 5px; + line-height: 12px; +} + +.event-listener-expand:hover { + background: transparent; +} + +.event-listener-group input[type="checkbox"] { + margin: 0px; + margin-inline-end: 4px; +} + +.event-listener-label { + display: flex; + align-items: center; + padding-inline-start: 2px; + padding-inline-end: 10px; +} + +.event-listener-category { + padding: 3px 0px; + line-height: 14px; +} + .event-listeners-content .arrow { margin-inline-end: 0; } @@ -4011,9 +4029,16 @@ html[dir="rtl"] .event-listeners-content .arrow.expanded { margin-inline-start: 30px; } +.event-listener-name { + line-height: 14px; + padding: 3px 0px; +} + .event-listener-event input { margin-inline-end: 4px; margin-inline-start: 0px; + margin-top: 0px; + margin-bottom: 0px; } /* 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 @@ -4094,7 +4119,7 @@ html[dir="rtl"] .object-node { This allows the commandbar to remain fixed when scrolling until the content completely ends. Not just the height of the wrapper. - Ref: https://github.com/devtools-html/debugger.html/issues/3426 + Ref: https://github.com/firefox-devtools/debugger.html/issues/3426 */ .secondary-panes-wrapper { @@ -4498,7 +4523,7 @@ html .welcomebox .toggle-button-end.collapsed { } .result-list li .result-item-icon { - background-color: var(--theme-comment); + background-color: var(--theme-icon-dimmed-color); } .result-list li .icon { diff --git a/devtools/client/debugger/new/dist/parser-worker.js b/devtools/client/debugger/new/dist/parser-worker.js index a89dbfb007560..3333196503069 100644 --- a/devtools/client/debugger/new/dist/parser-worker.js +++ b/devtools/client/debugger/new/dist/parser-worker.js @@ -560,48 +560,6 @@ function toKey(value) { module.exports = toKey; -/***/ }), - -/***/ 1127: -/***/ (function(module, exports, __webpack_require__) { - -var baseIsEqual = __webpack_require__(799); - -/** - * Performs a deep comparison between two values to determine if they are - * equivalent. - * - * **Note:** This method supports comparing arrays, array buffers, booleans, - * date objects, error objects, maps, numbers, `Object` objects, regexes, - * sets, strings, symbols, and typed arrays. `Object` objects are compared - * by their own, not inherited, enumerable properties. Functions and DOM - * nodes are compared by strict equality, i.e. `===`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.isEqual(object, other); - * // => true - * - * object === other; - * // => false - */ -function isEqual(value, other) { - return baseIsEqual(value, other); -} - -module.exports = isEqual; - - /***/ }), /***/ 114: @@ -1802,8 +1760,6 @@ var _validate = __webpack_require__(1629); var _frameworks = __webpack_require__(1703); -var _pausePoints = __webpack_require__(3612); - var _mapExpression = __webpack_require__(3755); var _mapExpression2 = _interopRequireDefault(_mapExpression); @@ -1812,9 +1768,11 @@ var _devtoolsUtils = __webpack_require__(3651); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -const { workerHandler } = _devtoolsUtils.workerUtils; /* 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 . */ +/* 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 . */ + +const { workerHandler } = _devtoolsUtils.workerUtils; self.onmessage = workerHandler({ findOutOfScopeLocations: _findOutOfScopeLocations2.default, @@ -1829,7 +1787,6 @@ self.onmessage = workerHandler({ getNextStep: _steps.getNextStep, hasSyntaxError: _validate.hasSyntaxError, getFramework: _frameworks.getFramework, - getPausePoints: _pausePoints.getPausePoints, mapExpression: _mapExpression2.default }); @@ -22486,185 +22443,6 @@ class SimplePath { /***/ }), -/***/ 3612: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.getPausePoints = getPausePoints; - -var _ast = __webpack_require__(1375); - -var _types = __webpack_require__(2268); - -var t = _interopRequireWildcard(_types); - -var _isEqual = __webpack_require__(1127); - -var _isEqual2 = _interopRequireDefault(_isEqual); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } - -const isForStatement = node => t.isForStatement(node) || t.isForOfStatement(node); /* 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 . */ - -const isControlFlow = node => isForStatement(node) || t.isWhileStatement(node) || t.isIfStatement(node) || t.isSwitchCase(node) || t.isSwitchStatement(node) || t.isTryStatement(node) || t.isWithStatement(node); - -const isAssignment = node => t.isVariableDeclarator(node) || t.isAssignmentExpression(node) || t.isAssignmentPattern(node); - -const isImport = node => t.isImport(node) || t.isImportDeclaration(node); -const isCall = node => t.isCallExpression(node) || t.isJSXElement(node); - -const inStepExpression = parent => t.isArrayExpression(parent) || t.isObjectProperty(parent) || t.isCallExpression(parent) || t.isJSXElement(parent) || t.isSequenceExpression(parent); - -const inExpression = (parent, grandParent) => inStepExpression(parent) || t.isJSXAttribute(grandParent) || t.isTemplateLiteral(parent); - -const isExport = node => t.isExportNamedDeclaration(node) || t.isExportDefaultDeclaration(node); - -// Finds the first call item in a step expression so that we can step -// to the beginning of the list and either step in or over. e.g. [], x(), { } -function isFirstCall(node, parentNode, grandParentNode) { - let children = []; - if (t.isArrayExpression(parentNode)) { - children = parentNode.elements; - } - - if (t.isObjectProperty(parentNode)) { - children = grandParentNode.properties.map(({ value }) => value); - } - - if (t.isSequenceExpression(parentNode)) { - children = parentNode.expressions; - } - - if (t.isCallExpression(parentNode)) { - children = parentNode.arguments; - } - - return children.find(child => isCall(child)) === node; -} - -function getPausePoints(sourceId) { - const state = {}; - (0, _ast.traverseAst)(sourceId, { enter: onEnter }, state); - return state; -} - -/* eslint-disable complexity */ -function onEnter(node, ancestors, state) { - const parent = ancestors[ancestors.length - 1]; - const parentNode = parent && parent.node; - const grandParent = ancestors[ancestors.length - 2]; - const grandParentNode = grandParent && grandParent.node; - const startLocation = node.loc.start; - - if (isImport(node) || t.isClassDeclaration(node) || isExport(node) || t.isDebuggerStatement(node) || t.isThrowStatement(node) || t.isBreakStatement(node) || t.isContinueStatement(node) || t.isReturnStatement(node)) { - return addStopPoint(state, startLocation); - } - - if (isControlFlow(node)) { - addStopPoint(state, startLocation); - - // We want to pause at tests so that we can pause at each iteration - // e.g `while (i++ < 3) { }` - const test = node.test || node.discriminant; - if (test) { - addStopPoint(state, test.loc.start); - } - return; - } - - if (t.isBlockStatement(node) || t.isArrayExpression(node)) { - return addEmptyPoint(state, startLocation); - } - - if (isAssignment(node)) { - // step at assignments unless the right side is a default assignment - // e.g. `( b = 2 ) => {}` - const defaultAssignment = t.isFunction(parentNode) && parent.key === "params"; - - return addPoint(state, startLocation, !defaultAssignment); - } - - if (isCall(node)) { - let location = startLocation; - - // When functions are chained, we want to use the property location - // e.g `foo().bar()` - if (t.isMemberExpression(node.callee)) { - location = node.callee.property.loc.start; - } - - // NOTE: We want to skip all nested calls in expressions except for the - // first call in arrays and objects expression e.g. [], {}, call - const step = isFirstCall(node, parentNode, grandParentNode) || !inExpression(parentNode, grandParentNode); - - // NOTE: we add a point at the beginning of the expression - // and each of the calls because the engine does not support - // column-based member expression calls. - addPoint(state, startLocation, { break: true, step }); - - if (location && !(0, _isEqual2.default)(location, startLocation)) { - addPoint(state, location, { break: true, step }); - } - - return; - } - - if (t.isClassProperty(node)) { - return addBreakPoint(state, startLocation); - } - - if (t.isFunction(node)) { - const { line, column } = node.loc.end; - addBreakPoint(state, startLocation); - return addEmptyPoint(state, { line, column: column - 1 }); - } - - if (!hasPoint(state, startLocation) && inStepExpression(parentNode)) { - return addEmptyPoint(state, startLocation); - } -} - -function hasPoint(state, { line, column }) { - return state[line] && state[line][column]; -} - -function addPoint(state, location, types) { - if (typeof types === "boolean") { - types = { step: types, break: types }; - } - - const { line, column } = location; - - if (!state[line]) { - state[line] = {}; - } - state[line][column] = { types, location }; - return state; -} - -function addStopPoint(state, location) { - return addPoint(state, location, { break: true, step: true }); -} - -function addEmptyPoint(state, location) { - return addPoint(state, location, {}); -} - -function addBreakPoint(state, location) { - return addPoint(state, location, { break: true }); -} - -/***/ }), - /***/ 3613: /***/ (function(module, exports, __webpack_require__) { diff --git a/devtools/client/debugger/new/dist/vendors.css b/devtools/client/debugger/new/dist/vendors.css index 6b6b822bbc860..0e52c744b22c8 100644 --- a/devtools/client/debugger/new/dist/vendors.css +++ b/devtools/client/debugger/new/dist/vendors.css @@ -55,30 +55,27 @@ } .tree-node button.arrow { - background:url("resource://devtools/client/debugger/new/images/arrow.svg") no-repeat; - background-size:contain; - background-position:center center; + mask: url("resource://devtools/client/debugger/new/images/arrow.svg") no-repeat center; + mask-size: 10px; + vertical-align: -1px; width: 10px; height: 10px; - border:0; - padding:0; + border: 0; + padding: 0; margin-inline-start: 1px; margin-inline-end: 4px; - transform: rotate(-90deg); transform-origin: center center; - transition: transform 0.125s ease; - align-self: center; - -moz-context-properties: fill; - fill: var(--theme-splitter-color, #9B9B9B); + transition: transform 125ms var(--animation-curve); + background-color: var(--theme-icon-dimmed-color); } -html[dir="rtl"] .tree-node button.arrow { - transform: rotate(90deg); +.tree-node button.arrow:not(.expanded) { + transform: rotate(-90deg); } -.tree-node button.arrow.expanded.expanded { - transform: rotate(0deg); - } +html[dir="rtl"] .tree-node button:not(.expanded) { + transform: rotate(90deg); +} .tree .tree-node.focused { color: white; @@ -86,7 +83,7 @@ html[dir="rtl"] .tree-node button.arrow { } .tree-node.focused button.arrow { - fill: currentColor; + background-color: currentColor; } /* vim:set ts=2 sw=2 sts=2 et: */ /* This Source Code Form is subject to the terms of the Mozilla Public diff --git a/devtools/client/debugger/new/dist/vendors.js b/devtools/client/debugger/new/dist/vendors.js index 1073c2266aafd..703b0cbc8d6aa 100644 --- a/devtools/client/debugger/new/dist/vendors.js +++ b/devtools/client/debugger/new/dist/vendors.js @@ -4814,6 +4814,10 @@ __webpack_require__(3671); // depth const AUTO_EXPAND_DEPTH = 0; +// Simplied selector targetting elements that can receive the focus, +// full version at https://stackoverflow.com/questions/1599660. +const FOCUSABLE_SELECTOR = ["a[href]:not([tabindex='-1'])", "button:not([disabled]):not([tabindex='-1'])", "iframe:not([tabindex='-1'])", "input:not([disabled]):not([tabindex='-1'])", "select:not([disabled]):not([tabindex='-1'])", "textarea:not([disabled]):not([tabindex='-1'])", "[tabindex]:not([tabindex='-1'])"].join(", "); + /** * An arrow that displays whether its node is expanded (▼) or collapsed * (▶). When its node has no children, it is hidden. @@ -4851,6 +4855,7 @@ class TreeNode extends Component { index: _propTypes2.default.number.isRequired, depth: _propTypes2.default.number.isRequired, focused: _propTypes2.default.bool.isRequired, + active: _propTypes2.default.bool.isRequired, expanded: _propTypes2.default.bool.isRequired, item: _propTypes2.default.any.isRequired, isExpandable: _propTypes2.default.bool.isRequired, @@ -4859,16 +4864,95 @@ class TreeNode extends Component { }; } + constructor(props) { + super(props); + + this.treeNodeRef = _react2.default.createRef(); + + this._onKeyDown = this._onKeyDown.bind(this); + } + + componentDidMount() { + // Make sure that none of the focusable elements inside the tree node + // container are tabbable if the tree node is not active. If the tree node + // is active and focus is outside its container, focus on the first + // focusable element inside. + const elms = this.getFocusableElements(); + if (this.props.active) { + if (elms.length > 0 && !elms.includes(document.activeElement)) { + elms[0].focus(); + } + } else { + elms.forEach(elm => elm.setAttribute("tabindex", "-1")); + } + } + shouldComponentUpdate(nextProps) { return this.props.item !== nextProps.item || this.props.focused !== nextProps.focused || this.props.expanded !== nextProps.expanded; } + /** + * Get a list of all elements that are focusable with a keyboard inside the + * tree node. + */ + getFocusableElements() { + return this.treeNodeRef.current ? Array.from(this.treeNodeRef.current.querySelectorAll(FOCUSABLE_SELECTOR)) : []; + } + + /** + * Wrap and move keyboard focus to first/last focusable element inside the + * tree node to prevent the focus from escaping the tree node boundaries. + * element). + * + * @param {DOMNode} current currently focused element + * @param {Boolean} back direction + * @return {Boolean} true there is a newly focused element. + */ + _wrapMoveFocus(current, back) { + const elms = this.getFocusableElements(); + let next; + + if (elms.length === 0) { + return false; + } + + if (back) { + if (elms.indexOf(current) === 0) { + next = elms[elms.length - 1]; + next.focus(); + } + } else if (elms.indexOf(current) === elms.length - 1) { + next = elms[0]; + next.focus(); + } + + return !!next; + } + + _onKeyDown(e) { + const { target, key, shiftKey } = e; + + if (key !== "Tab") { + return; + } + + const focusMoved = this._wrapMoveFocus(target, shiftKey); + if (focusMoved) { + // Focus was moved to the begining/end of the list, so we need to prevent + // the default focus change that would happen here. + e.preventDefault(); + } + + e.stopPropagation(); + } + render() { const { depth, id, item, focused, + active, expanded, renderItem, isExpandable @@ -4892,9 +4976,11 @@ class TreeNode extends Component { return _reactDomFactories2.default.div({ id, - className: `tree-node${focused ? " focused" : ""}`, + className: `tree-node${focused ? " focused" : ""}${active ? " active" : ""}`, onClick: this.props.onClick, + onKeyDownCapture: active ? this._onKeyDown : null, role: "treeitem", + ref: this.treeNodeRef, "aria-level": depth + 1, "aria-expanded": ariaExpanded, "data-expandable": this.props.isExpandable @@ -5128,6 +5214,8 @@ class Tree extends Component { // onExpand: item => dispatchExpandActionToRedux(item) onExpand: _propTypes2.default.func, onCollapse: _propTypes2.default.func, + // The currently active (keyboard) item, if any such item exists. + active: _propTypes2.default.any, // Optional event handler called with the current focused node when the // Enter key is pressed. Can be useful to allow further keyboard actions // within the tree node. @@ -5156,6 +5244,8 @@ class Tree extends Component { seen: new Set() }; + this.treeRef = _react2.default.createRef(); + this._onExpand = oncePerAnimationFrame(this._onExpand).bind(this); this._onCollapse = oncePerAnimationFrame(this._onCollapse).bind(this); this._focusPrevNode = oncePerAnimationFrame(this._focusPrevNode).bind(this); @@ -5166,22 +5256,21 @@ class Tree extends Component { this._autoExpand = this._autoExpand.bind(this); this._preventArrowKeyScrolling = this._preventArrowKeyScrolling.bind(this); + this._preventEvent = this._preventEvent.bind(this); this._dfs = this._dfs.bind(this); this._dfsFromRoots = this._dfsFromRoots.bind(this); this._focus = this._focus.bind(this); + this._activate = this._activate.bind(this); this._scrollNodeIntoView = this._scrollNodeIntoView.bind(this); this._onBlur = this._onBlur.bind(this); this._onKeyDown = this._onKeyDown.bind(this); this._nodeIsExpandable = this._nodeIsExpandable.bind(this); - this._activateNode = oncePerAnimationFrame(this._activateNode).bind(this); } componentDidMount() { this._autoExpand(); if (this.props.focused) { this._scrollNodeIntoView(this.props.focused); - // Always keep the focus on the tree itself. - this.treeRef.focus(); } } @@ -5192,8 +5281,6 @@ class Tree extends Component { componentDidUpdate(prevProps, prevState) { if (this.props.focused && prevProps.focused !== this.props.focused) { this._scrollNodeIntoView(this.props.focused); - // Always keep the focus on the tree itself. - this.treeRef.focus(); } } @@ -5242,16 +5329,21 @@ class Tree extends Component { case "ArrowDown": case "ArrowLeft": case "ArrowRight": - e.preventDefault(); - e.stopPropagation(); - if (e.nativeEvent) { - if (e.nativeEvent.preventDefault) { - e.nativeEvent.preventDefault(); - } - if (e.nativeEvent.stopPropagation) { - e.nativeEvent.stopPropagation(); - } - } + this._preventEvent(e); + break; + } + } + + _preventEvent(e) { + e.preventDefault(); + e.stopPropagation(); + if (e.nativeEvent) { + if (e.nativeEvent.preventDefault) { + e.nativeEvent.preventDefault(); + } + if (e.nativeEvent.stopPropagation) { + e.nativeEvent.stopPropagation(); + } } } @@ -5343,11 +5435,31 @@ class Tree extends Component { if (item && !preventAutoScroll) { this._scrollNodeIntoView(item, options); } + + if (this.props.active != undefined) { + this._activate(undefined); + if (this.treeRef.current !== document.activeElement) { + this.treeRef.current.focus(); + } + } + if (this.props.onFocus) { this.props.onFocus(item); } } + /** + * Sets the passed in item to be the active item. + * + * @param {Object|undefined} item + * The item to be activated, or undefined to activate no item. + */ + _activate(item) { + if (this.props.onActivate) { + this.props.onActivate(item); + } + } + /** * Sets the passed in item to be the focused item. * @@ -5362,7 +5474,7 @@ class Tree extends Component { */ _scrollNodeIntoView(item, options = {}) { if (item !== undefined) { - const treeElement = this.treeRef; + const treeElement = this.treeRef.current; const element = document.getElementById(this.props.getKey(item)); if (element) { @@ -5393,8 +5505,13 @@ class Tree extends Component { /** * Sets the state to have no focused item. */ - _onBlur() { - if (!this.props.preventBlur) { + _onBlur(e) { + if (this.props.active != undefined) { + const { relatedTarget } = e; + if (!this.treeRef.current.contains(relatedTarget)) { + this._activate(undefined); + } + } else if (!this.props.preventBlur) { this._focus(undefined); } } @@ -5404,6 +5521,7 @@ class Tree extends Component { * * @param {Event} e */ + // eslint-disable-next-line complexity _onKeyDown(e) { if (this.props.focused == null) { return; @@ -5450,7 +5568,25 @@ class Tree extends Component { return; case "Enter": - this._activateNode(); + case " ": + if (this.treeRef.current === document.activeElement) { + this._preventEvent(e); + if (this.props.active !== this.props.focused) { + this._activate(this.props.focused); + } + } + return; + + case "Escape": + this._preventEvent(e); + if (this.props.active != undefined) { + this._activate(undefined); + } + + if (this.treeRef.current !== document.activeElement) { + this.treeRef.current.focus(); + } + return; } } @@ -5529,31 +5665,29 @@ class Tree extends Component { this._focus(traversal[lastIndex].item, { alignTo: "bottom" }); } - _activateNode() { - if (this.props.onActivate) { - this.props.onActivate(this.props.focused); - } - } - _nodeIsExpandable(item) { return this.props.isExpandable ? this.props.isExpandable(item) : !!this.props.getChildren(item).length; } render() { const traversal = this._dfsFromRoots(); - const { focused } = this.props; + const { active, focused } = this.props; const nodes = traversal.map((v, i) => { const { item, depth } = traversal[i]; const key = this.props.getKey(item, i); return TreeNodeFactory({ - key, + // We make a key unique depending on whether the tree node is in active + // or inactive state to make sure that it is actually replaced and the + // tabbable state is reset. + key: `${key}-${active === item ? "active" : "inactive"}`, id: key, index: i, item, depth, renderItem: this.props.renderItem, focused: focused === item, + active: active === item, expanded: this.props.isExpanded(item), isExpandable: this._nodeIsExpandable(item), onExpand: this._onExpand, @@ -5571,6 +5705,9 @@ class Tree extends Component { } else { this.props.onExpand(item, e.altKey); } + + // Focus should always remain on the tree container itself. + this.treeRef.current.focus(); } }); }); @@ -5579,16 +5716,14 @@ class Tree extends Component { return _reactDomFactories2.default.div({ className: `tree ${this.props.className ? this.props.className : ""}`, - ref: el => { - this.treeRef = el; - }, + ref: this.treeRef, role: "tree", tabIndex: "0", onKeyDown: this._onKeyDown, onKeyPress: this._preventArrowKeyScrolling, onKeyUp: this._preventArrowKeyScrolling, onFocus: ({ nativeEvent }) => { - if (focused || !nativeEvent || !this.treeRef) { + if (focused || !nativeEvent || !this.treeRef.current) { return; } @@ -5596,7 +5731,7 @@ class Tree extends Component { // Only set default focus to the first tree node if the focus came // from outside the tree (e.g. by tabbing to the tree from other // external elements). - if (explicitOriginalTarget !== this.treeRef && !this.treeRef.contains(explicitOriginalTarget)) { + if (explicitOriginalTarget !== this.treeRef.current && !this.treeRef.current.contains(explicitOriginalTarget)) { this._focus(traversal[0].item); } }, @@ -7565,14 +7700,14 @@ module.exports = Svg; /***/ 3843: /***/ (function(module, exports) { -module.exports = "" +module.exports = "" /***/ }), /***/ 3844: /***/ (function(module, exports) { -module.exports = "" +module.exports = "" /***/ }), diff --git a/devtools/client/debugger/new/images/arrow.svg b/devtools/client/debugger/new/images/arrow.svg index d10640814c392..d1217f2dd2fe4 100644 --- a/devtools/client/debugger/new/images/arrow.svg +++ b/devtools/client/debugger/new/images/arrow.svg @@ -1,6 +1,6 @@ - + diff --git a/devtools/client/debugger/new/images/breakpoint.svg b/devtools/client/debugger/new/images/breakpoint.svg index 9df710aacc6a3..d4a67ae091828 100644 --- a/devtools/client/debugger/new/images/breakpoint.svg +++ b/devtools/client/debugger/new/images/breakpoint.svg @@ -1,6 +1,6 @@ - - + + diff --git a/devtools/client/debugger/new/index.html b/devtools/client/debugger/new/index.html index f471fb17282b7..73eb7cb13f33e 100644 --- a/devtools/client/debugger/new/index.html +++ b/devtools/client/debugger/new/index.html @@ -24,4 +24,4 @@ - \ No newline at end of file + diff --git a/devtools/client/debugger/new/packages/devtools-components/src/tests/__snapshots__/tree.js.snap b/devtools/client/debugger/new/packages/devtools-components/src/tests/__snapshots__/tree.js.snap index b78172f1fef06..1c0c3c088be29 100644 --- a/devtools/client/debugger/new/packages/devtools-components/src/tests/__snapshots__/tree.js.snap +++ b/devtools/client/debugger/new/packages/devtools-components/src/tests/__snapshots__/tree.js.snap @@ -17,6 +17,255 @@ Array [ ] `; +exports[`Tree active item - focus is inside the tree node and then blur 1`] = ` +" +▼ A +| ▼ B +| | ▼ E +| | | K +| | | [L anchor] +| | F +| | G +| ▼ C +| | H +| | I +| ▼ D +| | J +▼ M +| ▼ N +| | O +" +`; + +exports[`Tree active item - focus is inside the tree node when possible 1`] = ` +" +▼ A +| ▼ B +| | ▼ E +| | | K +| | | [L anchor] +| | F +| | G +| ▼ C +| | H +| | I +| ▼ D +| | J +▼ M +| ▼ N +| | O +" +`; + +exports[`Tree active item - focus is inside the tree node when possible 2`] = ` +" +▼ A +| ▼ B +| | ▼ E +| | | K +| | | [L anchor] +| | F +| | G +| ▼ C +| | H +| | I +| ▼ D +| | J +▼ M +| ▼ N +| | O +" +`; + +exports[`Tree active item - navigate inside the tree node 1`] = ` +" +▼ A +| ▼ B +| | ▼ E +| | | K +| | | [L anchor] +| | F +| | G +| ▼ C +| | H +| | I +| ▼ D +| | J +▼ M +| ▼ N +| | O +" +`; + +exports[`Tree active item - navigate inside the tree node 2`] = ` +" +▼ A +| ▼ B +| | ▼ E +| | | K +| | | [L anchor] +| | F +| | G +| ▼ C +| | H +| | I +| ▼ D +| | J +▼ M +| ▼ N +| | O +" +`; + +exports[`Tree active item - navigate inside the tree node 3`] = ` +" +▼ A +| ▼ B +| | ▼ E +| | | K +| | | [L anchor] +| | F +| | G +| ▼ C +| | H +| | I +| ▼ D +| | J +▼ M +| ▼ N +| | O +" +`; + +exports[`Tree active item - renders as expected when clicking away 1`] = ` +" +▼ A +| ▼ B +| | ▼ E +| | | K +| | | L +| | F +| | [G] +| ▼ C +| | H +| | I +| ▼ D +| | J +▼ M +| ▼ N +| | O +" +`; + +exports[`Tree active item - renders as expected when clicking away 2`] = ` +" +▶︎ [A] +▼ M +| ▼ N +| | O +" +`; + +exports[`Tree active item - renders as expected when moving away with keyboard 1`] = ` +" +▼ A +| ▼ B +| | ▼ E +| | | K +| | | [L] +| | F +| | G +| ▼ C +| | H +| | I +| ▼ D +| | J +▼ M +| ▼ N +| | O +" +`; + +exports[`Tree active item - renders as expected when tree blurs 1`] = ` +" +▼ A +| ▼ B +| | ▼ E +| | | K +| | | L +| | F +| | [G] +| ▼ C +| | H +| | I +| ▼ D +| | J +▼ M +| ▼ N +| | O +" +`; + +exports[`Tree active item - renders as expected when tree blurs 2`] = ` +" +▼ A +| ▼ B +| | ▼ E +| | | K +| | | L +| | F +| | [G] +| ▼ C +| | H +| | I +| ▼ D +| | J +▼ M +| ▼ N +| | O +" +`; + +exports[`Tree active item - renders as expected when using keyboard and Enter 1`] = ` +" +▼ A +| ▼ B +| | ▼ E +| | | K +| | | [L] +| | F +| | G +| ▼ C +| | H +| | I +| ▼ D +| | J +▼ M +| ▼ N +| | O +" +`; + +exports[`Tree active item - renders as expected when using keyboard and Space 1`] = ` +" +▼ A +| ▼ B +| | ▼ E +| | | K +| | | [L] +| | F +| | G +| ▼ C +| | H +| | I +| ▼ D +| | J +▼ M +| ▼ N +| | O +" +`; + exports[`Tree ignores key strokes when pressing modifiers 1`] = ` " ▼ A diff --git a/devtools/client/debugger/new/packages/devtools-components/src/tests/tree.js b/devtools/client/debugger/new/packages/devtools-components/src/tests/tree.js index d8ff858cf50bb..f3f9531346477 100644 --- a/devtools/client/debugger/new/packages/devtools-components/src/tests/tree.js +++ b/devtools/client/debugger/new/packages/devtools-components/src/tests/tree.js @@ -20,9 +20,11 @@ function mountTree(overrides = {}) { super(props); const state = { expanded: overrides.expanded || new Set(), - focused: overrides.focused + focused: overrides.focused, + active: overrides.active }; delete overrides.focused; + delete overrides.active; this.state = state; } @@ -49,6 +51,11 @@ function mountTree(overrides = {}) { return { focused: x }; }); }, + onActivate: x => { + this.setState(previousState => { + return { active: x }; + }); + }, onExpand: x => { this.setState(previousState => { const expanded = new Set(previousState.expanded); @@ -64,7 +71,8 @@ function mountTree(overrides = {}) { }); }, isExpanded: x => this.state && this.state.expanded.has(x), - focused: this.state.focused + focused: this.state.focused, + active: this.state.active }, overrides ) @@ -195,6 +203,160 @@ describe("Tree", () => { expect(formatTree(wrapper)).toMatchSnapshot(); }); + it("active item - renders as expected when clicking away", () => { + const wrapper = mountTree({ + expanded: new Set("ABCDEFGHIJKLMNO".split("")), + focused: "G", + active: "G" + }); + expect(formatTree(wrapper)).toMatchSnapshot(); + expect(wrapper.find(".active").prop("id")).toBe("key-G"); + + getTreeNodes(wrapper) + .first() + .simulate("click"); + expect(formatTree(wrapper)).toMatchSnapshot(); + expect(wrapper.find(".focused").prop("id")).toBe("key-A"); + expect(wrapper.find(".active").exists()).toBe(false); + }); + + it("active item - renders as expected when tree blurs", () => { + const wrapper = mountTree({ + expanded: new Set("ABCDEFGHIJKLMNO".split("")), + focused: "G", + active: "G" + }); + expect(formatTree(wrapper)).toMatchSnapshot(); + expect(wrapper.find(".active").prop("id")).toBe("key-G"); + + wrapper.simulate("blur"); + expect(formatTree(wrapper)).toMatchSnapshot(); + expect(wrapper.find(".active").exists()).toBe(false); + }); + + it("active item - renders as expected when moving away with keyboard", () => { + const wrapper = mountTree({ + expanded: new Set("ABCDEFGHIJKLMNO".split("")), + focused: "L", + active: "L" + }); + expect(formatTree(wrapper)).toMatchSnapshot(); + expect(wrapper.find(".active").prop("id")).toBe("key-L"); + + simulateKeyDown(wrapper, "ArrowUp"); + expect(wrapper.find(".active").exists()).toBe(false); + }); + + it("active item - renders as expected when using keyboard and Enter", () => { + const wrapper = mountTree({ + expanded: new Set("ABCDEFGHIJKLMNO".split("")), + focused: "L" + }); + wrapper.getDOMNode().focus(); + expect(formatTree(wrapper)).toMatchSnapshot(); + expect(wrapper.find(".active").exists()).toBe(false); + + simulateKeyDown(wrapper, "Enter"); + expect(wrapper.find(".active").prop("id")).toBe("key-L"); + + expect(wrapper.getDOMNode().ownerDocument.activeElement).toBe( + wrapper.getDOMNode() + ); + + simulateKeyDown(wrapper, "Escape"); + expect(wrapper.find(".active").exists()).toBe(false); + expect(wrapper.getDOMNode().ownerDocument.activeElement).toBe( + wrapper.getDOMNode() + ); + }); + + it("active item - renders as expected when using keyboard and Space", () => { + const wrapper = mountTree({ + expanded: new Set("ABCDEFGHIJKLMNO".split("")), + focused: "L" + }); + wrapper.getDOMNode().focus(); + expect(formatTree(wrapper)).toMatchSnapshot(); + expect(wrapper.find(".active").exists()).toBe(false); + + simulateKeyDown(wrapper, " "); + expect(wrapper.find(".active").prop("id")).toBe("key-L"); + + simulateKeyDown(wrapper, "Escape"); + expect(wrapper.find(".active").exists()).toBe(false); + }); + + it("active item - focus is inside the tree node when possible", () => { + const wrapper = mountTree({ + expanded: new Set("ABCDEFGHIJKLMNO".split("")), + focused: "L", + renderItem: renderItemWithFocusableContent + }); + wrapper.getDOMNode().focus(); + expect(formatTree(wrapper)).toMatchSnapshot(); + expect(wrapper.find(".active").exists()).toBe(false); + expect(wrapper.getDOMNode().ownerDocument.activeElement).toBe( + wrapper.getDOMNode() + ); + + simulateKeyDown(wrapper, "Enter"); + expect(wrapper.find(".active").prop("id")).toBe("key-L"); + expect(formatTree(wrapper)).toMatchSnapshot(); + expect(wrapper.getDOMNode().ownerDocument.activeElement).toBe( + wrapper.find("#active-anchor").getDOMNode() + ); + }); + + it("active item - navigate inside the tree node", () => { + const wrapper = mountTree({ + expanded: new Set("ABCDEFGHIJKLMNO".split("")), + focused: "L", + renderItem: renderItemWithFocusableContent + }); + wrapper.getDOMNode().focus(); + simulateKeyDown(wrapper, "Enter"); + expect(formatTree(wrapper)).toMatchSnapshot(); + expect(wrapper.find(".active").prop("id")).toBe("key-L"); + expect(wrapper.getDOMNode().ownerDocument.activeElement).toBe( + wrapper.find("#active-anchor").getDOMNode() + ); + + simulateKeyDown(wrapper, "Tab"); + expect(formatTree(wrapper)).toMatchSnapshot(); + expect(wrapper.find(".active").prop("id")).toBe("key-L"); + expect(wrapper.getDOMNode().ownerDocument.activeElement).toBe( + wrapper.find("#active-anchor").getDOMNode() + ); + + simulateKeyDown(wrapper, "Tab", { shiftKey: true }); + expect(formatTree(wrapper)).toMatchSnapshot(); + expect(wrapper.find(".active").prop("id")).toBe("key-L"); + expect(wrapper.getDOMNode().ownerDocument.activeElement).toBe( + wrapper.find("#active-anchor").getDOMNode() + ); + }); + + it("active item - focus is inside the tree node and then blur", () => { + const wrapper = mountTree({ + expanded: new Set("ABCDEFGHIJKLMNO".split("")), + focused: "L", + renderItem: renderItemWithFocusableContent + }); + wrapper.getDOMNode().focus(); + simulateKeyDown(wrapper, "Enter"); + expect(formatTree(wrapper)).toMatchSnapshot(); + expect(wrapper.find(".active").prop("id")).toBe("key-L"); + expect(wrapper.getDOMNode().ownerDocument.activeElement).toBe( + wrapper.find("#active-anchor").getDOMNode() + ); + + wrapper.find("#active-anchor").simulate("blur"); + expect(wrapper.find(".active").exists()).toBe(false); + expect(wrapper.getDOMNode().ownerDocument.activeElement).toBe( + wrapper.getDOMNode().ownerDocument.body + ); + }); + it("renders as expected when given a focused item", () => { const wrapper = mountTree({ expanded: new Set("ABCDEFGHIJKLMNO".split("")), @@ -512,7 +674,7 @@ describe("Tree", () => { const treeRef = wrapper .find("Tree") .first() - .instance().treeRef; + .instance().treeRef.current; treeRef.focus = jest.fn(); getTreeNodes(wrapper) @@ -529,48 +691,12 @@ describe("Tree", () => { const treeRef = wrapper .find("Tree") .first() - .instance().treeRef; + .instance().treeRef.current; treeRef.focus = jest.fn(); wrapper.simulate("blur"); expect(treeRef.focus.mock.calls).toHaveLength(0); }); - it("calls onActivate when expected", () => { - const onActivate = jest.fn(); - - const wrapper = mountTree({ - expanded: new Set("ABCDEFGHIJKLMNO".split("")), - focused: "A", - onActivate - }); - - simulateKeyDown(wrapper, "Enter"); - expect(onActivate.mock.calls).toHaveLength(1); - expect(onActivate.mock.calls[0][0]).toBe("A"); - - simulateKeyDown(wrapper, "Enter"); - expect(onActivate.mock.calls).toHaveLength(2); - expect(onActivate.mock.calls[1][0]).toBe("A"); - - simulateKeyDown(wrapper, "ArrowDown"); - simulateKeyDown(wrapper, "Enter"); - expect(onActivate.mock.calls).toHaveLength(3); - expect(onActivate.mock.calls[2][0]).toBe("B"); - - wrapper.simulate("blur"); - simulateKeyDown(wrapper, "Enter"); - expect(onActivate.mock.calls).toHaveLength(3); - }); - - it("does not throw when onActivate is undefined and Enter is pressed", () => { - const wrapper = mountTree({ - expanded: new Set("ABCDEFGHIJKLMNO".split("")), - focused: "A" - }); - - simulateKeyDown(wrapper, "Enter"); - }); - it("ignores key strokes when pressing modifiers", () => { const wrapper = mountTree({ expanded: new Set("ABCDEFGHIJKLMNO".split("")), @@ -653,14 +779,28 @@ function getTreeNodes(wrapper) { return wrapper.find(".tree-node"); } -function simulateKeyDown(wrapper, key) { +function simulateKeyDown(wrapper, key, options) { wrapper.simulate("keydown", { key, preventDefault: () => {}, - stopPropagation: () => {} + stopPropagation: () => {}, + ...options }); } +function renderItemWithFocusableContent(x, depth, focused, arrow) { + const children = [arrow, focused ? "[" : null, x]; + if (x === "L") { + children.push(dom.a({ id: "active-anchor", href: "#" }, " anchor")); + } + + if (focused) { + children.push("]"); + } + + return dom.div({}, ...children); +} + /* * Takes an Enzyme wrapper (obtained with mount/mount/…) and * returns a stringified version of the Tree, e.g. diff --git a/devtools/client/debugger/new/packages/devtools-components/src/tree.css b/devtools/client/debugger/new/packages/devtools-components/src/tree.css index ca98cbfa2d83a..fa343d0ea7081 100644 --- a/devtools/client/debugger/new/packages/devtools-components/src/tree.css +++ b/devtools/client/debugger/new/packages/devtools-components/src/tree.css @@ -55,30 +55,27 @@ } .tree-node button.arrow { - background:url(/images/arrow.svg) no-repeat; - background-size:contain; - background-position:center center; + mask: url(/images/arrow.svg) no-repeat center; + mask-size: 10px; + vertical-align: -1px; width: 10px; height: 10px; - border:0; - padding:0; + border: 0; + padding: 0; margin-inline-start: 1px; margin-inline-end: 4px; - transform: rotate(-90deg); transform-origin: center center; - transition: transform 0.125s ease; - align-self: center; - -moz-context-properties: fill; - fill: var(--theme-splitter-color, #9B9B9B); + transition: transform 125ms var(--animation-curve); + background-color: var(--theme-icon-dimmed-color); } -html[dir="rtl"] .tree-node button.arrow { - transform: rotate(90deg); +.tree-node button.arrow:not(.expanded) { + transform: rotate(-90deg); } -.tree-node button.arrow.expanded.expanded { - transform: rotate(0deg); - } +html[dir="rtl"] .tree-node button:not(.expanded) { + transform: rotate(90deg); +} .tree .tree-node.focused { color: white; @@ -86,5 +83,5 @@ html[dir="rtl"] .tree-node button.arrow { } .tree-node.focused button.arrow { - fill: currentColor; + background-color: currentColor; } diff --git a/devtools/client/debugger/new/packages/devtools-components/src/tree.js b/devtools/client/debugger/new/packages/devtools-components/src/tree.js index a9f230fec31c3..06f1ea5969b6f 100644 --- a/devtools/client/debugger/new/packages/devtools-components/src/tree.js +++ b/devtools/client/debugger/new/packages/devtools-components/src/tree.js @@ -12,6 +12,18 @@ require("./tree.css"); // depth const AUTO_EXPAND_DEPTH = 0; +// Simplied selector targetting elements that can receive the focus, +// full version at https://stackoverflow.com/questions/1599660. +const FOCUSABLE_SELECTOR = [ + "a[href]:not([tabindex='-1'])", + "button:not([disabled]):not([tabindex='-1'])", + "iframe:not([tabindex='-1'])", + "input:not([disabled]):not([tabindex='-1'])", + "select:not([disabled]):not([tabindex='-1'])", + "textarea:not([disabled]):not([tabindex='-1'])", + "[tabindex]:not([tabindex='-1'])" +].join(", "); + /** * An arrow that displays whether its node is expanded (▼) or collapsed * (▶). When its node has no children, it is hidden. @@ -49,6 +61,7 @@ class TreeNode extends Component { index: PropTypes.number.isRequired, depth: PropTypes.number.isRequired, focused: PropTypes.bool.isRequired, + active: PropTypes.bool.isRequired, expanded: PropTypes.bool.isRequired, item: PropTypes.any.isRequired, isExpandable: PropTypes.bool.isRequired, @@ -57,6 +70,29 @@ class TreeNode extends Component { }; } + constructor(props) { + super(props); + + this.treeNodeRef = React.createRef(); + + this._onKeyDown = this._onKeyDown.bind(this); + } + + componentDidMount() { + // Make sure that none of the focusable elements inside the tree node + // container are tabbable if the tree node is not active. If the tree node + // is active and focus is outside its container, focus on the first + // focusable element inside. + const elms = this.getFocusableElements(); + if (this.props.active) { + if (elms.length > 0 && !elms.includes(document.activeElement)) { + elms[0].focus(); + } + } else { + elms.forEach(elm => elm.setAttribute("tabindex", "-1")); + } + } + shouldComponentUpdate(nextProps) { return ( this.props.item !== nextProps.item || @@ -65,12 +101,72 @@ class TreeNode extends Component { ); } + /** + * Get a list of all elements that are focusable with a keyboard inside the + * tree node. + */ + getFocusableElements() { + return this.treeNodeRef.current + ? Array.from( + this.treeNodeRef.current.querySelectorAll(FOCUSABLE_SELECTOR) + ) + : []; + } + + /** + * Wrap and move keyboard focus to first/last focusable element inside the + * tree node to prevent the focus from escaping the tree node boundaries. + * element). + * + * @param {DOMNode} current currently focused element + * @param {Boolean} back direction + * @return {Boolean} true there is a newly focused element. + */ + _wrapMoveFocus(current, back) { + const elms = this.getFocusableElements(); + let next; + + if (elms.length === 0) { + return false; + } + + if (back) { + if (elms.indexOf(current) === 0) { + next = elms[elms.length - 1]; + next.focus(); + } + } else if (elms.indexOf(current) === elms.length - 1) { + next = elms[0]; + next.focus(); + } + + return !!next; + } + + _onKeyDown(e) { + const { target, key, shiftKey } = e; + + if (key !== "Tab") { + return; + } + + const focusMoved = this._wrapMoveFocus(target, shiftKey); + if (focusMoved) { + // Focus was moved to the begining/end of the list, so we need to prevent + // the default focus change that would happen here. + e.preventDefault(); + } + + e.stopPropagation(); + } + render() { const { depth, id, item, focused, + active, expanded, renderItem, isExpandable @@ -99,9 +195,13 @@ class TreeNode extends Component { return dom.div( { id, - className: `tree-node${focused ? " focused" : ""}`, + className: `tree-node${focused ? " focused" : ""}${ + active ? " active" : "" + }`, onClick: this.props.onClick, + onKeyDownCapture: active ? this._onKeyDown : null, role: "treeitem", + ref: this.treeNodeRef, "aria-level": depth + 1, "aria-expanded": ariaExpanded, "data-expandable": this.props.isExpandable @@ -337,6 +437,8 @@ class Tree extends Component { // onExpand: item => dispatchExpandActionToRedux(item) onExpand: PropTypes.func, onCollapse: PropTypes.func, + // The currently active (keyboard) item, if any such item exists. + active: PropTypes.any, // Optional event handler called with the current focused node when the // Enter key is pressed. Can be useful to allow further keyboard actions // within the tree node. @@ -365,6 +467,8 @@ class Tree extends Component { seen: new Set() }; + this.treeRef = React.createRef(); + this._onExpand = oncePerAnimationFrame(this._onExpand).bind(this); this._onCollapse = oncePerAnimationFrame(this._onCollapse).bind(this); this._focusPrevNode = oncePerAnimationFrame(this._focusPrevNode).bind(this); @@ -379,22 +483,21 @@ class Tree extends Component { this._autoExpand = this._autoExpand.bind(this); this._preventArrowKeyScrolling = this._preventArrowKeyScrolling.bind(this); + this._preventEvent = this._preventEvent.bind(this); this._dfs = this._dfs.bind(this); this._dfsFromRoots = this._dfsFromRoots.bind(this); this._focus = this._focus.bind(this); + this._activate = this._activate.bind(this); this._scrollNodeIntoView = this._scrollNodeIntoView.bind(this); this._onBlur = this._onBlur.bind(this); this._onKeyDown = this._onKeyDown.bind(this); this._nodeIsExpandable = this._nodeIsExpandable.bind(this); - this._activateNode = oncePerAnimationFrame(this._activateNode).bind(this); } componentDidMount() { this._autoExpand(); if (this.props.focused) { this._scrollNodeIntoView(this.props.focused); - // Always keep the focus on the tree itself. - this.treeRef.focus(); } } @@ -405,8 +508,6 @@ class Tree extends Component { componentDidUpdate(prevProps, prevState) { if (this.props.focused && prevProps.focused !== this.props.focused) { this._scrollNodeIntoView(this.props.focused); - // Always keep the focus on the tree itself. - this.treeRef.focus(); } } @@ -458,16 +559,21 @@ class Tree extends Component { case "ArrowDown": case "ArrowLeft": case "ArrowRight": - e.preventDefault(); - e.stopPropagation(); - if (e.nativeEvent) { - if (e.nativeEvent.preventDefault) { - e.nativeEvent.preventDefault(); - } - if (e.nativeEvent.stopPropagation) { - e.nativeEvent.stopPropagation(); - } - } + this._preventEvent(e); + break; + } + } + + _preventEvent(e) { + e.preventDefault(); + e.stopPropagation(); + if (e.nativeEvent) { + if (e.nativeEvent.preventDefault) { + e.nativeEvent.preventDefault(); + } + if (e.nativeEvent.stopPropagation) { + e.nativeEvent.stopPropagation(); + } } } @@ -559,11 +665,31 @@ class Tree extends Component { if (item && !preventAutoScroll) { this._scrollNodeIntoView(item, options); } + + if (this.props.active != undefined) { + this._activate(undefined); + if (this.treeRef.current !== document.activeElement) { + this.treeRef.current.focus(); + } + } + if (this.props.onFocus) { this.props.onFocus(item); } } + /** + * Sets the passed in item to be the active item. + * + * @param {Object|undefined} item + * The item to be activated, or undefined to activate no item. + */ + _activate(item) { + if (this.props.onActivate) { + this.props.onActivate(item); + } + } + /** * Sets the passed in item to be the focused item. * @@ -578,7 +704,7 @@ class Tree extends Component { */ _scrollNodeIntoView(item, options = {}) { if (item !== undefined) { - const treeElement = this.treeRef; + const treeElement = this.treeRef.current; const element = document.getElementById(this.props.getKey(item)); if (element) { @@ -616,8 +742,13 @@ class Tree extends Component { /** * Sets the state to have no focused item. */ - _onBlur() { - if (!this.props.preventBlur) { + _onBlur(e) { + if (this.props.active != undefined) { + const { relatedTarget } = e; + if (!this.treeRef.current.contains(relatedTarget)) { + this._activate(undefined); + } + } else if (!this.props.preventBlur) { this._focus(undefined); } } @@ -627,6 +758,7 @@ class Tree extends Component { * * @param {Event} e */ + // eslint-disable-next-line complexity _onKeyDown(e) { if (this.props.focused == null) { return; @@ -679,7 +811,25 @@ class Tree extends Component { return; case "Enter": - this._activateNode(); + case " ": + if (this.treeRef.current === document.activeElement) { + this._preventEvent(e); + if (this.props.active !== this.props.focused) { + this._activate(this.props.focused); + } + } + return; + + case "Escape": + this._preventEvent(e); + if (this.props.active != undefined) { + this._activate(undefined); + } + + if (this.treeRef.current !== document.activeElement) { + this.treeRef.current.focus(); + } + return; } } @@ -758,12 +908,6 @@ class Tree extends Component { this._focus(traversal[lastIndex].item, { alignTo: "bottom" }); } - _activateNode() { - if (this.props.onActivate) { - this.props.onActivate(this.props.focused); - } - } - _nodeIsExpandable(item) { return this.props.isExpandable ? this.props.isExpandable(item) @@ -772,19 +916,23 @@ class Tree extends Component { render() { const traversal = this._dfsFromRoots(); - const { focused } = this.props; + const { active, focused } = this.props; const nodes = traversal.map((v, i) => { const { item, depth } = traversal[i]; const key = this.props.getKey(item, i); return TreeNodeFactory({ - key, + // We make a key unique depending on whether the tree node is in active + // or inactive state to make sure that it is actually replaced and the + // tabbable state is reset. + key: `${key}-${active === item ? "active" : "inactive"}`, id: key, index: i, item, depth, renderItem: this.props.renderItem, focused: focused === item, + active: active === item, expanded: this.props.isExpanded(item), isExpandable: this._nodeIsExpandable(item), onExpand: this._onExpand, @@ -802,6 +950,9 @@ class Tree extends Component { } else { this.props.onExpand(item, e.altKey); } + + // Focus should always remain on the tree container itself. + this.treeRef.current.focus(); } }); }); @@ -811,16 +962,14 @@ class Tree extends Component { return dom.div( { className: `tree ${this.props.className ? this.props.className : ""}`, - ref: el => { - this.treeRef = el; - }, + ref: this.treeRef, role: "tree", tabIndex: "0", onKeyDown: this._onKeyDown, onKeyPress: this._preventArrowKeyScrolling, onKeyUp: this._preventArrowKeyScrolling, onFocus: ({ nativeEvent }) => { - if (focused || !nativeEvent || !this.treeRef) { + if (focused || !nativeEvent || !this.treeRef.current) { return; } @@ -829,8 +978,8 @@ class Tree extends Component { // from outside the tree (e.g. by tabbing to the tree from other // external elements). if ( - explicitOriginalTarget !== this.treeRef && - !this.treeRef.contains(explicitOriginalTarget) + explicitOriginalTarget !== this.treeRef.current && + !this.treeRef.current.contains(explicitOriginalTarget) ) { this._focus(traversal[0].item); } diff --git a/devtools/client/debugger/new/packages/devtools-reps/README.md b/devtools/client/debugger/new/packages/devtools-reps/README.md index 69765e6b9af69..a9c4557afb35e 100644 --- a/devtools/client/debugger/new/packages/devtools-reps/README.md +++ b/devtools/client/debugger/new/packages/devtools-reps/README.md @@ -45,7 +45,7 @@ Supported types: You need to clone the debugger.html repository, then install dependencies, for which you'll need the [Yarn](https://yarnpkg.com/en/) tool: ``` -git clone https://github.com/devtools-html/debugger.html.git +git clone https://github.com/firefox-devtools/debugger.html.git cd debugger.html yarn install ``` @@ -95,9 +95,9 @@ They were first moved to the [devtools-reps][gh-devtools-reps] repository, then [history]: https://github.com/mozilla/gecko-dev/commits/master/devtools/client/shared/components/reps [gh-devtools-reps]: -https://github.com/devtools-html/reps/commits/master +https://github.com/firefox-devtools/reps/commits/master [gh-devtools-core]: -https://github.com/devtools-html/devtools-core/commits/5ba3d6f6a44def9978a983edd6f2f89747dca2c7/packages/devtools-reps +https://github.com/firefox-devtools/devtools-core/commits/5ba3d6f6a44def9978a983edd6f2f89747dca2c7/packages/devtools-reps ## License diff --git a/devtools/client/debugger/new/packages/devtools-reps/package.json b/devtools/client/debugger/new/packages/devtools-reps/package.json index d4d3398363683..8d28e56505194 100644 --- a/devtools/client/debugger/new/packages/devtools-reps/package.json +++ b/devtools/client/debugger/new/packages/devtools-reps/package.json @@ -6,7 +6,7 @@ "scripts": { "start": "node bin/dev-server.js", "lint-js": "eslint src", - "firefox": "./node_modules/.bin/start-firefox --start --location https://devtools-html.github.io/debugger-examples/", + "firefox": "./node_modules/.bin/start-firefox --start --location https://firefox-devtools.github.io/debugger-examples/", "chrome": "./node_modules/.bin/start-chrome", "license-check": "devtools-license-check", "test": "jest --projects jest.config.js" @@ -14,7 +14,7 @@ "author": "", "license": "MPL-2.0", "repository": { - "url": "git://github.com/devtools-html/reps.git", + "url": "git://github.com/firefox-devtools/reps.git", "type": "git" }, "engineStrict": true, @@ -38,7 +38,7 @@ "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", "babel-preset-react": "^6.24.1", "devtools-config": "^0.0.16", - "devtools-launchpad": "^0.0.145", + "devtools-launchpad": "^0.0.149", "devtools-license-check": "^0.7.0", "devtools-modules": "~1.1.0", "devtools-services": "^0.0.1", diff --git a/devtools/client/debugger/new/packages/devtools-reps/src/object-inspector/components/ObjectInspector.js b/devtools/client/debugger/new/packages/devtools-reps/src/object-inspector/components/ObjectInspector.js index 5d6957383cbad..022a0709e0a8d 100644 --- a/devtools/client/debugger/new/packages/devtools-reps/src/object-inspector/components/ObjectInspector.js +++ b/devtools/client/debugger/new/packages/devtools-reps/src/object-inspector/components/ObjectInspector.js @@ -75,6 +75,7 @@ class ObjectInspector extends Component { self.isNodeExpandable = this.isNodeExpandable.bind(this); self.setExpanded = this.setExpanded.bind(this); self.focusItem = this.focusItem.bind(this); + self.activateItem = this.activateItem.bind(this); self.getRoots = this.getRoots.bind(this); self.getNodeKey = this.getNodeKey.bind(this); } @@ -82,6 +83,7 @@ class ObjectInspector extends Component { componentWillMount() { this.roots = this.props.roots; this.focusedItem = this.props.focusedItem; + this.activeItem = this.props.activeItem; } componentWillUpdate(nextProps) { @@ -92,6 +94,7 @@ class ObjectInspector extends Component { // so we need to cleanup the component internal state. this.roots = nextProps.roots; this.focusedItem = nextProps.focusedItem; + this.activeItem = nextProps.activeItem; if (this.props.rootsChanged) { this.props.rootsChanged(); } @@ -128,6 +131,7 @@ class ObjectInspector extends Component { // - OR the expanded paths number did not changed, but old and new sets // differ // - OR the focused node changed. + // - OR the active node changed. return ( loadedProperties.size !== nextProps.loadedProperties.size || evaluations.size !== nextProps.evaluations.size || @@ -138,6 +142,7 @@ class ObjectInspector extends Component { (expandedPaths.size === nextProps.expandedPaths.size && [...nextProps.expandedPaths].some(key => !expandedPaths.has(key))) || this.focusedItem !== nextProps.focusedItem || + this.activeItem !== nextProps.activeItem || this.roots !== nextProps.roots ); } @@ -219,6 +224,19 @@ class ObjectInspector extends Component { } } + activateItem(item: Node) { + const { focusable = true, onActivate } = this.props; + + if (focusable && this.activeItem !== item) { + this.activeItem = item; + this.forceUpdate(); + + if (onActivate) { + onActivate(item); + } + } + } + render() { const { autoExpandAll = true, @@ -242,6 +260,7 @@ class ObjectInspector extends Component { isExpanded: item => expandedPaths && expandedPaths.has(item.path), isExpandable: this.isNodeExpandable, focused: this.focusedItem, + active: this.activeItem, getRoots: this.getRoots, getParent, @@ -251,6 +270,7 @@ class ObjectInspector extends Component { onExpand: item => this.setExpanded(item, true), onCollapse: item => this.setExpanded(item, false), onFocus: focusable ? this.focusItem : null, + onActivate: focusable ? this.activateItem : null, renderItem: (item, depth, focused, arrow, expanded) => ObjectInspectorItem({ diff --git a/devtools/client/debugger/new/packages/devtools-reps/src/object-inspector/tests/component/__snapshots__/classnames.js.snap b/devtools/client/debugger/new/packages/devtools-reps/src/object-inspector/tests/component/__snapshots__/classnames.js.snap index e8db5f16e6e1c..8c630ba1ea711 100644 --- a/devtools/client/debugger/new/packages/devtools-reps/src/object-inspector/tests/component/__snapshots__/classnames.js.snap +++ b/devtools/client/debugger/new/packages/devtools-reps/src/object-inspector/tests/component/__snapshots__/classnames.js.snap @@ -18,6 +18,7 @@ exports[`ObjectInspector - classnames has the expected class 1`] = ` data-expandable={false} id="root" onClick={[Function]} + onKeyDownCapture={null} role="treeitem" >
any, + onActivate: ?(Node) => any, onDoubleClick: ?( item: Node, options: { @@ -132,6 +133,7 @@ export type Props = { actors: Set, expandedPaths: Set, focusedItem: ?Node, + activeItem: ?Node, loadedProperties: LoadedProperties, evaluations: Evaluations, loading: Map>> @@ -146,6 +148,7 @@ export type State = { actors: Set, expandedPaths: Set, focusedItem: ?Node, + activeItem: ?Node, loadedProperties: LoadedProperties }; diff --git a/devtools/client/debugger/new/packages/devtools-reps/src/reps/grip-array.js b/devtools/client/debugger/new/packages/devtools-reps/src/reps/grip-array.js index 8323046b2f78e..d2840e80f2668 100644 --- a/devtools/client/debugger/new/packages/devtools-reps/src/reps/grip-array.js +++ b/devtools/client/debugger/new/packages/devtools-reps/src/reps/grip-array.js @@ -225,7 +225,7 @@ function arrayIterator(props, grip, max) { } function getEmptySlotsElement(number) { - // TODO: Use l10N - See https://github.com/devtools-html/reps/issues/141 + // TODO: Use l10N - See https://github.com/firefox-devtools/reps/issues/141 return `<${number} empty slot${number > 1 ? "s" : ""}>`; } diff --git a/devtools/client/debugger/new/packages/devtools-reps/src/reps/reps.css b/devtools/client/debugger/new/packages/devtools-reps/src/reps/reps.css index ffb02674ffdef..3d4d4bd7bbba2 100644 --- a/devtools/client/debugger/new/packages/devtools-reps/src/reps/reps.css +++ b/devtools/client/debugger/new/packages/devtools-reps/src/reps/reps.css @@ -251,7 +251,7 @@ button.open-inspector { margin: 0 4px; padding: 0; border: none; - background-color: var(--comment-node-color); + background-color: var(--theme-icon-color); cursor: pointer; } @@ -260,7 +260,7 @@ button.open-inspector { .objectBox-textNode:hover .open-inspector, .open-accessibility-inspector:hover, .open-inspector:hover { - background-color: var(--theme-highlight-blue); + background-color: var(--theme-icon-checked-color); } /******************************************************************************/ @@ -269,14 +269,14 @@ button.open-inspector { button.jump-definition { mask: url(/images/jump-definition.svg) no-repeat; display: inline-block; - background-color: var(--comment-node-color); + background-color: var(--theme-icon-color); height: 16px; margin-left: 0.25em; vertical-align: middle; } .jump-definition:hover { - background-color: var(--theme-highlight-blue); + background-color: var(--theme-icon-checked-color); } /******************************************************************************/ @@ -285,14 +285,14 @@ button.jump-definition { button.invoke-getter { mask: url(/images/input.svg) no-repeat; display: inline-block; - background-color: var(--comment-node-color); + background-color: var(--theme-icon-color); height: 10px; vertical-align: middle; border:none; } .invoke-getter:hover { - background-color: var(--theme-highlight-blue); + background-color: var(--theme-icon-checked-color); } /******************************************************************************/ diff --git a/devtools/client/debugger/new/packages/devtools-source-map/package.json b/devtools/client/debugger/new/packages/devtools-source-map/package.json index 892ba14baee4c..eb00301c730e8 100644 --- a/devtools/client/debugger/new/packages/devtools-source-map/package.json +++ b/devtools/client/debugger/new/packages/devtools-source-map/package.json @@ -5,9 +5,9 @@ "license": "MPL-2.0", "author": "Jason Laster ", "repository": "github:devtools-html/debugger.html", - "bugs": "https://github.com/devtools-html/debugger.html/issues", + "bugs": "https://github.com/firefox-devtools/debugger.html/issues", "homepage": - "https://github.com/devtools-html/debugger.html/tree/master/packages/source-maps#readme", + "https://github.com/firefox-devtools/debugger.html/tree/master/packages/source-maps#readme", "main": "src/index.js", "browser": { "./src/utils/wasmAsset.js": "./src/utils/wasmAssetBrowser.js" diff --git a/devtools/client/debugger/new/packages/devtools-source-map/src/index.js b/devtools/client/debugger/new/packages/devtools-source-map/src/index.js index 37f8f849e82cd..498cd7b5f362d 100644 --- a/devtools/client/debugger/new/packages/devtools-source-map/src/index.js +++ b/devtools/client/debugger/new/packages/devtools-source-map/src/index.js @@ -8,7 +8,7 @@ const { workerUtils: { WorkerDispatcher } } = require("devtools-utils"); -import type { SourceLocation, Source, SourceId } from "debugger-html"; +import type { SourceLocation, Source, SourceId } from "../../../src/types"; import type { SourceMapConsumer } from "source-map"; import type { locationOptions } from "./source-map"; diff --git a/devtools/client/debugger/new/src/actions/README.md b/devtools/client/debugger/new/src/actions/README.md index 74a3c29d8c400..6fd0f8be181b5 100644 --- a/devtools/client/debugger/new/src/actions/README.md +++ b/devtools/client/debugger/new/src/actions/README.md @@ -22,5 +22,5 @@ in the UI: * disable/hide the pretty print button * show a progress ui -[req]: https://github.com/devtools-html/debugger.html/blob/master/src/actions/sources/loadSourceText.js -[state]: https://github.com/devtools-html/debugger.html/blob/master/src/reducers/sources.js +[req]: https://github.com/firefox-devtools/debugger.html/blob/master/src/actions/sources/loadSourceText.js +[state]: https://github.com/firefox-devtools/debugger.html/blob/master/src/reducers/sources.js diff --git a/devtools/client/debugger/new/src/actions/ast.js b/devtools/client/debugger/new/src/actions/ast.js index 718f456b8d8ec..3ef230c02a478 100644 --- a/devtools/client/debugger/new/src/actions/ast.js +++ b/devtools/client/debugger/new/src/actions/ast.js @@ -18,8 +18,6 @@ import { updateTab } from "./tabs"; import { PROMISE } from "./utils/middleware/promise"; import { setInScopeLines } from "./ast/setInScopeLines"; -import { setPausePoints } from "./ast/setPausePoints"; -export { setPausePoints }; import * as parser from "../workers/parser"; @@ -70,7 +68,6 @@ export function setSymbols(sourceId: SourceId) { await dispatch(mapFrames()); } - await dispatch(setPausePoints(sourceId)); await dispatch(setSourceMetaData(sourceId)); }; } diff --git a/devtools/client/debugger/new/src/actions/ast/moz.build b/devtools/client/debugger/new/src/actions/ast/moz.build index 20165b3129bc1..9b3166090103e 100644 --- a/devtools/client/debugger/new/src/actions/ast/moz.build +++ b/devtools/client/debugger/new/src/actions/ast/moz.build @@ -9,5 +9,4 @@ DIRS += [ DebuggerModules( 'setInScopeLines.js', - 'setPausePoints.js', ) diff --git a/devtools/client/debugger/new/src/actions/ast/setPausePoints.js b/devtools/client/debugger/new/src/actions/ast/setPausePoints.js index 9b84896d29833..5fa2f4ff3b67a 100644 --- a/devtools/client/debugger/new/src/actions/ast/setPausePoints.js +++ b/devtools/client/debugger/new/src/actions/ast/setPausePoints.js @@ -4,9 +4,8 @@ // @flow -import { getSourceFromId, getSourceActors } from "../../selectors"; +import { getSourceFromId } from "../../selectors"; import * as parser from "../../workers/parser"; -import { isGenerated } from "../../utils/source"; import { convertToList } from "../../utils/pause/pausePoints"; import { features } from "../../utils/prefs"; import { getGeneratedLocation } from "../../utils/source-maps"; diff --git a/devtools/client/debugger/new/src/actions/breakpoints/breakpointPositions.js b/devtools/client/debugger/new/src/actions/breakpoints/breakpointPositions.js index 249f1c0c8665e..2487944b418a7 100644 --- a/devtools/client/debugger/new/src/actions/breakpoints/breakpointPositions.js +++ b/devtools/client/debugger/new/src/actions/breakpoints/breakpointPositions.js @@ -4,34 +4,66 @@ // @flow +import { isOriginalId, originalToGeneratedId } from "devtools-source-map"; + import { - getSourceActors, - getBreakpointPositionsForLine + getSourceFromId, + getBreakpointPositionsForSource } from "../../selectors"; -import { makeSourceActorLocation } from "../../utils/breakpoint"; - import type { SourceLocation } from "../../types"; import type { ThunkArgs } from "../../actions/types"; +import { getOriginalLocation } from "../../utils/source-maps"; + +async function mapLocations(generatedLocations, state, source, sourceMaps) { + return Promise.all( + generatedLocations.map(async generatedLocation => { + const location = await getOriginalLocation( + generatedLocation, + source, + sourceMaps + ); + + return { location, generatedLocation }; + }) + ); +} + +function convertToList(results, sourceId) { + const positions = []; + + for (const line in results) { + for (const column of results[line]) { + positions.push({ line: Number(line), column: column, sourceId }); + } + } + + return positions; +} export function setBreakpointPositions(location: SourceLocation) { - return async ({ getState, dispatch, client }: ThunkArgs) => { - if ( - getBreakpointPositionsForLine( - getState(), - location.sourceId, - location.line - ) - ) { + return async ({ getState, dispatch, client, sourceMaps }: ThunkArgs) => { + let sourceId = location.sourceId; + if (getBreakpointPositionsForSource(getState(), sourceId)) { return; } - const sourceActors = getSourceActors(getState(), location.sourceId); - const sourceActor = sourceActors[0]; + let source = getSourceFromId(getState(), sourceId); + + let range; + if (isOriginalId(sourceId)) { + range = await sourceMaps.getFileGeneratedRange(source); + sourceId = originalToGeneratedId(sourceId); + source = getSourceFromId(getState(), sourceId); + } - const sourceActorLocation = makeSourceActorLocation(sourceActor, location); - const positions = await client.getBreakpointPositions(sourceActorLocation); + const results = await client.getBreakpointPositions( + source.actors[0], + range + ); + let positions = convertToList(results, sourceId); + positions = await mapLocations(positions, getState(), source, sourceMaps); return dispatch({ type: "ADD_BREAKPOINT_POSITIONS", positions, location }); }; } diff --git a/devtools/client/debugger/new/src/actions/breakpoints/index.js b/devtools/client/debugger/new/src/actions/breakpoints/index.js index 76504297c88b3..dfd07e132bf9f 100644 --- a/devtools/client/debugger/new/src/actions/breakpoints/index.js +++ b/devtools/client/debugger/new/src/actions/breakpoints/index.js @@ -299,7 +299,6 @@ export function setBreakpointOptions( getState(), bp.generatedLocation ); - await client.setBreakpoint(breakpointLocation, options); const newBreakpoint = { ...bp, disabled: false, options }; diff --git a/devtools/client/debugger/new/src/actions/breakpoints/syncBreakpoint.js b/devtools/client/debugger/new/src/actions/breakpoints/syncBreakpoint.js index 222321f3b7940..511ae24ecaeda 100644 --- a/devtools/client/debugger/new/src/actions/breakpoints/syncBreakpoint.js +++ b/devtools/client/debugger/new/src/actions/breakpoints/syncBreakpoint.js @@ -35,6 +35,17 @@ type BreakpointSyncData = { breakpoint: ?Breakpoint }; +async function isPossiblePosition(location, dispatch) { + if (features.columnBreakpoints && location.column != undefined) { + const { positions } = await dispatch(setBreakpointPositions(location)); + if (!positions.some(({ generatedLocation }) => generatedLocation.column)) { + return false; + } + } + + return true; +} + async function makeScopedLocation( { name, offset, index }: ASTLocation, location: SourceLocation, @@ -136,15 +147,10 @@ export async function syncBreakpointPromise( generatedLocation ); - let possiblePosition = true; - if (features.columnBreakpoints && generatedLocation.column != undefined) { - const { positions } = await dispatch( - setBreakpointPositions(generatedLocation) - ); - if (!positions.includes(generatedLocation.column)) { - possiblePosition = false; - } - } + const possiblePosition = await isPossiblePosition( + generatedLocation, + dispatch + ); /** ******* CASE 1: No server change ***********/ // early return if breakpoint is disabled or we are in the sameLocation diff --git a/devtools/client/debugger/new/src/actions/breakpoints/tests/__snapshots__/breakpoints.spec.js.snap b/devtools/client/debugger/new/src/actions/breakpoints/tests/__snapshots__/breakpoints.spec.js.snap index cfe986e1681ee..77559d14ee5a0 100644 --- a/devtools/client/debugger/new/src/actions/breakpoints/tests/__snapshots__/breakpoints.spec.js.snap +++ b/devtools/client/debugger/new/src/actions/breakpoints/tests/__snapshots__/breakpoints.spec.js.snap @@ -37,6 +37,13 @@ Array [ }, ], "source": Object { + "actors": Array [ + Object { + "actor": "a-actor", + "source": "a", + "thread": "FakeThread", + }, + ], "contentType": "text/javascript", "error": undefined, "id": "a", @@ -45,6 +52,7 @@ Array [ "isPrettyPrinted": false, "isWasm": false, "loadedState": "loaded", + "relativeUrl": "/examples/a", "sourceMapURL": undefined, "text": "function a() { return a @@ -129,6 +137,13 @@ Array [ }, ], "source": Object { + "actors": Array [ + Object { + "actor": "a-actor", + "source": "a", + "thread": "FakeThread", + }, + ], "contentType": "text/javascript", "error": undefined, "id": "a", @@ -137,6 +152,7 @@ Array [ "isPrettyPrinted": false, "isWasm": false, "loadedState": "loaded", + "relativeUrl": "/examples/a", "sourceMapURL": undefined, "text": "function a() { return a diff --git a/devtools/client/debugger/new/src/actions/breakpoints/tests/breakpoints.spec.js b/devtools/client/debugger/new/src/actions/breakpoints/tests/breakpoints.spec.js index 2316878ee5487..140c93d9d8b8c 100644 --- a/devtools/client/debugger/new/src/actions/breakpoints/tests/breakpoints.spec.js +++ b/devtools/client/debugger/new/src/actions/breakpoints/tests/breakpoints.spec.js @@ -23,9 +23,9 @@ describe("breakpoints", () => { sourceUrl: "http://localhost:8000/examples/a" }; - const csr = makeSource("a"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeSource("a"); + await dispatch(actions.newSource(source)); + await dispatch(actions.loadSourceText(source)); await dispatch(actions.addBreakpoint(loc1)); expect(selectors.getBreakpointCount(getState())).toEqual(1); @@ -44,9 +44,9 @@ describe("breakpoints", () => { line: 5, sourceUrl: "http://localhost:8000/examples/a" }; - const csr = makeSource("a"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeSource("a"); + await dispatch(actions.newSource(source)); + await dispatch(actions.loadSourceText(source)); await dispatch(actions.addBreakpoint(loc1)); expect(selectors.getBreakpointCount(getState())).toEqual(1); @@ -62,9 +62,9 @@ describe("breakpoints", () => { line: 5, sourceUrl: "http://localhost:8000/examples/a" }; - const csr = makeSource("a"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeSource("a"); + await dispatch(actions.newSource(source)); + await dispatch(actions.loadSourceText(source)); const breakpoint = await dispatch(actions.addBreakpoint(loc1)); await dispatch(actions.disableBreakpoint(breakpoint)); @@ -82,9 +82,9 @@ describe("breakpoints", () => { sourceUrl: "http://localhost:8000/examples/a" }; - const csr = makeSource("a"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeSource("a"); + await dispatch(actions.newSource(source)); + await dispatch(actions.loadSourceText(source)); await dispatch(actions.addBreakpoint(loc1)); expect(selectors.getBreakpointCount(getState())).toEqual(1); @@ -110,13 +110,13 @@ describe("breakpoints", () => { sourceUrl: "http://localhost:8000/examples/b" }; - const aCSR = makeSource("a"); - await dispatch(actions.newSource(aCSR)); - await dispatch(actions.loadSourceText(aCSR.source)); + const aSource = makeSource("a"); + await dispatch(actions.newSource(aSource)); + await dispatch(actions.loadSourceText(aSource)); - const bCSR = makeSource("b"); - await dispatch(actions.newSource(bCSR)); - await dispatch(actions.loadSourceText(bCSR.source)); + const bSource = makeSource("b"); + await dispatch(actions.newSource(bSource)); + await dispatch(actions.loadSourceText(bSource)); await dispatch(actions.addBreakpoint(loc1)); await dispatch(actions.addBreakpoint(loc2)); @@ -145,13 +145,13 @@ describe("breakpoints", () => { sourceUrl: "http://localhost:8000/examples/b" }; - const aCSR = makeSource("a"); - await dispatch(actions.newSource(aCSR)); - await dispatch(actions.loadSourceText(aCSR.source)); + const aSource = makeSource("a"); + await dispatch(actions.newSource(aSource)); + await dispatch(actions.loadSourceText(aSource)); - const bCSR = makeSource("b"); - await dispatch(actions.newSource(bCSR)); - await dispatch(actions.loadSourceText(bCSR.source)); + const bSource = makeSource("b"); + await dispatch(actions.newSource(bSource)); + await dispatch(actions.loadSourceText(bSource)); const breakpoint = await dispatch(actions.addBreakpoint(loc1)); await dispatch(actions.addBreakpoint(loc2)); @@ -170,9 +170,9 @@ describe("breakpoints", () => { sourceUrl: "http://localhost:8000/examples/a" }; - const aCSR = makeSource("a"); - await dispatch(actions.newSource(aCSR)); - await dispatch(actions.loadSourceText(aCSR.source)); + const aSource = makeSource("a"); + await dispatch(actions.newSource(aSource)); + await dispatch(actions.loadSourceText(aSource)); const breakpoint = await dispatch(actions.addBreakpoint(loc)); await dispatch(actions.disableBreakpoint(breakpoint)); @@ -201,13 +201,13 @@ describe("breakpoints", () => { sourceUrl: "http://localhost:8000/examples/b" }; - const aCSR = makeSource("a"); - await dispatch(actions.newSource(aCSR)); - await dispatch(actions.loadSourceText(aCSR.source)); + const aSource = makeSource("a"); + await dispatch(actions.newSource(aSource)); + await dispatch(actions.loadSourceText(aSource)); - const bCSR = makeSource("b"); - await dispatch(actions.newSource(bCSR)); - await dispatch(actions.loadSourceText(bCSR.source)); + const bSource = makeSource("b"); + await dispatch(actions.newSource(bSource)); + await dispatch(actions.loadSourceText(bSource)); await dispatch(actions.addBreakpoint(loc1)); await dispatch(actions.addBreakpoint(loc2)); @@ -233,9 +233,9 @@ describe("breakpoints", () => { const { dispatch, getState } = createStore(simpleMockThreadClient); - const csr = makeSource("foo1"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeSource("foo1"); + await dispatch(actions.newSource(source)); + await dispatch(actions.loadSourceText(source)); await dispatch(actions.selectLocation({ sourceId: "foo1", line: 1 })); @@ -253,9 +253,9 @@ describe("breakpoints", () => { const { dispatch, getState } = createStore(simpleMockThreadClient); - const csr = makeSource("foo1"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeSource("foo1"); + await dispatch(actions.newSource(source)); + await dispatch(actions.loadSourceText(source)); await dispatch(actions.selectLocation({ sourceId: "foo1", line: 1 })); @@ -280,9 +280,9 @@ describe("breakpoints", () => { sourceUrl: "http://localhost:8000/examples/a" }; - const csr = makeSource("a"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeSource("a"); + await dispatch(actions.newSource(source)); + await dispatch(actions.loadSourceText(source)); await dispatch(actions.addBreakpoint(loc)); @@ -338,9 +338,9 @@ describe("breakpoints", () => { sourceUrl: "http://localhost:8000/examples/a.js" }; - const csr = makeSource("a.js"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeSource("a.js"); + await dispatch(actions.newSource(source)); + await dispatch(actions.loadSourceText(source)); await dispatch(actions.addBreakpoint(loc)); await dispatch(actions.togglePrettyPrint("a.js")); diff --git a/devtools/client/debugger/new/src/actions/breakpoints/tests/syncing.spec.js b/devtools/client/debugger/new/src/actions/breakpoints/tests/syncing.spec.js index 66e509e9c61c3..b6fb9605f81a0 100644 --- a/devtools/client/debugger/new/src/actions/breakpoints/tests/syncing.spec.js +++ b/devtools/client/debugger/new/src/actions/breakpoints/tests/syncing.spec.js @@ -137,7 +137,7 @@ describe("loading the debugger", () => { threadClient, sourceMaps, dispatch, - reloadedSource.source.id, + reloadedSource.id, pendingBreakpoint() ); @@ -168,7 +168,7 @@ describe("loading the debugger", () => { threadClient, sourceMaps, dispatch, - reloadedSource.source.id, + reloadedSource.id, pendingBreakpoint() ); @@ -213,7 +213,7 @@ describe("reloading debuggee", () => { threadClient, sourceMaps, dispatch, - reloadedSource.source.id, + reloadedSource.id, pendingBreakpoint({ location: loc1 }) ); expect(threadClient.removeBreakpoint.mock.calls).toHaveLength(0); @@ -257,7 +257,7 @@ describe("reloading debuggee", () => { threadClient, sourceMaps, dispatch, - reloadedSource.source.id, + reloadedSource.id, pendingBreakpoint() ); expect(threadClient.removeBreakpoint.mock.calls).toHaveLength(1); @@ -279,7 +279,7 @@ describe("reloading debuggee", () => { await dispatch(actions.newSource(generatedSource)); const location = { - sourceId: reloadedSource.source.id, + sourceId: reloadedSource.id, line: 3, column: undefined }; @@ -293,7 +293,7 @@ describe("reloading debuggee", () => { await dispatch( actions.syncBreakpoint( - reloadedSource.source.id, + reloadedSource.id, pendingBreakpoint({ disabled: true }) ) ); diff --git a/devtools/client/debugger/new/src/actions/pause/paused.js b/devtools/client/debugger/new/src/actions/pause/paused.js index 6ce7c86e6c9eb..575175f167e7e 100644 --- a/devtools/client/debugger/new/src/actions/pause/paused.js +++ b/devtools/client/debugger/new/src/actions/pause/paused.js @@ -7,8 +7,6 @@ import { getHiddenBreakpoint, isEvaluatingExpression, getSelectedFrame, - getSources, - getLastCommand, wasStepping } from "../../selectors"; @@ -16,21 +14,13 @@ import { mapFrames } from "."; import { removeBreakpoint } from "../breakpoints"; import { evaluateExpressions } from "../expressions"; import { selectLocation } from "../sources"; -import { loadSourceText } from "../sources/loadSourceText"; import { togglePaneCollapse } from "../ui"; -import { command } from "./commands"; -import { shouldStep } from "../../utils/pause"; - -import { updateFrameLocation } from "./mapFrames"; import { fetchScopes } from "./fetchScopes"; -import type { Pause, Frame } from "../../types"; +import type { Pause } from "../../types"; import type { ThunkArgs } from "../types"; -async function getOriginalSourceForFrame(state, frame: Frame) { - return getSources(state)[frame.location.sourceId]; -} /** * Debugger has just paused * @@ -43,24 +33,6 @@ export function paused(pauseInfo: Pause) { const { thread, frames, why, loadedObjects } = pauseInfo; const topFrame = frames.length > 0 ? frames[0] : null; - // NOTE: do not step when leaving a frame or paused at a debugger statement - if (topFrame && !why.frameFinished && why.type == "resumeLimit") { - const mappedFrame = await updateFrameLocation(topFrame, sourceMaps); - const source = await getOriginalSourceForFrame(getState(), mappedFrame); - - // Ensure that the original file has loaded if there is one. - await dispatch(loadSourceText(source)); - - if (shouldStep(mappedFrame, getState(), sourceMaps)) { - // When stepping past a location we shouldn't pause at according to the - // source map, make sure we continue stepping in the same direction we - // were going previously. - const rewind = getLastCommand(getState(), thread) == "reverseStepOver"; - dispatch(command(rewind ? "reverseStepOver" : "stepOver")); - return; - } - } - dispatch({ type: "PAUSED", thread, diff --git a/devtools/client/debugger/new/src/actions/pause/tests/pause.spec.js b/devtools/client/debugger/new/src/actions/pause/tests/pause.spec.js index d28e8a77a3070..0a9595354cbeb 100644 --- a/devtools/client/debugger/new/src/actions/pause/tests/pause.spec.js +++ b/devtools/client/debugger/new/src/actions/pause/tests/pause.spec.js @@ -32,7 +32,6 @@ const mockThreadClient = { evaluateExpressions: async () => {}, getFrameScopes: async frame => frame.scope, - setPausePoints: async () => {}, setBreakpoint: () => new Promise(_resolve => {}), sourceContents: ({ source }) => { return new Promise((resolve, reject) => { @@ -159,9 +158,9 @@ describe("pause", () => { column: 0 }); - const csr = makeSource("await"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeSource("await"); + await dispatch(actions.newSource(source)); + await dispatch(actions.loadSourceText(source)); await dispatch(actions.paused(mockPauseInfo)); const getNextStepSpy = jest.spyOn(parser, "getNextStep"); @@ -179,9 +178,9 @@ describe("pause", () => { column: 6 }); - const csr = makeSource("await"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeSource("await"); + await dispatch(actions.newSource(source)); + await dispatch(actions.loadSourceText(source)); await dispatch(actions.paused(mockPauseInfo)); const getNextStepSpy = jest.spyOn(parser, "getNextStep"); @@ -205,10 +204,10 @@ describe("pause", () => { } }); - const csr = makeSource("foo"); - await dispatch(actions.newSource(csr)); + const source = makeSource("foo"); + await dispatch(actions.newSource(source)); await dispatch(actions.newSource(makeOriginalSource("foo"))); - await dispatch(actions.loadSourceText(csr.source)); + await dispatch(actions.loadSourceText(source)); await dispatch(actions.paused(mockPauseInfo)); expect(selectors.getFrames(getState())).toEqual([ @@ -267,12 +266,12 @@ describe("pause", () => { const { dispatch, getState } = store; const mockPauseInfo = createPauseInfo(generatedLocation); - const fooCSR = makeSource("foo"); - const fooOriginalCSR = makeSource("foo-original"); - await dispatch(actions.newSource(fooCSR)); - await dispatch(actions.newSource(fooOriginalCSR)); - await dispatch(actions.loadSourceText(fooCSR.source)); - await dispatch(actions.loadSourceText(fooOriginalCSR.source)); + const fooSource = makeSource("foo"); + const fooOriginalSource = makeSource("foo-original"); + await dispatch(actions.newSource(fooSource)); + await dispatch(actions.newSource(fooOriginalSource)); + await dispatch(actions.loadSourceText(fooSource)); + await dispatch(actions.loadSourceText(fooOriginalSource)); await dispatch(actions.setSymbols("foo-original")); await dispatch(actions.paused(mockPauseInfo)); @@ -328,13 +327,13 @@ describe("pause", () => { const { dispatch, getState } = store; const mockPauseInfo = createPauseInfo(generatedLocation); - const csr = makeSource("foo-wasm", { isWasm: true }); - const originalCSR = makeOriginalSource("foo-wasm"); + const source = makeSource("foo-wasm", { isWasm: true }); + const originalSource = makeOriginalSource("foo-wasm"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.newSource(originalCSR)); - await dispatch(actions.loadSourceText(csr.source)); - await dispatch(actions.loadSourceText(originalCSR.source)); + await dispatch(actions.newSource(source)); + await dispatch(actions.newSource(originalSource)); + await dispatch(actions.loadSourceText(source)); + await dispatch(actions.loadSourceText(originalSource)); await dispatch(actions.paused(mockPauseInfo)); expect(selectors.getFrames(getState())).toEqual([ diff --git a/devtools/client/debugger/new/src/actions/sources/blackbox.js b/devtools/client/debugger/new/src/actions/sources/blackbox.js index 5c50cc5faea63..556552e87a099 100644 --- a/devtools/client/debugger/new/src/actions/sources/blackbox.js +++ b/devtools/client/debugger/new/src/actions/sources/blackbox.js @@ -12,7 +12,7 @@ import { isOriginalId, originalToGeneratedId } from "devtools-source-map"; import { recordEvent } from "../../utils/telemetry"; import { features } from "../../utils/prefs"; -import { getSourceActors } from "../../selectors"; +import { getSourceFromId } from "../../selectors"; import { PROMISE } from "../utils/middleware/promise"; @@ -20,8 +20,8 @@ import type { Source } from "../../types"; import type { ThunkArgs } from "../types"; async function blackboxActors(state, client, sourceId, isBlackBoxed, range?) { - const sourceActors = getSourceActors(state, sourceId); - for (const sourceActor of sourceActors) { + const source = getSourceFromId(state, sourceId); + for (const sourceActor of source.actors) { await client.blackBox(sourceActor, isBlackBoxed, range); } return { isBlackBoxed: !isBlackBoxed }; diff --git a/devtools/client/debugger/new/src/actions/sources/loadSourceText.js b/devtools/client/debugger/new/src/actions/sources/loadSourceText.js index 858e1f3fb7b33..fc8648b463967 100644 --- a/devtools/client/debugger/new/src/actions/sources/loadSourceText.js +++ b/devtools/client/debugger/new/src/actions/sources/loadSourceText.js @@ -5,11 +5,7 @@ // @flow import { PROMISE } from "../utils/middleware/promise"; -import { - getGeneratedSource, - getSource, - getSourceActors -} from "../../selectors"; +import { getGeneratedSource, getSource } from "../../selectors"; import * as parser from "../../workers/parser"; import { isLoaded, isOriginal } from "../../utils/source"; import { Telemetry } from "devtools-modules"; @@ -26,21 +22,19 @@ const loadSourceHistogram = "DEVTOOLS_DEBUGGER_LOAD_SOURCE_MS"; const telemetry = new Telemetry(); async function loadSource(state, source: Source, { sourceMaps, client }) { - const { id } = source; if (isOriginal(source)) { return sourceMaps.getOriginalSourceText(source); } - const sourceActors = getSourceActors(state, id); - if (!sourceActors.length) { + if (!source.actors.length) { throw new Error("No source actor for loadSource"); } - const response = await client.sourceContents(sourceActors[0]); + const response = await client.sourceContents(source.actors[0]); telemetry.finish(loadSourceHistogram, source); return { - id, + id: source.id, text: response.source, contentType: response.contentType || "text/javascript" }; diff --git a/devtools/client/debugger/new/src/actions/sources/newSources.js b/devtools/client/debugger/new/src/actions/sources/newSources.js index fd10ea125e460..ad0d8ea24fd36 100644 --- a/devtools/client/debugger/new/src/actions/sources/newSources.js +++ b/devtools/client/debugger/new/src/actions/sources/newSources.js @@ -21,7 +21,6 @@ import { getRawSourceURL, isPrettyURL, isOriginal } from "../../utils/source"; import { getBlackBoxList, getSource, - hasSourceActor, getPendingSelectedLocation, getPendingBreakpointsForSource } from "../../selectors"; @@ -31,7 +30,6 @@ import sourceQueue from "../../utils/source-queue"; import type { Source, SourceId } from "../../types"; import type { Action, ThunkArgs } from "../types"; -import type { CreateSourceResult } from "../../client/firefox/types"; function createOriginalSource( originalUrl, @@ -46,7 +44,9 @@ function createOriginalSource( isWasm: false, isBlackBoxed: false, loadedState: "unloaded", - introductionUrl: null + introductionUrl: null, + isExtension: false, + actors: [] }; } @@ -62,7 +62,7 @@ function loadSourceMaps(sources: Source[]) { const sourceList = await Promise.all( sources.map(async ({ id }) => { const originalSources = await dispatch(loadSourceMap(id)); - sourceQueue.queueSources(originalSources.map(source => ({ source }))); + sourceQueue.queueSources(originalSources); return originalSources; }) ); @@ -203,36 +203,24 @@ function restoreBlackBoxedSources(sources: Source[]) { * @memberof actions/sources * @static */ -export function newSource(source: CreateSourceResult) { +export function newSource(source: Source) { return async ({ dispatch }: ThunkArgs) => { await dispatch(newSources([source])); }; } -export function newSources(createdSources: CreateSourceResult[]) { +export function newSources(foundSources: Source[]) { return async ({ dispatch, getState }: ThunkArgs) => { - // Find any sources we haven't seen before. - const sources = createdSources - .map(csr => csr.source) - .filter(source => !getSource(getState(), source.id)); - - // Find any source actors we haven't seen before. - const sourceActors = createdSources - .map(csr => csr.sourceActor) - .filter( - sourceActor => sourceActor && !hasSourceActor(getState(), sourceActor) - ); - - if (sources.length == 0 && sourceActors.length == 0) { - return; - } - - dispatch({ type: "ADD_SOURCES", sources, sourceActors }); + const sources = foundSources.filter( + source => !getSource(getState(), source.id) + ); if (sources.length == 0) { return; } + dispatch({ type: "ADD_SOURCES", sources }); + for (const source of sources) { dispatch(checkSelectedSource(source.id)); } diff --git a/devtools/client/debugger/new/src/actions/sources/prettyPrint.js b/devtools/client/debugger/new/src/actions/sources/prettyPrint.js index 0fc27c6400cdc..2b0cb93b85a38 100644 --- a/devtools/client/debugger/new/src/actions/sources/prettyPrint.js +++ b/devtools/client/debugger/new/src/actions/sources/prettyPrint.js @@ -8,7 +8,7 @@ import assert from "../../utils/assert"; import { recordEvent } from "../../utils/telemetry"; import { remapBreakpoints } from "../breakpoints"; -import { setPausePoints, setSymbols } from "../ast"; +import { setSymbols } from "../ast"; import { prettyPrint } from "../../workers/pretty-print"; import { setSource } from "../../workers/parser"; import { getPrettySourceURL, isLoaded } from "../../utils/source"; @@ -20,8 +20,7 @@ import { getSource, getSourceFromId, getSourceByURL, - getSelectedLocation, - getSourceActors + getSelectedLocation } from "../../selectors"; import type { Action, ThunkArgs } from "../types"; @@ -43,7 +42,9 @@ export function createPrettySource(sourceId: string) { isWasm: false, contentType: "text/javascript", loadedState: "loading", - introductionUrl: null + introductionUrl: null, + isExtension: false, + actors: [] }; dispatch(({ type: "ADD_SOURCE", source: prettySource }: Action)); @@ -54,8 +55,7 @@ export function createPrettySource(sourceId: string) { // The source map URL service used by other devtools listens to changes to // sources based on their actor IDs, so apply the mapping there too. - const sourceActors = getSourceActors(getState(), sourceId); - for (const sourceActor of sourceActors) { + for (const sourceActor of source.actors) { await sourceMaps.applySourceMap(sourceActor.actor, url, code, mappings); } @@ -125,7 +125,6 @@ export function togglePrettyPrint(sourceId: string) { await dispatch(remapBreakpoints(sourceId)); await dispatch(mapFrames()); - await dispatch(setPausePoints(newPrettySource.id)); await dispatch(setSymbols(newPrettySource.id)); dispatch( diff --git a/devtools/client/debugger/new/src/actions/sources/tests/__snapshots__/prettyPrint.spec.js.snap b/devtools/client/debugger/new/src/actions/sources/tests/__snapshots__/prettyPrint.spec.js.snap index 98ac7be5fcd80..e7e67586aad2a 100644 --- a/devtools/client/debugger/new/src/actions/sources/tests/__snapshots__/prettyPrint.spec.js.snap +++ b/devtools/client/debugger/new/src/actions/sources/tests/__snapshots__/prettyPrint.spec.js.snap @@ -2,6 +2,7 @@ exports[`sources - pretty print returns a pretty source for a minified file 1`] = ` Object { + "actors": Array [], "contentType": "text/javascript", "error": undefined, "id": "base.js/originalSource-36c718d4bde9a75edb388ff7733efe7f", diff --git a/devtools/client/debugger/new/src/actions/sources/tests/blackbox.spec.js b/devtools/client/debugger/new/src/actions/sources/tests/blackbox.spec.js index 69b615ca7856c..ca55829a4988d 100644 --- a/devtools/client/debugger/new/src/actions/sources/tests/blackbox.spec.js +++ b/devtools/client/debugger/new/src/actions/sources/tests/blackbox.spec.js @@ -16,9 +16,9 @@ describe("blackbox", () => { const store = createStore({ blackBox: async () => true }); const { dispatch, getState } = store; - const foo1CSR = makeSource("foo1"); - await dispatch(actions.newSource(foo1CSR)); - await dispatch(actions.toggleBlackBox(foo1CSR.source)); + const foo1Source = makeSource("foo1"); + await dispatch(actions.newSource(foo1Source)); + await dispatch(actions.toggleBlackBox(foo1Source)); const fooSource = selectors.getSource(getState(), "foo1"); @@ -26,13 +26,13 @@ describe("blackbox", () => { throw new Error("foo should exist"); } - const thread = (foo1CSR.sourceActor: any).thread; - const relativeSources = selectors.getRelativeSourcesForThread( + const thread = foo1Source.actors[0].thread; + const displayedSources = selectors.getDisplayedSourcesForThread( getState(), thread ); - expect(relativeSources[fooSource.id].isBlackBoxed).toEqual(true); + expect(displayedSources[fooSource.id].isBlackBoxed).toEqual(true); expect(fooSource.isBlackBoxed).toEqual(true); }); }); diff --git a/devtools/client/debugger/new/src/actions/sources/tests/loadSource.spec.js b/devtools/client/debugger/new/src/actions/sources/tests/loadSource.spec.js index 51c8879c44d70..ae05e5ed72412 100644 --- a/devtools/client/debugger/new/src/actions/sources/tests/loadSource.spec.js +++ b/devtools/client/debugger/new/src/actions/sources/tests/loadSource.spec.js @@ -17,9 +17,9 @@ describe("loadSourceText", () => { const store = createStore(sourceThreadClient); const { dispatch, getState } = store; - const foo1CSR = makeSource("foo1"); - await dispatch(actions.newSource(foo1CSR)); - await dispatch(actions.loadSourceText(foo1CSR.source)); + const foo1Source = makeSource("foo1"); + await dispatch(actions.newSource(foo1Source)); + await dispatch(actions.loadSourceText(foo1Source)); const fooSource = selectors.getSource(getState(), "foo1"); if (!fooSource || typeof fooSource.text != "string") { @@ -27,9 +27,9 @@ describe("loadSourceText", () => { } expect(fooSource.text.indexOf("return foo1")).not.toBe(-1); - const foo2CSR = makeSource("foo2"); - await dispatch(actions.newSource(foo2CSR)); - await dispatch(actions.loadSourceText(foo2CSR.source)); + const baseFoo2Source = makeSource("foo2"); + await dispatch(actions.newSource(baseFoo2Source)); + await dispatch(actions.loadSourceText(baseFoo2Source)); const foo2Source = selectors.getSource(getState(), "foo2"); if (!foo2Source || typeof foo2Source.text != "string") { @@ -49,9 +49,9 @@ describe("loadSourceText", () => { }) }); const id = "foo"; - const csr = makeSource(id, { loadedState: "unloaded" }); + const baseSource = makeSource(id, { loadedState: "unloaded" }); - await dispatch(actions.newSource(csr)); + await dispatch(actions.newSource(baseSource)); let source = selectors.getSource(getState(), id); dispatch(actions.loadSourceText(source)); @@ -81,9 +81,9 @@ describe("loadSourceText", () => { }) }); const id = "foo"; - const csr = makeSource(id, { loadedState: "unloaded" }); + const baseSource = makeSource(id, { loadedState: "unloaded" }); - await dispatch(actions.newSource(csr)); + await dispatch(actions.newSource(baseSource)); let source = selectors.getSource(getState(), id); const loading = dispatch(actions.loadSourceText(source)); @@ -104,8 +104,8 @@ describe("loadSourceText", () => { it("should cache subsequent source text loads", async () => { const { dispatch, getState } = createStore(sourceThreadClient); - const csr = makeSource("foo1"); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeSource("foo1"); + await dispatch(actions.loadSourceText(source)); const prevSource = selectors.getSource(getState(), "foo1"); await dispatch(actions.loadSourceText(prevSource)); @@ -118,8 +118,8 @@ describe("loadSourceText", () => { const { dispatch, getState } = createStore(sourceThreadClient); // Don't block on this so we can check the loading state. - const csr = makeSource("foo1"); - dispatch(actions.loadSourceText(csr.source)); + const source = makeSource("foo1"); + dispatch(actions.loadSourceText(source)); const fooSource = selectors.getSource(getState(), "foo1"); expect(fooSource && fooSource.loadedState).toEqual("loading"); }); @@ -127,9 +127,9 @@ describe("loadSourceText", () => { it("should indicate an errored source text", async () => { const { dispatch, getState } = createStore(sourceThreadClient); - const csr = makeSource("bad-id"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeSource("bad-id"); + await dispatch(actions.newSource(source)); + await dispatch(actions.loadSourceText(source)); const badSource = selectors.getSource(getState(), "bad-id"); if (!badSource || !badSource.error) { diff --git a/devtools/client/debugger/new/src/actions/sources/tests/newSources.spec.js b/devtools/client/debugger/new/src/actions/sources/tests/newSources.spec.js index 2a0fcec30091e..af60918d31326 100644 --- a/devtools/client/debugger/new/src/actions/sources/tests/newSources.spec.js +++ b/devtools/client/debugger/new/src/actions/sources/tests/newSources.spec.js @@ -46,14 +46,14 @@ describe("sources - new sources", () => { it("should automatically select a pending source", async () => { const { dispatch, getState } = createStore(threadClient); - const baseCSR = makeSource("base.js"); - await dispatch(actions.selectSourceURL(baseCSR.source.url)); + const baseSource = makeSource("base.js"); + await dispatch(actions.selectSourceURL(baseSource.url)); expect(getSelectedSource(getState())).toBe(undefined); - await dispatch(actions.newSource(baseCSR)); + await dispatch(actions.newSource(baseSource)); const selected = getSelectedSource(getState()); - expect(selected && selected.url).toBe(baseCSR.source.url); + expect(selected && selected.url).toBe(baseSource.url); }); it("should add original sources", async () => { @@ -65,8 +65,8 @@ describe("sources - new sources", () => { } ); - const baseCSR = makeSource("base.js", { sourceMapURL: "base.js.map" }); - await dispatch(actions.newSource(baseCSR)); + const baseSource = makeSource("base.js", { sourceMapURL: "base.js.map" }); + await dispatch(actions.newSource(baseSource)); const magic = getSourceByURL(getState(), "magic.js"); expect(magic && magic.url).toEqual("magic.js"); }); @@ -95,8 +95,8 @@ describe("sources - new sources", () => { getOriginalURLs: async () => new Promise(_ => {}) } ); - const baseCSR = makeSource("base.js", { sourceMapURL: "base.js.map" }); - await dispatch(actions.newSource(baseCSR)); + const baseSource = makeSource("base.js", { sourceMapURL: "base.js.map" }); + await dispatch(actions.newSource(baseSource)); expect(getSourceCount(getState())).toEqual(1); const base = getSource(getState(), "base.js"); expect(base && base.id).toEqual("base.js"); diff --git a/devtools/client/debugger/new/src/actions/sources/tests/prettyPrint.spec.js b/devtools/client/debugger/new/src/actions/sources/tests/prettyPrint.spec.js index 3c32461342948..3b159af3458b7 100644 --- a/devtools/client/debugger/new/src/actions/sources/tests/prettyPrint.spec.js +++ b/devtools/client/debugger/new/src/actions/sources/tests/prettyPrint.spec.js @@ -18,11 +18,11 @@ describe("sources - pretty print", () => { it("returns a pretty source for a minified file", async () => { const url = "base.js"; - const csr = makeSource(url); - await dispatch(actions.newSource(csr)); - await dispatch(createPrettySource(csr.source.id)); + const source = makeSource(url); + await dispatch(actions.newSource(source)); + await dispatch(createPrettySource(source.id)); - const prettyURL = `${csr.source.url}:formatted`; + const prettyURL = `${source.url}:formatted`; const pretty = selectors.getSourceByURL(getState(), prettyURL); expect(pretty && pretty.contentType).toEqual("text/javascript"); expect(pretty && pretty.url.includes(prettyURL)).toEqual(true); @@ -30,16 +30,16 @@ describe("sources - pretty print", () => { }); it("should create a source when first toggling pretty print", async () => { - const csr = makeSource("foobar.js", { loadedState: "loaded" }); - await dispatch(actions.togglePrettyPrint(csr.source.id)); + const source = makeSource("foobar.js", { loadedState: "loaded" }); + await dispatch(actions.togglePrettyPrint(source.id)); expect(selectors.getSourceCount(getState())).toEqual(2); }); it("should not make a second source when toggling pretty print", async () => { - const csr = makeSource("foobar.js", { loadedState: "loaded" }); - await dispatch(actions.togglePrettyPrint(csr.source.id)); + const source = makeSource("foobar.js", { loadedState: "loaded" }); + await dispatch(actions.togglePrettyPrint(source.id)); expect(selectors.getSourceCount(getState())).toEqual(2); - await dispatch(actions.togglePrettyPrint(csr.source.id)); + await dispatch(actions.togglePrettyPrint(source.id)); expect(selectors.getSourceCount(getState())).toEqual(2); }); }); diff --git a/devtools/client/debugger/new/src/actions/sources/tests/select.spec.js b/devtools/client/debugger/new/src/actions/sources/tests/select.spec.js index 7c02eecb73bb2..54b062900b824 100644 --- a/devtools/client/debugger/new/src/actions/sources/tests/select.spec.js +++ b/devtools/client/debugger/new/src/actions/sources/tests/select.spec.js @@ -79,9 +79,9 @@ describe("sources", () => { it("should select next tab on tab closed if no previous tab", async () => { const { dispatch, getState } = createStore(sourceThreadClient); - const fooCSR = makeSource("foo.js"); + const fooSource = makeSource("foo.js"); - await dispatch(actions.newSource(fooCSR)); + await dispatch(actions.newSource(fooSource)); await dispatch(actions.newSource(makeSource("bar.js"))); await dispatch(actions.newSource(makeSource("baz.js"))); @@ -98,7 +98,7 @@ describe("sources", () => { await dispatch(actions.selectLocation(initialLocation("foo.js"))); // closes the 1st tab, which should have no previous tab - await dispatch(actions.closeTab(fooCSR.source)); + await dispatch(actions.closeTab(fooSource)); const selected = getSelectedSource(getState()); expect(selected && selected.id).toBe("bar.js"); @@ -126,7 +126,7 @@ describe("sources", () => { await dispatch(actions.selectLocation(initialLocation("foo.js"))); await dispatch(actions.selectLocation(initialLocation("bar.js"))); await dispatch(actions.selectLocation(initialLocation("baz.js"))); - await dispatch(actions.closeTab(bazSource.source)); + await dispatch(actions.closeTab(bazSource)); const selected = getSelectedSource(getState()); expect(selected && selected.id).toBe("bar.js"); @@ -153,7 +153,7 @@ describe("sources", () => { // 3rd tab is reselected await dispatch(actions.selectLocation(initialLocation("foo.js"))); - await dispatch(actions.closeTab(bazSource.source)); + await dispatch(actions.closeTab(bazSource)); const selected = getSelectedSource(getState()); expect(selected && selected.id).toBe("foo.js"); @@ -163,9 +163,9 @@ describe("sources", () => { it("should not select new sources that lack a URL", async () => { const { dispatch, getState } = createStore(sourceThreadClient); - const csr = makeSource("foo"); - csr.source.url = ""; - await dispatch(actions.newSource(csr)); + const source = makeSource("foo"); + source.url = ""; + await dispatch(actions.newSource(source)); expect(getSourceCount(getState())).toEqual(1); const selectedLocation = getSelectedLocation(getState()); @@ -174,7 +174,7 @@ describe("sources", () => { it("sets and clears selected location correctly", () => { const { dispatch, getState } = createStore(sourceThreadClient); - const source = makeSource("testSource").source; + const source = makeSource("testSource"); const location = ({ test: "testLocation" }: any); // set value @@ -211,16 +211,16 @@ describe("sources", () => { it("should keep the generated the viewing context", async () => { const store = createStore(sourceThreadClient); const { dispatch, getState } = store; - const baseCSR = makeSource("base.js"); - await dispatch(actions.newSource(baseCSR)); + const baseSource = makeSource("base.js"); + await dispatch(actions.newSource(baseSource)); await dispatch( - actions.selectLocation({ sourceId: baseCSR.source.id, line: 1 }) + actions.selectLocation({ sourceId: baseSource.id, line: 1 }) ); const selected = getSelectedSource(getState()); - expect(selected && selected.id).toBe(baseCSR.source.id); - await waitForState(store, state => getSymbols(state, baseCSR.source)); + expect(selected && selected.id).toBe(baseSource.id); + await waitForState(store, state => getSymbols(state, baseSource)); }); it("should keep the original the viewing context", async () => { @@ -234,19 +234,17 @@ describe("sources", () => { } ); - const baseCSR = makeSource("base.js"); - await dispatch(actions.newSource(baseCSR)); + const baseSource = makeSource("base.js"); + await dispatch(actions.newSource(baseSource)); const originalBaseSource = makeOriginalSource("base.js"); await dispatch(actions.newSource(originalBaseSource)); - await dispatch(actions.selectSource(originalBaseSource.source.id)); + await dispatch(actions.selectSource(originalBaseSource.id)); - const fooCSR = makeSource("foo.js"); - await dispatch(actions.newSource(fooCSR)); - await dispatch( - actions.selectLocation({ sourceId: fooCSR.source.id, line: 1 }) - ); + const fooSource = makeSource("foo.js"); + await dispatch(actions.newSource(fooSource)); + await dispatch(actions.selectLocation({ sourceId: fooSource.id, line: 1 })); const selected = getSelectedLocation(getState()); expect(selected && selected.line).toBe(12); @@ -259,13 +257,13 @@ describe("sources", () => { { getOriginalLocation: async location => ({ ...location, line: 12 }) } ); - const baseCSR = makeOriginalSource("base.js"); - await dispatch(actions.newSource(baseCSR)); - await dispatch(actions.selectSource(baseCSR.source.id)); + const baseSource = makeOriginalSource("base.js"); + await dispatch(actions.newSource(baseSource)); + await dispatch(actions.selectSource(baseSource.id)); await dispatch( actions.selectSpecificLocation({ - sourceId: baseCSR.source.id, + sourceId: baseSource.id, line: 1 }) ); @@ -277,14 +275,14 @@ describe("sources", () => { describe("selectSourceURL", () => { it("should automatically select a pending source", async () => { const { dispatch, getState } = createStore(sourceThreadClient); - const baseCSR = makeSource("base.js"); - await dispatch(actions.selectSourceURL(baseCSR.source.url)); + const baseSource = makeSource("base.js"); + await dispatch(actions.selectSourceURL(baseSource.url)); expect(getSelectedSource(getState())).toBe(undefined); - await dispatch(actions.newSource(baseCSR)); + await dispatch(actions.newSource(baseSource)); const selected = getSelectedSource(getState()); - expect(selected && selected.url).toBe(baseCSR.source.url); + expect(selected && selected.url).toBe(baseSource.url); }); }); }); diff --git a/devtools/client/debugger/new/src/actions/tabs.js b/devtools/client/debugger/new/src/actions/tabs.js index 625395e482614..85f96ef9864e1 100644 --- a/devtools/client/debugger/new/src/actions/tabs.js +++ b/devtools/client/debugger/new/src/actions/tabs.js @@ -15,8 +15,8 @@ import { removeDocument } from "../utils/editor"; import { selectSource } from "./sources"; import { - getSourcesByURLs, getSourceTabs, + getSourceByURL, getNewSelectedSourceId, removeSourceFromTabList, removeSourcesFromTabList @@ -81,7 +81,9 @@ export function closeTab(source: Source) { */ export function closeTabs(urls: string[]) { return ({ dispatch, getState, client }: ThunkArgs) => { - const sources = getSourcesByURLs(getState(), urls); + const sources = urls + .map(url => getSourceByURL(getState(), url)) + .filter(Boolean); sources.map(source => removeDocument(source.id)); const tabs = removeSourcesFromTabList(getSourceTabs(getState()), sources); diff --git a/devtools/client/debugger/new/src/actions/tests/__snapshots__/ast.spec.js.snap b/devtools/client/debugger/new/src/actions/tests/__snapshots__/ast.spec.js.snap index 14fb94e55e0f5..3fb006a5a63d9 100644 --- a/devtools/client/debugger/new/src/actions/tests/__snapshots__/ast.spec.js.snap +++ b/devtools/client/debugger/new/src/actions/tests/__snapshots__/ast.spec.js.snap @@ -40,18 +40,6 @@ Array [ ] `; -exports[`ast setPausePoints scopes 1`] = ` -Array [ - 1, - 2, - 6, - 7, - 10, - 11, - 12, -] -`; - exports[`ast setSymbols when the source is loaded should be able to set symbols 1`] = ` Object { "callExpressions": Array [], diff --git a/devtools/client/debugger/new/src/actions/tests/ast.spec.js b/devtools/client/debugger/new/src/actions/tests/ast.spec.js index d3394086561a2..aeebd200bb3b6 100644 --- a/devtools/client/debugger/new/src/actions/tests/ast.spec.js +++ b/devtools/client/debugger/new/src/actions/tests/ast.spec.js @@ -19,7 +19,6 @@ import readFixture from "./helpers/readFixture"; const { getSource, getSymbols, - getEmptyLines, getOutOfScopeLocations, getSourceMetaData, getInScopeLines, @@ -33,7 +32,6 @@ const threadClient = { source: sourceTexts[source], contentType: "text/javascript" }), - setPausePoints: async () => {}, getFrameScopes: async () => {}, evaluate: async expression => ({ result: evaluationResult[expression] }), evaluateExpressions: async expressions => @@ -62,45 +60,25 @@ const evaluationResult = { }; describe("ast", () => { - describe("setPausePoints", () => { - it("scopes", async () => { - const store = createStore(threadClient); - const { dispatch, getState } = store; - const csr = makeSource("scopes.js"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); - await dispatch(actions.setPausePoints("scopes.js")); - await waitForState(store, state => { - const lines = getEmptyLines(state, csr.source.id); - return lines && lines.length > 0; - }); - - const emptyLines = getEmptyLines(getState(), csr.source.id); - expect(emptyLines).toMatchSnapshot(); - }); - }); - describe("setSourceMetaData", () => { it("should detect react components", async () => { const store = createStore(threadClient, {}, sourceMaps); const { dispatch, getState } = store; - const csr = makeOriginalSource("reactComponent.js"); + const source = makeOriginalSource("reactComponent.js"); await dispatch(actions.newSource(makeSource("reactComponent.js"))); - await dispatch(actions.newSource(csr)); + await dispatch(actions.newSource(source)); - await dispatch( - actions.loadSourceText(getSource(getState(), csr.source.id)) - ); - await dispatch(actions.setSourceMetaData(csr.source.id)); + await dispatch(actions.loadSourceText(getSource(getState(), source.id))); + await dispatch(actions.setSourceMetaData(source.id)); await waitForState(store, state => { - const metaData = getSourceMetaData(state, csr.source.id); + const metaData = getSourceMetaData(state, source.id); return metaData && metaData.framework; }); - const sourceMetaData = getSourceMetaData(getState(), csr.source.id); + const sourceMetaData = getSourceMetaData(getState(), source.id); expect(sourceMetaData.framework).toBe("React"); }); @@ -109,10 +87,10 @@ describe("ast", () => { const { dispatch, getState } = store; const base = makeSource("base.js"); await dispatch(actions.newSource(base)); - await dispatch(actions.loadSourceText(base.source)); + await dispatch(actions.loadSourceText(base)); await dispatch(actions.setSourceMetaData("base.js")); - const sourceMetaData = getSourceMetaData(getState(), base.source.id); + const sourceMetaData = getSourceMetaData(getState(), base.id); expect(sourceMetaData.framework).toBe(undefined); }); }); @@ -124,14 +102,11 @@ describe("ast", () => { const { dispatch, getState } = store; const base = makeSource("base.js"); await dispatch(actions.newSource(base)); - await dispatch(actions.loadSourceText(base.source)); + await dispatch(actions.loadSourceText(base)); await dispatch(actions.setSymbols("base.js")); - await waitForState( - store, - state => !isSymbolsLoading(state, base.source) - ); + await waitForState(store, state => !isSymbolsLoading(state, base)); - const baseSymbols = getSymbols(getState(), base.source); + const baseSymbols = getSymbols(getState(), base); expect(baseSymbols).toMatchSnapshot(); }); }); @@ -142,7 +117,7 @@ describe("ast", () => { const base = makeSource("base.js"); await dispatch(actions.newSource(base)); - const baseSymbols = getSymbols(getState(), base.source); + const baseSymbols = getSymbols(getState(), base); expect(baseSymbols).toEqual(null); }); }); @@ -164,8 +139,8 @@ describe("ast", () => { it("with selected line", async () => { const store = createStore(threadClient); const { dispatch, getState } = store; - const csr = makeSource("scopes.js"); - await dispatch(actions.newSource(csr)); + const source = makeSource("scopes.js"); + await dispatch(actions.newSource(source)); await dispatch( actions.selectLocation({ sourceId: "scopes.js", line: 5 }) diff --git a/devtools/client/debugger/new/src/actions/tests/expressions.spec.js b/devtools/client/debugger/new/src/actions/tests/expressions.spec.js index cf677759673a3..da45a905332a6 100644 --- a/devtools/client/debugger/new/src/actions/tests/expressions.spec.js +++ b/devtools/client/debugger/new/src/actions/tests/expressions.spec.js @@ -126,6 +126,8 @@ describe("expressions", () => { const { dispatch, getState } = createStore(mockThreadClient); await createFrames(dispatch); + await dispatch(actions.newSource(makeSource("source"))); + await dispatch(actions.addExpression("foo")); await dispatch(actions.addExpression("bar")); diff --git a/devtools/client/debugger/new/src/actions/tests/helpers/threadClient.js b/devtools/client/debugger/new/src/actions/tests/helpers/threadClient.js index 547246a98a231..26bc3ae9a86cb 100644 --- a/devtools/client/debugger/new/src/actions/tests/helpers/threadClient.js +++ b/devtools/client/debugger/new/src/actions/tests/helpers/threadClient.js @@ -49,7 +49,6 @@ export const simpleMockThreadClient = { _options: BreakpointOptions, _noSliding: boolean ) => Promise.resolve({ sourceId: "a", line: 5 }), - setPausePoints: () => Promise.resolve({}), sourceContents: ({ source }: SourceActor): Promise<{| source: any, contentType: ?string |}> => @@ -77,6 +76,5 @@ export const sourceThreadClient = { }, threadClient: async () => {}, getFrameScopes: async () => {}, - setPausePoints: async () => {}, evaluateExpressions: async () => {} }; diff --git a/devtools/client/debugger/new/src/actions/tests/pending-breakpoints.spec.js b/devtools/client/debugger/new/src/actions/tests/pending-breakpoints.spec.js index f17a973dc5742..a71503788386f 100644 --- a/devtools/client/debugger/new/src/actions/tests/pending-breakpoints.spec.js +++ b/devtools/client/debugger/new/src/actions/tests/pending-breakpoints.spec.js @@ -55,9 +55,10 @@ describe("when adding breakpoints", () => { loadInitialState() ); - const csr = makeOriginalSource("foo.js"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeOriginalSource("foo.js"); + await dispatch(actions.newSource(source)); + await dispatch(actions.newSource(makeSource("foo.js"))); + await dispatch(actions.loadSourceText(source)); const bp = generateBreakpoint("foo.js"); const id = makePendingLocationId(bp.location); @@ -88,14 +89,17 @@ describe("when adding breakpoints", () => { loadInitialState() ); - const csr1 = makeOriginalSource("foo"); - const csr2 = makeOriginalSource("foo2"); + const source1 = makeOriginalSource("foo"); + const source2 = makeOriginalSource("foo2"); - await dispatch(actions.newSource(csr1)); - await dispatch(actions.newSource(csr2)); + await dispatch(actions.newSource(makeSource("foo"))); + await dispatch(actions.newSource(makeSource("foo2"))); + + await dispatch(actions.newSource(source1)); + await dispatch(actions.newSource(source2)); - await dispatch(actions.loadSourceText(csr1.source)); - await dispatch(actions.loadSourceText(csr2.source)); + await dispatch(actions.loadSourceText(source1)); + await dispatch(actions.loadSourceText(source2)); await dispatch(actions.addBreakpoint(breakpoint1.location)); await dispatch(actions.addBreakpoint(breakpoint2.location)); @@ -111,9 +115,10 @@ describe("when adding breakpoints", () => { loadInitialState() ); - const csr = makeOriginalSource("foo"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeOriginalSource("foo"); + await dispatch(actions.newSource(makeSource("foo"))); + await dispatch(actions.newSource(source)); + await dispatch(actions.loadSourceText(source)); await dispatch( actions.addBreakpoint(breakpoint1.location, { hidden: true }) @@ -130,15 +135,16 @@ describe("when adding breakpoints", () => { ); await dispatch(actions.newSource(makeSource("foo"))); + await dispatch(actions.newSource(makeSource("foo2"))); - const csr1 = makeOriginalSource("foo"); - const csr2 = makeOriginalSource("foo2"); + const source1 = makeOriginalSource("foo"); + const source2 = makeOriginalSource("foo2"); - await dispatch(actions.newSource(csr1)); - await dispatch(actions.newSource(csr2)); + await dispatch(actions.newSource(source1)); + await dispatch(actions.newSource(source2)); - await dispatch(actions.loadSourceText(csr1.source)); - await dispatch(actions.loadSourceText(csr2.source)); + await dispatch(actions.loadSourceText(source1)); + await dispatch(actions.loadSourceText(source2)); await dispatch(actions.addBreakpoint(breakpoint1.location)); await dispatch(actions.addBreakpoint(breakpoint2.location)); @@ -160,9 +166,10 @@ describe("when changing an existing breakpoint", () => { const bp = generateBreakpoint("foo"); const id = makePendingLocationId(bp.location); - const csr = makeOriginalSource("foo"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeOriginalSource("foo"); + await dispatch(actions.newSource(source)); + await dispatch(actions.newSource(makeSource("foo"))); + await dispatch(actions.loadSourceText(source)); await dispatch(actions.addBreakpoint(bp.location)); await dispatch( @@ -183,9 +190,9 @@ describe("when changing an existing breakpoint", () => { await dispatch(actions.newSource(makeSource("foo"))); - const csr = makeOriginalSource("foo"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeOriginalSource("foo"); + await dispatch(actions.newSource(source)); + await dispatch(actions.loadSourceText(source)); await dispatch(actions.addBreakpoint(bp.location)); await dispatch(actions.disableBreakpoint(bp)); @@ -201,9 +208,10 @@ describe("when changing an existing breakpoint", () => { ); const bp = generateBreakpoint("foo.js"); - const csr = makeOriginalSource("foo.js"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeOriginalSource("foo.js"); + await dispatch(actions.newSource(source)); + await dispatch(actions.newSource(makeSource("foo.js"))); + await dispatch(actions.loadSourceText(source)); const id = makePendingLocationId(bp.location); @@ -236,9 +244,9 @@ describe("initializing when pending breakpoints exist in prefs", () => { await dispatch(actions.newSource(makeSource("bar.js"))); - const csr = makeOriginalSource("bar.js"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeOriginalSource("bar.js"); + await dispatch(actions.newSource(source)); + await dispatch(actions.loadSourceText(source)); await dispatch(actions.addBreakpoint(bar.location)); @@ -253,9 +261,10 @@ describe("initializing when pending breakpoints exist in prefs", () => { ); const bp = generateBreakpoint("foo.js"); - const csr = makeOriginalSource("foo.js"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeOriginalSource("foo.js"); + await dispatch(actions.newSource(source)); + await dispatch(actions.newSource(makeSource("foo.js"))); + await dispatch(actions.loadSourceText(source)); await dispatch(actions.addBreakpoint(bp.location)); @@ -272,27 +281,27 @@ describe("initializing with disabled pending breakpoints in prefs", () => { ); const { getState, dispatch } = store; - const csr = makeOriginalSource("bar.js"); + const source = makeOriginalSource("bar.js"); await dispatch(actions.newSource(makeSource("bar.js"))); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + await dispatch(actions.newSource(source)); + await dispatch(actions.loadSourceText(source)); await waitForState(store, state => { - const bps = selectors.getBreakpointsForSource(state, csr.source.id); + const bps = selectors.getBreakpointsForSource(state, source.id); return bps && Object.values(bps).length > 0; }); const bp = selectors.getBreakpointForLocation(getState(), { line: 5, column: undefined, - sourceUrl: csr.source.url, - sourceId: csr.source.id + sourceUrl: source.url, + sourceId: source.id }); if (!bp) { throw new Error("no bp"); } - expect(bp.location.sourceId).toEqual(csr.source.id); + expect(bp.location.sourceId).toEqual(source.id); expect(bp.disabled).toEqual(true); }); }); @@ -304,11 +313,11 @@ describe("adding sources", () => { expect(selectors.getBreakpointCount(getState())).toEqual(0); - const csr = makeOriginalSource("bar.js"); + const source = makeOriginalSource("bar.js"); await dispatch(actions.newSource(makeSource("bar.js"))); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + await dispatch(actions.newSource(source)); + await dispatch(actions.loadSourceText(source)); await waitForState(store, state => selectors.getBreakpointCount(state) > 0); @@ -316,9 +325,9 @@ describe("adding sources", () => { }); it("corresponding breakpoints are added to the original source", async () => { - const csr = makeOriginalSource("bar.js", { sourceMapURL: "foo" }); + const source = makeOriginalSource("bar.js", { sourceMapURL: "foo" }); const store = createStore(simpleMockThreadClient, loadInitialState(), { - getOriginalURLs: async () => [csr.source.url], + getOriginalURLs: async () => [source.url], getOriginalSourceText: async () => ({ source: "" }), getGeneratedLocation: async (location, _source) => ({ line: location.line, @@ -333,7 +342,7 @@ describe("adding sources", () => { expect(selectors.getBreakpointCount(getState())).toEqual(0); await dispatch(actions.newSource(makeSource("bar.js"))); - await dispatch(actions.newSource(csr)); + await dispatch(actions.newSource(source)); await waitForState(store, state => selectors.getBreakpointCount(state) > 0); @@ -346,12 +355,13 @@ describe("adding sources", () => { expect(selectors.getBreakpointCount(getState())).toEqual(0); - const csr1 = makeOriginalSource("bar.js"); - const csr2 = makeOriginalSource("foo.js"); + const source1 = makeOriginalSource("bar.js"); + const source2 = makeOriginalSource("foo.js"); await dispatch(actions.newSource(makeSource("bar.js"))); - await dispatch(actions.newSources([csr1, csr2])); - await dispatch(actions.loadSourceText(csr1.source)); - await dispatch(actions.loadSourceText(csr2.source)); + await dispatch(actions.newSource(makeSource("foo.js"))); + await dispatch(actions.newSources([source1, source2])); + await dispatch(actions.loadSourceText(source1)); + await dispatch(actions.loadSourceText(source2)); await waitForState(store, state => selectors.getBreakpointCount(state) > 0); diff --git a/devtools/client/debugger/new/src/actions/tests/project-text-search.spec.js b/devtools/client/debugger/new/src/actions/tests/project-text-search.spec.js index 2076d14b14bac..4674a2ef3d3e1 100644 --- a/devtools/client/debugger/new/src/actions/tests/project-text-search.spec.js +++ b/devtools/client/debugger/new/src/actions/tests/project-text-search.spec.js @@ -66,11 +66,11 @@ describe("project text search", () => { it("should search all the loaded sources based on the query", async () => { const { dispatch, getState } = createStore(threadClient); const mockQuery = "foo"; - const csr1 = makeSource("foo1"); - const csr2 = makeSource("foo2"); + const source1 = makeSource("foo1"); + const source2 = makeSource("foo2"); - await dispatch(actions.newSource(csr1)); - await dispatch(actions.newSource(csr2)); + await dispatch(actions.newSource(source1)); + await dispatch(actions.newSource(source2)); await dispatch(actions.searchSources(mockQuery)); @@ -79,22 +79,22 @@ describe("project text search", () => { }); it("should ignore sources with minified versions", async () => { - const csr1 = makeSource("bar", { sourceMapURL: "bar:formatted" }); - const csr2 = makeSource("bar:formatted"); + const source1 = makeSource("bar", { sourceMapURL: "bar:formatted" }); + const source2 = makeSource("bar:formatted"); const mockMaps = { getOriginalSourceText: async () => ({ source: "function bla(x, y) {\n const bar = 4; return 2;\n}", contentType: "text/javascript" }), - getOriginalURLs: async () => [csr2.source.url] + getOriginalURLs: async () => [source2.url] }; const { dispatch, getState } = createStore(threadClient, {}, mockMaps); const mockQuery = "bla"; - await dispatch(actions.newSource(csr1)); - await dispatch(actions.newSource(csr2)); + await dispatch(actions.newSource(source1)); + await dispatch(actions.newSource(source2)); await dispatch(actions.searchSources(mockQuery)); @@ -105,9 +105,9 @@ describe("project text search", () => { it("should search a specific source", async () => { const { dispatch, getState } = createStore(threadClient); - const csr = makeSource("bar"); - await dispatch(actions.newSource(csr)); - await dispatch(actions.loadSourceText(csr.source)); + const source = makeSource("bar"); + await dispatch(actions.newSource(source)); + await dispatch(actions.loadSourceText(source)); dispatch(actions.addSearchQuery("bla")); diff --git a/devtools/client/debugger/new/src/actions/tests/setProjectDirectoryRoot.spec.js b/devtools/client/debugger/new/src/actions/tests/setProjectDirectoryRoot.spec.js index c2e0d7da44ee7..0c745c12f1128 100644 --- a/devtools/client/debugger/new/src/actions/tests/setProjectDirectoryRoot.spec.js +++ b/devtools/client/debugger/new/src/actions/tests/setProjectDirectoryRoot.spec.js @@ -13,7 +13,7 @@ import { import type { Source } from "../../types"; -const { getProjectDirectoryRoot, getRelativeSources } = selectors; +const { getProjectDirectoryRoot, getDisplayedSources } = selectors; describe("setProjectDirectoryRoot", () => { it("should set domain directory as root", async () => { @@ -51,7 +51,7 @@ describe("setProjectDirectoryRoot", () => { dispatch(actions.setProjectDirectoryRoot("localhost:8000/examples/js")); - const filteredSourcesByThread = getRelativeSources(getState()); + const filteredSourcesByThread = getDisplayedSources(getState()); const filteredSources = Object.values(filteredSourcesByThread)[0]; const firstSource: Source = (Object.values(filteredSources)[0]: any); diff --git a/devtools/client/debugger/new/src/actions/tests/tabs.spec.js b/devtools/client/debugger/new/src/actions/tests/tabs.spec.js index caef9ff609498..344ec779855d5 100644 --- a/devtools/client/debugger/new/src/actions/tests/tabs.spec.js +++ b/devtools/client/debugger/new/src/actions/tests/tabs.spec.js @@ -18,10 +18,10 @@ describe("closing tabs", () => { it("closing a tab", async () => { const { dispatch, getState } = createStore(threadClient); - const fooCSR = makeSource("foo.js"); - await dispatch(actions.newSource(fooCSR)); + const fooSource = makeSource("foo.js"); + await dispatch(actions.newSource(fooSource)); await dispatch(actions.selectLocation({ sourceId: "foo.js", line: 1 })); - dispatch(actions.closeTab(fooCSR.source)); + dispatch(actions.closeTab(fooSource)); expect(getSelectedSource(getState())).toBe(undefined); expect(getSourceTabs(getState())).toHaveLength(0); @@ -30,12 +30,12 @@ describe("closing tabs", () => { it("closing the inactive tab", async () => { const { dispatch, getState } = createStore(threadClient); - const fooCSR = makeSource("foo.js"); - await dispatch(actions.newSource(fooCSR)); + const fooSource = makeSource("foo.js"); + await dispatch(actions.newSource(fooSource)); await dispatch(actions.newSource(makeSource("bar.js"))); await dispatch(actions.selectLocation({ sourceId: "foo.js", line: 1 })); await dispatch(actions.selectLocation({ sourceId: "bar.js", line: 1 })); - dispatch(actions.closeTab(fooCSR.source)); + dispatch(actions.closeTab(fooSource)); const selected = getSelectedSource(getState()); expect(selected && selected.id).toBe("bar.js"); @@ -45,10 +45,10 @@ describe("closing tabs", () => { it("closing the only tab", async () => { const { dispatch, getState } = createStore(threadClient); - const fooCSR = makeSource("foo.js"); - await dispatch(actions.newSource(fooCSR)); + const fooSource = makeSource("foo.js"); + await dispatch(actions.newSource(fooSource)); await dispatch(actions.selectLocation({ sourceId: "foo.js", line: 1 })); - dispatch(actions.closeTab(fooCSR.source)); + dispatch(actions.closeTab(fooSource)); expect(getSelectedSource(getState())).toBe(undefined); expect(getSourceTabs(getState())).toHaveLength(0); @@ -57,12 +57,12 @@ describe("closing tabs", () => { it("closing the active tab", async () => { const { dispatch, getState } = createStore(threadClient); - const barCSR = makeSource("bar.js"); + const barSource = makeSource("bar.js"); await dispatch(actions.newSource(makeSource("foo.js"))); - await dispatch(actions.newSource(barCSR)); + await dispatch(actions.newSource(barSource)); await dispatch(actions.selectLocation({ sourceId: "foo.js", line: 1 })); await dispatch(actions.selectLocation({ sourceId: "bar.js", line: 1 })); - await dispatch(actions.closeTab(barCSR.source)); + await dispatch(actions.closeTab(barSource)); const selected = getSelectedSource(getState()); expect(selected && selected.id).toBe("foo.js"); @@ -72,10 +72,10 @@ describe("closing tabs", () => { it("closing many inactive tabs", async () => { const { dispatch, getState } = createStore(threadClient); - const fooCSR = makeSource("foo.js"); - const barCSR = makeSource("bar.js"); - await dispatch(actions.newSource(fooCSR)); - await dispatch(actions.newSource(barCSR)); + const fooSource = makeSource("foo.js"); + const barSource = makeSource("bar.js"); + await dispatch(actions.newSource(fooSource)); + await dispatch(actions.newSource(barSource)); await dispatch(actions.newSource(makeSource("bazz.js"))); await dispatch(actions.selectLocation({ sourceId: "foo.js", line: 1 })); await dispatch(actions.selectLocation({ sourceId: "bar.js", line: 1 })); diff --git a/devtools/client/debugger/new/src/actions/tests/ui.spec.js b/devtools/client/debugger/new/src/actions/tests/ui.spec.js index a88db9ee73b27..825011138163a 100644 --- a/devtools/client/debugger/new/src/actions/tests/ui.spec.js +++ b/devtools/client/debugger/new/src/actions/tests/ui.spec.js @@ -17,7 +17,7 @@ const { getPaneCollapse, getHighlightedLineRange, getProjectDirectoryRoot, - getRelativeSources + getDisplayedSources } = selectors; import type { Source } from "../../types"; @@ -119,7 +119,7 @@ describe("setProjectDirectoryRoot", () => { dispatch(actions.setProjectDirectoryRoot("localhost:8000/examples/js")); - const filteredSourcesByThread = getRelativeSources(getState()); + const filteredSourcesByThread = getDisplayedSources(getState()); const filteredSources = Object.values(filteredSourcesByThread)[0]; const firstSource: Source = (Object.values(filteredSources)[0]: any); diff --git a/devtools/client/debugger/new/src/actions/types/ASTAction.js b/devtools/client/debugger/new/src/actions/types/ASTAction.js index 555606d36186f..0eb70d60ffdc4 100644 --- a/devtools/client/debugger/new/src/actions/types/ASTAction.js +++ b/devtools/client/debugger/new/src/actions/types/ASTAction.js @@ -5,7 +5,7 @@ // @flow import type { SymbolDeclarations, AstLocation } from "../../workers/parser"; -import type { PausePoints, SourceMetaDataType } from "../../reducers/types"; +import type { SourceMetaDataType } from "../../reducers/types"; import type { PromiseAction } from "../utils/middleware/promise"; export type ASTAction = @@ -16,12 +16,6 @@ export type ASTAction = |}, SymbolDeclarations > - | {| - +type: "SET_PAUSE_POINTS", - +sourceText: string, - +sourceId: string, - +pausePoints: PausePoints - |} | {| +type: "OUT_OF_SCOPE_LOCATIONS", +locations: ?(AstLocation[]) diff --git a/devtools/client/debugger/new/src/actions/types/BreakpointAction.js b/devtools/client/debugger/new/src/actions/types/BreakpointAction.js index 49e96622ad638..c27d16198eec7 100644 --- a/devtools/client/debugger/new/src/actions/types/BreakpointAction.js +++ b/devtools/client/debugger/new/src/actions/types/BreakpointAction.js @@ -8,7 +8,7 @@ import type { Breakpoint, SourceLocation, XHRBreakpoint, - BreakpointLinePositions + BreakpointPositions } from "../../types"; import type { PromiseAction } from "../utils/middleware/promise"; @@ -94,6 +94,6 @@ export type BreakpointAction = |} | {| type: "ADD_BREAKPOINT_POSITIONS", - positions: BreakpointLinePositions, + positions: BreakpointPositions, location: SourceLocation |}; diff --git a/devtools/client/debugger/new/src/actions/types/SourceAction.js b/devtools/client/debugger/new/src/actions/types/SourceAction.js index 14508d1df3d99..ff20f3c7824d5 100644 --- a/devtools/client/debugger/new/src/actions/types/SourceAction.js +++ b/devtools/client/debugger/new/src/actions/types/SourceAction.js @@ -4,7 +4,7 @@ // @flow -import type { Source, SourceActor, SourceLocation } from "../../types"; +import type { Source, SourceLocation } from "../../types"; import type { PromiseAction } from "../utils/middleware/promise"; export type LoadSourceAction = PromiseAction< @@ -22,8 +22,7 @@ export type SourceAction = |} | {| +type: "ADD_SOURCES", - +sources: Array, - +sourceActors: SourceActor[] + +sources: Array |} | {| +type: "UPDATE_SOURCE", diff --git a/devtools/client/debugger/new/src/client/README.md b/devtools/client/debugger/new/src/client/README.md index 88181a51618c2..a1ff89aa95701 100644 --- a/devtools/client/debugger/new/src/client/README.md +++ b/devtools/client/debugger/new/src/client/README.md @@ -38,7 +38,7 @@ We want to do these interrupts transparently, so we've decided that the client should not notify the application that the thread has been paused or resumed. [protocol]: https://searchfox.org/mozilla-central/source/devtools/docs/backend/protocol.md -[dt-connect]: https://github.com/devtools-html/devtools-core/tree/master/packages/devtools-connection +[dt-connect]: https://github.com/firefox-devtools/devtools-core/tree/master/packages/devtools-connection [devtools-client.js]: https://searchfox.org/mozilla-central/source/devtools/shared/client/debugger-client.js ## Chrome diff --git a/devtools/client/debugger/new/src/client/chrome/commands.js b/devtools/client/debugger/new/src/client/chrome/commands.js index b80b4227b6e15..2b5bdb5b5df9f 100644 --- a/devtools/client/debugger/new/src/client/chrome/commands.js +++ b/devtools/client/debugger/new/src/client/chrome/commands.js @@ -114,8 +114,6 @@ function navigate(url: string) { function getBreakpointByLocation(location: SourceLocation) {} -function setPausePoints() {} - function getFrameScopes() {} function evaluateInFrame() {} function evaluateExpressions() {} @@ -135,7 +133,6 @@ const clientCommands = { navigate, getProperties, getBreakpointByLocation, - setPausePoints, getFrameScopes, evaluateInFrame, evaluateExpressions diff --git a/devtools/client/debugger/new/src/client/firefox/commands.js b/devtools/client/debugger/new/src/client/firefox/commands.js index 60f2b6b68d9c7..adfb5a5593a2a 100644 --- a/devtools/client/debugger/new/src/client/firefox/commands.js +++ b/devtools/client/debugger/new/src/client/firefox/commands.js @@ -18,8 +18,8 @@ import type { Script, SourceId, SourceActor, - SourceActorLocation, - Worker + Worker, + Range } from "../../types"; import type { @@ -31,8 +31,6 @@ import type { SourcesPacket } from "./types"; -import type { PausePointsMap } from "../../workers/parser"; - let workerClients: Object; let threadClient: ThreadClient; let tabTarget: TabTarget; @@ -295,17 +293,6 @@ async function blackBox( } } -async function setPausePoints( - sourceActor: SourceActor, - pausePoints: PausePointsMap -) { - return sendPacket({ - to: sourceActor.actor, - type: "setPausePoints", - pausePoints - }); -} - async function setSkipPausing(thread: string, shouldSkip: boolean) { const client = lookupThreadClient(thread); return client.request({ @@ -404,20 +391,16 @@ function getMainThread() { } async function getBreakpointPositions( - location: SourceActorLocation -): Promise> { - const { - sourceActor: { thread, actor }, - line - } = location; + sourceActor: SourceActor, + range: ?Range +): Promise<{ [string]: number[] }> { + const { thread, actor } = sourceActor; const sourceThreadClient = lookupThreadClient(thread); const sourceClient = sourceThreadClient.source({ actor }); - const { positions } = await sourceClient.getBreakpointPositionsCompressed({ - start: { line }, - end: { line } - }); - - return positions ? positions[line] : []; + const { positions } = await sourceClient.getBreakpointPositionsCompressed( + range + ); + return positions; } const clientCommands = { @@ -457,7 +440,6 @@ const clientCommands = { fetchWorkers, getMainThread, sendPacket, - setPausePoints, setSkipPausing, setEventListenerBreakpoints }; diff --git a/devtools/client/debugger/new/src/client/firefox/create.js b/devtools/client/debugger/new/src/client/firefox/create.js index af1f75366d68a..548156befa48f 100644 --- a/devtools/client/debugger/new/src/client/firefox/create.js +++ b/devtools/client/debugger/new/src/client/firefox/create.js @@ -10,8 +10,7 @@ import type { PausedPacket, FramesResponse, FramePacket, - SourcePayload, - CreateSourceResult + SourcePayload } from "./types"; import { clientCommands } from "./commands"; @@ -20,7 +19,7 @@ export function createFrame(thread: ThreadId, frame: FramePacket): ?Frame { if (!frame) { return null; } - + const location = { sourceId: clientCommands.getSourceForActor(frame.where.actor), line: frame.where.line, @@ -47,9 +46,15 @@ export function createSource( thread: string, source: SourcePayload, { supportsWasm }: { supportsWasm: boolean } -): CreateSourceResult { +): Source { + const id = makeSourceId(source); + const sourceActor = { + actor: source.actor, + source: id, + thread + }; const createdSource: any = { - id: makeSourceId(source), + id, url: source.url, relativeUrl: source.url, isPrettyPrinted: false, @@ -57,15 +62,11 @@ export function createSource( introductionUrl: source.introductionUrl, isBlackBoxed: false, loadedState: "unloaded", - isWasm: supportsWasm && source.introductionType === "wasm" - }; - const sourceActor = { - actor: source.actor, - source: createdSource.id, - thread + isWasm: supportsWasm && source.introductionType === "wasm", + actors: [sourceActor] }; clientCommands.registerSourceActor(sourceActor); - return { sourceActor, source: (createdSource: Source) }; + return createdSource; } export function createPause( diff --git a/devtools/client/debugger/new/src/client/firefox/types.js b/devtools/client/debugger/new/src/client/firefox/types.js index f97e60d0edaaa..92c627a251df2 100644 --- a/devtools/client/debugger/new/src/client/firefox/types.js +++ b/devtools/client/debugger/new/src/client/firefox/types.js @@ -21,7 +21,7 @@ import type { Frame, SourceId, Worker, - SourceActor + Range } from "../../types"; type URL = string; @@ -71,7 +71,7 @@ type URL = string; export type FramePacket = { actor: ActorId, arguments: any[], - callee: any, + displayName: string, environment: any, this: any, depth?: number, @@ -120,11 +120,6 @@ export type SourcesPacket = { sources: SourcePayload[] }; -export type CreateSourceResult = {| - sourceActor?: SourceActor, - +source: Source -|}; - /** * Pause Packet sent when the server is in a "paused" state * @@ -314,10 +309,7 @@ export type SourceClient = { source: () => { source: any, contentType?: string }, _activeThread: ThreadClient, actor: string, - getBreakpointPositionsCompressed: (range: { - start: { line: number }, - end: { line: number } - }) => Promise, + getBreakpointPositionsCompressed: (range: ?Range) => Promise, prettyPrint: number => Promise<*>, disablePrettyPrint: () => Promise<*>, blackBox: (range?: Range) => Promise<*>, diff --git a/devtools/client/debugger/new/src/components/Editor/ColumnBreakpoint.js b/devtools/client/debugger/new/src/components/Editor/ColumnBreakpoint.js index 925ae404de3f6..7a38da3fb2d49 100644 --- a/devtools/client/debugger/new/src/components/Editor/ColumnBreakpoint.js +++ b/devtools/client/debugger/new/src/components/Editor/ColumnBreakpoint.js @@ -32,11 +32,10 @@ ReactDOM.render(, breakpointImg); function makeBookmark({ breakpoint }, { onClick, onContextMenu }) { const bp = breakpointImg.cloneNode(true); - if (!breakpoint) { - return; - } - const { condition, logValue } = breakpoint.options; + const isActive = breakpoint && !breakpoint.disabled; + const condition = breakpoint && breakpoint.options.condition; + const logValue = breakpoint && breakpoint.options.logValue; bp.className = classnames("column-breakpoint", { "has-condition": condition, diff --git a/devtools/client/debugger/new/src/components/Editor/ColumnBreakpoints.css b/devtools/client/debugger/new/src/components/Editor/ColumnBreakpoints.css index 0a015f0d28a80..c7e8e05b43e07 100644 --- a/devtools/client/debugger/new/src/components/Editor/ColumnBreakpoints.css +++ b/devtools/client/debugger/new/src/components/Editor/ColumnBreakpoints.css @@ -4,8 +4,8 @@ .column-breakpoint { display: inline; - padding: 0; - padding-inline-end: 4px; + padding-inline-start: 1px; + padding-inline-end: 3px; } .column-breakpoint:hover { @@ -13,10 +13,10 @@ } .column-breakpoint svg { - display: inline; + display: inline-block; cursor: pointer; - height: 12px; - width: 9px; + height: 13px; + width: 11px; vertical-align: top; } diff --git a/devtools/client/debugger/new/src/components/Editor/Editor.css b/devtools/client/debugger/new/src/components/Editor/Editor.css index 6fca58385810e..c7ede464931df 100644 --- a/devtools/client/debugger/new/src/components/Editor/Editor.css +++ b/devtools/client/debugger/new/src/components/Editor/Editor.css @@ -40,7 +40,7 @@ /** * There's a known codemirror flex issue with chrome that this addresses. - * BUG https://github.com/devtools-html/debugger.html/issues/63 + * BUG https://github.com/firefox-devtools/debugger.html/issues/63 */ .editor-wrapper { position: absolute; @@ -78,20 +78,6 @@ html[dir="rtl"] .editor-mount { color: var(--grey-50); } -:not(.empty-line):not(.new-breakpoint) - > .CodeMirror-gutter-wrapper:hover - > .CodeMirror-linenumber { - height: 13px; - color: var(--theme-body-color); - /* Add 1px offset to the background to match it - with the actual breakpoint image dimensions */ - background: linear-gradient( - to bottom, - transparent 1px, - var(--gutter-hover-background-color) 0 - ); -} - .new-breakpoint .CodeMirror-linenumber { pointer-events: none; } @@ -101,12 +87,16 @@ html[dir="rtl"] .editor-mount { > .CodeMirror-linenumber::after { content: ""; position: absolute; - top: 1px; - height: 12px; - width: 9px; + /* paint below the number */ + z-index: -1; + top: 0; + left: 0; + right: -7px; + bottom: 0; + height: 15px; background-color: var(--gutter-hover-background-color); mask: url(/images/breakpoint.svg) no-repeat; - mask-size: auto 12px; + mask-size: auto 15px; mask-position: right; } @@ -126,7 +116,7 @@ html[dir="rtl"] .editor-mount { } .editor.hit-marker { - height: 14px; + height: 15px; } .editor-wrapper .highlight-lines { @@ -137,7 +127,7 @@ html[dir="rtl"] .editor-mount { fill: var(--breakpoint-fill); stroke: var(--breakpoint-stroke); width: 60px; - height: 14px; + height: 15px; position: absolute; top: 0px; right: -4px; @@ -182,7 +172,7 @@ html[dir="rtl"] .editor-mount { fill: var(--theme-selection-background); vertical-align: middle; width: 17px; - height: 14px; + height: 15px; } .editor.column-breakpoint.breakpoint-disabled svg { @@ -197,11 +187,8 @@ html[dir="rtl"] .editor-mount { .editor-wrapper .editor-mount { width: 100%; background-color: var(--theme-body-background); -} - -.CodeMirror-linenumber { - font-size: 11px; - line-height: 14px; + font-size: var(--theme-code-font-size); + line-height: var(--theme-code-line-height); } .folding-enabled .CodeMirror-linenumber { @@ -222,10 +209,6 @@ html[dir="rtl"] .editor-mount { z-index: 0; } -.editor-wrapper .CodeMirror-line { - font-size: 11px; -} - .theme-dark .editor-wrapper .CodeMirror-line .cm-comment { color: var(--theme-comment); } diff --git a/devtools/client/debugger/new/src/components/Editor/Footer.css b/devtools/client/debugger/new/src/components/Editor/Footer.css index d392e33c68ff8..7b9c2ac70dac0 100644 --- a/devtools/client/debugger/new/src/components/Editor/Footer.css +++ b/devtools/client/debugger/new/src/components/Editor/Footer.css @@ -58,7 +58,7 @@ } .source-footer > .commands > .blackboxed > .img.blackBox { - background-color: var(--theme-highlight-blue); + background-color: var(--theme-icon-checked-color); } .source-footer .blackbox-summary, diff --git a/devtools/client/debugger/new/src/components/Editor/Tab.js b/devtools/client/debugger/new/src/components/Editor/Tab.js index f21f5d14d30bd..3f4358cd4336e 100644 --- a/devtools/client/debugger/new/src/components/Editor/Tab.js +++ b/devtools/client/debugger/new/src/components/Editor/Tab.js @@ -23,7 +23,8 @@ import { getRawSourceURL, getSourceQueryString, getTruncatedFileName, - isPretty + isPretty, + shouldBlackbox } from "../../utils/source"; import { shouldShowPrettyPrint } from "../../utils/editor"; import { copyToTheClipboard } from "../../utils/clipboard"; @@ -51,7 +52,8 @@ type Props = { closeTab: typeof actions.closeTab, closeTabs: typeof actions.closeTabs, togglePrettyPrint: typeof actions.togglePrettyPrint, - showSource: typeof actions.showSource + showSource: typeof actions.showSource, + toggleBlackBox: typeof actions.toggleBlackBox }; class Tab extends PureComponent { @@ -66,6 +68,7 @@ class Tab extends PureComponent { closeTabs, tabSources, showSource, + toggleBlackBox, togglePrettyPrint, selectedSource, source @@ -135,13 +138,25 @@ class Tab extends PureComponent { } ]; - items.push({ - item: { - ...tabMenuItems.prettyPrint, - click: () => togglePrettyPrint(tab), - disabled: !shouldShowPrettyPrint(source) + items.push( + { + item: { + ...tabMenuItems.toggleBlackBox, + label: source.isBlackBoxed + ? L10N.getStr("sourceFooter.unblackbox") + : L10N.getStr("sourceFooter.blackbox"), + disabled: !shouldBlackbox(source), + click: () => toggleBlackBox(source) + } + }, + { + item: { + ...tabMenuItems.prettyPrint, + click: () => togglePrettyPrint(tab), + disabled: !shouldShowPrettyPrint(source) + } } - }); + ); showMenu(e, buildMenu(items)); } @@ -234,6 +249,7 @@ export default connect( closeTab: actions.closeTab, closeTabs: actions.closeTabs, togglePrettyPrint: actions.togglePrettyPrint, - showSource: actions.showSource + showSource: actions.showSource, + toggleBlackBox: actions.toggleBlackBox } )(Tab); diff --git a/devtools/client/debugger/new/src/components/Editor/Tabs.css b/devtools/client/debugger/new/src/components/Editor/Tabs.css index 24e50439f489d..f326337092e06 100644 --- a/devtools/client/debugger/new/src/components/Editor/Tabs.css +++ b/devtools/client/debugger/new/src/components/Editor/Tabs.css @@ -8,7 +8,6 @@ height: var(--editor-header-height); border-bottom: 1px solid var(--theme-splitter-color); background-color: var(--theme-toolbar-background); - --overflow-button-width: 28px; } .source-header * { diff --git a/devtools/client/debugger/new/src/components/Editor/tests/DebugLine.spec.js b/devtools/client/debugger/new/src/components/Editor/tests/DebugLine.spec.js index 7a475e444d54e..5b8411724b1bf 100644 --- a/devtools/client/debugger/new/src/components/Editor/tests/DebugLine.spec.js +++ b/devtools/client/debugger/new/src/components/Editor/tests/DebugLine.spec.js @@ -31,7 +31,7 @@ function generateDefaults(editor, overrides) { why: { type: "breakpoint" } }, frame: null, - source: makeSource("foo").source, + source: makeSource("foo"), ...overrides }; } @@ -65,7 +65,7 @@ describe("DebugLine Component", () => { describe("pausing at the first location", () => { it("should show a new debug line", async () => { const { component, props, doc } = render({ - source: makeSource("foo", { loadedState: "loaded" }).source + source: makeSource("foo", { loadedState: "loaded" }) }); const line = 2; const frame = createFrame(line); @@ -81,7 +81,7 @@ describe("DebugLine Component", () => { describe("pausing at a new location", () => { it("should replace the first debug line", async () => { const { props, component, clear, doc } = render({ - source: makeSource("foo", { loadedState: "loaded" }).source + source: makeSource("foo", { loadedState: "loaded" }) }); component.instance().debugExpression = { clear: jest.fn() }; diff --git a/devtools/client/debugger/new/src/components/Editor/tests/Footer.spec.js b/devtools/client/debugger/new/src/components/Editor/tests/Footer.spec.js index d1461d6f39a0f..ffd48072ae148 100644 --- a/devtools/client/debugger/new/src/components/Editor/tests/Footer.spec.js +++ b/devtools/client/debugger/new/src/components/Editor/tests/Footer.spec.js @@ -29,7 +29,7 @@ function generateDefaults(overrides) { } }, endPanelCollapsed: false, - selectedSource: makeSource("foo").source, + selectedSource: makeSource("foo"), ...overrides }; } diff --git a/devtools/client/debugger/new/src/components/PrimaryPanes/OutlineFilter.js b/devtools/client/debugger/new/src/components/PrimaryPanes/OutlineFilter.js index 0736581a0a034..c508beadd5da1 100644 --- a/devtools/client/debugger/new/src/components/PrimaryPanes/OutlineFilter.js +++ b/devtools/client/debugger/new/src/components/PrimaryPanes/OutlineFilter.js @@ -37,7 +37,7 @@ export default class OutlineFilter extends Component { this.props.updateFilter(""); } else if (e.key === "Enter") { // We must prevent the form submission from taking any action - // https://github.com/devtools-html/debugger.html/pull/7308 + // https://github.com/firefox-devtools/debugger.html/pull/7308 e.preventDefault(); } }; diff --git a/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTree.js b/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTree.js index ba6c6663008b0..495b7185a0957 100644 --- a/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTree.js +++ b/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTree.js @@ -16,7 +16,7 @@ import { getDebuggeeUrl, getExpandedState, getProjectDirectoryRoot, - getRelativeSourcesForThread, + getDisplayedSourcesForThread, getFocusedSourceItem, getWorkerByThread, getWorkerCount @@ -344,7 +344,7 @@ class SourcesTree extends Component { function getSourceForTree( state: AppState, - relativeSources: SourcesMap, + displayedSources: SourcesMap, source: ?Source, thread ): ?Source { @@ -352,7 +352,7 @@ function getSourceForTree( return null; } - source = relativeSources[source.id]; + source = displayedSources[source.id]; if (!source || !source.isPrettyPrinted) { return source; } @@ -365,13 +365,13 @@ const mapStateToProps = (state, props) => { const shownSource = getShownSource(state); const focused = getFocusedSourceItem(state); const thread = props.thread; - const relativeSources = getRelativeSourcesForThread(state, thread); + const displayedSources = getDisplayedSourcesForThread(state, thread); return { - shownSource: getSourceForTree(state, relativeSources, shownSource, thread), + shownSource: getSourceForTree(state, displayedSources, shownSource, thread), selectedSource: getSourceForTree( state, - relativeSources, + displayedSources, selectedSource, thread ), @@ -379,8 +379,8 @@ const mapStateToProps = (state, props) => { expanded: getExpandedState(state, props.thread), focused: focused && focused.thread == props.thread ? focused.item : null, projectRoot: getProjectDirectoryRoot(state), - sources: relativeSources, - sourceCount: Object.values(relativeSources).length, + sources: displayedSources, + sourceCount: Object.values(displayedSources).length, worker: getWorkerByThread(state, thread), workerCount: getWorkerCount(state) }; diff --git a/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTreeItem.js b/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTreeItem.js index 6317d2ae543b7..d0301b7a226b6 100644 --- a/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTreeItem.js +++ b/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTreeItem.js @@ -22,7 +22,8 @@ import actions from "../../actions"; import { isOriginal as isOriginalSource, getSourceQueryString, - isUrlExtension + isUrlExtension, + shouldBlackbox } from "../../utils/source"; import { isDirectory } from "../../utils/sources-tree"; import { copyToTheClipboard } from "../../utils/clipboard"; @@ -46,7 +47,8 @@ type Props = { selectItem: TreeNode => void, setExpanded: (TreeNode, boolean, boolean) => void, clearProjectDirectoryRoot: typeof actions.clearProjectDirectoryRoot, - setProjectDirectoryRoot: typeof actions.setProjectDirectoryRoot + setProjectDirectoryRoot: typeof actions.setProjectDirectoryRoot, + toggleBlackBox: typeof actions.toggleBlackBox }; type State = {}; @@ -132,7 +134,19 @@ class SourceTreeItem extends Component { click: () => copyToTheClipboard(contents.url) }; - menuOptions.push(copySourceUri2); + const { source } = this.props; + if (source) { + const blackBoxMenuItem = { + id: "node-menu-blackbox", + label: source.isBlackBoxed + ? L10N.getStr("sourceFooter.unblackbox") + : L10N.getStr("sourceFooter.blackbox"), + accesskey: L10N.getStr("sourceFooter.blackbox.accesskey"), + disabled: !shouldBlackbox(source), + click: () => this.props.toggleBlackBox(source) + }; + menuOptions.push(copySourceUri2, blackBoxMenuItem); + } } } @@ -269,6 +283,7 @@ export default connect( mapStateToProps, { setProjectDirectoryRoot: actions.setProjectDirectoryRoot, - clearProjectDirectoryRoot: actions.clearProjectDirectoryRoot + clearProjectDirectoryRoot: actions.clearProjectDirectoryRoot, + toggleBlackBox: actions.toggleBlackBox } )(SourceTreeItem); diff --git a/devtools/client/debugger/new/src/components/PrimaryPanes/index.js b/devtools/client/debugger/new/src/components/PrimaryPanes/index.js index ad2da064e10b3..61a5ffb89267b 100644 --- a/devtools/client/debugger/new/src/components/PrimaryPanes/index.js +++ b/devtools/client/debugger/new/src/components/PrimaryPanes/index.js @@ -10,7 +10,7 @@ import { Tab, Tabs, TabList, TabPanels } from "react-aria-components/src/tabs"; import actions from "../../actions"; import { - getRelativeSources, + getDisplayedSources, getActiveSearch, getProjectDirectoryRoot, getSelectedPrimaryPaneTab, @@ -165,7 +165,7 @@ class PrimaryPanes extends Component { const mapStateToProps = state => ({ selectedTab: getSelectedPrimaryPaneTab(state), - sources: getRelativeSources(state), + sources: getDisplayedSources(state), sourceSearchOn: getActiveSearch(state) === "source", threads: getThreads(state), projectRoot: getProjectDirectoryRoot(state) diff --git a/devtools/client/debugger/new/src/components/PrimaryPanes/tests/SourcesTree.spec.js b/devtools/client/debugger/new/src/components/PrimaryPanes/tests/SourcesTree.spec.js index dae15bbccb08c..833254616dd42 100644 --- a/devtools/client/debugger/new/src/components/PrimaryPanes/tests/SourcesTree.spec.js +++ b/devtools/client/debugger/new/src/components/PrimaryPanes/tests/SourcesTree.spec.js @@ -9,7 +9,7 @@ import { shallow } from "enzyme"; import { showMenu } from "devtools-contextmenu"; import SourcesTree from "../SourcesTree"; -import { createSource } from "../../../reducers/sources"; +import { makeMockSource } from "../../../utils/test-mockup"; import { copyToTheClipboard } from "../../../utils/clipboard"; jest.mock("devtools-contextmenu", () => ({ showMenu: jest.fn() })); @@ -399,16 +399,11 @@ function createMockSource( sourceMapURL = null, thread = "" ) { - return createSource({ - id: id, - thread, - url: url, - isPrettyPrinted: false, - isWasm: false, - sourceMapURL, - isBlackBoxed: isBlackBoxed, - loadedState: "unloaded" - }); + return { + ...makeMockSource(url, id), + isBlackBoxed, + sourceMapURL + }; } function createMockDirectory(path = "folder/", name = "folder", contents = []) { diff --git a/devtools/client/debugger/new/src/components/PrimaryPanes/tests/SourcesTreeItem.spec.js b/devtools/client/debugger/new/src/components/PrimaryPanes/tests/SourcesTreeItem.spec.js index 37482c3fa755b..d8e7e62475c36 100644 --- a/devtools/client/debugger/new/src/components/PrimaryPanes/tests/SourcesTreeItem.spec.js +++ b/devtools/client/debugger/new/src/components/PrimaryPanes/tests/SourcesTreeItem.spec.js @@ -9,7 +9,7 @@ import { shallow } from "enzyme"; import { showMenu } from "devtools-contextmenu"; import SourcesTreeItem from "../SourcesTreeItem"; -import { createSource } from "../../../reducers/sources"; +import { makeMockSource } from "../../../utils/test-mockup"; import { copyToTheClipboard } from "../../../utils/clipboard"; jest.mock("devtools-contextmenu", () => ({ showMenu: jest.fn() })); @@ -83,6 +83,13 @@ describe("SourceTreeItem", () => { disabled: false, id: "node-menu-copy-source", label: "Copy source URI" + }, + { + accesskey: "B", + click: expect.any(Function), + disabled: true, + id: "node-menu-blackbox", + label: "Blackbox source" } ]; const mockEvent = { @@ -92,9 +99,9 @@ describe("SourceTreeItem", () => { const { props, instance } = render({ projectRoot: "root/" }); - const { item } = instance.props; + const { item, source } = instance.props; - await instance.onContextMenu(mockEvent, item); + await instance.onContextMenu(mockEvent, item, source); expect(showMenu).toHaveBeenCalledWith(mockEvent, menuOptions); @@ -107,6 +114,45 @@ describe("SourceTreeItem", () => { expect(copyToTheClipboard).toHaveBeenCalled(); }); + it("shows context menu on file to blackbox source", async () => { + const menuOptions = [ + { + accesskey: "u", + click: expect.any(Function), + disabled: false, + id: "node-menu-copy-source", + label: "Copy source URI" + }, + { + accesskey: "B", + click: expect.any(Function), + disabled: true, + id: "node-menu-blackbox", + label: "Blackbox source" + } + ]; + const mockEvent = { + preventDefault: jest.fn(), + stopPropagation: jest.fn() + }; + const { props, instance } = render({ + projectRoot: "root/" + }); + const { item, source } = instance.props; + + await instance.onContextMenu(mockEvent, item, source); + + expect(showMenu).toHaveBeenCalledWith(mockEvent, menuOptions); + + expect(mockEvent.preventDefault).toHaveBeenCalled(); + expect(mockEvent.stopPropagation).toHaveBeenCalled(); + + showMenu.mock.calls[0][1][1].click(); + expect(props.setProjectDirectoryRoot).not.toHaveBeenCalled(); + expect(props.clearProjectDirectoryRoot).not.toHaveBeenCalled(); + expect(props.toggleBlackBox).toHaveBeenCalled(); + }); + it("shows context menu on root to remove directory root", async () => { const menuOptions = [ { @@ -295,10 +341,10 @@ describe("SourceTreeItem", () => { }); function generateDefaults(overrides) { - const source = createSource({ - id: "server1.conn13.child1/39", - url: "http://mdn.com/one.js" - }); + const source = makeMockSource( + "http://mdn.com/one.js", + "server1.conn13.child1/39" + ); const item = { name: "one.js", @@ -314,6 +360,7 @@ function generateDefaults(overrides) { projectRoot: "", clearProjectDirectoryRoot: jest.fn(), setProjectDirectoryRoot: jest.fn(), + toggleBlackBox: jest.fn(), selectItem: jest.fn(), focusItem: jest.fn(), setExpanded: jest.fn(), @@ -343,10 +390,10 @@ function createMockDirectory(path = "folder/", name = "folder", contents = []) { function createMockItem(overrides = {}) { overrides = { ...overrides, - contents: createSource({ - id: "server1.conn13.child1/39", + contents: { + ...makeMockSource(undefined, "server1.conn13.child1/39"), ...(overrides.contents || {}) - }) + } }; return { diff --git a/devtools/client/debugger/new/src/components/PrimaryPanes/tests/__snapshots__/SourcesTree.spec.js.snap b/devtools/client/debugger/new/src/components/PrimaryPanes/tests/__snapshots__/SourcesTree.spec.js.snap index dc35051c97b68..8d6ac0f50a206 100644 --- a/devtools/client/debugger/new/src/components/PrimaryPanes/tests/__snapshots__/SourcesTree.spec.js.snap +++ b/devtools/client/debugger/new/src/components/PrimaryPanes/tests/__snapshots__/SourcesTree.spec.js.snap @@ -122,17 +122,18 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi Array [ Object { "contents": Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/41", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", + "relativeUrl": "http://mdn.com/three.js", "sourceMapURL": null, - "text": undefined, - "thread": "", + "text": "", "url": "http://mdn.com/three.js", }, "name": "three.js", @@ -143,17 +144,18 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi "contents": Array [ Object { "contents": Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/42", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", + "relativeUrl": "http://mdn.com/four.js", "sourceMapURL": "data:application/json?charset=utf?dsffewrsf", - "text": undefined, - "thread": "", + "text": "", "url": "http://mdn.com/four.js", }, "name": "four.js", @@ -162,17 +164,18 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi }, Object { "contents": Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/42/originalSource-sha", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", + "relativeUrl": "http://mdn.com/four.js", "sourceMapURL": null, - "text": undefined, - "thread": "", + "text": "", "url": "http://mdn.com/four.js", }, "name": "four.js", @@ -181,17 +184,18 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi }, Object { "contents": Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/39", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", + "relativeUrl": "http://mdn.com/one.js", "sourceMapURL": null, - "text": undefined, - "thread": "", + "text": "", "url": "http://mdn.com/one.js", }, "name": "one.js", @@ -200,17 +204,18 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi }, Object { "contents": Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/41", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", + "relativeUrl": "http://mdn.com/three.js", "sourceMapURL": null, - "text": undefined, - "thread": "", + "text": "", "url": "http://mdn.com/three.js", }, "name": "three.js", @@ -219,17 +224,18 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi }, Object { "contents": Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/40", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", + "relativeUrl": "http://mdn.com/two.js", "sourceMapURL": null, - "text": undefined, - "thread": "", + "text": "", "url": "http://mdn.com/two.js", }, "name": "two.js", diff --git a/devtools/client/debugger/new/src/components/PrimaryPanes/tests/__snapshots__/SourcesTreeItem.spec.js.snap b/devtools/client/debugger/new/src/components/PrimaryPanes/tests/__snapshots__/SourcesTreeItem.spec.js.snap index 6dae1aa9d77c9..1ea322b8abcf3 100644 --- a/devtools/client/debugger/new/src/components/PrimaryPanes/tests/__snapshots__/SourcesTreeItem.spec.js.snap +++ b/devtools/client/debugger/new/src/components/PrimaryPanes/tests/__snapshots__/SourcesTreeItem.spec.js.snap @@ -14,16 +14,17 @@ Object { , "_forcedUpdate": false, "_instance": [Circular], @@ -146,16 +153,17 @@ Object { , "_forcedUpdate": false, "_instance": [Circular], @@ -371,16 +389,17 @@ Object { , "_forcedUpdate": false, "_instance": [Circular], @@ -605,17 +633,18 @@ Object { "focusItem": [MockFunction], "item": Object { "contents": Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/39", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", - "sourceMapURL": undefined, - "text": undefined, - "url": undefined, + "relativeUrl": "url", + "text": "", + "url": "url", }, "name": "root", "path": "root", @@ -626,18 +655,20 @@ Object { "setExpanded": [MockFunction], "setProjectDirectoryRoot": [MockFunction], "source": Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/39", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", - "sourceMapURL": undefined, - "text": undefined, + "relativeUrl": "http://mdn.com/one.js", + "text": "", "url": "http://mdn.com/one.js", }, + "toggleBlackBox": [MockFunction], }, } `; @@ -687,18 +718,20 @@ Object { "setExpanded": [MockFunction], "setProjectDirectoryRoot": [MockFunction], "source": Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/39", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", - "sourceMapURL": undefined, - "text": undefined, + "relativeUrl": "http://mdn.com/one.js", + "text": "", "url": "http://mdn.com/one.js", }, + "toggleBlackBox": [MockFunction], }, "refs": Object {}, "state": null, @@ -726,19 +759,21 @@ Object { setProjectDirectoryRoot={[MockFunction]} source={ Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/39", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", - "sourceMapURL": undefined, - "text": undefined, + "relativeUrl": "http://mdn.com/one.js", + "text": "", "url": "http://mdn.com/one.js", } } + toggleBlackBox={[MockFunction]} />, "_forcedUpdate": false, "_instance": [Circular], @@ -784,18 +819,20 @@ Object { "setExpanded": [MockFunction], "setProjectDirectoryRoot": [MockFunction], "source": Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/39", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", - "sourceMapURL": undefined, - "text": undefined, + "relativeUrl": "http://mdn.com/one.js", + "text": "", "url": "http://mdn.com/one.js", }, + "toggleBlackBox": [MockFunction], }, } `; @@ -846,18 +883,20 @@ Object { "setExpanded": [MockFunction], "setProjectDirectoryRoot": [MockFunction], "source": Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/39", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", - "sourceMapURL": undefined, - "text": undefined, + "relativeUrl": "http://mdn.com/one.js", + "text": "", "url": "http://mdn.com/one.js", }, + "toggleBlackBox": [MockFunction], }, "refs": Object {}, "state": null, @@ -886,19 +925,21 @@ Object { setProjectDirectoryRoot={[MockFunction]} source={ Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/39", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", - "sourceMapURL": undefined, - "text": undefined, + "relativeUrl": "http://mdn.com/one.js", + "text": "", "url": "http://mdn.com/one.js", } } + toggleBlackBox={[MockFunction]} />, "_forcedUpdate": false, "_instance": [Circular], @@ -945,18 +986,20 @@ Object { "setExpanded": [MockFunction], "setProjectDirectoryRoot": [MockFunction], "source": Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/39", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", - "sourceMapURL": undefined, - "text": undefined, + "relativeUrl": "http://mdn.com/one.js", + "text": "", "url": "http://mdn.com/one.js", }, + "toggleBlackBox": [MockFunction], }, } `; @@ -1007,6 +1050,7 @@ Object { "setExpanded": [MockFunction], "setProjectDirectoryRoot": [MockFunction], "source": null, + "toggleBlackBox": [MockFunction], }, "refs": Object {}, "state": null, @@ -1034,6 +1078,7 @@ Object { setExpanded={[MockFunction]} setProjectDirectoryRoot={[MockFunction]} source={null} + toggleBlackBox={[MockFunction]} />, "_forcedUpdate": false, "_instance": [Circular], @@ -1080,6 +1125,7 @@ Object { "setExpanded": [MockFunction], "setProjectDirectoryRoot": [MockFunction], "source": null, + "toggleBlackBox": [MockFunction], }, } `; @@ -1128,18 +1174,20 @@ Object { "setExpanded": [MockFunction], "setProjectDirectoryRoot": [MockFunction], "source": Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/39", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", - "sourceMapURL": undefined, - "text": undefined, + "relativeUrl": "http://mdn.com/one.js", + "text": "", "url": "http://mdn.com/one.js", }, + "toggleBlackBox": [MockFunction], }, "refs": Object {}, "state": null, @@ -1166,19 +1214,21 @@ Object { setProjectDirectoryRoot={[MockFunction]} source={ Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/39", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", - "sourceMapURL": undefined, - "text": undefined, + "relativeUrl": "http://mdn.com/one.js", + "text": "", "url": "http://mdn.com/one.js", } } + toggleBlackBox={[MockFunction]} />, "_forcedUpdate": false, "_instance": [Circular], @@ -1223,18 +1273,20 @@ Object { "setExpanded": [MockFunction], "setProjectDirectoryRoot": [MockFunction], "source": Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/39", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", - "sourceMapURL": undefined, - "text": undefined, + "relativeUrl": "http://mdn.com/one.js", + "text": "", "url": "http://mdn.com/one.js", }, + "toggleBlackBox": [MockFunction], }, } `; @@ -1283,6 +1335,7 @@ Object { "setExpanded": [MockFunction], "setProjectDirectoryRoot": [MockFunction], "source": null, + "toggleBlackBox": [MockFunction], }, "refs": Object {}, "state": null, @@ -1308,6 +1361,7 @@ Object { setExpanded={[MockFunction]} setProjectDirectoryRoot={[MockFunction]} source={null} + toggleBlackBox={[MockFunction]} />, "_forcedUpdate": false, "_instance": [Circular], @@ -1352,6 +1406,7 @@ Object { "setExpanded": [MockFunction], "setProjectDirectoryRoot": [MockFunction], "source": null, + "toggleBlackBox": [MockFunction], }, } `; @@ -1402,6 +1457,7 @@ Object { "setExpanded": [MockFunction], "setProjectDirectoryRoot": [MockFunction], "source": null, + "toggleBlackBox": [MockFunction], }, "refs": Object {}, "state": null, @@ -1429,6 +1485,7 @@ Object { setExpanded={[MockFunction]} setProjectDirectoryRoot={[MockFunction]} source={null} + toggleBlackBox={[MockFunction]} />, "_forcedUpdate": false, "_instance": [Circular], @@ -1475,6 +1532,7 @@ Object { "setExpanded": [MockFunction], "setProjectDirectoryRoot": [MockFunction], "source": null, + "toggleBlackBox": [MockFunction], }, } `; @@ -1524,18 +1582,20 @@ Object { "setExpanded": [MockFunction], "setProjectDirectoryRoot": [MockFunction], "source": Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/39", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", - "sourceMapURL": undefined, - "text": undefined, + "relativeUrl": "http://mdn.com/one.js", + "text": "", "url": "http://mdn.com/one.js", }, + "toggleBlackBox": [MockFunction], }, "refs": Object {}, "state": null, @@ -1563,19 +1623,21 @@ Object { setProjectDirectoryRoot={[MockFunction]} source={ Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/39", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", - "sourceMapURL": undefined, - "text": undefined, + "relativeUrl": "http://mdn.com/one.js", + "text": "", "url": "http://mdn.com/one.js", } } + toggleBlackBox={[MockFunction]} />, "_forcedUpdate": false, "_instance": [Circular], @@ -1621,18 +1683,20 @@ Object { "setExpanded": [MockFunction], "setProjectDirectoryRoot": [MockFunction], "source": Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/39", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", - "sourceMapURL": undefined, - "text": undefined, + "relativeUrl": "http://mdn.com/one.js", + "text": "", "url": "http://mdn.com/one.js", }, + "toggleBlackBox": [MockFunction], }, } `; @@ -1681,18 +1745,20 @@ Object { "setExpanded": [MockFunction], "setProjectDirectoryRoot": [MockFunction], "source": Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/39", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", - "sourceMapURL": undefined, - "text": undefined, + "relativeUrl": "http://mdn.com/one.js", + "text": "", "url": "http://mdn.com/one.js", }, + "toggleBlackBox": [MockFunction], }, "refs": Object {}, "state": null, @@ -1719,19 +1785,21 @@ Object { setProjectDirectoryRoot={[MockFunction]} source={ Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/39", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", - "sourceMapURL": undefined, - "text": undefined, + "relativeUrl": "http://mdn.com/one.js", + "text": "", "url": "http://mdn.com/one.js", } } + toggleBlackBox={[MockFunction]} />, "_forcedUpdate": false, "_instance": [Circular], @@ -1776,18 +1844,20 @@ Object { "setExpanded": [MockFunction], "setProjectDirectoryRoot": [MockFunction], "source": Object { - "contentType": "", - "error": undefined, + "actors": Array [], + "contentType": "text/javascript", "id": "server1.conn13.child1/39", + "introductionUrl": null, "isBlackBoxed": false, "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", - "sourceMapURL": undefined, - "text": undefined, + "relativeUrl": "http://mdn.com/one.js", + "text": "", "url": "http://mdn.com/one.js", }, + "toggleBlackBox": [MockFunction], }, } `; @@ -1806,16 +1876,17 @@ Object { , "_forcedUpdate": false, "_instance": [Circular], @@ -1940,16 +2017,17 @@ Object { , "_forcedUpdate": false, "_instance": [Circular], @@ -2161,16 +2249,17 @@ Object { { it("paused at an original location", () => { const { component } = render( { - selectedSource: makeOriginalSource("foo").source, + selectedSource: makeOriginalSource("foo"), frame: { selectedLocation: location } }, { location, options: {} } @@ -72,9 +72,9 @@ function makeBreakpoint(overrides = {}) { } function generateDefaults(overrides = {}, breakpointOverrides = {}) { - const source = makeSource("foo").source; + const source = makeSource("foo"); const breakpoint = makeBreakpoint(breakpointOverrides); - const selectedSource = makeSource("foo").source; + const selectedSource = makeSource("foo"); return { source, breakpoint, diff --git a/devtools/client/debugger/new/src/components/SecondaryPanes/CommandBar.css b/devtools/client/debugger/new/src/components/SecondaryPanes/CommandBar.css index e76cf81fada9b..8bac62a0b69c5 100644 --- a/devtools/client/debugger/new/src/components/SecondaryPanes/CommandBar.css +++ b/devtools/client/debugger/new/src/components/SecondaryPanes/CommandBar.css @@ -42,7 +42,7 @@ html[dir="rtl"] .command-bar { } .command-bar .active .disable-pausing { - background-color: var(--theme-highlight-blue); + background-color: var(--theme-icon-checked-color); } .bottom { diff --git a/devtools/client/debugger/new/src/components/SecondaryPanes/EventListeners.css b/devtools/client/debugger/new/src/components/SecondaryPanes/EventListeners.css index f1075fe21c6b3..27697ec4ade26 100644 --- a/devtools/client/debugger/new/src/components/SecondaryPanes/EventListeners.css +++ b/devtools/client/debugger/new/src/components/SecondaryPanes/EventListeners.css @@ -3,7 +3,10 @@ * file, You can obtain one at . */ .event-listeners-content { - padding: 4px 20px; + padding-top: 4px; + padding-bottom: 4px; + padding-inline-start: 14px; + padding-inline-end: 20px; } .event-listeners-content ul { @@ -15,6 +18,39 @@ user-select: none; } +.event-listener-header { + display: flex; + align-items: center; +} + +.event-listener-expand { + border: none; + background: none; + padding: 4px 5px; + line-height: 12px; +} + +.event-listener-expand:hover { + background: transparent; +} + +.event-listener-group input[type="checkbox"] { + margin: 0px; + margin-inline-end: 4px; +} + +.event-listener-label { + display: flex; + align-items: center; + padding-inline-start: 2px; + padding-inline-end: 10px; +} + +.event-listener-category { + padding: 3px 0px; + line-height: 14px; +} + .event-listeners-content .arrow { margin-inline-end: 0; } @@ -33,7 +69,14 @@ html[dir="rtl"] .event-listeners-content .arrow.expanded { margin-inline-start: 30px; } +.event-listener-name { + line-height: 14px; + padding: 3px 0px; +} + .event-listener-event input { margin-inline-end: 4px; margin-inline-start: 0px; + margin-top: 0px; + margin-bottom: 0px; } diff --git a/devtools/client/debugger/new/src/components/SecondaryPanes/EventListeners.js b/devtools/client/debugger/new/src/components/SecondaryPanes/EventListeners.js index 3ab1b7ef57f5f..c97039a38a937 100644 --- a/devtools/client/debugger/new/src/components/SecondaryPanes/EventListeners.js +++ b/devtools/client/debugger/new/src/components/SecondaryPanes/EventListeners.js @@ -46,8 +46,6 @@ class EventListeners extends Component { } onCategoryToggle(category, event) { - event.preventDefault(); - const { expandedCategories } = this.state; if (expandedCategories.includes(category)) { @@ -102,20 +100,24 @@ class EventListeners extends Component { ); return ( -
); } @@ -134,14 +136,14 @@ class EventListeners extends Component { const key = getKey(category, eventType); return (
  • -
  • ); diff --git a/devtools/client/debugger/new/src/components/SecondaryPanes/Expressions.js b/devtools/client/debugger/new/src/components/SecondaryPanes/Expressions.js index 3bd6d3f26a9b3..2fabc32a769ed 100644 --- a/devtools/client/debugger/new/src/components/SecondaryPanes/Expressions.js +++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Expressions.js @@ -249,7 +249,6 @@ class Expressions extends Component { roots={[root]} autoExpandDepth={0} disableWrap={true} - focusable={false} openLink={openLink} createObjectClient={grip => createObjectClient(grip)} onDOMNodeClick={grip => openElementInInspector(grip)} diff --git a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/Group.css b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/Group.css index 66e1a71e3b1c1..e540a9058a715 100644 --- a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/Group.css +++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/Group.css @@ -2,8 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at . */ -.frames ul .frames-group .group, -.frames ul .frames-group .group .location { +.frames [role="list"] .frames-group .group, +.frames [role="list"] .frames-group .group .location { font-weight: 500; cursor: default; /* @@ -14,21 +14,21 @@ direction: ltr; } -.frames ul .frames-group.expanded .group, -.frames ul .frames-group.expanded .group .location { +.frames [role="list"] .frames-group.expanded .group, +.frames [role="list"] .frames-group.expanded .group .location { color: var(--theme-highlight-blue); } -.frames ul .frames-group .frames-list li { +.frames [role="list"] .frames-group .frames-list [role="listitem"] { padding-left: 30px; } -.frames ul .frames-group .frames-list { +.frames [role="list"] .frames-group .frames-list { border-top: 1px solid var(--theme-splitter-color); border-bottom: 1px solid var(--theme-splitter-color); } -.frames ul .frames-group.expanded .badge { +.frames [role="list"] .frames-group.expanded .badge { color: var(--theme-highlight-blue); } diff --git a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/__snapshots__/Frame.spec.js.snap b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/__snapshots__/Frame.spec.js.snap index a089b769e844d..f442c23f4db6d 100644 --- a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/__snapshots__/Frame.spec.js.snap +++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/__snapshots__/Frame.spec.js.snap @@ -37,10 +37,12 @@ exports[`Frame getFrameTitle 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -89,10 +91,12 @@ exports[`Frame getFrameTitle 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -148,10 +152,12 @@ exports[`Frame library frame 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -201,10 +207,12 @@ exports[`Frame library frame 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -259,10 +267,12 @@ exports[`Frame user frame (not selected) 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -311,10 +321,12 @@ exports[`Frame user frame (not selected) 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -369,10 +381,12 @@ exports[`Frame user frame 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -421,10 +435,12 @@ exports[`Frame user frame 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", diff --git a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/__snapshots__/Frames.spec.js.snap b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/__snapshots__/Frames.spec.js.snap index 81a45be85d514..d9e4bf4ce631e 100644 --- a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/__snapshots__/Frames.spec.js.snap +++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/__snapshots__/Frames.spec.js.snap @@ -34,10 +34,12 @@ exports[`Frames Blackboxed Frames filters blackboxed frames 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "1", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -78,10 +80,12 @@ exports[`Frames Blackboxed Frames filters blackboxed frames 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "1", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -124,10 +128,12 @@ exports[`Frames Blackboxed Frames filters blackboxed frames 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "1", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -168,10 +174,12 @@ exports[`Frames Blackboxed Frames filters blackboxed frames 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "1", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", diff --git a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/__snapshots__/Group.spec.js.snap b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/__snapshots__/Group.spec.js.snap index 7aaa8394d8878..cd4f275952257 100644 --- a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/__snapshots__/Group.spec.js.snap +++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/__snapshots__/Group.spec.js.snap @@ -41,10 +41,12 @@ exports[`Group displays a group 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -113,10 +115,12 @@ exports[`Group passes the getFrameTitle prop to the Frame components 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -176,10 +180,12 @@ exports[`Group passes the getFrameTitle prop to the Frame components 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -222,10 +228,12 @@ exports[`Group passes the getFrameTitle prop to the Frame components 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -273,10 +281,12 @@ exports[`Group passes the getFrameTitle prop to the Frame components 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -319,10 +329,12 @@ exports[`Group passes the getFrameTitle prop to the Frame components 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -370,10 +382,12 @@ exports[`Group passes the getFrameTitle prop to the Frame components 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -416,10 +430,12 @@ exports[`Group passes the getFrameTitle prop to the Frame components 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -480,10 +496,12 @@ exports[`Group renders group with anonymous functions 1`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -552,10 +570,12 @@ exports[`Group renders group with anonymous functions 2`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -615,10 +635,12 @@ exports[`Group renders group with anonymous functions 2`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -660,10 +682,12 @@ exports[`Group renders group with anonymous functions 2`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -711,10 +735,12 @@ exports[`Group renders group with anonymous functions 2`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -756,10 +782,12 @@ exports[`Group renders group with anonymous functions 2`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -807,10 +835,12 @@ exports[`Group renders group with anonymous functions 2`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", @@ -852,10 +882,12 @@ exports[`Group renders group with anonymous functions 2`] = ` "type": "block", }, "source": Object { + "actors": Array [], "contentType": "text/javascript", "id": "source", "introductionUrl": null, "isBlackBoxed": false, + "isExtension": false, "isPrettyPrinted": false, "isWasm": false, "loadedState": "unloaded", diff --git a/devtools/client/debugger/new/src/components/SecondaryPanes/Scopes.js b/devtools/client/debugger/new/src/components/SecondaryPanes/Scopes.js index 60d0588e60479..e07d98a2d0b35 100644 --- a/devtools/client/debugger/new/src/components/SecondaryPanes/Scopes.js +++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Scopes.js @@ -116,7 +116,6 @@ class Scopes extends PureComponent { autoExpandAll={false} autoExpandDepth={1} disableWrap={true} - focusable={false} dimTopLevelWindow={true} openLink={openLink} createObjectClient={grip => createObjectClient(grip)} diff --git a/devtools/client/debugger/new/src/components/SecondaryPanes/SecondaryPanes.css b/devtools/client/debugger/new/src/components/SecondaryPanes/SecondaryPanes.css index a7399cdc4d3ac..6363a61fdfd77 100644 --- a/devtools/client/debugger/new/src/components/SecondaryPanes/SecondaryPanes.css +++ b/devtools/client/debugger/new/src/components/SecondaryPanes/SecondaryPanes.css @@ -17,7 +17,7 @@ This allows the commandbar to remain fixed when scrolling until the content completely ends. Not just the height of the wrapper. - Ref: https://github.com/devtools-html/debugger.html/issues/3426 + Ref: https://github.com/firefox-devtools/debugger.html/issues/3426 */ .secondary-panes-wrapper { diff --git a/devtools/client/debugger/new/src/components/SecondaryPanes/tests/__snapshots__/Expressions.spec.js.snap b/devtools/client/debugger/new/src/components/SecondaryPanes/tests/__snapshots__/Expressions.spec.js.snap index 6087f247d8d42..bb8b0310a46e4 100644 --- a/devtools/client/debugger/new/src/components/SecondaryPanes/tests/__snapshots__/Expressions.spec.js.snap +++ b/devtools/client/debugger/new/src/components/SecondaryPanes/tests/__snapshots__/Expressions.spec.js.snap @@ -17,7 +17,6 @@ exports[`Expressions should always have unique keys 1`] = ` autoExpandDepth={0} createObjectClient={[Function]} disableWrap={true} - focusable={false} onDOMNodeClick={[Function]} onInspectIconClick={[Function]} roots={ @@ -58,7 +57,6 @@ exports[`Expressions should always have unique keys 1`] = ` autoExpandDepth={0} createObjectClient={[Function]} disableWrap={true} - focusable={false} onDOMNodeClick={[Function]} onInspectIconClick={[Function]} roots={ @@ -133,7 +131,6 @@ exports[`Expressions should render 1`] = ` autoExpandDepth={0} createObjectClient={[Function]} disableWrap={true} - focusable={false} onDOMNodeClick={[Function]} onInspectIconClick={[Function]} roots={ @@ -174,7 +171,6 @@ exports[`Expressions should render 1`] = ` autoExpandDepth={0} createObjectClient={[Function]} disableWrap={true} - focusable={false} onDOMNodeClick={[Function]} onInspectIconClick={[Function]} roots={ diff --git a/devtools/client/debugger/new/src/components/shared/Button/PaneToggleButton.js b/devtools/client/debugger/new/src/components/shared/Button/PaneToggleButton.js index c3931a80149d8..d15c1a857faba 100644 --- a/devtools/client/debugger/new/src/components/shared/Button/PaneToggleButton.js +++ b/devtools/client/debugger/new/src/components/shared/Button/PaneToggleButton.js @@ -9,23 +9,34 @@ import AccessibleImage from "../AccessibleImage"; import { CommandBarButton } from "./"; import "./styles/PaneToggleButton.css"; +type Position = "start" | "end"; + type Props = { collapsed: boolean, - handleClick: (string, boolean) => void, + handleClick: (Position, boolean) => void, horizontal: boolean, - position: string + position: Position }; class PaneToggleButton extends PureComponent { static defaultProps = { - horizontal: false + horizontal: false, + position: "start" }; + label(position: Position, collapsed: boolean) { + switch (position) { + case "start": + return L10N.getStr(collapsed ? "expandSources" : "collapseSources"); + case "end": + return L10N.getStr( + collapsed ? "expandBreakpoints" : "collapseBreakpoints" + ); + } + } + render() { const { position, collapsed, horizontal, handleClick } = this.props; - const title = collapsed - ? L10N.getStr("expandPanes") - : L10N.getStr("collapsePanes"); return ( { vertical: !horizontal })} onClick={() => handleClick(position, !collapsed)} - title={title} + title={this.label(position, collapsed)} > { ); @@ -44,7 +44,7 @@ describe("PaneToggleButton", () => { }); it("handleClick is called", () => { - const position = "testPosition"; + const position = "end"; const collapsed = false; wrapper.setProps({ position, collapsed }); wrapper.simulate("click"); diff --git a/devtools/client/debugger/new/src/components/shared/Button/tests/__snapshots__/PaneToggleButton.spec.js.snap b/devtools/client/debugger/new/src/components/shared/Button/tests/__snapshots__/PaneToggleButton.spec.js.snap index 058e190933c4d..86067066a6949 100644 --- a/devtools/client/debugger/new/src/components/shared/Button/tests/__snapshots__/PaneToggleButton.spec.js.snap +++ b/devtools/client/debugger/new/src/components/shared/Button/tests/__snapshots__/PaneToggleButton.spec.js.snap @@ -2,9 +2,9 @@ exports[`PaneToggleButton renders default 1`] = `
    @@ -251,6 +253,7 @@ exports[`ManagedTree sets expanded items 1`] = `
    @@ -279,6 +283,7 @@ exports[`ManagedTree sets expanded items 1`] = `
    @@ -442,6 +448,7 @@ exports[`ManagedTree sets expanded items 2`] = ` tabIndex="0" >
    @@ -469,6 +477,7 @@ exports[`ManagedTree sets expanded items 2`] = `
    @@ -497,6 +507,7 @@ exports[`ManagedTree sets expanded items 2`] = `
    diff --git a/devtools/client/debugger/new/src/components/test/__snapshots__/ProjectSearch.spec.js.snap b/devtools/client/debugger/new/src/components/test/__snapshots__/ProjectSearch.spec.js.snap index 4dc8bbe119abc..b44717af8547e 100644 --- a/devtools/client/debugger/new/src/components/test/__snapshots__/ProjectSearch.spec.js.snap +++ b/devtools/client/debugger/new/src/components/test/__snapshots__/ProjectSearch.spec.js.snap @@ -229,6 +229,7 @@ exports[`ProjectSearch found search results 1`] = ` tabIndex="0" >
    ; -export type PausePoint = { - location: Position, - generatedLocation: SourceLocation, - types: { break: boolean, step: boolean } -}; - -export type PausePointsMap = { - [line: string]: { [column: string]: PausePoint } -}; -export type PausePoints = PausePoint[]; -export type PausePointsState = Map; - export type Preview = | {| updating: true |} | null @@ -62,7 +49,6 @@ export type ASTState = { outOfScopeLocations: ?Array, inScopeLines: ?Array, preview: Preview, - pausePoints: PausePointsState, sourceMetaData: SourceMetaDataMap }; @@ -73,7 +59,6 @@ export function initialASTState(): Record { outOfScopeLocations: null, inScopeLines: null, preview: null, - pausePoints: I.Map(), sourceMetaData: I.Map() })(); } @@ -93,15 +78,6 @@ function update( return state.setIn(["symbols", sourceId], value); } - case "SET_PAUSE_POINTS": { - const { sourceText, sourceId, pausePoints } = action; - const emptyLines = findEmptyLines(sourceText, pausePoints); - - return state - .setIn(["pausePoints", sourceId], pausePoints) - .setIn(["emptyLines", sourceId], emptyLines); - } - case "OUT_OF_SCOPE_LOCATIONS": { return state.set("outOfScopeLocations", action.locations); } @@ -156,7 +132,7 @@ function update( } // NOTE: we'd like to have the app state fully typed -// https://github.com/devtools-html/debugger.html/blob/master/src/reducers/sources.js#L179-L185 +// https://github.com/firefox-devtools/debugger.html/blob/master/src/reducers/sources.js#L179-L185 type OuterState = { ast: Record }; export function getSymbols(state: OuterState, source: ?Source): ?Symbols { @@ -195,48 +171,6 @@ export function isEmptyLineInSource( return emptyLines && emptyLines.includes(line); } -export function getEmptyLines(state: OuterState, sourceId: string) { - if (!sourceId) { - return null; - } - - return state.ast.emptyLines.get(sourceId); -} - -export function getPausePoints( - state: OuterState, - sourceId: string -): ?PausePoints { - return state.ast.pausePoints.get(sourceId); -} - -export function getPausePoint( - state: OuterState, - location: ?SourceLocation -): ?PausePoint { - if (!location) { - return; - } - - const { column, line, sourceId } = location; - const pausePoints = getPausePoints(state, sourceId); - if (!pausePoints) { - return; - } - - for (const point of pausePoints) { - const { location: pointLocation } = point; - if (pointLocation.line == line && pointLocation.column == column) { - return point; - } - } -} - -export function hasPausePoints(state: OuterState, sourceId: string): boolean { - const pausePoints = getPausePoints(state, sourceId); - return !!pausePoints; -} - export function getOutOfScopeLocations(state: OuterState) { return state.ast.get("outOfScopeLocations"); } @@ -263,4 +197,12 @@ export function isLineInScope(state: OuterState, line: number) { return linesInScope && linesInScope.includes(line); } +export function getEmptyLines(state: OuterState, sourceId: string) { + if (!sourceId) { + return null; + } + + return state.ast.emptyLines.get(sourceId); +} + export default update; diff --git a/devtools/client/debugger/new/src/reducers/breakpoints.js b/devtools/client/debugger/new/src/reducers/breakpoints.js index f158ca5f28927..4561dc3d28070 100644 --- a/devtools/client/debugger/new/src/reducers/breakpoints.js +++ b/devtools/client/debugger/new/src/reducers/breakpoints.js @@ -9,7 +9,7 @@ * @module reducers/breakpoints */ -import { isGeneratedId } from "devtools-source-map"; +import { isGeneratedId, isOriginalId } from "devtools-source-map"; import { isEqual } from "lodash"; import { makeBreakpointId } from "../utils/breakpoint"; @@ -19,18 +19,17 @@ import type { Breakpoint, BreakpointId, SourceLocation, - BreakpointPositions, - BreakpointLinePositions, - BreakpointSourcePositions + BreakpointPositions } from "../types"; import type { Action, DonePromiseAction } from "../actions/types"; export type BreakpointsMap = { [BreakpointId]: Breakpoint }; export type XHRBreakpointsList = $ReadOnlyArray; +export type BreakpointPositionsMap = { [string]: BreakpointPositions }; export type BreakpointsState = { breakpoints: BreakpointsMap, - breakpointPositions: BreakpointPositions, + breakpointPositions: BreakpointPositionsMap, xhrBreakpoints: XHRBreakpointsList, breakpointsDisabled: boolean }; @@ -113,15 +112,14 @@ function update( case "ADD_BREAKPOINT_POSITIONS": { const { - location: { sourceId, line }, + location: { sourceId }, positions } = action; - const sourcePositions = state.breakpointPositions[sourceId] || {}; return { ...state, breakpointPositions: { ...state.breakpointPositions, - [sourceId]: { ...sourcePositions, [line]: positions } + [sourceId]: positions } }; } @@ -354,14 +352,14 @@ export function getHiddenBreakpoint(state: OuterState): ?Breakpoint { export function getBreakpointPositions( state: OuterState -): ?BreakpointPositions { +): BreakpointPositionsMap { return state.breakpoints.breakpointPositions; } export function getBreakpointPositionsForSource( state: OuterState, sourceId: string -): ?BreakpointSourcePositions { +): ?BreakpointPositions { const positions = getBreakpointPositions(state); return positions && positions[sourceId]; } @@ -370,9 +368,15 @@ export function getBreakpointPositionsForLine( state: OuterState, sourceId: string, line: number -): ?BreakpointLinePositions { +): ?BreakpointPositions { const positions = getBreakpointPositionsForSource(state, sourceId); - return positions ? positions[line] : null; + if (!positions) { + return []; + } + return positions.filter(({ location, generatedLocation }) => { + const loc = isOriginalId(sourceId) ? location : generatedLocation; + return loc.line == line; + }); } export default update; diff --git a/devtools/client/debugger/new/src/reducers/file-search.js b/devtools/client/debugger/new/src/reducers/file-search.js index e8b9589a0c8fe..57151dfd1e401 100644 --- a/devtools/client/debugger/new/src/reducers/file-search.js +++ b/devtools/client/debugger/new/src/reducers/file-search.js @@ -98,7 +98,7 @@ function update( } // NOTE: we'd like to have the app state fully typed -// https://github.com/devtools-html/debugger.html/blob/master/src/reducers/sources.js#L179-L185 +// https://github.com/firefox-devtools/debugger.html/blob/master/src/reducers/sources.js#L179-L185 type OuterState = { fileSearch: Record }; export function getFileSearchQuery(state: OuterState): string { diff --git a/devtools/client/debugger/new/src/reducers/pause.js b/devtools/client/debugger/new/src/reducers/pause.js index a3cef3d2b5ba0..e64c95350505f 100644 --- a/devtools/client/debugger/new/src/reducers/pause.js +++ b/devtools/client/debugger/new/src/reducers/pause.js @@ -359,10 +359,6 @@ export function getPauseCommand(state: OuterState): Command { return getCurrentPauseState(state).command; } -export function getLastCommand(state: OuterState, thread: string) { - return getThreadPauseState(state.pause, thread).lastCommand; -} - export function wasStepping(state: OuterState): boolean { return getCurrentPauseState(state).wasStepping; } diff --git a/devtools/client/debugger/new/src/reducers/sources.js b/devtools/client/debugger/new/src/reducers/sources.js index cafee5098b336..7537775953abc 100644 --- a/devtools/client/debugger/new/src/reducers/sources.js +++ b/devtools/client/debugger/new/src/reducers/sources.js @@ -24,7 +24,6 @@ import { prefs } from "../utils/prefs"; import type { Source, - SourceActor, SourceId, SourceLocation, ThreadId, @@ -33,32 +32,26 @@ import type { import type { PendingSelectedLocation, Selector } from "./types"; import type { Action, DonePromiseAction, FocusItem } from "../actions/types"; import type { LoadSourceAction } from "../actions/types/SourceAction"; -import { omitBy, mapValues } from "lodash"; +import { mapValues, uniqBy } from "lodash"; export type SourcesMap = { [SourceId]: Source }; export type SourcesMapByThread = { [ThreadId]: SourcesMap }; -type SourceActorsMap = { [SourceId]: SourceActor[] }; type UrlsMap = { [string]: SourceId[] }; -type GetRelativeSourcesSelector = OuterState => SourcesMapByThread; +type DisplayedSources = { [ThreadId]: { [SourceId]: boolean } }; +type GetDisplayedSourcesSelector = OuterState => { [ThreadId]: SourcesMap }; export type SourcesState = { // All known sources. sources: SourcesMap, - // Actors associated with each source. - sourceActors: SourceActorsMap, - // All sources associated with a given URL. When using source maps, multiple // sources can have the same URL. urls: UrlsMap, - // All original sources associated with a generated source. - originalSources: { [SourceId]: SourceId[] }, - // For each thread, all sources in that thread that are under the project root // and should be shown in the editor's sources pane. - relativeSources: SourcesMapByThread, + displayed: DisplayedSources, pendingSelectedLocation?: PendingSelectedLocation, selectedLocation: ?SourceLocation, @@ -67,13 +60,15 @@ export type SourcesState = { focusedItem: ?FocusItem }; +const emptySources = { + sources: {}, + urls: {}, + displayed: {} +}; + export function initialSourcesState(): SourcesState { return { - sources: {}, - sourceActors: {}, - urls: {}, - originalSources: {}, - relativeSources: {}, + ...emptySources, selectedLocation: undefined, pendingSelectedLocation: prefs.pendingSelectedLocation, projectDirectoryRoot: prefs.projectDirectoryRoot, @@ -82,7 +77,8 @@ export function initialSourcesState(): SourcesState { }; } -export function createSource(source: Object): Source { +export function createSource(state: SourcesState, source: Object): Source { + const root = state.projectDirectoryRoot; return { id: undefined, url: undefined, @@ -95,6 +91,8 @@ export function createSource(source: Object): Source { contentType: "", error: undefined, loadedState: "unloaded", + relativeUrl: getRelativeUrl(source, root), + actors: [], ...source }; } @@ -113,7 +111,7 @@ function update( return updateSources(state, [action.source]); case "ADD_SOURCES": - return updateSources(state, action.sources, action.sourceActors); + return updateSources(state, action.sources); case "SET_WORKERS": return updateWorkers(state, action.workers, action.mainThread); @@ -214,56 +212,30 @@ function setSourceTextProps(state, action: LoadSourceAction): SourcesState { return updateSources(state, [source]); } -function updateSources(state, sources, sourceActors) { - const relativeSources = { ...state.relativeSources }; - for (const thread in relativeSources) { - relativeSources[thread] = { ...relativeSources[thread] }; +function updateSources(state, sources: Object[]) { + const displayed = { ...state.displayed }; + for (const thread in displayed) { + displayed[thread] = { ...displayed[thread] }; } state = { ...state, sources: { ...state.sources }, - sourceActors: { ...state.sourceActors }, urls: { ...state.urls }, - originalSources: { ...state.originalSources }, - relativeSources + displayed }; sources.forEach(source => updateSource(state, source)); - if (sourceActors) { - sourceActors.forEach(sourceActor => - updateForNewSourceActor(state, sourceActor) - ); - } - return state; } -function updateSourceUrl(state: SourcesState, source: Object) { +function updateSourceUrl(state: SourcesState, source: Source) { const existing = state.urls[source.url] || []; if (!existing.includes(source.id)) { state.urls[source.url] = [...existing, source.id]; } } -function updateOriginalSources(state: SourcesState, source: Object) { - if (!isOriginalSource(source)) { - return; - } - const generatedId = originalToGeneratedId(source.id); - const existing = state.originalSources[generatedId] || []; - if (!existing.includes(source.id)) { - state.originalSources[generatedId] = [...existing, source.id]; - - // Update relative sources for any affected threads. - if (state.sourceActors[generatedId]) { - for (const sourceActor of state.sourceActors[generatedId]) { - updateRelativeSource(state, source, sourceActor); - } - } - } -} - function updateSource(state: SourcesState, source: Object) { if (!source.id) { return; @@ -272,64 +244,46 @@ function updateSource(state: SourcesState, source: Object) { const existingSource = state.sources[source.id]; const updatedSource = existingSource ? { ...existingSource, ...source } - : createSource(source); + : createSource(state, source); - state.sources[source.id] = updatedSource; - - updateExistingRelativeSource(state, source); - updateSourceUrl(state, source); - updateOriginalSources(state, source); -} + // Any actors in the source are added to the existing ones. + if (existingSource && source.actors) { + updatedSource.actors = uniqBy( + [...existingSource.actors, ...updatedSource.actors], + ({ actor }) => actor + ); + } -function updateExistingRelativeSource(state: SourcesState, source: Object) { - const relativeSources = { ...state.relativeSources }; + state.sources[source.id] = updatedSource; - for (const thread in relativeSources) { - if (relativeSources[thread][source.id]) { - relativeSources[thread] = { ...relativeSources[thread] }; - const existingRelativeSource = relativeSources[thread][source.id]; - const updatedRelativeSource = { ...existingRelativeSource, ...source }; - state.relativeSources[thread][source.id] = updatedRelativeSource; - } - } + updateSourceUrl(state, updatedSource); + updateDisplayedSource(state, updatedSource); } -function updateRelativeSource( - state: SourcesState, - source: Object, - sourceActor: SourceActor -) { +function updateDisplayedSource(state: SourcesState, source: Source) { const root = state.projectDirectoryRoot; - if (!underRoot(source, root)) { + if ( + !underRoot(source, root) || + (!getChromeAndExtenstionsEnabled({ sources: state }) && source.isExtension) + ) { return; } - const relativeSource: Source = ({ - ...source, - relativeUrl: getRelativeUrl(source, root) - }: any); + let actors = source.actors; - if (!state.relativeSources[sourceActor.thread]) { - state.relativeSources[sourceActor.thread] = {}; + // Original sources do not have actors, so use the generated source. + if (isOriginalSource(source)) { + const generatedSource = state.sources[originalToGeneratedId(source.id)]; + actors = generatedSource ? generatedSource.actors : []; } - state.relativeSources[sourceActor.thread][source.id] = relativeSource; -} - -function updateForNewSourceActor( - state: SourcesState, - sourceActor: SourceActor -) { - const existing = state.sourceActors[sourceActor.source] || []; - - // Do not allow duplicate source actors in the store. - if (existing.some(({ actor }) => actor == sourceActor.actor)) { - return; - } - - state.sourceActors[sourceActor.source] = [...existing, sourceActor]; - updateRelativeSource(state, state.sources[sourceActor.source], sourceActor); + actors.forEach(({ thread }) => { + if (!state.displayed[thread]) { + state.displayed[thread] = {}; + } + state.displayed[thread][source.id] = true; + }); } function updateWorkers( @@ -337,44 +291,32 @@ function updateWorkers( workers: WorkerList, mainThread: ThreadId ) { - // Clear out actors for any removed workers by regenerating source actor - // state for all remaining workers. - const sourceActors = []; - for (const actors: any of Object.values(state.sourceActors)) { - for (const sourceActor of actors) { - if ( - workers.some(worker => worker.actor == sourceActor.thread) || - mainThread == sourceActor.thread - ) { - sourceActors.push(sourceActor); - } - } - } + // Filter out source actors for all removed threads. + const threads = [mainThread, ...workers.map(({ actor }) => actor)]; + const updateActors = source => + source.actors.filter(({ thread }) => threads.includes(thread)); - return updateSources( - { ...state, sourceActors: {}, relativeSources: {} }, - [], - sourceActors - ); + const sources: Source[] = Object.values(state.sources) + .map((source: any) => ({ ...source, actors: updateActors(source) })) + + // Regenerate derived information from the updated sources. + return updateSources({ ...state, ...emptySources }, sources); } function updateProjectDirectoryRoot(state: SourcesState, root: string) { prefs.projectDirectoryRoot = root; - const sourceActors = []; - for (const actors: any of Object.values(state.sourceActors)) { - actors.forEach(sourceActor => sourceActors.push(sourceActor)); - } + const sources: Source[] = Object.values(state.sources).map((source: any) => { + return { + ...source, + relativeUrl: getRelativeUrl(source, root) + }; + }); + // Regenerate derived information from the updated sources. return updateSources( - { - ...state, - projectDirectoryRoot: root, - sourceActors: {}, - relativeSources: {} - }, - [], - sourceActors + { ...state, projectDirectoryRoot: root, ...emptySources }, + sources ); } @@ -408,43 +350,53 @@ type OuterState = { sources: SourcesState }; const getSourcesState = (state: OuterState) => state.sources; -export function getSource(state: OuterState, id: SourceId) { +export function getSourceInSources(sources: SourcesMap, id: string): ?Source { + return sources[id]; +} + +export function getSource(state: OuterState, id: SourceId): ?Source { return getSourceInSources(getSources(state), id); } export function getSourceFromId(state: OuterState, id: string): Source { - return getSourcesState(state).sources[id]; + const source = getSource(state, id); + if (!source) { + throw new Error(`source ${id} does not exist`); + } + return source; } -export function getSourceActors(state: OuterState, id: SourceId) { - return getSourcesState(state).sourceActors[id] || []; +export function getSourcesByURLInSources( + sources: SourcesMap, + urls: UrlsMap, + url: string +): Source[] { + if (!url || !urls[url]) { + return []; + } + return urls[url].map(id => sources[id]); } -export function hasSourceActor(state: OuterState, sourceActor: SourceActor) { - const existing = getSourceActors(state, sourceActor.source); - return existing.some(({ actor }) => actor == sourceActor.actor); +export function getSourcesByURL(state: OuterState, url: string): Source[] { + return getSourcesByURLInSources(getSources(state), getUrls(state), url); } -export function getOriginalSourceByURL( - state: OuterState, - url: string -): ?Source { - return getOriginalSourceByUrlInSources( - getSources(state), - getUrls(state), - url - ); +export function getSourceByURL(state: OuterState, url: string): ?Source { + const foundSources = getSourcesByURL(state, url); + return foundSources ? foundSources[0] : null; } -export function getGeneratedSourceByURL( - state: OuterState, - url: string +export function getSpecificSourceByURLInSources( + sources: SourcesMap, + urls: UrlsMap, + url: string, + isOriginal: boolean ): ?Source { - return getGeneratedSourceByUrlInSources( - getSources(state), - getUrls(state), - url - ); + const foundSources = getSourcesByURLInSources(sources, urls, url); + if (foundSources) { + return foundSources.find(source => isOriginalSource(source) == isOriginal); + } + return null; } export function getSpecificSourceByURL( @@ -452,21 +404,26 @@ export function getSpecificSourceByURL( url: string, isOriginal: boolean ): ?Source { - return isOriginal - ? getOriginalSourceByUrlInSources(getSources(state), getUrls(state), url) - : getGeneratedSourceByUrlInSources(getSources(state), getUrls(state), url); -} - -export function getSourceByURL(state: OuterState, url: string): ?Source { - return getSourceByUrlInSources(getSources(state), getUrls(state), url); + return getSpecificSourceByURLInSources( + getSources(state), + getUrls(state), + url, + isOriginal + ); } -export function getSourcesByURLs(state: OuterState, urls: string[]) { - return urls.map(url => getSourceByURL(state, url)).filter(Boolean); +export function getOriginalSourceByURL( + state: OuterState, + url: string +): ?Source { + return getSpecificSourceByURL(state, url, true); } -export function getSourcesByURL(state: OuterState, url: string): Source[] { - return getSourcesByUrlInSources(getSources(state), getUrls(state), url); +export function getGeneratedSourceByURL( + state: OuterState, + url: string +): ?Source { + return getSpecificSourceByURL(state, url, false); } export function getGeneratedSource( @@ -498,70 +455,13 @@ export function getPrettySource(state: OuterState, id: ?string) { return; } - return getSpecificSourceByURL(state, getPrettySourceURL(source.url), true); + return getOriginalSourceByURL(state, getPrettySourceURL(source.url)); } export function hasPrettySource(state: OuterState, id: string) { return !!getPrettySource(state, id); } -function getSourceHelper( - original: boolean, - sources: SourcesMap, - urls: UrlsMap, - url: string -) { - const foundSources = getSourcesByUrlInSources(sources, urls, url); - if (!foundSources) { - return null; - } - - return foundSources.find(source => isOriginalSource(source) == original); -} - -export const getOriginalSourceByUrlInSources = getSourceHelper.bind(null, true); - -export const getGeneratedSourceByUrlInSources = getSourceHelper.bind( - null, - false -); - -export function getSpecificSourceByUrlInSources( - sources: SourcesMap, - urls: UrlsMap, - url: string, - isOriginal: boolean -) { - return isOriginal - ? getOriginalSourceByUrlInSources(sources, urls, url) - : getGeneratedSourceByUrlInSources(sources, urls, url); -} - -export function getSourceByUrlInSources( - sources: SourcesMap, - urls: UrlsMap, - url: string -) { - const foundSources = getSourcesByUrlInSources(sources, urls, url); - if (!foundSources) { - return null; - } - - return foundSources[0]; -} - -function getSourcesByUrlInSources( - sources: SourcesMap, - urls: UrlsMap, - url: string -) { - if (!url || !urls[url]) { - return []; - } - - return urls[url].map(id => sources[id]); -} - export function getSourcesUrlsInSources( state: OuterState, url: string @@ -585,10 +485,6 @@ export function getHasSiblingOfSameName(state: OuterState, source: ?Source) { return getSourcesUrlsInSources(state, source.url).length > 1; } -export function getSourceInSources(sources: SourcesMap, id: string): ?Source { - return sources[id]; -} - export function getSources(state: OuterState) { return state.sources.sources; } @@ -601,8 +497,8 @@ export function getSourceList(state: OuterState): Source[] { return (Object.values(getSources(state)): any); } -export function getRelativeSourcesList(state: OuterState): Source[] { - return ((Object.values(getRelativeSources(state)): any).flatMap( +export function getDisplayedSourcesList(state: OuterState): Source[] { + return ((Object.values(getDisplayedSources(state)): any).flatMap( Object.values ): any); } @@ -632,32 +528,30 @@ export function getProjectDirectoryRoot(state: OuterState): string { return state.sources.projectDirectoryRoot; } -function getAllRelativeSources(state: OuterState): SourcesMapByThread { - return state.sources.relativeSources; +function getAllDisplayedSources(state: OuterState) { + return state.sources.displayed; } function getChromeAndExtenstionsEnabled(state: OuterState) { return state.sources.chromeAndExtenstionsEnabled; } -export const getRelativeSources: GetRelativeSourcesSelector = createSelector( +export const getDisplayedSources: GetDisplayedSourcesSelector = createSelector( + getSources, getChromeAndExtenstionsEnabled, - getAllRelativeSources, - (chromeAndExtenstionsEnabled, relativeSources) => { - if (!chromeAndExtenstionsEnabled) { - return mapValues(relativeSources, threadSources => { - return omitBy(threadSources, source => source.isExtension); - }); - } - return relativeSources; + getAllDisplayedSources, + (sources, chromeAndExtenstionsEnabled, displayed) => { + return mapValues(displayed, threadSourceIds => + mapValues(threadSourceIds, (_, id) => sources[id]) + ); } ); -export function getRelativeSourcesForThread( +export function getDisplayedSourcesForThread( state: OuterState, thread: string ): SourcesMap { - return getRelativeSources(state)[thread] || {}; + return getDisplayedSources(state)[thread] || {}; } export function getFocusedSourceItem(state: OuterState): ?FocusItem { diff --git a/devtools/client/debugger/new/src/reducers/tabs.js b/devtools/client/debugger/new/src/reducers/tabs.js index ab12ef94aaf46..b4b1c8cc79556 100644 --- a/devtools/client/debugger/new/src/reducers/tabs.js +++ b/devtools/client/debugger/new/src/reducers/tabs.js @@ -19,7 +19,7 @@ import { getSources, getUrls, getSpecificSourceByURL, - getSpecificSourceByUrlInSources + getSpecificSourceByURLInSources } from "./sources"; import type { Action } from "../actions/types"; @@ -167,9 +167,8 @@ export function getNewSelectedSourceId( const availableTab = availableTabs[newSelectedTabIndex]; if (availableTab) { - const tabSource = getSpecificSourceByUrlInSources( - getSources(state), - getUrls(state), + const tabSource = getSpecificSourceByURL( + state, availableTab.url, availableTab.isOriginal ); @@ -213,7 +212,7 @@ export const getSourcesForTabs: Selector = createSelector( function getTabWithOrWithoutUrl(tab, sources, urls) { if (tab.url) { - return getSpecificSourceByUrlInSources( + return getSpecificSourceByURLInSources( sources, urls, tab.url, diff --git a/devtools/client/debugger/new/src/reducers/tests/sources.spec.js b/devtools/client/debugger/new/src/reducers/tests/sources.spec.js index 38c6cdba72eee..adc2445f0553e 100644 --- a/devtools/client/debugger/new/src/reducers/tests/sources.spec.js +++ b/devtools/client/debugger/new/src/reducers/tests/sources.spec.js @@ -7,44 +7,45 @@ declare var describe: (name: string, func: () => void) => void; declare var it: (desc: string, func: () => void) => void; declare var expect: (value: any) => any; -import update, { initialSourcesState, getRelativeSources } from "../sources"; +import update, { initialSourcesState, getDisplayedSources } from "../sources"; import { foobar } from "../../test/fixtures"; import type { Source } from "../../types"; import { prefs } from "../../utils/prefs"; const fakeSources = foobar.sources.sources; -const extenstionSource = { - id: "extenstionId", - url: "http://example.com/script.js" +const extensionSource = { + id: "extensionId", + url: "http://example.com/script.js", + actors: [{ actor: "extensionId-actor", source: "extensionId", thread: "foo" }] }; const firefoxExtensionSource = { id: "firefoxExtension", - url: "moz-extension://id/js/content.js" + url: "moz-extension://id/js/content.js", + actors: [ + { + actor: "firefoxExtension-actor", + source: "firefoxExtension", + thread: "foo" + } + ] }; const chromeExtensionSource = { id: "chromeExtension", - url: "chrome-extension://id/js/content.js" + url: "chrome-extension://id/js/content.js", + actors: [ + { actor: "chromeExtension-actor", source: "chromeExtension", thread: "foo" } + ] }; const mockedSources = [ - extenstionSource, + extensionSource, firefoxExtensionSource, chromeExtensionSource ]; -const mockedSourceActors = [ - { actor: "extensionId-actor", source: "extenstionId", thread: "foo" }, - { - actor: "firefoxExtension-actor", - source: "firefoxExtension", - thread: "foo" - }, - { actor: "chromeExtension-actor", source: "chromeExtension", thread: "foo" } -]; - describe("sources reducer", () => { it("should work", () => { let state = initialSourcesState(); @@ -65,12 +66,11 @@ describe("sources selectors", () => { sources: update(state, { type: "ADD_SOURCES", // coercing to a Source for the purpose of this test - sources: ((mockedSources: any): Source[]), - sourceActors: mockedSourceActors + sources: ((mockedSources: any): Source[]) }) }; - const selectedRelativeSources = getRelativeSources(state); - const threadSources = selectedRelativeSources.foo; + const selectedDisplayedSources = getDisplayedSources(state); + const threadSources = selectedDisplayedSources.foo; expect(Object.values(threadSources)).toHaveLength(3); }); @@ -81,12 +81,11 @@ describe("sources selectors", () => { sources: update(state, { type: "ADD_SOURCES", // coercing to a Source for the purpose of this test - sources: ((mockedSources: any): Source[]), - sourceActors: mockedSourceActors + sources: ((mockedSources: any): Source[]) }) }; - const selectedRelativeSources = getRelativeSources(state); - const threadSources = selectedRelativeSources.foo; + const selectedDisplayedSources = getDisplayedSources(state); + const threadSources = selectedDisplayedSources.foo; expect(Object.values(threadSources)).toHaveLength(1); }); }); diff --git a/devtools/client/debugger/new/src/reducers/types.js b/devtools/client/debugger/new/src/reducers/types.js index 092f61bcfd929..67d9245c81af7 100644 --- a/devtools/client/debugger/new/src/reducers/types.js +++ b/devtools/client/debugger/new/src/reducers/types.js @@ -50,10 +50,4 @@ export type { SourcesMap, SourcesMapByThread } from "./sources"; export type { ActiveSearchType, OrientationType } from "./ui"; export type { BreakpointsMap, XHRBreakpointsList } from "./breakpoints"; export type { Command } from "./pause"; -export type { - SourceMetaDataMap, - SourceMetaDataType, - PausePoints, - PausePointsMap, - PausePoint -} from "./ast"; +export type { SourceMetaDataMap, SourceMetaDataType } from "./ast"; diff --git a/devtools/client/debugger/new/src/reducers/ui.js b/devtools/client/debugger/new/src/reducers/ui.js index b67ba7c1d3566..42aa70dbc577b 100644 --- a/devtools/client/debugger/new/src/reducers/ui.js +++ b/devtools/client/debugger/new/src/reducers/ui.js @@ -136,7 +136,7 @@ function update( } // NOTE: we'd like to have the app state fully typed -// https://github.com/devtools-html/debugger.html/blob/master/src/reducers/sources.js#L179-L185 +// https://github.com/firefox-devtools/debugger.html/blob/master/src/reducers/sources.js#L179-L185 type OuterState = { ui: Record }; export function getSelectedPrimaryPaneTab( diff --git a/devtools/client/debugger/new/src/selectors/index.js b/devtools/client/debugger/new/src/selectors/index.js index 4927f521f4966..3641b82f930b2 100644 --- a/devtools/client/debugger/new/src/selectors/index.js +++ b/devtools/client/debugger/new/src/selectors/index.js @@ -40,7 +40,6 @@ export { getVisibleSelectedFrame } from "./visibleSelectedFrame"; export { getBreakpointSources } from "./breakpointSources"; export { getXHRBreakpoints, shouldPauseOnAnyXHR } from "./breakpoints"; export { visibleColumnBreakpoints } from "./visibleColumnBreakpoints"; -export { getVisiblePausePoints } from "./visiblePausePoints"; import { objectInspector } from "devtools-reps"; diff --git a/devtools/client/debugger/new/src/selectors/moz.build b/devtools/client/debugger/new/src/selectors/moz.build index bd6503eaff88a..476b36348fd6a 100644 --- a/devtools/client/debugger/new/src/selectors/moz.build +++ b/devtools/client/debugger/new/src/selectors/moz.build @@ -17,6 +17,5 @@ DebuggerModules( 'isSelectedFrameVisible.js', 'visibleBreakpoints.js', 'visibleColumnBreakpoints.js', - 'visiblePausePoints.js', 'visibleSelectedFrame.js', ) diff --git a/devtools/client/debugger/new/src/selectors/test/visibleColumnBreakpoints.spec.js b/devtools/client/debugger/new/src/selectors/test/visibleColumnBreakpoints.spec.js index 4dabcabf44409..f613be1d9e7e6 100644 --- a/devtools/client/debugger/new/src/selectors/test/visibleColumnBreakpoints.spec.js +++ b/devtools/client/debugger/new/src/selectors/test/visibleColumnBreakpoints.spec.js @@ -9,8 +9,8 @@ import { makeMockSource, makeMockBreakpoint } from "../../utils/test-mockup"; function pp(line, column) { return { - location: { sourceId: "", line, column }, - generatedLocation: { sourceId: "", line, column }, + location: { sourceId: "foo", line, column }, + generatedLocation: { sourceId: "foo", line, column }, types: { break: true, step: false } }; } @@ -32,13 +32,7 @@ describe("visible column breakpoints", () => { const pausePoints = [pp(1, 1), pp(1, 5), pp(3, 1)]; const breakpoints = [bp(1, 1), bp(4, 0), bp(4, 3)]; - const selectedSource = defaultSource(); - const columnBps = getColumnBreakpoints( - pausePoints, - breakpoints, - viewport, - selectedSource - ); + const columnBps = getColumnBreakpoints(pausePoints, breakpoints, viewport); expect(columnBps).toMatchSnapshot(); }); @@ -49,13 +43,8 @@ describe("visible column breakpoints", () => { }; const pausePoints = [pp(1, 1), pp(1, 1), pp(1, 3)]; const breakpoints = [bp(1, 1)]; - const selectedSource = defaultSource(); - const columnBps = getColumnBreakpoints( - pausePoints, - breakpoints, - viewport, - selectedSource - ); + + const columnBps = getColumnBreakpoints(pausePoints, breakpoints, viewport); expect(columnBps).toMatchSnapshot(); }); @@ -66,13 +55,7 @@ describe("visible column breakpoints", () => { }; const pausePoints = [pp(1, 1), pp(1, 3), pp(2, 1)]; const breakpoints = [bp(1, 1)]; - const selectedSource = defaultSource(); - const columnBps = getColumnBreakpoints( - pausePoints, - breakpoints, - viewport, - selectedSource - ); + const columnBps = getColumnBreakpoints(pausePoints, breakpoints, viewport); expect(columnBps).toMatchSnapshot(); }); @@ -83,14 +66,8 @@ describe("visible column breakpoints", () => { }; const pausePoints = [pp(1, 1), pp(1, 3), pp(20, 1)]; const breakpoints = [bp(1, 1)]; - const selectedSource = defaultSource(); - const columnBps = getColumnBreakpoints( - pausePoints, - breakpoints, - viewport, - selectedSource - ); + const columnBps = getColumnBreakpoints(pausePoints, breakpoints, viewport); expect(columnBps).toMatchSnapshot(); }); }); diff --git a/devtools/client/debugger/new/src/selectors/visibleBreakpoints.js b/devtools/client/debugger/new/src/selectors/visibleBreakpoints.js index 8d3bef83f770e..3d31c47f3f2fc 100644 --- a/devtools/client/debugger/new/src/selectors/visibleBreakpoints.js +++ b/devtools/client/debugger/new/src/selectors/visibleBreakpoints.js @@ -9,21 +9,14 @@ import { uniqBy } from "lodash"; import { getBreakpointsList, - getBreakpointPositionsForLine, - getBreakpointPositions + getBreakpointPositionsForLine } from "../reducers/breakpoints"; -import { getPausePoints } from "../reducers/ast"; import { getSelectedSource } from "../reducers/sources"; import { sortBreakpoints } from "../utils/breakpoint"; import { getSelectedLocation } from "../utils/source-maps"; -import type { - Breakpoint, - Source, - SourceLocation, - BreakpointPositions -} from "../types"; +import type { Breakpoint, Source, SourceLocation } from "../types"; import type { Selector, State } from "../reducers/types"; function isVisible(breakpoint: Breakpoint, selectedSource: Source) { @@ -37,12 +30,7 @@ function isVisible(breakpoint: Breakpoint, selectedSource: Source) { export const getVisibleBreakpoints: Selector = createSelector( getSelectedSource, getBreakpointsList, - getBreakpointPositions, - ( - selectedSource: ?Source, - breakpoints: Breakpoint[], - positions: ?BreakpointPositions - ) => { + (selectedSource: ?Source, breakpoints: Breakpoint[]) => { if (selectedSource == null) { return null; } @@ -59,26 +47,8 @@ export function getFirstVisibleBreakpointPosition( location: SourceLocation ): ?SourceLocation { const { sourceId, line } = location; - const pausePoints = getPausePoints(state, location.sourceId); const positions = getBreakpointPositionsForLine(state, sourceId, line); - - if (!pausePoints || !positions) { - return null; - } - - const pausesAtLine = pausePoints.filter( - p => p.location.line == line && positions.includes(p.location.column) - ); - - if (pausesAtLine.length > 0) { - const firstPausePoint = pausesAtLine.find( - pausePoint => pausePoint.types.break - ); - if (firstPausePoint) { - return { ...firstPausePoint.location, sourceId }; - } - } - return location; + return positions && positions[0].location; } /* diff --git a/devtools/client/debugger/new/src/selectors/visibleColumnBreakpoints.js b/devtools/client/debugger/new/src/selectors/visibleColumnBreakpoints.js index 6312383849f7f..bd4021e0f213c 100644 --- a/devtools/client/debugger/new/src/selectors/visibleColumnBreakpoints.js +++ b/devtools/client/debugger/new/src/selectors/visibleColumnBreakpoints.js @@ -1,24 +1,26 @@ +// @flow /* 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 . */ -// @flow - import { groupBy, sortedUniqBy } from "lodash"; import { createSelector } from "reselect"; -import { getViewport, getSelectedSource } from "../selectors"; +import { + getViewport, + getSelectedSource, + getBreakpointPositions +} from "../selectors"; import { getVisibleBreakpoints } from "./visibleBreakpoints"; -import { getVisiblePausePoints } from "./visiblePausePoints"; import { makeBreakpointId } from "../utils/breakpoint"; -import type { Selector, PausePoint } from "../reducers/types"; +import type { Selector } from "../reducers/types"; import type { SourceLocation, PartialPosition, Breakpoint, Range, - Source + BreakpointPositions } from "../types"; export type ColumnBreakpoint = {| @@ -38,6 +40,10 @@ function contains(location: PartialPosition, range: Range) { ); } +function inViewport(viewport, location) { + return viewport && contains(location, viewport); +} + function groupBreakpoints(breakpoints) { if (!breakpoints) { return {}; @@ -87,33 +93,25 @@ export function formatColumnBreakpoints(columnBreakpoints: ColumnBreakpoints) { } export function getColumnBreakpoints( - pausePoints: ?(PausePoint[]), + positions: ?BreakpointPositions, breakpoints: ?(Breakpoint[]), - viewport: Range, - selectedSource: ?Source + viewport: Range ) { - if (!pausePoints) { + if (!positions) { return []; } const breakpointMap = groupBreakpoints(breakpoints); // We only want to show a column breakpoint if several conditions are matched - // 1. it is a "break" point and not a "step" point - // 2. there is a breakpoint on that line - // 3. the breakpoint is in the current viewport + // 1. there is a breakpoint on that line + // 2. the position is in the current viewport // 4. it is the first breakpoint to appear at that generated location // 5. there is atleast one other breakpoint on that line - let columnBreakpoints = pausePoints.filter( - ({ types, location }) => - // 1. check that the pause point is a "break" point - types.break && - // 2. check that there is a registered breakpoint on the line - breakpointMap[location.line] && - // 3. check that the breakpoint is visible - viewport && - contains(location, viewport) + let columnBreakpoints = positions.filter( + ({ location }) => + breakpointMap[location.line] && inViewport(viewport, location) ); // 4. Only show one column breakpoint per generated location @@ -127,17 +125,22 @@ export function getColumnBreakpoints( ({ location: { line } }) => lineCount[line] > 1 ); - const sourceId = selectedSource && selectedSource.id; return (columnBreakpoints: any).map(({ location }) => ({ - location: { ...location, sourceId }, + location, breakpoint: findBreakpoint(location, breakpointMap) })); } +const getVisibleBreakpointPositions = createSelector( + getSelectedSource, + getBreakpointPositions, + (source, positions) => source && positions[source.id] +); + export const visibleColumnBreakpoints: Selector< ColumnBreakpoints > = createSelector( - getVisiblePausePoints, + getVisibleBreakpointPositions, getVisibleBreakpoints, getViewport, getSelectedSource, diff --git a/devtools/client/debugger/new/src/types.js b/devtools/client/debugger/new/src/types.js index 8a73b30d13268..7d057fab198de 100644 --- a/devtools/client/debugger/new/src/types.js +++ b/devtools/client/debugger/new/src/types.js @@ -327,6 +327,12 @@ export type Grip = { name?: string }; +export type SourceActor = {| + +actor: ActorId, + +source: SourceId, + +thread: ThreadId +|}; + /** * BaseSource * @@ -344,7 +350,9 @@ type BaseSource = {| +error?: string, +loadedState: "unloaded" | "loading" | "loaded", +relativeUrl: string, - introductionUrl: ?string + +introductionUrl: ?string, + +isExtension: boolean, + +actors: SourceActor[] |}; /** @@ -375,12 +383,6 @@ export type WasmSource = {| export type Source = JsSource | WasmSource; -export type SourceActor = {| - +actor: ActorId, - +source: SourceId, - +thread: ThreadId -|}; - /** * Script * This describes scripts which are sent to the debug server to be eval'd @@ -453,7 +455,5 @@ export type EventListenerBreakpoints = string[]; export type SourceDocuments = { [string]: Object }; -export type BreakpointPosition = { line: number, string: number }; -export type BreakpointLinePositions = Array; -export type BreakpointSourcePositions = { [number]: BreakpointLinePositions }; -export type BreakpointPositions = { [string]: BreakpointSourcePositions }; +export type BreakpointPosition = MappedLocation; +export type BreakpointPositions = BreakpointPosition[]; diff --git a/devtools/client/debugger/new/src/utils/ast.js b/devtools/client/debugger/new/src/utils/ast.js index e64dbf2f179e6..e786db862fa7c 100644 --- a/devtools/client/debugger/new/src/utils/ast.js +++ b/devtools/client/debugger/new/src/utils/ast.js @@ -4,7 +4,6 @@ // @flow -import { xor, range } from "lodash"; import type { SourceLocation, Position } from "../types"; import type { Symbols } from "../reducers/ast"; @@ -14,7 +13,6 @@ import type { FunctionDeclaration, ClassDeclaration } from "../workers/parser"; -import type { PausePoints } from "../reducers/types"; export function findBestMatchExpression(symbols: Symbols, tokenPos: Position) { if (symbols.loading) { @@ -41,26 +39,6 @@ export function findBestMatchExpression(symbols: Symbols, tokenPos: Position) { }, null); } -export function findEmptyLines( - sourceText: string, - pausePoints: PausePoints -): number[] { - if (!pausePoints || !sourceText) { - return []; - } - - const breakpoints = pausePoints.filter(point => point.types.break); - const breakpointLines = breakpoints.map(point => point.location.line); - - if (!sourceText || breakpointLines.length == 0) { - return []; - } - - const lineCount = sourceText.split("\n").length; - const sourceLines = range(1, lineCount + 1); - return xor(sourceLines, breakpointLines); -} - export function containsPosition(a: AstLocation, b: AstPosition) { const startsBefore = a.start.line < b.line || diff --git a/devtools/client/debugger/new/src/utils/breakpoint/index.js b/devtools/client/debugger/new/src/utils/breakpoint/index.js index 6f9718361f647..7d4e837ecaafc 100644 --- a/devtools/client/debugger/new/src/utils/breakpoint/index.js +++ b/devtools/client/debugger/new/src/utils/breakpoint/index.js @@ -6,7 +6,7 @@ import { sortBy } from "lodash"; -import { getBreakpoint, getSource, getSourceActors } from "../../selectors"; +import { getBreakpoint, getSource } from "../../selectors"; import { isGenerated } from "../source"; import assert from "../assert"; @@ -84,8 +84,7 @@ export function makeBreakpointLocation( if (source.url) { breakpointLocation.sourceUrl = source.url; } else { - const sourceActors = getSourceActors(state, location.sourceId); - breakpointLocation.sourceId = sourceActors[0].actor; + breakpointLocation.sourceId = source.actors[0].actor; } return breakpointLocation; } diff --git a/devtools/client/debugger/new/src/utils/dbg.js b/devtools/client/debugger/new/src/utils/dbg.js index d2c97d49c512e..f032d03788289 100644 --- a/devtools/client/debugger/new/src/utils/dbg.js +++ b/devtools/client/debugger/new/src/utils/dbg.js @@ -7,7 +7,6 @@ import * as timings from "./timings"; import { prefs, asyncStore, features } from "./prefs"; import { isDevelopment, isTesting } from "devtools-environment"; -import { formatPausePoints } from "./pause/pausePoints"; function findSource(dbg: any, url: string) { const sources = dbg.selectors.getSourceList(); @@ -48,13 +47,6 @@ function getCM() { return cm && cm.CodeMirror; } -function _formatPausePoints(dbg: Object, url: string) { - const source = - dbg.helpers.findSource(url) || dbg.selectors.getSelectedSource(); - const pausePoints = dbg.selectors.getPausePoints(source.id); - console.log(formatPausePoints(source.text, pausePoints)); -} - function _formatColumnBreapoints(dbg: Object) { console.log( dbg.selectors.formatColumnBreakpoints( @@ -81,7 +73,6 @@ export function setupHelper(obj: Object) { sendPacket: (packet, cbk) => sendPacket(dbg, packet, cbk) }, formatters: { - pausePoints: url => _formatPausePoints(dbg, url), visibleColumnBreakpoints: () => _formatColumnBreapoints(dbg) }, _telemetry: { @@ -93,7 +84,7 @@ export function setupHelper(obj: Object) { if (isDevelopment() && !isTesting()) { console.group("Development Notes"); - const baseUrl = "https://devtools-html.github.io/debugger.html"; + const baseUrl = "https://firefox-devtools.github.io/debugger.html"; const localDevelopmentUrl = `${baseUrl}/docs/dbg.html`; console.log("Debugging Tips", localDevelopmentUrl); console.log("dbg", window.dbg); diff --git a/devtools/client/debugger/new/src/utils/editor/create-editor.js b/devtools/client/debugger/new/src/utils/editor/create-editor.js index a187c3f1dcdca..3ddc5651350c5 100644 --- a/devtools/client/debugger/new/src/utils/editor/create-editor.js +++ b/devtools/client/debugger/new/src/utils/editor/create-editor.js @@ -5,7 +5,7 @@ // @flow import SourceEditor from "./source-editor"; -import { features } from "../prefs"; +import { features, prefs } from "../prefs"; export function createEditor() { const gutters = ["breakpoints", "hit-markers", "CodeMirror-linenumbers"]; @@ -22,7 +22,7 @@ export function createEditor() { lineNumbers: true, theme: "mozilla", styleActiveLine: false, - lineWrapping: false, + lineWrapping: prefs.editorWrapping, matchBrackets: true, showAnnotationRuler: true, gutters, diff --git a/devtools/client/debugger/new/src/utils/editor/source-editor.css b/devtools/client/debugger/new/src/utils/editor/source-editor.css index 2ed59ff4f57d2..380256b58dfe4 100644 --- a/devtools/client/debugger/new/src/utils/editor/source-editor.css +++ b/devtools/client/debugger/new/src/utils/editor/source-editor.css @@ -47,33 +47,6 @@ pointer-events: none; } -.CodeMirror-linenumber:before { - content: " "; - display: block; - width: calc(100% - 3px); - position: absolute; - top: 1px; - left: 0; - height: 12px; - z-index: -1; - background-size: calc(100% - 2px) 12px; - background-repeat: no-repeat; - background-position: right center; - padding-inline-end: 9px; -} - -.breakpoint .CodeMirror-linenumber { - color: var(--theme-body-background); -} - -.breakpoint .CodeMirror-linenumber:before { - background-image: var(--breakpoint-background) !important; -} - -.conditional .CodeMirror-linenumber:before { - background-image: var(--breakpoint-conditional-background) !important; -} - .theme-dark .debug-line .CodeMirror-linenumber { color: #c0c0c0; } diff --git a/devtools/client/debugger/new/src/utils/pause/index.js b/devtools/client/debugger/new/src/utils/pause/index.js index 2d97a5e55cc8b..a2dfcb8e5a4f7 100644 --- a/devtools/client/debugger/new/src/utils/pause/index.js +++ b/devtools/client/debugger/new/src/utils/pause/index.js @@ -5,4 +5,3 @@ // @flow export * from "./why"; -export * from "./stepping"; diff --git a/devtools/client/debugger/new/src/utils/pause/moz.build b/devtools/client/debugger/new/src/utils/pause/moz.build index 2509ef98a7c96..a1c9b13218ff6 100644 --- a/devtools/client/debugger/new/src/utils/pause/moz.build +++ b/devtools/client/debugger/new/src/utils/pause/moz.build @@ -11,7 +11,5 @@ DIRS += [ DebuggerModules( 'index.js', - 'pausePoints.js', - 'stepping.js', 'why.js', ) diff --git a/devtools/client/debugger/new/src/utils/prefs.js b/devtools/client/debugger/new/src/utils/prefs.js index 69dcbd5174086..bf1e617c97186 100644 --- a/devtools/client/debugger/new/src/utils/prefs.js +++ b/devtools/client/debugger/new/src/utils/prefs.js @@ -5,12 +5,11 @@ // @flow import { PrefsHelper } from "devtools-modules"; -import { isDevelopment } from "devtools-environment"; +import { isDevelopment, isTesting } from "devtools-environment"; import Services from "devtools-services"; import { asyncStoreHelper } from "./asyncStoreHelper"; const prefsSchemaVersion = "1.0.8"; - const pref = Services.pref; if (isDevelopment()) { @@ -36,6 +35,7 @@ if (isDevelopment()) { pref("devtools.debugger.end-panel-size", 300); pref("devtools.debugger.tabs", "[]"); pref("devtools.debugger.tabsBlackBoxed", "[]"); + pref("devtools.debugger.ui.editor-wrapping", false); pref("devtools.debugger.ui.framework-grouping-on", true); pref("devtools.debugger.pending-selected-location", "{}"); pref("devtools.debugger.pending-breakpoints", "{}"); @@ -56,7 +56,6 @@ if (isDevelopment()) { pref("devtools.debugger.features.code-folding", false); pref("devtools.debugger.features.outline", true); pref("devtools.debugger.features.column-breakpoints", false); - pref("devtools.debugger.features.pause-points", true); pref("devtools.debugger.features.skip-pausing", true); pref("devtools.debugger.features.component-pane", false); pref("devtools.debugger.features.autocomplete-expressions", false); @@ -64,13 +63,14 @@ if (isDevelopment()) { pref("devtools.debugger.features.map-await-expression", true); pref("devtools.debugger.features.xhr-breakpoints", true); pref("devtools.debugger.features.original-blackbox", true); - pref("devtools.debugger.features.windowless-workers", false); + pref("devtools.debugger.features.windowless-workers", true); pref("devtools.debugger.features.event-listeners-breakpoints", true); pref("devtools.debugger.features.log-points", true); } export const prefs = new PrefsHelper("devtools", { logging: ["Bool", "debugger.logging"], + editorWrapping: ["Bool", "debugger.ui.editor-wrapping"], alphabetizeOutline: ["Bool", "debugger.alphabetize-outline"], autoPrettyPrint: ["Bool", "debugger.auto-pretty-print"], clientSourceMapsEnabled: ["Bool", "source-map.client-service.enabled"], @@ -116,7 +116,6 @@ export const features = new PrefsHelper("devtools.debugger.features", { windowlessWorkers: ["Bool", "windowless-workers"], outline: ["Bool", "outline"], codeFolding: ["Bool", "code-folding"], - pausePoints: ["Bool", "pause-points"], skipPausing: ["Bool", "skip-pausing"], autocompleteExpression: ["Bool", "autocomplete-expressions"], mapExpressionBindings: ["Bool", "map-expression-bindings"], @@ -135,7 +134,7 @@ export const asyncStore = asyncStoreHelper("debugger", { eventListenerBreakpoints: ["event-listener-breakpoints", []] }); -if (prefs.debuggerPrefsSchemaVersion !== prefsSchemaVersion) { +if (!isTesting && prefs.debuggerPrefsSchemaVersion !== prefsSchemaVersion) { // clear pending Breakpoints asyncStore.pendingBreakpoints = {}; asyncStore.tabs = []; diff --git a/devtools/client/debugger/new/src/utils/source-maps.js b/devtools/client/debugger/new/src/utils/source-maps.js index 360823195ad53..a7064b3e435f6 100644 --- a/devtools/client/debugger/new/src/utils/source-maps.js +++ b/devtools/client/debugger/new/src/utils/source-maps.js @@ -6,9 +6,10 @@ import { isOriginalId } from "devtools-source-map"; import { getSource } from "../selectors"; +import { isGenerated } from "../utils/source"; import type { SourceLocation, MappedLocation, Source } from "../types"; -import { isGenerated } from "../utils/source"; +import typeof SourceMaps from "../../packages/devtools-source-map/src"; export async function getGeneratedLocation( state: Object, @@ -27,7 +28,7 @@ export async function getGeneratedLocation( const generatedSource = getSource(state, sourceId); if (!generatedSource) { - return location; + throw new Error(`Could not find generated source ${sourceId}`); } return { @@ -38,6 +39,18 @@ export async function getGeneratedLocation( }; } +export async function getOriginalLocation( + generatedLocation: SourceLocation, + source: Source, + sourceMaps: SourceMaps +) { + if (isOriginalId(generatedLocation.sourceId)) { + return location; + } + + return sourceMaps.getOriginalLocation(generatedLocation); +} + export async function getMappedLocation( state: Object, sourceMaps: Object, diff --git a/devtools/client/debugger/new/src/utils/source-queue.js b/devtools/client/debugger/new/src/utils/source-queue.js index e90124b6c107f..772a8c6e33212 100644 --- a/devtools/client/debugger/new/src/utils/source-queue.js +++ b/devtools/client/debugger/new/src/utils/source-queue.js @@ -5,7 +5,7 @@ // @flow import { throttle } from "lodash"; -import type { CreateSourceResult } from "../client/firefox/types"; +import type { Source } from "../types"; let newSources; let queuedSources; @@ -24,11 +24,11 @@ export default { newSources = actions.newSources; queuedSources = []; }, - queue: (source: CreateSourceResult) => { + queue: (source: Source) => { queuedSources.push(source); queue(); }, - queueSources: (sources: CreateSourceResult[]) => { + queueSources: (sources: Source[]) => { queuedSources = queuedSources.concat(sources); queue(); }, diff --git a/devtools/client/debugger/new/src/utils/sources-tree/tests/__snapshots__/updateTree.spec.js.snap b/devtools/client/debugger/new/src/utils/sources-tree/tests/__snapshots__/updateTree.spec.js.snap index 751bf65ef4e49..002176fe64b88 100644 --- a/devtools/client/debugger/new/src/utils/sources-tree/tests/__snapshots__/updateTree.spec.js.snap +++ b/devtools/client/debugger/new/src/utils/sources-tree/tests/__snapshots__/updateTree.spec.js.snap @@ -20,10 +20,14 @@ exports[`calls updateTree.js adds one source 1`] = ` \\"url\\": \\"https://davidwalsh.name/\\", \\"isBlackBoxed\\": false, \\"isPrettyPrinted\\": false, + \\"loadedState\\": \\"unloaded\\", + \\"relativeUrl\\": \\"https://davidwalsh.name/\\", + \\"introductionUrl\\": null, + \\"actors\\": [], \\"isWasm\\": false, + \\"contentType\\": \\"text/javascript\\", \\"isExtension\\": false, - \\"contentType\\": \\"\\", - \\"loadedState\\": \\"unloaded\\" + \\"text\\": \\"\\" } }, { @@ -35,10 +39,14 @@ exports[`calls updateTree.js adds one source 1`] = ` \\"url\\": \\"https://davidwalsh.name/source1.js\\", \\"isBlackBoxed\\": false, \\"isPrettyPrinted\\": false, + \\"loadedState\\": \\"unloaded\\", + \\"relativeUrl\\": \\"https://davidwalsh.name/source1.js\\", + \\"introductionUrl\\": null, + \\"actors\\": [], \\"isWasm\\": false, + \\"contentType\\": \\"text/javascript\\", \\"isExtension\\": false, - \\"contentType\\": \\"\\", - \\"loadedState\\": \\"unloaded\\" + \\"text\\": \\"\\" } } ] @@ -67,10 +75,14 @@ exports[`calls updateTree.js adds two sources 1`] = ` \\"url\\": \\"https://davidwalsh.name/\\", \\"isBlackBoxed\\": false, \\"isPrettyPrinted\\": false, + \\"loadedState\\": \\"unloaded\\", + \\"relativeUrl\\": \\"https://davidwalsh.name/\\", + \\"introductionUrl\\": null, + \\"actors\\": [], \\"isWasm\\": false, + \\"contentType\\": \\"text/javascript\\", \\"isExtension\\": false, - \\"contentType\\": \\"\\", - \\"loadedState\\": \\"unloaded\\" + \\"text\\": \\"\\" } }, { @@ -82,10 +94,14 @@ exports[`calls updateTree.js adds two sources 1`] = ` \\"url\\": \\"https://davidwalsh.name/source1.js\\", \\"isBlackBoxed\\": false, \\"isPrettyPrinted\\": false, + \\"loadedState\\": \\"unloaded\\", + \\"relativeUrl\\": \\"https://davidwalsh.name/source1.js\\", + \\"introductionUrl\\": null, + \\"actors\\": [], \\"isWasm\\": false, + \\"contentType\\": \\"text/javascript\\", \\"isExtension\\": false, - \\"contentType\\": \\"\\", - \\"loadedState\\": \\"unloaded\\" + \\"text\\": \\"\\" } }, { @@ -97,10 +113,14 @@ exports[`calls updateTree.js adds two sources 1`] = ` \\"url\\": \\"https://davidwalsh.name/source2.js\\", \\"isBlackBoxed\\": false, \\"isPrettyPrinted\\": false, + \\"loadedState\\": \\"unloaded\\", + \\"relativeUrl\\": \\"https://davidwalsh.name/source2.js\\", + \\"introductionUrl\\": null, + \\"actors\\": [], \\"isWasm\\": false, + \\"contentType\\": \\"text/javascript\\", \\"isExtension\\": false, - \\"contentType\\": \\"\\", - \\"loadedState\\": \\"unloaded\\" + \\"text\\": \\"\\" } } ] @@ -129,10 +149,14 @@ exports[`calls updateTree.js shows all the sources 1`] = ` \\"url\\": \\"https://davidwalsh.name/\\", \\"isBlackBoxed\\": false, \\"isPrettyPrinted\\": false, + \\"loadedState\\": \\"unloaded\\", + \\"relativeUrl\\": \\"https://davidwalsh.name/\\", + \\"introductionUrl\\": null, + \\"actors\\": [], \\"isWasm\\": false, + \\"contentType\\": \\"text/javascript\\", \\"isExtension\\": false, - \\"contentType\\": \\"\\", - \\"loadedState\\": \\"unloaded\\" + \\"text\\": \\"\\" } }, { @@ -144,10 +168,14 @@ exports[`calls updateTree.js shows all the sources 1`] = ` \\"url\\": \\"https://davidwalsh.name/source1.js\\", \\"isBlackBoxed\\": false, \\"isPrettyPrinted\\": false, + \\"loadedState\\": \\"unloaded\\", + \\"relativeUrl\\": \\"https://davidwalsh.name/source1.js\\", + \\"introductionUrl\\": null, + \\"actors\\": [], \\"isWasm\\": false, + \\"contentType\\": \\"text/javascript\\", \\"isExtension\\": false, - \\"contentType\\": \\"\\", - \\"loadedState\\": \\"unloaded\\" + \\"text\\": \\"\\" } } ] diff --git a/devtools/client/debugger/new/src/utils/sources-tree/tests/addToTree.spec.js b/devtools/client/debugger/new/src/utils/sources-tree/tests/addToTree.spec.js index b88d1e945f8fc..52cc76491a07b 100644 --- a/devtools/client/debugger/new/src/utils/sources-tree/tests/addToTree.spec.js +++ b/devtools/client/debugger/new/src/utils/sources-tree/tests/addToTree.spec.js @@ -6,7 +6,7 @@ /* eslint max-nested-callbacks: ["error", 4]*/ -import { createSource } from "../../../reducers/sources"; +import { makeMockSource } from "../../../utils/test-mockup"; import { addToTree, @@ -21,15 +21,15 @@ type RawSource = {| url: string, id: string |}; function createSourcesMap(sources: RawSource[]) { const sourcesMap = sources.reduce((map, source) => { - map[source.id] = createSource(source); + map[source.id] = makeMockSource(source.url, source.id); return map; }, {}); return sourcesMap; } -function createSourcesList(sources) { - return sources.map((s, i) => createSource(s)); +function createSourcesList(sources: { url: string, id?: string }[]) { + return sources.map((s, i) => makeMockSource(s.url, s.id)); } function getChildNode(tree, ...path) { @@ -39,10 +39,7 @@ function getChildNode(tree, ...path) { describe("sources-tree", () => { describe("addToTree", () => { it("should provide node API", () => { - const source = createSource({ - url: "http://example.com/a/b/c.js", - id: "actor1" - }); + const source = makeMockSource("http://example.com/a/b/c.js", "actor1"); const root = createDirectoryNode("root", "", [ createSourceNode("foo", "/foo", source) @@ -60,10 +57,10 @@ describe("sources-tree", () => { }); it("builds a path-based tree", () => { - const source1 = createSource({ - url: "http://example.com/foo/source1.js", - id: "actor1" - }); + const source1 = makeMockSource( + "http://example.com/foo/source1.js", + "actor1" + ); const tree = createDirectoryNode("root", "", []); addToTree(tree, source1, "http://example.com/", ""); @@ -85,10 +82,10 @@ describe("sources-tree", () => { const sourceName = // eslint-disable-next-line max-len "B9724220.131821496;dc_ver=42.111;sz=468x60;u_sd=2;dc_adk=2020465299;ord=a53rpc;dc_rfl=1,https%3A%2F%2Fdavidwalsh.name%2F$0;xdt=1"; - const source1 = createSource({ - url: `https://example.com/foo/${sourceName}`, - id: "actor1" - }); + const source1 = makeMockSource( + `https://example.com/foo/${sourceName}`, + "actor1" + ); const tree = createDirectoryNode("root", "", []); @@ -101,10 +98,10 @@ describe("sources-tree", () => { it("name does not include query params", () => { const sourceName = "name.js?bar=3"; - const source1 = createSource({ - url: `https://example.com/foo/${sourceName}`, - id: "actor1" - }); + const source1 = makeMockSource( + `https://example.com/foo/${sourceName}`, + "actor1" + ); const tree = createDirectoryNode("root", "", []); @@ -178,18 +175,15 @@ describe("sources-tree", () => { }); it("excludes javascript: URLs from the tree", () => { - const source1 = createSource({ - url: "javascript:alert('Hello World')", - id: "actor1" - }); - const source2 = createSource({ - url: "http://example.com/source1.js", - id: "actor2" - }); - const source3 = createSource({ - url: "javascript:let i = 10; while (i > 0) i--; console.log(i);", - id: "actor3" - }); + const source1 = makeMockSource( + "javascript:alert('Hello World')", + "actor1" + ); + const source2 = makeMockSource("http://example.com/source1.js", "actor2"); + const source3 = makeMockSource( + "javascript:let i = 10; while (i > 0) i--; console.log(i);", + "actor3" + ); const tree = createDirectoryNode("root", "", []); addToTree(tree, source1, "http://example.com/", ""); @@ -205,10 +199,7 @@ describe("sources-tree", () => { }); it("correctly parses file sources", () => { - const source = createSource({ - url: "file:///a/b.js", - id: "actor1" - }); + const source = makeMockSource("file:///a/b.js", "actor1"); const tree = createDirectoryNode("root", "", []); addToTree(tree, source, "file:///a/index.html", ""); diff --git a/devtools/client/debugger/new/src/utils/sources-tree/tests/collapseTree.spec.js b/devtools/client/debugger/new/src/utils/sources-tree/tests/collapseTree.spec.js index 4609e87e8e734..d1bdd4a6ac32a 100644 --- a/devtools/client/debugger/new/src/utils/sources-tree/tests/collapseTree.spec.js +++ b/devtools/client/debugger/new/src/utils/sources-tree/tests/collapseTree.spec.js @@ -4,7 +4,7 @@ // @flow -import { createSource } from "../../../reducers/sources"; +import { makeMockSource } from "../../../utils/test-mockup"; import { collapseTree, @@ -14,18 +14,9 @@ import { createDirectoryNode } from "../index"; -const abcSource = createSource({ - url: "http://example.com/a/b/c.js", - id: "actor1" -}); -const abcdeSource = createSource({ - url: "http://example.com/a/b/c/d/e.js", - id: "actor2" -}); -const abxSource = createSource({ - url: "http://example.com/a/b/x.js", - id: "actor3" -}); +const abcSource = makeMockSource("http://example.com/a/b/c.js", "actor1"); +const abcdeSource = makeMockSource("http://example.com/a/b/c/d/e.js", "actor2"); +const abxSource = makeMockSource("http://example.com/a/b/x.js", "actor3"); describe("sources tree", () => { describe("collapseTree", () => { diff --git a/devtools/client/debugger/new/src/utils/sources-tree/tests/getDirectories.spec.js b/devtools/client/debugger/new/src/utils/sources-tree/tests/getDirectories.spec.js index ef4b3809ccb15..ccc499eae2eec 100644 --- a/devtools/client/debugger/new/src/utils/sources-tree/tests/getDirectories.spec.js +++ b/devtools/client/debugger/new/src/utils/sources-tree/tests/getDirectories.spec.js @@ -4,7 +4,7 @@ // @flow -import { createSource } from "../../../reducers/sources"; +import { makeMockSource } from "../../../utils/test-mockup"; import { getDirectories, createTree } from "../index"; @@ -16,7 +16,7 @@ function formatDirectories(source, tree) { function createSources(urls) { return urls.reduce((sources, url, index) => { const id = `a${index}`; - sources[id] = createSource({ url, id }); + sources[id] = makeMockSource(url, id); return sources; }, {}); } diff --git a/devtools/client/debugger/new/src/utils/sources-tree/tests/getUrl.spec.js b/devtools/client/debugger/new/src/utils/sources-tree/tests/getUrl.spec.js index 659434520e095..db83e1cc763e8 100644 --- a/devtools/client/debugger/new/src/utils/sources-tree/tests/getUrl.spec.js +++ b/devtools/client/debugger/new/src/utils/sources-tree/tests/getUrl.spec.js @@ -5,11 +5,13 @@ // @flow import { getURL } from "../getURL"; -import { createSource } from "../../../reducers/sources"; +import { makeMockSource } from "../../../utils/test-mockup"; +import type { Source } from "../../../types"; -function createMockSource(props) { - return createSource( - Object.assign( +function createMockSource(props): Source { + const rv = { + ...makeMockSource(), + ...Object.assign( { id: "server1.conn13.child1/39", url: "", @@ -24,7 +26,8 @@ function createMockSource(props) { }, props ) - ); + }; + return (rv: any); } describe("getUrl", () => { diff --git a/devtools/client/debugger/new/src/utils/sources-tree/tests/sortTree.spec.js b/devtools/client/debugger/new/src/utils/sources-tree/tests/sortTree.spec.js index a1b2b69e0bf4b..83e6fa6255a49 100644 --- a/devtools/client/debugger/new/src/utils/sources-tree/tests/sortTree.spec.js +++ b/devtools/client/debugger/new/src/utils/sources-tree/tests/sortTree.spec.js @@ -5,7 +5,7 @@ // @flow -import { createSource } from "../../../reducers/sources"; +import { makeMockSource } from "../../../utils/test-mockup"; import { addToTree, @@ -17,18 +17,15 @@ import { describe("sources-tree", () => { describe("sortEntireTree", () => { it("alphabetically sorts children", () => { - const source1 = createSource({ - url: "http://example.com/source1.js", - id: "actor1" - }); - const source2 = createSource({ - url: "http://example.com/foo/b_source2.js", - id: "actor2" - }); - const source3 = createSource({ - url: "http://example.com/foo/a_source3.js", - id: "actor3" - }); + const source1 = makeMockSource("http://example.com/source1.js", "actor1"); + const source2 = makeMockSource( + "http://example.com/foo/b_source2.js", + "actor2" + ); + const source3 = makeMockSource( + "http://example.com/foo/a_source3.js", + "actor3" + ); const _tree = createDirectoryNode("root", "", []); addToTree(_tree, source1, "http://example.com/", ""); @@ -54,30 +51,12 @@ describe("sources-tree", () => { it("sorts folders first", () => { const sources = [ - createSource({ - url: "http://example.com/a.js", - id: "actor1" - }), - createSource({ - url: "http://example.com/b.js/b_source.js", - id: "actor2" - }), - createSource({ - url: "http://example.com/c.js", - id: "actor3" - }), - createSource({ - url: "http://example.com", - id: "actor4" - }), - createSource({ - url: "http://example.com/d/d_source.js", - id: "actor5" - }), - createSource({ - url: "http://example.com/b2", - id: "actor6" - }) + makeMockSource("http://example.com/a.js", "actor1"), + makeMockSource("http://example.com/b.js/b_source.js", "actor2"), + makeMockSource("http://example.com/c.js", "actor3"), + makeMockSource("http://example.com", "actor4"), + makeMockSource("http://example.com/d/d_source.js", "actor5"), + makeMockSource("http://example.com/b2", "actor6") ]; const _tree = createDirectoryNode("root", "", []); @@ -116,18 +95,9 @@ describe("sources-tree", () => { it("puts folder at the top of the sort", () => { const sources = [ - createSource({ - url: "http://example.com/folder/a.js", - id: "actor1" - }), - createSource({ - url: "http://example.com/folder/b/b.js", - id: "actor2" - }), - createSource({ - url: "http://example.com/folder/c/", - id: "actor3" - }) + makeMockSource("http://example.com/folder/a.js", "actor1"), + makeMockSource("http://example.com/folder/b/b.js", "actor2"), + makeMockSource("http://example.com/folder/c/", "actor3") ]; const _tree = createDirectoryNode("root", "", []); @@ -155,18 +125,9 @@ describe("sources-tree", () => { it("puts root debugee url at the top of the sort", () => { const sources = [ - createSource({ - url: "http://api.example.com/a.js", - id: "actor1" - }), - createSource({ - url: "http://example.com/b.js", - id: "actor2" - }), - createSource({ - url: "http://demo.com/c.js", - id: "actor3" - }) + makeMockSource("http://api.example.com/a.js", "actor1"), + makeMockSource("http://example.com/b.js", "actor2"), + makeMockSource("http://demo.com/c.js", "actor3") ]; const rootA = "http://example.com/path/to/file.html"; diff --git a/devtools/client/debugger/new/src/utils/sources-tree/tests/updateTree.spec.js b/devtools/client/debugger/new/src/utils/sources-tree/tests/updateTree.spec.js index 5b9d5503d7e81..bd09adcac8f5e 100644 --- a/devtools/client/debugger/new/src/utils/sources-tree/tests/updateTree.spec.js +++ b/devtools/client/debugger/new/src/utils/sources-tree/tests/updateTree.spec.js @@ -4,14 +4,14 @@ // @flow -import { createSource } from "../../../reducers/sources"; +import { makeMockSource } from "../../../utils/test-mockup"; import { updateTree, createTree } from "../index"; type RawSource = {| url: string, id: string |}; function createSourcesMap(sources: RawSource[]) { const sourcesMap = sources.reduce((map, source) => { - map[source.id] = createSource(source); + map[source.id] = makeMockSource(source.url, source.id); return map; }, {}); diff --git a/devtools/client/debugger/new/src/utils/sources-tree/tests/utils.spec.js b/devtools/client/debugger/new/src/utils/sources-tree/tests/utils.spec.js index 89264dd4c40e7..3df5533fa0675 100644 --- a/devtools/client/debugger/new/src/utils/sources-tree/tests/utils.spec.js +++ b/devtools/client/debugger/new/src/utils/sources-tree/tests/utils.spec.js @@ -5,8 +5,6 @@ // @flow -import { createSource } from "../../../reducers/sources"; - import { makeMockSource } from "../../test-mockup"; import { @@ -44,14 +42,8 @@ describe("sources tree", () => { describe("isDirectory", () => { it("identifies directories correctly", () => { const sources = [ - createSource({ - url: "http://example.com/a.js", - id: "actor1" - }), - createSource({ - url: "http://example.com/b/c/d.js", - id: "actor2" - }) + makeMockSource("http://example.com/a.js", "actor1"), + makeMockSource("http://example.com/b/c/d.js", "actor2") ]; const tree = createDirectoryNode("root", "", []); diff --git a/devtools/client/debugger/new/src/utils/tabs.js b/devtools/client/debugger/new/src/utils/tabs.js index 5ffaf9270c8ec..7b2b15115b698 100644 --- a/devtools/client/debugger/new/src/utils/tabs.js +++ b/devtools/client/debugger/new/src/utils/tabs.js @@ -95,6 +95,12 @@ export function getTabMenuItems() { accesskey: L10N.getStr("copySourceUri2.accesskey"), disabled: false }, + toggleBlackBox: { + id: "node-menu-blackbox", + label: L10N.getStr("sourceFooter.blackbox"), + accesskey: L10N.getStr("sourceFooter.blackbox.accesskey"), + disabled: false + }, prettyPrint: { id: "node-menu-pretty-print", label: L10N.getStr("sourceTabs.prettyPrint"), diff --git a/devtools/client/debugger/new/src/utils/test-head.js b/devtools/client/debugger/new/src/utils/test-head.js index 336784fc8c1fe..69adee42b7cf4 100644 --- a/devtools/client/debugger/new/src/utils/test-head.js +++ b/devtools/client/debugger/new/src/utils/test-head.js @@ -17,6 +17,7 @@ import * as selectors from "../selectors"; import { getHistory } from "../test/utils/history"; import configureStore from "../actions/utils/create-store"; import sourceQueue from "../utils/source-queue"; +import type { Source } from "../types"; /** * This file contains older interfaces used by tests that have not been @@ -64,7 +65,7 @@ function makeFrame({ id, sourceId }: Object, opts: Object = {}) { }; } -function makeSourceRaw(name: string, props: any = {}) { +function makeSourceRaw(name: string, props: any = {}): Source { return { id: name, loadedState: "unloaded", @@ -77,20 +78,26 @@ function makeSourceRaw(name: string, props: any = {}) { * @memberof utils/test-head * @static */ -function makeSource(name: string, props: any = {}) { - return { - source: makeSourceRaw(name, props), - sourceActor: { - actor: `${name}-actor`, - source: name, - thread: "FakeThread" - } +function makeSource(name: string, props: any = {}): Source { + const rv = { + ...makeSourceRaw(name, props), + actors: [ + { + actor: `${name}-actor`, + source: name, + thread: "FakeThread" + } + ] }; + return (rv: any); } -function makeOriginalSource(name: string, props?: Object) { - const source = makeSourceRaw(name, props); - return { source: { ...source, id: `${name}/originalSource` } }; +function makeOriginalSource(name: string, props?: Object): Source { + const rv = { + ...makeSourceRaw(name, props), + id: `${name}/originalSource` + }; + return (rv: any); } function makeFuncLocation(startLine, endLine) { diff --git a/devtools/client/debugger/new/src/utils/test-mockup.js b/devtools/client/debugger/new/src/utils/test-mockup.js index 793f87682bcc3..ca8f6c3dff5e7 100644 --- a/devtools/client/debugger/new/src/utils/test-mockup.js +++ b/devtools/client/debugger/new/src/utils/test-mockup.js @@ -39,8 +39,10 @@ function makeMockSource( loadedState: text ? "loaded" : "unloaded", relativeUrl: url, introductionUrl: null, + actors: [], isWasm: false, contentType, + isExtension: false, text }; } @@ -54,7 +56,9 @@ function makeMockWasmSource(text: {| binary: Object |}): WasmSource { loadedState: "unloaded", relativeUrl: "url", introductionUrl: null, + actors: [], isWasm: true, + isExtension: false, text }; } diff --git a/devtools/client/debugger/new/src/workers/parser/index.js b/devtools/client/debugger/new/src/workers/parser/index.js index 396a50f52ef5d..21a40be555c14 100644 --- a/devtools/client/debugger/new/src/workers/parser/index.js +++ b/devtools/client/debugger/new/src/workers/parser/index.js @@ -11,7 +11,6 @@ import type { AstLocation, AstPosition } from "./types"; import type { SourceLocation, Source, SourceId } from "../../types"; import type { SourceScope } from "./getScopes/visitor"; import type { SymbolDeclarations } from "./getSymbols"; -import type { PausePointsMap } from "../../reducers/types"; const dispatcher = new WorkerDispatcher(); export const start = (url: string, win: any = window) => @@ -80,10 +79,6 @@ export const mapExpression = async ( export const getFramework = async (sourceId: string): Promise => dispatcher.invoke("getFramework", sourceId); -export const getPausePoints = async ( - sourceId: string -): Promise => dispatcher.invoke("getPausePoints", sourceId); - export type { SourceScope, BindingData, @@ -94,12 +89,7 @@ export type { BindingType } from "./getScopes"; -export type { - AstLocation, - AstPosition, - PausePoint, - PausePointsMap -} from "./types"; +export type { AstLocation, AstPosition } from "./types"; export type { ClassDeclaration, diff --git a/devtools/client/debugger/new/src/workers/parser/tests/sources.spec.js b/devtools/client/debugger/new/src/workers/parser/tests/sources.spec.js index 13996f63c06f9..2da46373d977a 100644 --- a/devtools/client/debugger/new/src/workers/parser/tests/sources.spec.js +++ b/devtools/client/debugger/new/src/workers/parser/tests/sources.spec.js @@ -19,7 +19,9 @@ describe("sources", () => { isBlackBoxed: false, isPrettyPrinted: false, isWasm: false, - loadedState: "loaded" + loadedState: "loaded", + isExtension: false, + actors: [] }; expect(hasSource(sourceId)).toEqual(false); diff --git a/devtools/client/debugger/new/src/workers/parser/types.js b/devtools/client/debugger/new/src/workers/parser/types.js index 5ebc491493112..f58d3e8dbf1a8 100644 --- a/devtools/client/debugger/new/src/workers/parser/types.js +++ b/devtools/client/debugger/new/src/workers/parser/types.js @@ -6,13 +6,3 @@ export type AstPosition = { +line: number, +column: number }; export type AstLocation = { +end: AstPosition, +start: AstPosition }; - -export type PausePoint = {| - types: { break: boolean, step: boolean }, - location: AstPosition, - generatedLocation: AstPosition -|}; - -export type PausePointsMap = { - [line: string]: { [column: string]: PausePoint } -}; diff --git a/devtools/client/debugger/new/src/workers/parser/worker.js b/devtools/client/debugger/new/src/workers/parser/worker.js index b07183011cbcc..51f92f425ba51 100644 --- a/devtools/client/debugger/new/src/workers/parser/worker.js +++ b/devtools/client/debugger/new/src/workers/parser/worker.js @@ -12,7 +12,6 @@ import findOutOfScopeLocations from "./findOutOfScopeLocations"; import { getNextStep } from "./steps"; import { hasSyntaxError } from "./validate"; import { getFramework } from "./frameworks"; -import { getPausePoints } from "./pausePoints"; import mapExpression from "./mapExpression"; import { workerUtils } from "devtools-utils"; @@ -31,6 +30,5 @@ self.onmessage = workerHandler({ getNextStep, hasSyntaxError, getFramework, - getPausePoints, mapExpression }); diff --git a/devtools/client/debugger/new/test/mochitest/browser.ini b/devtools/client/debugger/new/test/mochitest/browser.ini index bd0c1c2f303fa..73e6cccf72160 100644 --- a/devtools/client/debugger/new/test/mochitest/browser.ini +++ b/devtools/client/debugger/new/test/mochitest/browser.ini @@ -667,7 +667,7 @@ skip-if = (os == "win" && ccov) # Bug 1453549 [browser_dbg-sourcemapped-scopes.js] skip-if = ccov || (verify && debug && (os == 'linux')) # Bug 1441545 [browser_dbg-sourcemapped-stepping.js] -skip-if = (os == 'win' && os_version == '10.0' && ccov) # Bug 1480680 +skip-if = true # original stepping is currently disabled [browser_dbg-sourcemapped-preview.js] skip-if = os == "win" # Bug 1448523, Bug 1448450 [browser_dbg-breaking.js] diff --git a/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-actions.js b/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-actions.js index 749e1b8200c49..bf94279a86335 100644 --- a/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-actions.js +++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-actions.js @@ -1,11 +1,11 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.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 . */ -function openFirstBreakpointContextMenu(dbg){ +function openFirstBreakpointContextMenu(dbg) { rightClickElement(dbg, "breakpointItem", 3); } - // Tests to see if we can trigger a breakpoint action via the context menu add_task(async function() { const dbg = await initDebugger("doc-scripts.html", "simple2"); @@ -14,11 +14,14 @@ add_task(async function() { await addBreakpoint(dbg, "simple2", 3); - openFirstBreakpointContextMenu(dbg) + openFirstBreakpointContextMenu(dbg); // select "Remove breakpoint" selectContextMenuItem(dbg, selectors.breakpointContextMenu.remove); - await waitForState(dbg, state => dbg.selectors.getBreakpointCount(state) === 0); + await waitForState( + dbg, + state => dbg.selectors.getBreakpointCount(state) === 0 + ); ok("successfully removed the breakpoint"); }); @@ -39,10 +42,11 @@ add_task(async function() { // which promises get resolved. The problem seems to indicate a coverage gap // in waitUntilService(). Workaround this by only waiting for one dispatch, // though this is fragile and could break again in the future. - let dispatched = waitForDispatch(dbg, "DISABLE_BREAKPOINT", /*2*/ 1); + let dispatched = waitForDispatch(dbg, "DISABLE_BREAKPOINT", /* 2*/ 1); selectContextMenuItem(dbg, selectors.breakpointContextMenu.disableOthers); await waitForState(dbg, state => - dbg.selectors.getBreakpointsList(state) + dbg.selectors + .getBreakpointsList(state) .every(bp => (bp.location.line !== 4) === bp.disabled) ); await dispatched; @@ -63,7 +67,8 @@ add_task(async function() { dispatched = waitForDispatch(dbg, "ENABLE_BREAKPOINT", 2); selectContextMenuItem(dbg, selectors.breakpointContextMenu.enableOthers); await waitForState(dbg, state => - dbg.selectors.getBreakpointsList(state) + dbg.selectors + .getBreakpointsList(state) .every(bp => (bp.location.line === 4) === bp.disabled) ); await dispatched; @@ -73,9 +78,11 @@ add_task(async function() { // select "Remove Others" dispatched = waitForDispatch(dbg, "REMOVE_BREAKPOINT", 2); selectContextMenuItem(dbg, selectors.breakpointContextMenu.removeOthers); - await waitForState(dbg, state => - dbg.selectors.getBreakpointsList(state).length === 1 && - dbg.selectors.getBreakpointsList(state)[0].location.line === 4 + await waitForState( + dbg, + state => + dbg.selectors.getBreakpointsList(state).length === 1 && + dbg.selectors.getBreakpointsList(state)[0].location.line === 4 ); await dispatched; ok("remaining breakpoint should be on line 4"); diff --git a/devtools/client/debugger/new/test/mochitest/browser_dbg-pretty-print-console.js b/devtools/client/debugger/new/test/mochitest/browser_dbg-pretty-print-console.js index 46f8669bfc3a9..c35acf4fc90c3 100644 --- a/devtools/client/debugger/new/test/mochitest/browser_dbg-pretty-print-console.js +++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-pretty-print-console.js @@ -1,7 +1,6 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; +/* 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 . */ async function waitForConsoleLink(dbg, text) { const toolbox = dbg.toolbox; diff --git a/devtools/client/debugger/new/test/mochitest/browser_dbg-preview-module.js b/devtools/client/debugger/new/test/mochitest/browser_dbg-preview-module.js index 365639c78599c..74bf692f0a804 100644 --- a/devtools/client/debugger/new/test/mochitest/browser_dbg-preview-module.js +++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-preview-module.js @@ -1,11 +1,15 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.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 . */ // Test hovering in a script that is paused on load // and doesn't have functions. add_task(async function() { const dbg = await initDebugger("doc-scripts.html"); - const { selectors: { getSelectedSource }, getState } = dbg; + const { + selectors: { getSelectedSource }, + getState + } = dbg; navigate(dbg, "doc-on-load.html"); diff --git a/devtools/client/debugger/new/test/mochitest/browser_dbg-stepping.js b/devtools/client/debugger/new/test/mochitest/browser_dbg-stepping.js index c856aca232da7..3393df4d62764 100644 --- a/devtools/client/debugger/new/test/mochitest/browser_dbg-stepping.js +++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-stepping.js @@ -1,5 +1,6 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.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 . */ // This test can be really slow on debug platforms requestLongerTimeout(5); diff --git a/devtools/client/debugger/new/test/mochitest/helpers.js b/devtools/client/debugger/new/test/mochitest/helpers.js index 287aaea540314..d3cff7e982e29 100644 --- a/devtools/client/debugger/new/test/mochitest/helpers.js +++ b/devtools/client/debugger/new/test/mochitest/helpers.js @@ -243,8 +243,7 @@ function waitForSelectedSource(dbg, url) { state, source.id ); - const hasPausePoints = dbg.selectors.hasPausePoints(state, source.id); - return hasSymbols && hasSourceMetaData && hasPausePoints; + return hasSymbols && hasSourceMetaData; }, "selected source" ); @@ -1317,7 +1316,17 @@ async function hoverAtPos(dbg, { line, ch }) { await waitForScrolling(cm); const coords = getCoordsFromPosition(cm, { line: line - 1, ch }); - const tokenEl = dbg.win.document.elementFromPoint(coords.left, coords.top); + + const { left, top } = coords; + + // Adds a vertical offset due to increased line height + // https://github.com/firefox-devtools/debugger.html/pull/7934 + const lineHeightOffset = 3; + + const tokenEl = dbg.win.document.elementFromPoint( + left, + top + lineHeightOffset + ); if (!tokenEl) { return false; diff --git a/devtools/client/locales/en-US/debugger.properties b/devtools/client/locales/en-US/debugger.properties index 008df57b0097a..08c4afc86c21b 100644 --- a/devtools/client/locales/en-US/debugger.properties +++ b/devtools/client/locales/en-US/debugger.properties @@ -10,9 +10,13 @@ # A good criteria is the language in which you'd find the best # documentation on web development on the web. -# LOCALIZATION NOTE (collapsePanes): This is the tooltip for the button -# that collapses the left and right panes in the debugger UI. -collapsePanes=Collapse panes +# LOCALIZATION NOTE (collapseSources): This is the tooltip for the button +# that collapses the Sources and Outlines panes in the debugger UI. +collapseSources=Collapse Sources and Outline panes + +# LOCALIZATION NOTE (collapseBreakpoints): This is the tooltip for the button +# that collapses the Breakpoints panes in the debugger UI. +collapseBreakpoints=Collapse Breakpoints pane # LOCALIZATION NOTE (copyToClipboard.label): This is the text that appears in the # context menu to copy the complete source of the open file. @@ -58,9 +62,13 @@ copyFunction.accesskey=F copyStackTrace=Copy stack trace copyStackTrace.accesskey=c -# LOCALIZATION NOTE (expandPanes): This is the tooltip for the button -# that expands the left and right panes in the debugger UI. -expandPanes=Expand panes +# LOCALIZATION NOTE (expandSources): This is the tooltip for the button +# that expands the Sources and Outlines panes in the debugger UI. +expandSources=Expand Sources and Outline panes + +# LOCALIZATION NOTE (expandBreakpoints): This is the tooltip for the button +# that expands the Breakpoints panes in the debugger UI. +expandBreakpoints=Expand Breakpoints pane # LOCALIZATION NOTE (evaluateInConsole.label): Editor right-click menu item # to execute selected text in browser console. diff --git a/devtools/client/preferences/debugger.js b/devtools/client/preferences/debugger.js index 25907cd6cad23..e175ae5964008 100644 --- a/devtools/client/preferences/debugger.js +++ b/devtools/client/preferences/debugger.js @@ -26,6 +26,7 @@ pref("devtools.debugger.ui.variables-sorting-enabled", true); pref("devtools.debugger.ui.variables-only-enum-visible", false); pref("devtools.debugger.ui.variables-searchbox-visible", false); pref("devtools.debugger.ui.framework-grouping-on", true); +pref("devtools.debugger.ui.editor-wrapping", false); pref("devtools.debugger.call-stack-visible", true); pref("devtools.debugger.scopes-visible", true); pref("devtools.debugger.component-visible", true); @@ -62,7 +63,6 @@ pref("devtools.debugger.features.workers", true); pref("devtools.debugger.features.code-coverage", false); pref("devtools.debugger.features.code-folding", false); pref("devtools.debugger.features.outline", true); -pref("devtools.debugger.features.pause-points", true); pref("devtools.debugger.features.component-pane", false); pref("devtools.debugger.features.async-stepping", true); pref("devtools.debugger.features.skip-pausing", true); @@ -70,6 +70,6 @@ pref("devtools.debugger.features.autocomplete-expressions", false); pref("devtools.debugger.features.map-expression-bindings", true); pref("devtools.debugger.features.xhr-breakpoints", true); pref("devtools.debugger.features.original-blackbox", true); -pref("devtools.debugger.features.windowless-workers", false); +pref("devtools.debugger.features.windowless-workers", true); pref("devtools.debugger.features.event-listeners-breakpoints", false); pref("devtools.debugger.features.log-points", true); diff --git a/devtools/client/shared/components/reps/reps.css b/devtools/client/shared/components/reps/reps.css index 5d97af519deb2..c5d8d20fd95a0 100644 --- a/devtools/client/shared/components/reps/reps.css +++ b/devtools/client/shared/components/reps/reps.css @@ -251,7 +251,7 @@ button.open-inspector { margin: 0 4px; padding: 0; border: none; - background-color: var(--comment-node-color); + background-color: var(--theme-icon-color); cursor: pointer; } @@ -260,7 +260,7 @@ button.open-inspector { .objectBox-textNode:hover .open-inspector, .open-accessibility-inspector:hover, .open-inspector:hover { - background-color: var(--theme-highlight-blue); + background-color: var(--theme-icon-checked-color); } /******************************************************************************/ @@ -269,14 +269,14 @@ button.open-inspector { button.jump-definition { mask: url("resource://devtools/client/shared/components/reps/images/jump-definition.svg") no-repeat; display: inline-block; - background-color: var(--comment-node-color); + background-color: var(--theme-icon-color); height: 16px; margin-left: 0.25em; vertical-align: middle; } .jump-definition:hover { - background-color: var(--theme-highlight-blue); + background-color: var(--theme-icon-checked-color); } /******************************************************************************/ @@ -285,14 +285,14 @@ button.jump-definition { button.invoke-getter { mask: url("resource://devtools/client/shared/components/reps/images/input.svg") no-repeat; display: inline-block; - background-color: var(--comment-node-color); + background-color: var(--theme-icon-color); height: 10px; vertical-align: middle; border:none; } .invoke-getter:hover { - background-color: var(--theme-highlight-blue); + background-color: var(--theme-icon-checked-color); } /******************************************************************************/ @@ -357,30 +357,27 @@ button.invoke-getter { } .tree-node button.arrow { - background:url("resource://devtools/client/debugger/new/images/arrow.svg") no-repeat; - background-size:contain; - background-position:center center; + mask: url("resource://devtools/client/debugger/new/images/arrow.svg") no-repeat center; + mask-size: 10px; + vertical-align: -1px; width: 10px; height: 10px; - border:0; - padding:0; + border: 0; + padding: 0; margin-inline-start: 1px; margin-inline-end: 4px; - transform: rotate(-90deg); transform-origin: center center; - transition: transform 0.125s ease; - align-self: center; - -moz-context-properties: fill; - fill: var(--theme-splitter-color, #9B9B9B); + transition: transform 125ms var(--animation-curve); + background-color: var(--theme-icon-dimmed-color); } -html[dir="rtl"] .tree-node button.arrow { - transform: rotate(90deg); +.tree-node button.arrow:not(.expanded) { + transform: rotate(-90deg); } -.tree-node button.arrow.expanded.expanded { - transform: rotate(0deg); - } +html[dir="rtl"] .tree-node button:not(.expanded) { + transform: rotate(90deg); +} .tree .tree-node.focused { color: white; @@ -388,7 +385,7 @@ html[dir="rtl"] .tree-node button.arrow { } .tree-node.focused button.arrow { - fill: currentColor; + background-color: currentColor; } /* 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 diff --git a/devtools/client/shared/components/reps/reps.js b/devtools/client/shared/components/reps/reps.js index a5679f6b6d726..fd5ff547086e1 100644 --- a/devtools/client/shared/components/reps/reps.js +++ b/devtools/client/shared/components/reps/reps.js @@ -3828,6 +3828,10 @@ __webpack_require__(3671); // depth const AUTO_EXPAND_DEPTH = 0; +// Simplied selector targetting elements that can receive the focus, +// full version at https://stackoverflow.com/questions/1599660. +const FOCUSABLE_SELECTOR = ["a[href]:not([tabindex='-1'])", "button:not([disabled]):not([tabindex='-1'])", "iframe:not([tabindex='-1'])", "input:not([disabled]):not([tabindex='-1'])", "select:not([disabled]):not([tabindex='-1'])", "textarea:not([disabled]):not([tabindex='-1'])", "[tabindex]:not([tabindex='-1'])"].join(", "); + /** * An arrow that displays whether its node is expanded (▼) or collapsed * (▶). When its node has no children, it is hidden. @@ -3865,6 +3869,7 @@ class TreeNode extends Component { index: _propTypes2.default.number.isRequired, depth: _propTypes2.default.number.isRequired, focused: _propTypes2.default.bool.isRequired, + active: _propTypes2.default.bool.isRequired, expanded: _propTypes2.default.bool.isRequired, item: _propTypes2.default.any.isRequired, isExpandable: _propTypes2.default.bool.isRequired, @@ -3873,16 +3878,95 @@ class TreeNode extends Component { }; } + constructor(props) { + super(props); + + this.treeNodeRef = _react2.default.createRef(); + + this._onKeyDown = this._onKeyDown.bind(this); + } + + componentDidMount() { + // Make sure that none of the focusable elements inside the tree node + // container are tabbable if the tree node is not active. If the tree node + // is active and focus is outside its container, focus on the first + // focusable element inside. + const elms = this.getFocusableElements(); + if (this.props.active) { + if (elms.length > 0 && !elms.includes(document.activeElement)) { + elms[0].focus(); + } + } else { + elms.forEach(elm => elm.setAttribute("tabindex", "-1")); + } + } + shouldComponentUpdate(nextProps) { return this.props.item !== nextProps.item || this.props.focused !== nextProps.focused || this.props.expanded !== nextProps.expanded; } + /** + * Get a list of all elements that are focusable with a keyboard inside the + * tree node. + */ + getFocusableElements() { + return this.treeNodeRef.current ? Array.from(this.treeNodeRef.current.querySelectorAll(FOCUSABLE_SELECTOR)) : []; + } + + /** + * Wrap and move keyboard focus to first/last focusable element inside the + * tree node to prevent the focus from escaping the tree node boundaries. + * element). + * + * @param {DOMNode} current currently focused element + * @param {Boolean} back direction + * @return {Boolean} true there is a newly focused element. + */ + _wrapMoveFocus(current, back) { + const elms = this.getFocusableElements(); + let next; + + if (elms.length === 0) { + return false; + } + + if (back) { + if (elms.indexOf(current) === 0) { + next = elms[elms.length - 1]; + next.focus(); + } + } else if (elms.indexOf(current) === elms.length - 1) { + next = elms[0]; + next.focus(); + } + + return !!next; + } + + _onKeyDown(e) { + const { target, key, shiftKey } = e; + + if (key !== "Tab") { + return; + } + + const focusMoved = this._wrapMoveFocus(target, shiftKey); + if (focusMoved) { + // Focus was moved to the begining/end of the list, so we need to prevent + // the default focus change that would happen here. + e.preventDefault(); + } + + e.stopPropagation(); + } + render() { const { depth, id, item, focused, + active, expanded, renderItem, isExpandable @@ -3906,9 +3990,11 @@ class TreeNode extends Component { return _reactDomFactories2.default.div({ id, - className: `tree-node${focused ? " focused" : ""}`, + className: `tree-node${focused ? " focused" : ""}${active ? " active" : ""}`, onClick: this.props.onClick, + onKeyDownCapture: active ? this._onKeyDown : null, role: "treeitem", + ref: this.treeNodeRef, "aria-level": depth + 1, "aria-expanded": ariaExpanded, "data-expandable": this.props.isExpandable @@ -4142,6 +4228,8 @@ class Tree extends Component { // onExpand: item => dispatchExpandActionToRedux(item) onExpand: _propTypes2.default.func, onCollapse: _propTypes2.default.func, + // The currently active (keyboard) item, if any such item exists. + active: _propTypes2.default.any, // Optional event handler called with the current focused node when the // Enter key is pressed. Can be useful to allow further keyboard actions // within the tree node. @@ -4170,6 +4258,8 @@ class Tree extends Component { seen: new Set() }; + this.treeRef = _react2.default.createRef(); + this._onExpand = oncePerAnimationFrame(this._onExpand).bind(this); this._onCollapse = oncePerAnimationFrame(this._onCollapse).bind(this); this._focusPrevNode = oncePerAnimationFrame(this._focusPrevNode).bind(this); @@ -4180,22 +4270,21 @@ class Tree extends Component { this._autoExpand = this._autoExpand.bind(this); this._preventArrowKeyScrolling = this._preventArrowKeyScrolling.bind(this); + this._preventEvent = this._preventEvent.bind(this); this._dfs = this._dfs.bind(this); this._dfsFromRoots = this._dfsFromRoots.bind(this); this._focus = this._focus.bind(this); + this._activate = this._activate.bind(this); this._scrollNodeIntoView = this._scrollNodeIntoView.bind(this); this._onBlur = this._onBlur.bind(this); this._onKeyDown = this._onKeyDown.bind(this); this._nodeIsExpandable = this._nodeIsExpandable.bind(this); - this._activateNode = oncePerAnimationFrame(this._activateNode).bind(this); } componentDidMount() { this._autoExpand(); if (this.props.focused) { this._scrollNodeIntoView(this.props.focused); - // Always keep the focus on the tree itself. - this.treeRef.focus(); } } @@ -4206,8 +4295,6 @@ class Tree extends Component { componentDidUpdate(prevProps, prevState) { if (this.props.focused && prevProps.focused !== this.props.focused) { this._scrollNodeIntoView(this.props.focused); - // Always keep the focus on the tree itself. - this.treeRef.focus(); } } @@ -4256,16 +4343,21 @@ class Tree extends Component { case "ArrowDown": case "ArrowLeft": case "ArrowRight": - e.preventDefault(); - e.stopPropagation(); - if (e.nativeEvent) { - if (e.nativeEvent.preventDefault) { - e.nativeEvent.preventDefault(); - } - if (e.nativeEvent.stopPropagation) { - e.nativeEvent.stopPropagation(); - } - } + this._preventEvent(e); + break; + } + } + + _preventEvent(e) { + e.preventDefault(); + e.stopPropagation(); + if (e.nativeEvent) { + if (e.nativeEvent.preventDefault) { + e.nativeEvent.preventDefault(); + } + if (e.nativeEvent.stopPropagation) { + e.nativeEvent.stopPropagation(); + } } } @@ -4357,11 +4449,31 @@ class Tree extends Component { if (item && !preventAutoScroll) { this._scrollNodeIntoView(item, options); } + + if (this.props.active != undefined) { + this._activate(undefined); + if (this.treeRef.current !== document.activeElement) { + this.treeRef.current.focus(); + } + } + if (this.props.onFocus) { this.props.onFocus(item); } } + /** + * Sets the passed in item to be the active item. + * + * @param {Object|undefined} item + * The item to be activated, or undefined to activate no item. + */ + _activate(item) { + if (this.props.onActivate) { + this.props.onActivate(item); + } + } + /** * Sets the passed in item to be the focused item. * @@ -4376,7 +4488,7 @@ class Tree extends Component { */ _scrollNodeIntoView(item, options = {}) { if (item !== undefined) { - const treeElement = this.treeRef; + const treeElement = this.treeRef.current; const element = document.getElementById(this.props.getKey(item)); if (element) { @@ -4407,8 +4519,13 @@ class Tree extends Component { /** * Sets the state to have no focused item. */ - _onBlur() { - if (!this.props.preventBlur) { + _onBlur(e) { + if (this.props.active != undefined) { + const { relatedTarget } = e; + if (!this.treeRef.current.contains(relatedTarget)) { + this._activate(undefined); + } + } else if (!this.props.preventBlur) { this._focus(undefined); } } @@ -4418,6 +4535,7 @@ class Tree extends Component { * * @param {Event} e */ + // eslint-disable-next-line complexity _onKeyDown(e) { if (this.props.focused == null) { return; @@ -4464,7 +4582,25 @@ class Tree extends Component { return; case "Enter": - this._activateNode(); + case " ": + if (this.treeRef.current === document.activeElement) { + this._preventEvent(e); + if (this.props.active !== this.props.focused) { + this._activate(this.props.focused); + } + } + return; + + case "Escape": + this._preventEvent(e); + if (this.props.active != undefined) { + this._activate(undefined); + } + + if (this.treeRef.current !== document.activeElement) { + this.treeRef.current.focus(); + } + return; } } @@ -4543,31 +4679,29 @@ class Tree extends Component { this._focus(traversal[lastIndex].item, { alignTo: "bottom" }); } - _activateNode() { - if (this.props.onActivate) { - this.props.onActivate(this.props.focused); - } - } - _nodeIsExpandable(item) { return this.props.isExpandable ? this.props.isExpandable(item) : !!this.props.getChildren(item).length; } render() { const traversal = this._dfsFromRoots(); - const { focused } = this.props; + const { active, focused } = this.props; const nodes = traversal.map((v, i) => { const { item, depth } = traversal[i]; const key = this.props.getKey(item, i); return TreeNodeFactory({ - key, + // We make a key unique depending on whether the tree node is in active + // or inactive state to make sure that it is actually replaced and the + // tabbable state is reset. + key: `${key}-${active === item ? "active" : "inactive"}`, id: key, index: i, item, depth, renderItem: this.props.renderItem, focused: focused === item, + active: active === item, expanded: this.props.isExpanded(item), isExpandable: this._nodeIsExpandable(item), onExpand: this._onExpand, @@ -4585,6 +4719,9 @@ class Tree extends Component { } else { this.props.onExpand(item, e.altKey); } + + // Focus should always remain on the tree container itself. + this.treeRef.current.focus(); } }); }); @@ -4593,16 +4730,14 @@ class Tree extends Component { return _reactDomFactories2.default.div({ className: `tree ${this.props.className ? this.props.className : ""}`, - ref: el => { - this.treeRef = el; - }, + ref: this.treeRef, role: "tree", tabIndex: "0", onKeyDown: this._onKeyDown, onKeyPress: this._preventArrowKeyScrolling, onKeyUp: this._preventArrowKeyScrolling, onFocus: ({ nativeEvent }) => { - if (focused || !nativeEvent || !this.treeRef) { + if (focused || !nativeEvent || !this.treeRef.current) { return; } @@ -4610,7 +4745,7 @@ class Tree extends Component { // Only set default focus to the first tree node if the focus came // from outside the tree (e.g. by tabbing to the tree from other // external elements). - if (explicitOriginalTarget !== this.treeRef && !this.treeRef.contains(explicitOriginalTarget)) { + if (explicitOriginalTarget !== this.treeRef.current && !this.treeRef.current.contains(explicitOriginalTarget)) { this._focus(traversal[0].item); } }, @@ -6778,6 +6913,7 @@ class ObjectInspector extends Component { self.isNodeExpandable = this.isNodeExpandable.bind(this); self.setExpanded = this.setExpanded.bind(this); self.focusItem = this.focusItem.bind(this); + self.activateItem = this.activateItem.bind(this); self.getRoots = this.getRoots.bind(this); self.getNodeKey = this.getNodeKey.bind(this); } @@ -6785,6 +6921,7 @@ class ObjectInspector extends Component { componentWillMount() { this.roots = this.props.roots; this.focusedItem = this.props.focusedItem; + this.activeItem = this.props.activeItem; } componentWillUpdate(nextProps) { @@ -6795,6 +6932,7 @@ class ObjectInspector extends Component { // so we need to cleanup the component internal state. this.roots = nextProps.roots; this.focusedItem = nextProps.focusedItem; + this.activeItem = nextProps.activeItem; if (this.props.rootsChanged) { this.props.rootsChanged(); } @@ -6831,7 +6969,8 @@ class ObjectInspector extends Component { // - OR the expanded paths number did not changed, but old and new sets // differ // - OR the focused node changed. - return loadedProperties.size !== nextProps.loadedProperties.size || evaluations.size !== nextProps.evaluations.size || expandedPaths.size !== nextProps.expandedPaths.size && [...nextProps.expandedPaths].every(path => nextProps.loadedProperties.has(path)) || expandedPaths.size === nextProps.expandedPaths.size && [...nextProps.expandedPaths].some(key => !expandedPaths.has(key)) || this.focusedItem !== nextProps.focusedItem || this.roots !== nextProps.roots; + // - OR the active node changed. + return loadedProperties.size !== nextProps.loadedProperties.size || evaluations.size !== nextProps.evaluations.size || expandedPaths.size !== nextProps.expandedPaths.size && [...nextProps.expandedPaths].every(path => nextProps.loadedProperties.has(path)) || expandedPaths.size === nextProps.expandedPaths.size && [...nextProps.expandedPaths].some(key => !expandedPaths.has(key)) || this.focusedItem !== nextProps.focusedItem || this.activeItem !== nextProps.activeItem || this.roots !== nextProps.roots; } componentWillUnmount() { @@ -6906,6 +7045,19 @@ class ObjectInspector extends Component { } } + activateItem(item) { + const { focusable = true, onActivate } = this.props; + + if (focusable && this.activeItem !== item) { + this.activeItem = item; + this.forceUpdate(); + + if (onActivate) { + onActivate(item); + } + } + } + render() { const { autoExpandAll = true, @@ -6929,6 +7081,7 @@ class ObjectInspector extends Component { isExpanded: item => expandedPaths && expandedPaths.has(item.path), isExpandable: this.isNodeExpandable, focused: this.focusedItem, + active: this.activeItem, getRoots: this.getRoots, getParent, @@ -6938,6 +7091,7 @@ class ObjectInspector extends Component { onExpand: item => this.setExpanded(item, true), onCollapse: item => this.setExpanded(item, false), onFocus: focusable ? this.focusItem : null, + onActivate: focusable ? this.activateItem : null, renderItem: (item, depth, focused, arrow, expanded) => ObjectInspectorItem({ ...this.props, @@ -7220,4 +7374,4 @@ module.exports = ObjectInspectorItem; /***/ }) /******/ }); -}); +}); \ No newline at end of file diff --git a/devtools/client/webconsole/test/mochitest/browser_webconsole_object_in_sidebar_keyboard_nav.js b/devtools/client/webconsole/test/mochitest/browser_webconsole_object_in_sidebar_keyboard_nav.js index 17acad6df48ed..91e3fe81dccd8 100644 --- a/devtools/client/webconsole/test/mochitest/browser_webconsole_object_in_sidebar_keyboard_nav.js +++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_object_in_sidebar_keyboard_nav.js @@ -35,6 +35,7 @@ add_task(async function() { // There are 5 nodes: the root, a, b, c, and proto. await waitFor(() => objectInspector.querySelectorAll(".node").length === 5); + objectInspector.focus(); const [ root, diff --git a/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp b/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp index 4a9bc714584a4..84d3b89f74de9 100644 --- a/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp +++ b/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp @@ -58,8 +58,6 @@ typedef enum FT_LcdFilter_ #define SK_FONTHOST_CAIRO_STANDALONE 1 #endif -static cairo_user_data_key_t kSkTypefaceKey; - static bool gFontHintingEnabled = true; static FT_Error (*gSetLcdFilter)(FT_Library, FT_LcdFilter) = nullptr; static void (*gGlyphSlotEmbolden)(FT_GlyphSlot) = nullptr; @@ -259,7 +257,6 @@ class SkCairoFTTypeface : public SkTypeface { , fFontFace(fontFace) , fPattern(pattern) { - cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, this, nullptr); cairo_font_face_reference(fFontFace); #ifdef CAIRO_HAS_FC_FONT if (fPattern) { @@ -268,10 +265,11 @@ class SkCairoFTTypeface : public SkTypeface { #endif } + cairo_font_face_t* GetCairoFontFace() const { return fFontFace; } + private: ~SkCairoFTTypeface() { - cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, nullptr, nullptr); cairo_font_face_destroy(fFontFace); #ifdef CAIRO_HAS_FC_FONT if (fPattern) { @@ -284,16 +282,18 @@ class SkCairoFTTypeface : public SkTypeface { FcPattern* fPattern; }; +static bool FindByCairoFontFace(SkTypeface* typeface, void* context) { + return static_cast(typeface)->GetCairoFontFace() == static_cast(context); +} + SkTypeface* SkCreateTypefaceFromCairoFTFontWithFontconfig(cairo_scaled_font_t* scaledFont, FcPattern* pattern) { cairo_font_face_t* fontFace = cairo_scaled_font_get_font_face(scaledFont); SkASSERT(cairo_font_face_status(fontFace) == CAIRO_STATUS_SUCCESS); SkASSERT(cairo_font_face_get_type(fontFace) == CAIRO_FONT_TYPE_FT); - SkTypeface* typeface = reinterpret_cast(cairo_font_face_get_user_data(fontFace, &kSkTypefaceKey)); - if (typeface) { - typeface->ref(); - } else { + SkTypeface* typeface = SkTypefaceCache::FindByProcAndRef(FindByCairoFontFace, fontFace); + if (!typeface) { typeface = new SkCairoFTTypeface(fontFace, pattern); SkTypefaceCache::Add(typeface); } diff --git a/js/src/wasm/WasmBaselineCompile.cpp b/js/src/wasm/WasmBaselineCompile.cpp index 370bc50622019..288a20b3b6a35 100644 --- a/js/src/wasm/WasmBaselineCompile.cpp +++ b/js/src/wasm/WasmBaselineCompile.cpp @@ -8395,6 +8395,12 @@ bool BaseCompiler::emitEnd() { } switch (kind) { + case LabelKind::Body: + endBlock(type); + iter_.popEnd(); + MOZ_ASSERT(iter_.controlStackEmpty()); + doReturn(type, PopStack(false)); + return iter_.readFunctionEnd(iter_.end()); case LabelKind::Block: endBlock(type); break; @@ -8558,6 +8564,9 @@ bool BaseCompiler::emitDrop() { } void BaseCompiler::doReturn(ExprType type, bool popStack) { + if (deadCode_) { + return; + } switch (type.code()) { case ExprType::Void: { returnCleanup(popStack); @@ -10944,12 +10953,8 @@ bool BaseCompiler::emitBody() { if (!emitEnd()) { return false; } - if (iter_.controlStackEmpty()) { - if (!deadCode_) { - doReturn(funcType().ret(), PopStack(false)); - } - return iter_.readFunctionEnd(iter_.end()); + return true; } NEXT(); diff --git a/js/src/wasm/WasmCode.h b/js/src/wasm/WasmCode.h index 43e3e2572ac13..315c5fe39d86b 100644 --- a/js/src/wasm/WasmCode.h +++ b/js/src/wasm/WasmCode.h @@ -19,6 +19,7 @@ #ifndef wasm_code_h #define wasm_code_h +#include "jit/shared/Assembler-shared.h" #include "js/HashTable.h" #include "threading/ExclusiveData.h" #include "vm/MutexIDs.h" @@ -292,11 +293,6 @@ class FuncImport { typedef Vector FuncImportVector; -// A wasm module can either use no memory, a unshared memory (ArrayBuffer) or -// shared memory (SharedArrayBuffer). - -enum class MemoryUsage { None = false, Unshared = 1, Shared = 2 }; - // Metadata holds all the data that is needed to describe compiled wasm code // at runtime (as opposed to data that is only used to statically link or // instantiate a module). diff --git a/js/src/wasm/WasmInstance.cpp b/js/src/wasm/WasmInstance.cpp index bcea25cb9493d..420ec5af2a37c 100644 --- a/js/src/wasm/WasmInstance.cpp +++ b/js/src/wasm/WasmInstance.cpp @@ -1212,9 +1212,9 @@ bool Instance::init(JSContext* cx, const DataSegmentVector& dataSegments, } JitRuntime* jitRuntime = cx->runtime()->jitRuntime(); - jsJitArgsRectifier_ = jitRuntime->getArgumentsRectifier(); - jsJitExceptionHandler_ = jitRuntime->getExceptionTail(); - preBarrierCode_ = jitRuntime->preBarrier(MIRType::Object); + jsJitArgsRectifier_ = jitRuntime->getArgumentsRectifier().value; + jsJitExceptionHandler_ = jitRuntime->getExceptionTail().value; + preBarrierCode_ = jitRuntime->preBarrier(MIRType::Object).value; if (!passiveDataSegments_.resize(dataSegments.length())) { return false; diff --git a/js/src/wasm/WasmInstance.h b/js/src/wasm/WasmInstance.h index 70ac7e2b8e617..3549bea02ebdc 100644 --- a/js/src/wasm/WasmInstance.h +++ b/js/src/wasm/WasmInstance.h @@ -21,7 +21,6 @@ #include "builtin/TypedObject.h" #include "gc/Barrier.h" -#include "jit/shared/Assembler-shared.h" #include "vm/SharedMem.h" #include "wasm/WasmCode.h" #include "wasm/WasmDebug.h" @@ -45,9 +44,9 @@ namespace wasm { class Instance { JS::Realm* const realm_; ReadBarrieredWasmInstanceObject object_; - jit::TrampolinePtr jsJitArgsRectifier_; - jit::TrampolinePtr jsJitExceptionHandler_; - jit::TrampolinePtr preBarrierCode_; + void* jsJitArgsRectifier_; + void* jsJitExceptionHandler_; + void* preBarrierCode_; const SharedCode code_; const UniqueTlsData tlsData_; GCPtrWasmMemoryObject memory_; diff --git a/js/src/wasm/WasmIonCompile.cpp b/js/src/wasm/WasmIonCompile.cpp index 5092f2451781e..ee76fdfa8af6b 100644 --- a/js/src/wasm/WasmIonCompile.cpp +++ b/js/src/wasm/WasmIonCompile.cpp @@ -1784,6 +1784,17 @@ static bool EmitEnd(FunctionCompiler& f) { MDefinition* def = nullptr; switch (kind) { + case LabelKind::Body: + MOZ_ASSERT(f.iter().controlStackEmpty()); + if (!f.finishBlock(&def)) { + return false; + } + if (f.inDeadCode() || IsVoid(type)) { + f.returnVoid(); + } else { + f.returnExpr(def); + } + return f.iter().readFunctionEnd(f.iter().end()); case LabelKind::Block: if (!f.finishBlock(&def)) { return false; @@ -3109,14 +3120,8 @@ static bool EmitBodyExprs(FunctionCompiler& f) { if (!EmitEnd(f)) { return false; } - if (f.iter().controlStackEmpty()) { - if (f.inDeadCode() || IsVoid(f.funcType().ret())) { - f.returnVoid(); - } else { - f.returnExpr(f.iter().getResult()); - } - return f.iter().readFunctionEnd(f.iter().end()); + return true; } break; diff --git a/js/src/wasm/WasmModule.h b/js/src/wasm/WasmModule.h index 8f66b97952acf..c4477facd252c 100644 --- a/js/src/wasm/WasmModule.h +++ b/js/src/wasm/WasmModule.h @@ -19,14 +19,10 @@ #ifndef wasm_module_h #define wasm_module_h -#include "jit/shared/Assembler-shared.h" -#include "js/TypeDecls.h" -#include "threading/ConditionVariable.h" -#include "threading/Mutex.h" -#include "vm/MutexIDs.h" +#include "js/BuildId.h" + #include "wasm/WasmCode.h" #include "wasm/WasmTable.h" -#include "wasm/WasmValidate.h" namespace js { namespace wasm { diff --git a/js/src/wasm/WasmOpIter.h b/js/src/wasm/WasmOpIter.h index 34ec6a3091522..7210f96100d9d 100644 --- a/js/src/wasm/WasmOpIter.h +++ b/js/src/wasm/WasmOpIter.h @@ -30,7 +30,7 @@ namespace js { namespace wasm { // The kind of a control-flow stack item. -enum class LabelKind : uint8_t { Block, Loop, Then, Else }; +enum class LabelKind : uint8_t { Body, Block, Loop, Then, Else }; // The type of values on the operand stack during validation. The Any type // represents the type of a value produced by an unconditional branch. @@ -637,37 +637,13 @@ inline bool OpIter::popStackType(StackType* type, Value* value) { // expected type which can either be a specific value type or a type variable. template inline bool OpIter::popWithType(ValType expectedType, Value* value) { - ControlStackEntry& block = controlStack_.back(); - - MOZ_ASSERT(valueStack_.length() >= block.valueStackStart()); - if (MOZ_UNLIKELY(valueStack_.length() == block.valueStackStart())) { - // If the base of this block's stack is polymorphic, then we can pop a - // dummy value of any expected type; it won't be used since we're in - // unreachable code. - if (block.polymorphicBase()) { - *value = Value(); - - // Maintain the invariant that, after a pop, there is always memory - // reserved to push a value infallibly. - return valueStack_.reserve(valueStack_.length() + 1); - } - - return failEmptyStack(); - } - - TypeAndValue observed = valueStack_.popCopy(); - - if (observed.type() == StackType::TVar) { - *value = Value(); - return true; - } - - if (!checkIsSubtypeOf(NonTVarToValType(observed.type()), expectedType)) { + StackType stackType(expectedType); + if (!popStackType(&stackType, value)) { return false; } - *value = observed.value(); - return true; + return stackType == StackType::TVar || + checkIsSubtypeOf(NonTVarToValType(stackType), expectedType); } // This function pops as many types from the stack as determined by the given @@ -839,7 +815,7 @@ inline bool OpIter::readFunctionStart(ExprType ret) { MOZ_ASSERT(controlStack_.empty()); MOZ_ASSERT(op_.b0 == uint16_t(Op::Limit)); - return pushControl(LabelKind::Block, ret); + return pushControl(LabelKind::Body, ret); } template @@ -864,7 +840,7 @@ inline bool OpIter::readReturn(Value* value) { MOZ_ASSERT(Classify(op_) == OpKind::Return); ControlStackEntry& body = controlStack_[0]; - MOZ_ASSERT(body.kind() == LabelKind::Block); + MOZ_ASSERT(body.kind() == LabelKind::Body); if (!popWithType(body.resultType(), value)) { return false; diff --git a/js/src/wasm/WasmSignalHandlers.cpp b/js/src/wasm/WasmSignalHandlers.cpp index 4ca060acfa521..fc49f361d82a7 100644 --- a/js/src/wasm/WasmSignalHandlers.cpp +++ b/js/src/wasm/WasmSignalHandlers.cpp @@ -23,6 +23,7 @@ #include "mozilla/ThreadLocal.h" #include "threading/Thread.h" +#include "vm/Realm.h" #include "vm/Runtime.h" #include "wasm/WasmInstance.h" diff --git a/js/src/wasm/WasmTypes.h b/js/src/wasm/WasmTypes.h index 82390415bc66a..3c90b52f7d139 100644 --- a/js/src/wasm/WasmTypes.h +++ b/js/src/wasm/WasmTypes.h @@ -624,6 +624,11 @@ enum class CompileMode { Once, Tier1, Tier2 }; enum class DebugEnabled { False, True }; +// A wasm module can either use no memory, a unshared memory (ArrayBuffer) or +// shared memory (SharedArrayBuffer). + +enum class MemoryUsage { None = false, Unshared = 1, Shared = 2 }; + // Iterator over tiers present in a tiered data structure. class Tiers { diff --git a/js/src/wasm/WasmValidate.h b/js/src/wasm/WasmValidate.h index 093f463a11785..e97570c491af5 100644 --- a/js/src/wasm/WasmValidate.h +++ b/js/src/wasm/WasmValidate.h @@ -21,7 +21,6 @@ #include "mozilla/TypeTraits.h" -#include "wasm/WasmCode.h" #include "wasm/WasmTypes.h" namespace js { diff --git a/python/mozbuild/mozbuild/artifacts.py b/python/mozbuild/mozbuild/artifacts.py index 5eee57f17df46..d51c3899676ae 100644 --- a/python/mozbuild/mozbuild/artifacts.py +++ b/python/mozbuild/mozbuild/artifacts.py @@ -1051,13 +1051,6 @@ def _pushheads_from_rev(self, rev, count): found_pushids = {} search_trees = list(CANDIDATE_TREES) - # We aren't generally interested in pushes from autoland because - # people aren't generally working off of autoland locally, but we - # sometimes find errant public pushheads on autoland in automation, - # so we check autoland in automation as a workaround. - if os.environ.get('MOZ_AUTOMATION'): - search_trees += ['integration/autoland'] - for tree in search_trees: self.log(logging.INFO, 'artifact', {'tree': tree, @@ -1318,6 +1311,23 @@ def install_from_revset(self, revset, distdir): pushheads = [(list(CANDIDATE_TREES) + ['try'], revision)] return self._install_from_hg_pushheads(pushheads, distdir) + def install_from_task(self, taskId, distdir): + artifacts = list_artifacts(taskId) + + urls = [] + for artifact_name in self._artifact_job.find_candidate_artifacts(artifacts): + # We can easily extract the task ID from the URL. We can't easily + # extract the build ID; we use the .ini files embedded in the + # downloaded artifact for this. + url = get_artifact_url(taskId, artifact_name) + urls.append(url) + if not urls: + raise ValueError('Task {taskId} existed, but no artifacts found!'.format(taskId=taskId)) + for url in urls: + if self.install_from_url(url, distdir): + return 1 + return 0 + def install_from(self, source, distdir): """Install artifacts from a ``source`` into the given ``distdir``. """ @@ -1332,6 +1342,9 @@ def install_from(self, source, distdir): if source: return self.install_from_revset(source, distdir) + if 'MOZ_ARTIFACT_TASK' in os.environ: + return self.install_from_task(os.environ['MOZ_ARTIFACT_TASK'], distdir) + return self.install_from_recent(distdir) diff --git a/python/mozbuild/mozbuild/base.py b/python/mozbuild/mozbuild/base.py index e6b17d6767737..580bb22839378 100644 --- a/python/mozbuild/mozbuild/base.py +++ b/python/mozbuild/mozbuild/base.py @@ -247,13 +247,17 @@ def depends_impl(self, *args, **kwargs): sandbox = ReducedConfigureSandbox({}, environ=env, argv=['mach', '--help'], stdout=out, stderr=out) base_dir = os.path.join(topsrcdir, 'build', 'moz.configure') - sandbox.include_file(os.path.join(base_dir, 'init.configure')) - # Force mozconfig options injection before getting the target. - sandbox._value_for(sandbox['mozconfig_options']) - return ( - sandbox._value_for(sandbox['mozconfig']), - sandbox._value_for(sandbox['real_target']), - ) + try: + sandbox.include_file(os.path.join(base_dir, 'init.configure')) + # Force mozconfig options injection before getting the target. + sandbox._value_for(sandbox['mozconfig_options']) + return ( + sandbox._value_for(sandbox['mozconfig']), + sandbox._value_for(sandbox['real_target']), + ) + except SystemExit: + print(out.getvalue()) + raise @property def mozconfig_and_target(self): diff --git a/python/mozbuild/mozbuild/configure/__init__.py b/python/mozbuild/mozbuild/configure/__init__.py index 44ae9aa2ce8d7..14c896b5f6c88 100644 --- a/python/mozbuild/mozbuild/configure/__init__.py +++ b/python/mozbuild/mozbuild/configure/__init__.py @@ -41,6 +41,10 @@ import mozpack.path as mozpath +# TRACE logging level, below (thus more verbose than) DEBUG +TRACE = 5 + + class ConfigureError(Exception): pass @@ -149,8 +153,7 @@ def result(self): return self._func(*resolved_args) def __repr__(self): - return '<%s.%s %s(%s)>' % ( - self.__class__.__module__, + return '<%s %s(%s)>' % ( self.__class__.__name__, self.name, ', '.join(repr(d) for d in self.dependencies), @@ -333,6 +336,7 @@ def __init__(self, config, environ=os.environ, argv=sys.argv, assert isinstance(config, dict) self._config = config + logging.addLevelName(TRACE, 'TRACE') if logger is None: logger = moz_logger = logging.getLogger('moz.configure') logger.setLevel(logging.DEBUG) @@ -511,7 +515,9 @@ def _value_for(self, obj): @memoize def _value_for_depends(self, obj): - return obj.result() + value = obj.result() + self._logger.log(TRACE, '%r = %r', obj, value) + return value @memoize def _value_for_option(self, option): @@ -572,8 +578,10 @@ def _value_for_option(self, option): raise InvalidOptionError( '%s is not available in this configuration' % option_string.split('=', 1)[0]) + self._logger.log(TRACE, '%r = None', option) return None + self._logger.log(TRACE, '%r = %r', option, value) return value def _dependency(self, arg, callee_name, arg_name=None): @@ -906,6 +914,11 @@ def _resolve_and_set(self, data, name, value, when=None): "exists" % name) value = self._resolve(value) if value is not None: + if self._logger.isEnabledFor(TRACE): + if data is self._config: + self._logger.log(TRACE, 'set_config(%s, %r)', name, value) + elif data is self._config.get('DEFINES'): + self._logger.log(TRACE, 'set_define(%s, %r)', name, value) data[name] = value def set_config_impl(self, name, value, when=None): diff --git a/python/mozbuild/mozbuild/configure/options.py b/python/mozbuild/mozbuild/configure/options.py index c26c99a2f48dc..b8e4365abd21d 100644 --- a/python/mozbuild/mozbuild/configure/options.py +++ b/python/mozbuild/mozbuild/configure/options.py @@ -388,8 +388,7 @@ def get_value(self, option=None, origin='unknown'): return values def __repr__(self): - return '<%s.%s [%s]>' % (self.__class__.__module__, - self.__class__.__name__, self.option) + return '<%s [%s]>' % (self.__class__.__name__, self.option) class CommandLineHelper(object): diff --git a/python/mozbuild/mozbuild/mach_commands.py b/python/mozbuild/mozbuild/mach_commands.py index 77169bb7fc391..668eee91d80ce 100644 --- a/python/mozbuild/mozbuild/mach_commands.py +++ b/python/mozbuild/mozbuild/mach_commands.py @@ -1194,22 +1194,41 @@ def default(self, obj): return json.JSONEncoder.default(self, obj) json.dump(self, cls=EnvironmentEncoder, sort_keys=True, fp=out) + +JOB_CHOICES = { + 'android-api-16-opt', + 'android-api-16-debug', + 'android-x86-opt', + 'android-x86_64-opt', + 'android-x86_64-debug', + 'android-aarch64-opt', + 'android-aarch64-debug', + 'linux-opt', + 'linux-pgo', + 'linux-debug', + 'linux64-opt', + 'linux64-pgo', + 'linux64-debug', + 'macosx64-opt', + 'macosx64-debug', + 'win32-opt', + 'win32-pgo', + 'win32-debug', + 'win64-opt', + 'win64-pgo', + 'win64-debug', + 'win64-aarch64-opt', + 'win64-aarch64-debug', +} + + class ArtifactSubCommand(SubCommand): def __call__(self, func): after = SubCommand.__call__(self, func) - jobchoices = { - 'android-api-16', - 'android-x86', - 'linux', - 'linux64', - 'macosx64', - 'win32', - 'win64' - } args = [ CommandArgument('--tree', metavar='TREE', type=str, help='Firefox tree.'), - CommandArgument('--job', metavar='JOB', choices=jobchoices, + CommandArgument('--job', metavar='JOB', choices=JOB_CHOICES, help='Build job.'), CommandArgument('--verbose', '-v', action='store_true', help='Print verbose output.'), @@ -1251,7 +1270,12 @@ def _make_artifacts(self, tree=None, job=None, skip_cache=False): if conditions.is_git(self): git = self.substs['GIT'] - from mozbuild.artifacts import Artifacts + from mozbuild.artifacts import (Artifacts, JOB_DETAILS) + # We can't derive JOB_CHOICES from JOB_DETAILS because we don't want to + # import the artifacts module globally ; and this module can't be + # imported in unit tests, so do the check here. + assert set(JOB_DETAILS.keys()) == JOB_CHOICES + artifacts = Artifacts(tree, self.substs, self.defines, job, log=self.log, cache_dir=cache_dir, skip_cache=skip_cache, hg=hg, git=git, diff --git a/python/mozbuild/mozbuild/test/configure/test_moz_configure.py b/python/mozbuild/mozbuild/test/configure/test_moz_configure.py index 502ce889a83fb..fa88e700d0cf5 100644 --- a/python/mozbuild/mozbuild/test/configure/test_moz_configure.py +++ b/python/mozbuild/mozbuild/test/configure/test_moz_configure.py @@ -20,6 +20,8 @@ def get_target(self, args, env={}): platform = 'linux2' elif 'mingw' in self.HOST: platform = 'win32' + elif 'openbsd6' in self.HOST: + platform = 'openbsd6' else: raise Exception('Missing platform for HOST {}'.format(self.HOST)) wrapped_sys = {} @@ -122,6 +124,20 @@ def test_target(self): 'arm-unknown-linux-androideabi') +class TestTargetOpenBSD(TargetTest): + # config.guess returns amd64 on OpenBSD, which we need to pass through to + # config.sub so that it canonicalizes to x86_64. + HOST = 'amd64-unknown-openbsd6.4' + + def test_target(self): + self.assertEqual(self.get_target([]), 'x86_64-unknown-openbsd6.4') + + def config_sub(self, stdin, args): + if args[0] == 'amd64-unknown-openbsd6.4': + return 0, 'x86_64-unknown-openbsd6.4', '' + return super(TestTargetOpenBSD, self).config_sub(stdin, args) + + class TestMozConfigure(BaseConfigureTest): def test_nsis_version(self): this = self diff --git a/taskcluster/ci/artifact-build/kind.yml b/taskcluster/ci/artifact-build/kind.yml index 8f300983e3386..4073a54b90c41 100644 --- a/taskcluster/ci/artifact-build/kind.yml +++ b/taskcluster/ci/artifact-build/kind.yml @@ -31,6 +31,7 @@ jobs: max-run-time: 3600 env: PERFHERDER_EXTRA_OPTIONS: artifact + MOZ_ARTIFACT_TASK: {task-reference: ''} run: using: mozharness actions: [get-secrets, build] @@ -42,5 +43,7 @@ jobs: tooltool-downloads: public need-xvfb: true keep-artifacts: false + dependencies: + linux64-opt: build-linux64/opt toolchains: - linux64-node diff --git a/taskcluster/ci/build/android.yml b/taskcluster/ci/build/android.yml index bb5375f45b637..c4064bb212bd3 100644 --- a/taskcluster/ci/build/android.yml +++ b/taskcluster/ci/build/android.yml @@ -272,7 +272,6 @@ android-x86-nightly/opt: - linux64-rust-android - linux64-rust-size - linux64-cbindgen - - linux64-sccache - linux64-node android-api-16/opt: @@ -436,7 +435,6 @@ android-api-16-nightly/opt: - linux64-rust-android - linux64-rust-size - linux64-cbindgen - - linux64-sccache - linux64-node android-aarch64/opt: @@ -602,7 +600,6 @@ android-aarch64-nightly/opt: - linux64-clang - linux64-rust-android - linux64-rust-size - - linux64-sccache - linux64-cbindgen - linux64-node @@ -715,7 +712,6 @@ android-x86_64-nightly/opt: - linux64-clang - linux64-rust-android - linux64-rust-size - - linux64-sccache - linux64-cbindgen - linux64-node diff --git a/taskcluster/ci/build/linux.yml b/taskcluster/ci/build/linux.yml index b01ad67bfcab1..d443c8f32c973 100644 --- a/taskcluster/ci/build/linux.yml +++ b/taskcluster/ci/build/linux.yml @@ -243,7 +243,6 @@ linux64-devedition-nightly/opt: - linux64-rust - linux64-rust-size - linux64-cbindgen - - linux64-sccache - linux64-node linux64-base-toolchains/opt: @@ -591,7 +590,6 @@ linux-devedition-nightly/opt: - linux64-rust - linux64-rust-size - linux64-cbindgen - - linux64-sccache - linux64-node linux-nightly/opt: @@ -629,7 +627,6 @@ linux-nightly/opt: - linux64-rust - linux64-rust-size - linux64-cbindgen - - linux64-sccache - linux64-node linux64-asan/opt: @@ -809,7 +806,6 @@ linux64-asan-reporter-nightly/opt: - linux64-rust - linux64-rust-size - linux64-cbindgen - - linux64-sccache - linux64-node linux64-asan/debug: @@ -880,7 +876,6 @@ linux64-nightly/opt: - linux64-rust - linux64-rust-size - linux64-cbindgen - - linux64-sccache - linux64-node linux64-noopt/debug: diff --git a/taskcluster/ci/build/macosx.yml b/taskcluster/ci/build/macosx.yml index 8cd78a79571cd..4359846cc010e 100644 --- a/taskcluster/ci/build/macosx.yml +++ b/taskcluster/ci/build/macosx.yml @@ -154,7 +154,6 @@ macosx64-devedition-nightly/opt: - linux64-rust-macos - linux64-rust-size - linux64-cbindgen - - linux64-sccache - linux64-node macosx64-noopt/debug: @@ -273,7 +272,6 @@ macosx64-nightly/opt: - linux64-rust-macos - linux64-rust-size - linux64-cbindgen - - linux64-sccache - linux64-node macosx64-ccov/debug: diff --git a/taskcluster/ci/build/windows.yml b/taskcluster/ci/build/windows.yml index bc1050b149ff1..29e9e85d08d2b 100755 --- a/taskcluster/ci/build/windows.yml +++ b/taskcluster/ci/build/windows.yml @@ -323,7 +323,6 @@ win32-nightly/opt: - win64-rust - win64-rust-size - win64-cbindgen - - win64-sccache - win64-nasm - win64-node @@ -363,7 +362,6 @@ win64-nightly/opt: - win64-rust - win64-rust-size - win64-cbindgen - - win64-sccache - win64-nasm - win64-node @@ -825,7 +823,6 @@ win64-asan-reporter-nightly/opt: - win64-rust - win64-rust-size - win64-cbindgen - - win64-sccache - win64-nasm - win64-node @@ -907,7 +904,6 @@ win32-devedition-nightly/opt: - win64-rust - win64-rust-size - win64-cbindgen - - win64-sccache - win64-nasm - win64-node @@ -948,7 +944,6 @@ win64-devedition-nightly/opt: - win64-rust - win64-rust-size - win64-cbindgen - - win64-sccache - win64-nasm - win64-node @@ -1060,7 +1055,6 @@ win64-aarch64-nightly/opt: - win64-clang-cl - win64-aarch64-rust - win64-cbindgen - - win64-sccache - win64-nasm - win64-node diff --git a/taskcluster/docker/custom-v8/Dockerfile b/taskcluster/docker/custom-v8/Dockerfile index 9a35f6dcd2cc0..9acd7833e9263 100644 --- a/taskcluster/docker/custom-v8/Dockerfile +++ b/taskcluster/docker/custom-v8/Dockerfile @@ -13,12 +13,10 @@ RUN apt-get update && \ bzip2 \ curl \ libbz2-dev \ + libglib2.0-dev \ lsb-core \ - sudo \ + pkg-config \ tar \ unzip \ wget \ zip - -RUN adduser worker sudo -RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers diff --git a/taskcluster/scripts/misc/build-custom-v8.sh b/taskcluster/scripts/misc/build-custom-v8.sh index fefd9ef7149cc..ad2a831910174 100755 --- a/taskcluster/scripts/misc/build-custom-v8.sh +++ b/taskcluster/scripts/misc/build-custom-v8.sh @@ -28,22 +28,12 @@ cd $HOME_DIR/src # Setup depot_tools git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git export PATH=$PATH:$HOME_DIR/src/depot_tools -gclient -# Get v8 source code -mkdir v8 -cd v8 +# Get v8 source code and dependencies fetch v8 cd v8 -# Build dependencies -gclient sync -./build/install-build-deps.sh - # Build v8 -git checkout master -git pull && gclient sync - gn gen out/release --args="$CONFIG" ninja -C out/release d8 diff --git a/taskcluster/taskgraph/util/verify.py b/taskcluster/taskgraph/util/verify.py index 195e131307bb1..393b764be1157 100644 --- a/taskcluster/taskgraph/util/verify.py +++ b/taskcluster/taskgraph/util/verify.py @@ -218,3 +218,11 @@ def verify_always_optimized(task, taskgraph, scratch_pad, graph_config): return if task.task.get('workerType') == 'always-optimized': raise Exception('Could not optimize the task {!r}'.format(task.label)) + + +@verifications.add('full_task_graph') +def verify_nightly_no_sccache(task, taskgraph, scratch_pad, graph_config): + if task and task.attributes.get('nightly'): + if task.task.get('payload', {}).get('env', {}).get('USE_SCCACHE'): + raise Exception( + 'Nightly job {} cannot use sccache'.format(task.label)) diff --git a/toolkit/moz.configure b/toolkit/moz.configure index 08a64b734bd47..55ae2ccbfa158 100644 --- a/toolkit/moz.configure +++ b/toolkit/moz.configure @@ -500,47 +500,44 @@ set_define('MOZ_OMX', openmax) # EME Support # ============================================================== +@depends(target) +def eme_choices(target): + if (target.kernel in ('Darwin', 'WINNT', 'Linux') and + target.os not in ('Android', 'iOS') and + target.cpu in ('x86', 'x86_64')): + return ('widevine',) + + # Widevine is enabled by default in desktop browser builds. -@depends(build_project) -def eme_default(build_project): +@depends(build_project, eme_choices) +def eme_default(build_project, choices): if build_project == 'browser': - return 'widevine' + return choices + option('--enable-eme', - nargs='*', - choices=('widevine',), + nargs='+', + choices=eme_choices, default=eme_default, + when=eme_choices, help='{Enable|Disable} support for Encrypted Media Extensions') -@depends('--enable-eme', target) -def enable_eme(value, target): - # Widevine EME by default enabled on desktop Windows, MacOS and Linux, - # x86 and x64 builds. - if (target.kernel in ('Darwin', 'WINNT', 'Linux') and - target.os not in ('Android', 'iOS') and - target.cpu in ('x86', 'x86_64')): - return value - elif value and value.origin != 'default': - die('%s is not supported on %s' % (value.format('--enable-eme'), target.alias)) - # Return the same type of OptionValue (Positive or Negative), with an empty tuple. - return value.__class__(()) -@depends(enable_eme, fmp4) -def eme(value, fmp4): - enabled = bool(value) - if value.origin == 'default': - enabled = enabled or fmp4 - if enabled and not fmp4: +@depends('--enable-eme', fmp4, when=eme_choices) +def eme(enabled, fmp4): + if enabled and enabled.origin != 'default' and not fmp4: die('Encrypted Media Extension support requires ' 'Fragmented MP4 support') - if enabled: - return True -@depends(enable_eme) + +@depends('--enable-eme', when=eme_choices) def eme_modules(value): return value -set_config('MOZ_EME_MODULES', eme_modules) + +# Fallback to an empty list when eme_choices is empty, setting eme_modules to +# None. +set_config('MOZ_EME_MODULES', eme_modules | dependable([])) option(name='--enable-chrome-format', help='Select FORMAT of chrome files during packaging.',