mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-10-11 14:14:36 +08:00
This CL creates a new CSS grid setting histogram to replace the previous one, which was firing multiple times per setting change. Previously, the histogram could fire once per target on the debug target page when a setting changed. This new histogram fires once on devtools launch, allowing us to gain insight on user's settings preferences while also filtering out several events from users quickly trying different settings before settling on a prefered option Backend CL: https://crrev.com/c/2304166 Bug: 1106888 Change-Id: I929befb8997ac0908e6c9aa90af509582b77ae49 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2308256 Reviewed-by: Alex Rudenko <alexrudenko@chromium.org> Reviewed-by: Shane Clifford <shanejc@microsoft.com> Commit-Queue: Brandon Goddard <brgoddar@microsoft.com>
1520 lines
42 KiB
JavaScript
1520 lines
42 KiB
JavaScript
// 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.push(...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;
|
|
}
|
|
console.error('Error while decoding chunk in streamWrite');
|
|
return '';
|
|
}
|
|
};
|
|
|
|
const DevToolsAPI = new DevToolsAPIImpl();
|
|
window.DevToolsAPI = DevToolsAPI;
|
|
|
|
// InspectorFrontendHostImpl --------------------------------------------------
|
|
|
|
/**
|
|
* Enum for recordPerformanceHistogram
|
|
* Warning: There are three definitions of this enum in the DevTools code base, keep them in sync.
|
|
* @readonly
|
|
* @enum {string}
|
|
*/
|
|
const EnumeratedHistogram = {
|
|
ActionTaken: 'DevTools.ActionTaken',
|
|
PanelShown: 'DevTools.PanelShown',
|
|
KeyboardShortcutFired: 'DevTools.KeyboardShortcutFired',
|
|
IssuesPanelOpenedFrom: 'DevTools.IssuesPanelOpenedFrom',
|
|
KeybindSetSettingChanged: 'DevTools.KeybindSetSettingChanged',
|
|
DualScreenDeviceEmulated: 'DevTools.DualScreenDeviceEmulated',
|
|
CSSGridSettings: 'DevTools.CSSGridSettings',
|
|
};
|
|
|
|
/**
|
|
* @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 {!InspectorFrontendHostAPI.EnumeratedHistogram} actionName
|
|
* @param {number} actionCode
|
|
* @param {number} bucketSize
|
|
*/
|
|
recordEnumeratedHistogram(actionName, actionCode, bucketSize) {
|
|
if (!Object.values(EnumeratedHistogram).includes(actionName)) {
|
|
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 {?FileSystem}
|
|
*/
|
|
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) {
|
|
// Do not record actions, as that may crash the DevTools renderer.
|
|
}
|
|
|
|
/**
|
|
* Support for legacy front-ends (<M44).
|
|
* @param {number} panelCode
|
|
*/
|
|
recordPanelShown(panelCode) {
|
|
// Do not record actions, as that may crash the DevTools renderer.
|
|
}
|
|
};
|
|
|
|
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.locationOverride',
|
|
'emulation.showDeviceMode',
|
|
'emulation.showRulers',
|
|
'enableAsyncStackTraces',
|
|
'eventListenerBreakpoints',
|
|
'fileMappingEntries',
|
|
'fileSystemMapping',
|
|
'FileSystemViewSidebarWidth',
|
|
'fileSystemViewSplitViewState',
|
|
'filterBar-consoleView',
|
|
'filterBar-networkPanel',
|
|
'filterBar-promisePane',
|
|
'filterBar-timelinePanel',
|
|
'frameViewerHideChromeWindow',
|
|
'heapSnapshotRetainersViewSize',
|
|
'heapSnapshotSplitViewState',
|
|
'hideCollectedPromises',
|
|
'hideNetworkMessages',
|
|
'highlightNodeOnHoverInOverlay',
|
|
'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);
|