| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| /* eslint-disable indent */ |
| (function(window) { |
| |
| // DevToolsAPI ---------------------------------------------------------------- |
| |
| /** |
| * @unrestricted |
| */ |
| const DevToolsAPIImpl = class { |
| constructor() { |
| /** |
| * @type {number} |
| */ |
| this._lastCallId = 0; |
| |
| /** |
| * @type {!Object.<number, function(?Object)>} |
| */ |
| this._callbacks = {}; |
| |
| /** |
| * @type {!Array.<!ExtensionDescriptor>} |
| */ |
| this._pendingExtensionDescriptors = []; |
| |
| /** |
| * @type {?function(!ExtensionDescriptor)} |
| */ |
| this._addExtensionCallback = null; |
| } |
| |
| /** |
| * @param {number} id |
| * @param {?Object} arg |
| */ |
| embedderMessageAck(id, arg) { |
| const callback = this._callbacks[id]; |
| delete this._callbacks[id]; |
| if (callback) { |
| callback(arg); |
| } |
| } |
| |
| /** |
| * @param {string} method |
| * @param {!Array.<*>} args |
| * @param {?function(?Object)} callback |
| */ |
| sendMessageToEmbedder(method, args, callback) { |
| const callId = ++this._lastCallId; |
| if (callback) { |
| this._callbacks[callId] = callback; |
| } |
| const message = {'id': callId, 'method': method}; |
| if (args.length) { |
| message.params = args; |
| } |
| DevToolsHost.sendMessageToEmbedder(JSON.stringify(message)); |
| } |
| |
| /** |
| * @param {string} method |
| * @param {!Array<*>} args |
| */ |
| _dispatchOnInspectorFrontendAPI(method, args) { |
| const inspectorFrontendAPI = /** @type {!Object<string, function()>} */ (window['InspectorFrontendAPI']); |
| inspectorFrontendAPI[method].apply(inspectorFrontendAPI, args); |
| } |
| |
| // API methods below this line -------------------------------------------- |
| |
| /** |
| * @param {!Array.<!ExtensionDescriptor>} extensions |
| */ |
| addExtensions(extensions) { |
| // Support for legacy front-ends (<M41). |
| if (window['WebInspector'] && window['WebInspector']['addExtensions']) { |
| window['WebInspector']['addExtensions'](extensions); |
| } else { |
| // The addExtensions command is sent as the onload event happens for |
| // DevTools front-end. We should buffer this command until the frontend |
| // is ready for it. |
| if (this._addExtensionCallback) { |
| extensions.forEach(this._addExtensionCallback); |
| } else { |
| this._pendingExtensionDescriptors.pushAll(extensions); |
| } |
| } |
| } |
| |
| /** |
| * @param {string} url |
| */ |
| appendedToURL(url) { |
| this._dispatchOnInspectorFrontendAPI('appendedToURL', [url]); |
| } |
| |
| /** |
| * @param {string} url |
| */ |
| canceledSaveURL(url) { |
| this._dispatchOnInspectorFrontendAPI('canceledSaveURL', [url]); |
| } |
| |
| contextMenuCleared() { |
| this._dispatchOnInspectorFrontendAPI('contextMenuCleared', []); |
| } |
| |
| /** |
| * @param {string} id |
| */ |
| contextMenuItemSelected(id) { |
| this._dispatchOnInspectorFrontendAPI('contextMenuItemSelected', [id]); |
| } |
| |
| /** |
| * @param {number} count |
| */ |
| deviceCountUpdated(count) { |
| this._dispatchOnInspectorFrontendAPI('deviceCountUpdated', [count]); |
| } |
| |
| /** |
| * @param {!Adb.Config} config |
| */ |
| devicesDiscoveryConfigChanged(config) { |
| this._dispatchOnInspectorFrontendAPI('devicesDiscoveryConfigChanged', [config]); |
| } |
| |
| /** |
| * @param {!Adb.PortForwardingStatus} status |
| */ |
| devicesPortForwardingStatusChanged(status) { |
| this._dispatchOnInspectorFrontendAPI('devicesPortForwardingStatusChanged', [status]); |
| } |
| |
| /** |
| * @param {!Array.<!Adb.Device>} devices |
| */ |
| devicesUpdated(devices) { |
| this._dispatchOnInspectorFrontendAPI('devicesUpdated', [devices]); |
| } |
| |
| /** |
| * @param {string} message |
| */ |
| dispatchMessage(message) { |
| this._dispatchOnInspectorFrontendAPI('dispatchMessage', [message]); |
| } |
| |
| /** |
| * @param {string} messageChunk |
| * @param {number} messageSize |
| */ |
| dispatchMessageChunk(messageChunk, messageSize) { |
| this._dispatchOnInspectorFrontendAPI('dispatchMessageChunk', [messageChunk, messageSize]); |
| } |
| |
| enterInspectElementMode() { |
| this._dispatchOnInspectorFrontendAPI('enterInspectElementMode', []); |
| } |
| |
| /** |
| * @param {!{r: number, g: number, b: number, a: number}} color |
| */ |
| eyeDropperPickedColor(color) { |
| this._dispatchOnInspectorFrontendAPI('eyeDropperPickedColor', [color]); |
| } |
| |
| /** |
| * @param {!Array.<!{fileSystemName: string, rootURL: string, fileSystemPath: string}>} fileSystems |
| */ |
| fileSystemsLoaded(fileSystems) { |
| this._dispatchOnInspectorFrontendAPI('fileSystemsLoaded', [fileSystems]); |
| } |
| |
| /** |
| * @param {string} fileSystemPath |
| */ |
| fileSystemRemoved(fileSystemPath) { |
| this._dispatchOnInspectorFrontendAPI('fileSystemRemoved', [fileSystemPath]); |
| } |
| |
| /** |
| * @param {?string} error |
| * @param {?{type: string, fileSystemName: string, rootURL: string, fileSystemPath: string}} fileSystem |
| */ |
| fileSystemAdded(error, fileSystem) { |
| this._dispatchOnInspectorFrontendAPI('fileSystemAdded', [error, fileSystem]); |
| } |
| |
| /** |
| * @param {!Array<string>} changedPaths |
| * @param {!Array<string>} addedPaths |
| * @param {!Array<string>} removedPaths |
| */ |
| fileSystemFilesChangedAddedRemoved(changedPaths, addedPaths, removedPaths) { |
| // Support for legacy front-ends (<M58) |
| if (window['InspectorFrontendAPI'] && window['InspectorFrontendAPI']['fileSystemFilesChanged']) { |
| this._dispatchOnInspectorFrontendAPI( |
| 'fileSystemFilesChanged', [changedPaths.concat(addedPaths).concat(removedPaths)]); |
| } else { |
| this._dispatchOnInspectorFrontendAPI( |
| 'fileSystemFilesChangedAddedRemoved', [changedPaths, addedPaths, removedPaths]); |
| } |
| } |
| |
| /** |
| * @param {number} requestId |
| * @param {string} fileSystemPath |
| * @param {number} totalWork |
| */ |
| indexingTotalWorkCalculated(requestId, fileSystemPath, totalWork) { |
| this._dispatchOnInspectorFrontendAPI('indexingTotalWorkCalculated', [requestId, fileSystemPath, totalWork]); |
| } |
| |
| /** |
| * @param {number} requestId |
| * @param {string} fileSystemPath |
| * @param {number} worked |
| */ |
| indexingWorked(requestId, fileSystemPath, worked) { |
| this._dispatchOnInspectorFrontendAPI('indexingWorked', [requestId, fileSystemPath, worked]); |
| } |
| |
| /** |
| * @param {number} requestId |
| * @param {string} fileSystemPath |
| */ |
| indexingDone(requestId, fileSystemPath) { |
| this._dispatchOnInspectorFrontendAPI('indexingDone', [requestId, fileSystemPath]); |
| } |
| |
| /** |
| * @param {{type: string, key: string, code: string, keyCode: number, modifiers: number}} event |
| */ |
| keyEventUnhandled(event) { |
| event.keyIdentifier = keyCodeToKeyIdentifier(event.keyCode); |
| this._dispatchOnInspectorFrontendAPI('keyEventUnhandled', [event]); |
| } |
| |
| /** |
| * @param {function(!ExtensionDescriptor)} callback |
| */ |
| setAddExtensionCallback(callback) { |
| this._addExtensionCallback = callback; |
| if (this._pendingExtensionDescriptors.length) { |
| this._pendingExtensionDescriptors.forEach(this._addExtensionCallback); |
| this._pendingExtensionDescriptors = []; |
| } |
| } |
| |
| reattachMainTarget() { |
| this._dispatchOnInspectorFrontendAPI('reattachMainTarget', []); |
| } |
| |
| /** |
| * @param {boolean} hard |
| */ |
| reloadInspectedPage(hard) { |
| this._dispatchOnInspectorFrontendAPI('reloadInspectedPage', [hard]); |
| } |
| |
| /** |
| * @param {string} url |
| * @param {number} lineNumber |
| * @param {number} columnNumber |
| */ |
| revealSourceLine(url, lineNumber, columnNumber) { |
| this._dispatchOnInspectorFrontendAPI('revealSourceLine', [url, lineNumber, columnNumber]); |
| } |
| |
| /** |
| * @param {string} url |
| * @param {string=} fileSystemPath |
| */ |
| savedURL(url, fileSystemPath) { |
| this._dispatchOnInspectorFrontendAPI('savedURL', [url, fileSystemPath]); |
| } |
| |
| /** |
| * @param {number} requestId |
| * @param {string} fileSystemPath |
| * @param {!Array.<string>} files |
| */ |
| searchCompleted(requestId, fileSystemPath, files) { |
| this._dispatchOnInspectorFrontendAPI('searchCompleted', [requestId, fileSystemPath, files]); |
| } |
| |
| /** |
| * @param {string} tabId |
| */ |
| setInspectedTabId(tabId) { |
| this._inspectedTabIdValue = tabId; |
| |
| // Support for legacy front-ends (<M41). |
| if (window['WebInspector'] && window['WebInspector']['setInspectedTabId']) { |
| window['WebInspector']['setInspectedTabId'](tabId); |
| } else { |
| this._dispatchOnInspectorFrontendAPI('setInspectedTabId', [tabId]); |
| } |
| } |
| |
| /** |
| * @return {string|undefined} |
| */ |
| getInspectedTabId() { |
| return this._inspectedTabIdValue; |
| } |
| |
| /** |
| * @param {boolean} useSoftMenu |
| */ |
| setUseSoftMenu(useSoftMenu) { |
| this._dispatchOnInspectorFrontendAPI('setUseSoftMenu', [useSoftMenu]); |
| } |
| |
| /** |
| * @param {string} panelName |
| */ |
| showPanel(panelName) { |
| this._dispatchOnInspectorFrontendAPI('showPanel', [panelName]); |
| } |
| |
| /** |
| * @param {number} id |
| * @param {string} chunk |
| * @param {boolean} encoded |
| */ |
| streamWrite(id, chunk, encoded) { |
| this._dispatchOnInspectorFrontendAPI('streamWrite', [id, encoded ? this._decodeBase64(chunk) : chunk]); |
| } |
| |
| /** |
| * @param {string} chunk |
| * @return {string} |
| */ |
| _decodeBase64(chunk) { |
| const request = new XMLHttpRequest(); |
| request.open('GET', 'data:text/plain;base64,' + chunk, false); |
| request.send(null); |
| if (request.status === 200) { |
| return request.responseText; |
| } else { |
| console.error('Error while decoding chunk in streamWrite'); |
| return ''; |
| } |
| } |
| }; |
| |
| const DevToolsAPI = new DevToolsAPIImpl(); |
| window.DevToolsAPI = DevToolsAPI; |
| |
| // InspectorFrontendHostImpl -------------------------------------------------- |
| |
| /** |
| * @implements {InspectorFrontendHostAPI} |
| * @unrestricted |
| */ |
| const InspectorFrontendHostImpl = class { |
| /** |
| * @return {string} |
| */ |
| getSelectionBackgroundColor() { |
| return '#6e86ff'; |
| } |
| |
| /** |
| * @return {string} |
| */ |
| getSelectionForegroundColor() { |
| return '#ffffff'; |
| } |
| |
| /** |
| * @return {string} |
| */ |
| getInactiveSelectionBackgroundColor() { |
| return '#c9c8c8'; |
| } |
| |
| /** |
| * @return {string} |
| */ |
| getInactiveSelectionForegroundColor() { |
| return '#323232'; |
| } |
| |
| /** |
| * @override |
| * @return {string} |
| */ |
| platform() { |
| return DevToolsHost.platform(); |
| } |
| |
| /** |
| * @override |
| */ |
| loadCompleted() { |
| DevToolsAPI.sendMessageToEmbedder('loadCompleted', [], null); |
| // Support for legacy (<57) frontends. |
| if (window.Runtime && window.Runtime.queryParam) { |
| const panelToOpen = window.Runtime.queryParam('panel'); |
| if (panelToOpen) { |
| window.DevToolsAPI.showPanel(panelToOpen); |
| } |
| } |
| } |
| |
| /** |
| * @override |
| */ |
| bringToFront() { |
| DevToolsAPI.sendMessageToEmbedder('bringToFront', [], null); |
| } |
| |
| /** |
| * @override |
| */ |
| closeWindow() { |
| DevToolsAPI.sendMessageToEmbedder('closeWindow', [], null); |
| } |
| |
| /** |
| * @override |
| * @param {boolean} isDocked |
| * @param {function()} callback |
| */ |
| setIsDocked(isDocked, callback) { |
| DevToolsAPI.sendMessageToEmbedder('setIsDocked', [isDocked], callback); |
| } |
| |
| /** |
| * Requests inspected page to be placed atop of the inspector frontend with specified bounds. |
| * @override |
| * @param {{x: number, y: number, width: number, height: number}} bounds |
| */ |
| setInspectedPageBounds(bounds) { |
| DevToolsAPI.sendMessageToEmbedder('setInspectedPageBounds', [bounds], null); |
| } |
| |
| /** |
| * @override |
| */ |
| inspectElementCompleted() { |
| DevToolsAPI.sendMessageToEmbedder('inspectElementCompleted', [], null); |
| } |
| |
| /** |
| * @override |
| * @param {string} url |
| * @param {string} headers |
| * @param {number} streamId |
| * @param {function(!InspectorFrontendHostAPI.LoadNetworkResourceResult)} callback |
| */ |
| loadNetworkResource(url, headers, streamId, callback) { |
| DevToolsAPI.sendMessageToEmbedder( |
| 'loadNetworkResource', [url, headers, streamId], /** @type {function(?Object)} */ (callback)); |
| } |
| |
| /** |
| * @override |
| * @param {function(!Object<string, string>)} callback |
| */ |
| getPreferences(callback) { |
| DevToolsAPI.sendMessageToEmbedder('getPreferences', [], /** @type {function(?Object)} */ (callback)); |
| } |
| |
| /** |
| * @override |
| * @param {string} name |
| * @param {string} value |
| */ |
| setPreference(name, value) { |
| DevToolsAPI.sendMessageToEmbedder('setPreference', [name, value], null); |
| } |
| |
| /** |
| * @override |
| * @param {string} name |
| */ |
| removePreference(name) { |
| DevToolsAPI.sendMessageToEmbedder('removePreference', [name], null); |
| } |
| |
| /** |
| * @override |
| */ |
| clearPreferences() { |
| DevToolsAPI.sendMessageToEmbedder('clearPreferences', [], null); |
| } |
| |
| /** |
| * @override |
| * @param {string} origin |
| * @param {string} script |
| */ |
| setInjectedScriptForOrigin(origin, script) { |
| DevToolsAPI.sendMessageToEmbedder('registerExtensionsAPI', [origin, script], null); |
| } |
| |
| /** |
| * @override |
| * @param {string} url |
| */ |
| inspectedURLChanged(url) { |
| DevToolsAPI.sendMessageToEmbedder('inspectedURLChanged', [url], null); |
| } |
| |
| /** |
| * @override |
| * @param {string} text |
| */ |
| copyText(text) { |
| DevToolsHost.copyText(text); |
| } |
| |
| /** |
| * @override |
| * @param {string} url |
| */ |
| openInNewTab(url) { |
| DevToolsAPI.sendMessageToEmbedder('openInNewTab', [url], null); |
| } |
| |
| /** |
| * @override |
| * @param {string} fileSystemPath |
| */ |
| showItemInFolder(fileSystemPath) { |
| DevToolsAPI.sendMessageToEmbedder('showItemInFolder', [fileSystemPath], null); |
| } |
| |
| /** |
| * @override |
| * @param {string} url |
| * @param {string} content |
| * @param {boolean} forceSaveAs |
| */ |
| save(url, content, forceSaveAs) { |
| DevToolsAPI.sendMessageToEmbedder('save', [url, content, forceSaveAs], null); |
| } |
| |
| /** |
| * @override |
| * @param {string} url |
| * @param {string} content |
| */ |
| append(url, content) { |
| DevToolsAPI.sendMessageToEmbedder('append', [url, content], null); |
| } |
| |
| /** |
| * @override |
| * @param {string} url |
| */ |
| close(url) { |
| } |
| |
| /** |
| * @override |
| * @param {string} message |
| */ |
| sendMessageToBackend(message) { |
| DevToolsAPI.sendMessageToEmbedder('dispatchProtocolMessage', [message], null); |
| } |
| |
| /** |
| * @override |
| * @param {string} actionName |
| * @param {number} actionCode |
| * @param {number} bucketSize |
| */ |
| recordEnumeratedHistogram(actionName, actionCode, bucketSize) { |
| // Support for M49 frontend. |
| if (actionName === 'DevTools.DrawerShown') { |
| return; |
| } |
| DevToolsAPI.sendMessageToEmbedder('recordEnumeratedHistogram', [actionName, actionCode, bucketSize], null); |
| } |
| |
| /** |
| * @override |
| * @param {string} histogramName |
| * @param {number} duration |
| */ |
| recordPerformanceHistogram(histogramName, duration) { |
| DevToolsAPI.sendMessageToEmbedder('recordPerformanceHistogram', [histogramName, duration], null); |
| } |
| |
| /** |
| * @override |
| * @param {string} umaName |
| */ |
| recordUserMetricsAction(umaName) { |
| DevToolsAPI.sendMessageToEmbedder('recordUserMetricsAction', [umaName], null); |
| } |
| |
| /** |
| * @override |
| */ |
| requestFileSystems() { |
| DevToolsAPI.sendMessageToEmbedder('requestFileSystems', [], null); |
| } |
| |
| /** |
| * @override |
| * @param {string=} type |
| */ |
| addFileSystem(type) { |
| DevToolsAPI.sendMessageToEmbedder('addFileSystem', [type || ''], null); |
| } |
| |
| /** |
| * @override |
| * @param {string} fileSystemPath |
| */ |
| removeFileSystem(fileSystemPath) { |
| DevToolsAPI.sendMessageToEmbedder('removeFileSystem', [fileSystemPath], null); |
| } |
| |
| /** |
| * @override |
| * @param {string} fileSystemId |
| * @param {string} registeredName |
| * @return {?DOMFileSystem} |
| */ |
| isolatedFileSystem(fileSystemId, registeredName) { |
| return DevToolsHost.isolatedFileSystem(fileSystemId, registeredName); |
| } |
| |
| /** |
| * @override |
| * @param {!FileSystem} fileSystem |
| */ |
| upgradeDraggedFileSystemPermissions(fileSystem) { |
| DevToolsHost.upgradeDraggedFileSystemPermissions(fileSystem); |
| } |
| |
| /** |
| * @override |
| * @param {number} requestId |
| * @param {string} fileSystemPath |
| * @param {string} excludedFolders |
| */ |
| indexPath(requestId, fileSystemPath, excludedFolders) { |
| // |excludedFolders| added in M67. For backward compatibility, |
| // pass empty array. |
| excludedFolders = excludedFolders || '[]'; |
| DevToolsAPI.sendMessageToEmbedder('indexPath', [requestId, fileSystemPath, excludedFolders], null); |
| } |
| |
| /** |
| * @override |
| * @param {number} requestId |
| */ |
| stopIndexing(requestId) { |
| DevToolsAPI.sendMessageToEmbedder('stopIndexing', [requestId], null); |
| } |
| |
| /** |
| * @override |
| * @param {number} requestId |
| * @param {string} fileSystemPath |
| * @param {string} query |
| */ |
| searchInPath(requestId, fileSystemPath, query) { |
| DevToolsAPI.sendMessageToEmbedder('searchInPath', [requestId, fileSystemPath, query], null); |
| } |
| |
| /** |
| * @override |
| * @return {number} |
| */ |
| zoomFactor() { |
| return DevToolsHost.zoomFactor(); |
| } |
| |
| /** |
| * @override |
| */ |
| zoomIn() { |
| DevToolsAPI.sendMessageToEmbedder('zoomIn', [], null); |
| } |
| |
| /** |
| * @override |
| */ |
| zoomOut() { |
| DevToolsAPI.sendMessageToEmbedder('zoomOut', [], null); |
| } |
| |
| /** |
| * @override |
| */ |
| resetZoom() { |
| DevToolsAPI.sendMessageToEmbedder('resetZoom', [], null); |
| } |
| |
| /** |
| * @override |
| * @param {string} shortcuts |
| */ |
| setWhitelistedShortcuts(shortcuts) { |
| DevToolsAPI.sendMessageToEmbedder('setWhitelistedShortcuts', [shortcuts], null); |
| } |
| |
| /** |
| * @override |
| * @param {boolean} active |
| */ |
| setEyeDropperActive(active) { |
| DevToolsAPI.sendMessageToEmbedder('setEyeDropperActive', [active], null); |
| } |
| |
| /** |
| * @override |
| * @param {!Array<string>} certChain |
| */ |
| showCertificateViewer(certChain) { |
| DevToolsAPI.sendMessageToEmbedder('showCertificateViewer', [JSON.stringify(certChain)], null); |
| } |
| |
| /** |
| * Only needed to run Lighthouse on old devtools. |
| * @override |
| * @param {function()} callback |
| */ |
| reattach(callback) { |
| DevToolsAPI.sendMessageToEmbedder('reattach', [], callback); |
| } |
| |
| /** |
| * @override |
| */ |
| readyForTest() { |
| DevToolsAPI.sendMessageToEmbedder('readyForTest', [], null); |
| } |
| |
| /** |
| * @override |
| */ |
| connectionReady() { |
| DevToolsAPI.sendMessageToEmbedder('connectionReady', [], null); |
| } |
| |
| /** |
| * @override |
| * @param {boolean} value |
| */ |
| setOpenNewWindowForPopups(value) { |
| DevToolsAPI.sendMessageToEmbedder('setOpenNewWindowForPopups', [value], null); |
| } |
| |
| /** |
| * @override |
| * @param {!Adb.Config} config |
| */ |
| setDevicesDiscoveryConfig(config) { |
| DevToolsAPI.sendMessageToEmbedder( |
| 'setDevicesDiscoveryConfig', |
| [ |
| config.discoverUsbDevices, config.portForwardingEnabled, JSON.stringify(config.portForwardingConfig), |
| config.networkDiscoveryEnabled, JSON.stringify(config.networkDiscoveryConfig) |
| ], |
| null); |
| } |
| |
| /** |
| * @override |
| * @param {boolean} enabled |
| */ |
| setDevicesUpdatesEnabled(enabled) { |
| DevToolsAPI.sendMessageToEmbedder('setDevicesUpdatesEnabled', [enabled], null); |
| } |
| |
| /** |
| * @override |
| * @param {string} pageId |
| * @param {string} action |
| */ |
| performActionOnRemotePage(pageId, action) { |
| DevToolsAPI.sendMessageToEmbedder('performActionOnRemotePage', [pageId, action], null); |
| } |
| |
| /** |
| * @override |
| * @param {string} browserId |
| * @param {string} url |
| */ |
| openRemotePage(browserId, url) { |
| DevToolsAPI.sendMessageToEmbedder('openRemotePage', [browserId, url], null); |
| } |
| |
| /** |
| * @override |
| */ |
| openNodeFrontend() { |
| DevToolsAPI.sendMessageToEmbedder('openNodeFrontend', [], null); |
| } |
| |
| /** |
| * @override |
| * @param {number} x |
| * @param {number} y |
| * @param {!Array.<!InspectorFrontendHostAPI.ContextMenuDescriptor>} items |
| * @param {!Document} document |
| */ |
| showContextMenuAtPoint(x, y, items, document) { |
| DevToolsHost.showContextMenuAtPoint(x, y, items, document); |
| } |
| |
| /** |
| * @override |
| * @return {boolean} |
| */ |
| isHostedMode() { |
| return DevToolsHost.isHostedMode(); |
| } |
| |
| /** |
| * @override |
| * @param {function(!ExtensionDescriptor)} callback |
| */ |
| setAddExtensionCallback(callback) { |
| DevToolsAPI.setAddExtensionCallback(callback); |
| } |
| |
| // Backward-compatible methods below this line -------------------------------------------- |
| |
| /** |
| * Support for legacy front-ends (<M65). |
| * @return {boolean} |
| */ |
| isUnderTest() { |
| return false; |
| } |
| |
| /** |
| * Support for legacy front-ends (<M50). |
| * @param {string} message |
| */ |
| sendFrontendAPINotification(message) { |
| } |
| |
| /** |
| * Support for legacy front-ends (<M41). |
| * @return {string} |
| */ |
| port() { |
| return 'unknown'; |
| } |
| |
| /** |
| * Support for legacy front-ends (<M38). |
| * @param {number} zoomFactor |
| */ |
| setZoomFactor(zoomFactor) { |
| } |
| |
| /** |
| * Support for legacy front-ends (<M34). |
| */ |
| sendMessageToEmbedder() { |
| } |
| |
| /** |
| * Support for legacy front-ends (<M34). |
| * @param {string} dockSide |
| */ |
| requestSetDockSide(dockSide) { |
| DevToolsAPI.sendMessageToEmbedder('setIsDocked', [dockSide !== 'undocked'], null); |
| } |
| |
| /** |
| * Support for legacy front-ends (<M34). |
| * @return {boolean} |
| */ |
| supportsFileSystems() { |
| return true; |
| } |
| |
| /** |
| * Support for legacy front-ends (<M44). |
| * @param {number} actionCode |
| */ |
| recordActionTaken(actionCode) { |
| this.recordEnumeratedHistogram('DevTools.ActionTaken', actionCode, 100); |
| } |
| |
| /** |
| * Support for legacy front-ends (<M44). |
| * @param {number} panelCode |
| */ |
| recordPanelShown(panelCode) { |
| this.recordEnumeratedHistogram('DevTools.PanelShown', panelCode, 20); |
| } |
| }; |
| |
| window.InspectorFrontendHost = new InspectorFrontendHostImpl(); |
| |
| // DevToolsApp --------------------------------------------------------------- |
| |
| function installObjectObserve() { |
| /** @type {!Array<string>} */ |
| const properties = [ |
| 'advancedSearchConfig', |
| 'auditsPanelSplitViewState', |
| 'auditsSidebarWidth', |
| 'blockedURLs', |
| 'breakpoints', |
| 'cacheDisabled', |
| 'colorFormat', |
| 'consoleHistory', |
| 'consoleTimestampsEnabled', |
| 'cpuProfilerView', |
| 'cssSourceMapsEnabled', |
| 'currentDockState', |
| 'customColorPalette', |
| 'customDevicePresets', |
| 'customEmulatedDeviceList', |
| 'customFormatters', |
| 'customUserAgent', |
| 'databaseTableViewVisibleColumns', |
| 'dataGrid-cookiesTable', |
| 'dataGrid-DOMStorageItemsView', |
| 'debuggerSidebarHidden', |
| 'disableDataSaverInfobar', |
| 'disablePausedStateOverlay', |
| 'domBreakpoints', |
| 'domWordWrap', |
| 'elementsPanelSplitViewState', |
| 'elementsSidebarWidth', |
| 'emulation.deviceHeight', |
| 'emulation.deviceModeValue', |
| 'emulation.deviceOrientationOverride', |
| 'emulation.deviceScale', |
| 'emulation.deviceScaleFactor', |
| 'emulation.deviceUA', |
| 'emulation.deviceWidth', |
| 'emulation.geolocationOverride', |
| 'emulation.showDeviceMode', |
| 'emulation.showRulers', |
| 'enableAsyncStackTraces', |
| 'eventListenerBreakpoints', |
| 'fileMappingEntries', |
| 'fileSystemMapping', |
| 'FileSystemViewSidebarWidth', |
| 'fileSystemViewSplitViewState', |
| 'filterBar-consoleView', |
| 'filterBar-networkPanel', |
| 'filterBar-promisePane', |
| 'filterBar-timelinePanel', |
| 'frameViewerHideChromeWindow', |
| 'heapSnapshotRetainersViewSize', |
| 'heapSnapshotSplitViewState', |
| 'hideCollectedPromises', |
| 'hideNetworkMessages', |
| 'highlightNodeOnHoverInOverlay', |
| 'highResolutionCpuProfiling', |
| 'inlineVariableValues', |
| 'Inspector.drawerSplitView', |
| 'Inspector.drawerSplitViewState', |
| 'InspectorView.panelOrder', |
| 'InspectorView.screencastSplitView', |
| 'InspectorView.screencastSplitViewState', |
| 'InspectorView.splitView', |
| 'InspectorView.splitViewState', |
| 'javaScriptDisabled', |
| 'jsSourceMapsEnabled', |
| 'lastActivePanel', |
| 'lastDockState', |
| 'lastSelectedSourcesSidebarPaneTab', |
| 'lastSnippetEvaluationIndex', |
| 'layerDetailsSplitView', |
| 'layerDetailsSplitViewState', |
| 'layersPanelSplitViewState', |
| 'layersShowInternalLayers', |
| 'layersSidebarWidth', |
| 'messageLevelFilters', |
| 'messageURLFilters', |
| 'monitoringXHREnabled', |
| 'navigatorGroupByFolder', |
| 'navigatorHidden', |
| 'networkColorCodeResourceTypes', |
| 'networkConditions', |
| 'networkConditionsCustomProfiles', |
| 'networkHideDataURL', |
| 'networkLogColumnsVisibility', |
| 'networkLogLargeRows', |
| 'networkLogShowOverview', |
| 'networkPanelSplitViewState', |
| 'networkRecordFilmStripSetting', |
| 'networkResourceTypeFilters', |
| 'networkShowPrimaryLoadWaterfall', |
| 'networkSidebarWidth', |
| 'openLinkHandler', |
| 'pauseOnCaughtException', |
| 'pauseOnExceptionEnabled', |
| 'preserveConsoleLog', |
| 'prettyPrintInfobarDisabled', |
| 'previouslyViewedFiles', |
| 'profilesPanelSplitViewState', |
| 'profilesSidebarWidth', |
| 'promiseStatusFilters', |
| 'recordAllocationStacks', |
| 'requestHeaderFilterSetting', |
| 'request-info-formData-category-expanded', |
| 'request-info-general-category-expanded', |
| 'request-info-queryString-category-expanded', |
| 'request-info-requestHeaders-category-expanded', |
| 'request-info-requestPayload-category-expanded', |
| 'request-info-responseHeaders-category-expanded', |
| 'resources', |
| 'resourcesLastSelectedItem', |
| 'resourcesPanelSplitViewState', |
| 'resourcesSidebarWidth', |
| 'resourceViewTab', |
| 'savedURLs', |
| 'screencastEnabled', |
| 'scriptsPanelNavigatorSidebarWidth', |
| 'searchInContentScripts', |
| 'selectedAuditCategories', |
| 'selectedColorPalette', |
| 'selectedProfileType', |
| 'shortcutPanelSwitch', |
| 'showAdvancedHeapSnapshotProperties', |
| 'showEventListenersForAncestors', |
| 'showFrameowkrListeners', |
| 'showHeaSnapshotObjectsHiddenProperties', |
| 'showInheritedComputedStyleProperties', |
| 'showMediaQueryInspector', |
| 'showNativeFunctionsInJSProfile', |
| 'showUAShadowDOM', |
| 'showWhitespacesInEditor', |
| 'sidebarPosition', |
| 'skipContentScripts', |
| 'skipStackFramesPattern', |
| 'sourceMapInfobarDisabled', |
| 'sourcesPanelDebuggerSidebarSplitViewState', |
| 'sourcesPanelNavigatorSplitViewState', |
| 'sourcesPanelSplitSidebarRatio', |
| 'sourcesPanelSplitViewState', |
| 'sourcesSidebarWidth', |
| 'standardEmulatedDeviceList', |
| 'StylesPaneSplitRatio', |
| 'stylesPaneSplitViewState', |
| 'textEditorAutocompletion', |
| 'textEditorAutoDetectIndent', |
| 'textEditorBracketMatching', |
| 'textEditorIndent', |
| 'textEditorTabMovesFocus', |
| 'timelineCaptureFilmStrip', |
| 'timelineCaptureLayersAndPictures', |
| 'timelineCaptureMemory', |
| 'timelineCaptureNetwork', |
| 'timeline-details', |
| 'timelineEnableJSSampling', |
| 'timelineOverviewMode', |
| 'timelinePanelDetailsSplitViewState', |
| 'timelinePanelRecorsSplitViewState', |
| 'timelinePanelTimelineStackSplitViewState', |
| 'timelinePerspective', |
| 'timeline-split', |
| 'timelineTreeGroupBy', |
| 'timeline-view', |
| 'timelineViewMode', |
| 'uiTheme', |
| 'watchExpressions', |
| 'WebInspector.Drawer.lastSelectedView', |
| 'WebInspector.Drawer.showOnLoad', |
| 'workspaceExcludedFolders', |
| 'workspaceFolderExcludePattern', |
| 'workspaceInfobarDisabled', |
| 'workspaceMappingInfobarDisabled', |
| 'xhrBreakpoints' |
| ]; |
| |
| /** |
| * @this {!{_storage: Object, _name: string}} |
| */ |
| function settingRemove() { |
| this._storage[this._name] = undefined; |
| } |
| |
| /** |
| * @param {!Object} object |
| * @param {function(!Array<!{name: string}>)} observer |
| */ |
| function objectObserve(object, observer) { |
| if (window['WebInspector']) { |
| const settingPrototype = /** @type {!Object} */ (window['WebInspector']['Setting']['prototype']); |
| if (typeof settingPrototype['remove'] === 'function') { |
| settingPrototype['remove'] = settingRemove; |
| } |
| } |
| /** @type {!Set<string>} */ |
| const changedProperties = new Set(); |
| let scheduled = false; |
| |
| function scheduleObserver() { |
| if (scheduled) { |
| return; |
| } |
| scheduled = true; |
| setImmediate(callObserver); |
| } |
| |
| function callObserver() { |
| scheduled = false; |
| const changes = /** @type {!Array<!{name: string}>} */ ([]); |
| changedProperties.forEach(function(name) { |
| changes.push({name: name}); |
| }); |
| changedProperties.clear(); |
| observer.call(null, changes); |
| } |
| |
| /** @type {!Map<string, *>} */ |
| const storage = new Map(); |
| |
| /** |
| * @param {string} property |
| */ |
| function defineProperty(property) { |
| if (property in object) { |
| storage.set(property, object[property]); |
| delete object[property]; |
| } |
| |
| Object.defineProperty(object, property, { |
| /** |
| * @return {*} |
| */ |
| get: function() { |
| return storage.get(property); |
| }, |
| |
| /** |
| * @param {*} value |
| */ |
| set: function(value) { |
| storage.set(property, value); |
| changedProperties.add(property); |
| scheduleObserver(); |
| } |
| }); |
| } |
| |
| for (let i = 0; i < properties.length; ++i) { |
| defineProperty(properties[i]); |
| } |
| } |
| |
| window.Object.observe = objectObserve; |
| } |
| |
| /** @type {!Map<number, string>} */ |
| const staticKeyIdentifiers = new Map([ |
| [0x12, 'Alt'], |
| [0x11, 'Control'], |
| [0x10, 'Shift'], |
| [0x14, 'CapsLock'], |
| [0x5b, 'Win'], |
| [0x5c, 'Win'], |
| [0x0c, 'Clear'], |
| [0x28, 'Down'], |
| [0x23, 'End'], |
| [0x0a, 'Enter'], |
| [0x0d, 'Enter'], |
| [0x2b, 'Execute'], |
| [0x70, 'F1'], |
| [0x71, 'F2'], |
| [0x72, 'F3'], |
| [0x73, 'F4'], |
| [0x74, 'F5'], |
| [0x75, 'F6'], |
| [0x76, 'F7'], |
| [0x77, 'F8'], |
| [0x78, 'F9'], |
| [0x79, 'F10'], |
| [0x7a, 'F11'], |
| [0x7b, 'F12'], |
| [0x7c, 'F13'], |
| [0x7d, 'F14'], |
| [0x7e, 'F15'], |
| [0x7f, 'F16'], |
| [0x80, 'F17'], |
| [0x81, 'F18'], |
| [0x82, 'F19'], |
| [0x83, 'F20'], |
| [0x84, 'F21'], |
| [0x85, 'F22'], |
| [0x86, 'F23'], |
| [0x87, 'F24'], |
| [0x2f, 'Help'], |
| [0x24, 'Home'], |
| [0x2d, 'Insert'], |
| [0x25, 'Left'], |
| [0x22, 'PageDown'], |
| [0x21, 'PageUp'], |
| [0x13, 'Pause'], |
| [0x2c, 'PrintScreen'], |
| [0x27, 'Right'], |
| [0x91, 'Scroll'], |
| [0x29, 'Select'], |
| [0x26, 'Up'], |
| [0x2e, 'U+007F'], // Standard says that DEL becomes U+007F. |
| [0xb0, 'MediaNextTrack'], |
| [0xb1, 'MediaPreviousTrack'], |
| [0xb2, 'MediaStop'], |
| [0xb3, 'MediaPlayPause'], |
| [0xad, 'VolumeMute'], |
| [0xae, 'VolumeDown'], |
| [0xaf, 'VolumeUp'], |
| ]); |
| |
| /** |
| * @param {number} keyCode |
| * @return {string} |
| */ |
| function keyCodeToKeyIdentifier(keyCode) { |
| let result = staticKeyIdentifiers.get(keyCode); |
| if (result !== undefined) { |
| return result; |
| } |
| result = 'U+'; |
| const hexString = keyCode.toString(16).toUpperCase(); |
| for (let i = hexString.length; i < 4; ++i) { |
| result += '0'; |
| } |
| result += hexString; |
| return result; |
| } |
| |
| function installBackwardsCompatibility() { |
| const majorVersion = getRemoteMajorVersion(); |
| if (!majorVersion) { |
| return; |
| } |
| |
| /** @type {!Array<string>} */ |
| const styleRules = []; |
| // Shadow DOM V0 polyfill |
| if (majorVersion <= 73 && !Element.prototype.createShadowRoot) { |
| Element.prototype.createShadowRoot = function() { |
| try { |
| return this.attachShadow({mode: 'open'}); |
| } catch (e) { |
| // some elements we use to add shadow roots can no |
| // longer have shadow roots. |
| const fakeShadowHost = document.createElement('span'); |
| this.appendChild(fakeShadowHost); |
| fakeShadowHost.className = 'fake-shadow-host'; |
| return fakeShadowHost.createShadowRoot(); |
| } |
| }; |
| |
| const origAdd = DOMTokenList.prototype.add; |
| DOMTokenList.prototype.add = function(...tokens) { |
| if (tokens[0].startsWith('insertion-point') || tokens[0].startsWith('tabbed-pane-header')) { |
| this._myElement.slot = '.' + tokens[0]; |
| } |
| return origAdd.apply(this, tokens); |
| }; |
| |
| const origCreateElement = Document.prototype.createElement; |
| Document.prototype.createElement = function(tagName, ...rest) { |
| if (tagName === 'content') { |
| tagName = 'slot'; |
| } |
| const element = origCreateElement.call(this, tagName, ...rest); |
| element.classList._myElement = element; |
| return element; |
| }; |
| |
| Object.defineProperty(HTMLSlotElement.prototype, 'select', { |
| async set(selector) { |
| this.name = selector; |
| } |
| }); |
| |
| function overrideCreateElementWithClass() { |
| window.removeEventListener('DOMContentLoaded', overrideCreateElementWithClass); |
| |
| const origCreateElementWithClass = Document.prototype.createElementWithClass; |
| Document.prototype.createElementWithClass = function(tagName, className, ...rest) { |
| if (tagName !== 'button' || (className !== 'soft-dropdown' && className !== 'dropdown-button')) { |
| return origCreateElementWithClass.call(this, tagName, className, ...rest); |
| } |
| const element = origCreateElementWithClass.call(this, 'div', className, ...rest); |
| element.tabIndex = 0; |
| element.role = 'button'; |
| return element; |
| }; |
| } |
| |
| // Document.prototype.createElementWithClass is a DevTools method, so we |
| // need to wait for DOMContentLoaded in order to override it. |
| if (window.document.head && |
| (window.document.readyState === 'complete' || window.document.readyState === 'interactive')) { |
| overrideCreateElementWithClass(); |
| } else { |
| window.addEventListener('DOMContentLoaded', overrideCreateElementWithClass); |
| } |
| } |
| |
| // Custom Elements V0 polyfill |
| if (majorVersion <= 73 && !Document.prototype.hasOwnProperty('registerElement')) { |
| const fakeRegistry = new Map(); |
| Document.prototype.registerElement = function(typeExtension, options) { |
| const {prototype, extends: localName} = options; |
| const document = this; |
| const callback = function() { |
| const element = document.createElement(localName || typeExtension); |
| const skip = new Set(['constructor', '__proto__']); |
| for (const key of Object.keys(Object.getOwnPropertyDescriptors(prototype.__proto__ || {}))) { |
| if (skip.has(key)) { |
| continue; |
| } |
| element[key] = prototype[key]; |
| } |
| element.setAttribute('is', typeExtension); |
| if (element['createdCallback']) { |
| element['createdCallback'](); |
| } |
| return element; |
| }; |
| fakeRegistry.set(typeExtension, callback); |
| return callback; |
| }; |
| |
| const origCreateElement = Document.prototype.createElement; |
| Document.prototype.createElement = function(tagName, fakeCustomElementType) { |
| const fakeConstructor = fakeRegistry.get(fakeCustomElementType); |
| if (fakeConstructor) { |
| return fakeConstructor(); |
| } |
| return origCreateElement.call(this, tagName, fakeCustomElementType); |
| }; |
| |
| // DevTools front-ends mistakenly assume that |
| // classList.toggle('a', undefined) works as |
| // classList.toggle('a', false) rather than as |
| // classList.toggle('a'); |
| const originalDOMTokenListToggle = DOMTokenList.prototype.toggle; |
| DOMTokenList.prototype.toggle = function(token, force) { |
| if (arguments.length === 1) { |
| force = !this.contains(token); |
| } |
| return originalDOMTokenListToggle.call(this, token, !!force); |
| }; |
| } |
| |
| if (majorVersion <= 66) { |
| /** @type {(!function(number, number):Element|undefined)} */ |
| ShadowRoot.prototype.__originalShadowRootElementFromPoint; |
| |
| if (!ShadowRoot.prototype.__originalShadowRootElementFromPoint) { |
| ShadowRoot.prototype.__originalShadowRootElementFromPoint = ShadowRoot.prototype.elementFromPoint; |
| /** |
| * @param {number} x |
| * @param {number} y |
| * @return {Element} |
| */ |
| ShadowRoot.prototype.elementFromPoint = function(x, y) { |
| const originalResult = ShadowRoot.prototype.__originalShadowRootElementFromPoint.apply(this, arguments); |
| if (this.host && originalResult === this.host) { |
| return null; |
| } |
| return originalResult; |
| }; |
| } |
| } |
| |
| if (majorVersion <= 53) { |
| Object.defineProperty(window.KeyboardEvent.prototype, 'keyIdentifier', { |
| /** |
| * @return {string} |
| * @this {KeyboardEvent} |
| */ |
| get: function() { |
| return keyCodeToKeyIdentifier(this.keyCode); |
| } |
| }); |
| } |
| |
| if (majorVersion <= 50) { |
| installObjectObserve(); |
| } |
| |
| if (majorVersion <= 45) { |
| /** |
| * @param {string} property |
| * @return {!CSSValue|null} |
| * @this {CSSStyleDeclaration} |
| */ |
| function getValue(property) { |
| // Note that |property| comes from another context, so we can't use === here. |
| // eslint-disable-next-line eqeqeq |
| if (property == 'padding-left') { |
| return /** @type {!CSSValue} */ ({ |
| /** |
| * @return {number} |
| * @this {!{__paddingLeft: number}} |
| */ |
| getFloatValue: function() { |
| return this.__paddingLeft; |
| }, |
| __paddingLeft: parseFloat(this.paddingLeft) |
| }); |
| } |
| throw new Error('getPropertyCSSValue is undefined'); |
| } |
| |
| window.CSSStyleDeclaration.prototype.getPropertyCSSValue = getValue; |
| |
| function CSSPrimitiveValue() { |
| } |
| CSSPrimitiveValue.CSS_PX = 5; |
| window.CSSPrimitiveValue = CSSPrimitiveValue; |
| } |
| |
| if (majorVersion <= 45) { |
| styleRules.push('* { min-width: 0; min-height: 0; }'); |
| } |
| |
| if (majorVersion <= 51) { |
| // Support for quirky border-image behavior (<M51), see: |
| // https://bugs.chromium.org/p/chromium/issues/detail?id=559258 |
| styleRules.push('.cm-breakpoint .CodeMirror-linenumber { border-style: solid !important; }'); |
| styleRules.push( |
| '.cm-breakpoint.cm-breakpoint-conditional .CodeMirror-linenumber { border-style: solid !important; }'); |
| } |
| if (majorVersion <= 71) { |
| styleRules.push( |
| '.coverage-toolbar-container, .animation-timeline-toolbar-container, .computed-properties { flex-basis: auto; }'); |
| } |
| |
| if (majorVersion <= 50) { |
| Event.prototype.deepPath = undefined; |
| } |
| |
| if (majorVersion <= 54) { |
| window.FileError = /** @type {!function (new: FileError) : ?} */ ({ |
| NOT_FOUND_ERR: DOMException.NOT_FOUND_ERR, |
| ABORT_ERR: DOMException.ABORT_ERR, |
| INVALID_MODIFICATION_ERR: DOMException.INVALID_MODIFICATION_ERR, |
| NOT_READABLE_ERR: 0 // No matching DOMException, so code will be 0. |
| }); |
| } |
| |
| installExtraStyleRules(styleRules); |
| } |
| |
| /** |
| * @return {?number} |
| */ |
| function getRemoteMajorVersion() { |
| try { |
| const remoteVersion = new URLSearchParams(window.location.search).get('remoteVersion'); |
| if (!remoteVersion) { |
| return null; |
| } |
| const majorVersion = parseInt(remoteVersion.split('.')[0], 10); |
| return majorVersion; |
| } catch (e) { |
| return null; |
| } |
| } |
| |
| /** |
| * @param {!Array<string>} styleRules |
| */ |
| function installExtraStyleRules(styleRules) { |
| if (!styleRules.length) { |
| return; |
| } |
| const styleText = styleRules.join('\n'); |
| document.head.appendChild(createStyleElement(styleText)); |
| |
| const origCreateShadowRoot = HTMLElement.prototype.createShadowRoot; |
| HTMLElement.prototype.createShadowRoot = function(...args) { |
| const shadowRoot = origCreateShadowRoot.call(this, ...args); |
| shadowRoot.appendChild(createStyleElement(styleText)); |
| return shadowRoot; |
| }; |
| } |
| |
| /** |
| * @param {string} styleText |
| * @return {!Element} |
| */ |
| function createStyleElement(styleText) { |
| const style = document.createElement('style'); |
| style.textContent = styleText; |
| return style; |
| } |
| |
| installBackwardsCompatibility(); |
| |
| })(window); |