debug-server-next
Version:
Dev server for hippy-core.
770 lines (769 loc) • 42.3 kB
JavaScript
// Copyright 2021 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.
/*
* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com).
* Copyright (C) 2009 Joseph Pecoraro
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* eslint-disable rulesdir/no_underscored_properties */
import * as Common from '../../core/common/common.js';
import * as Host from '../../core/host/host.js';
import * as i18n from '../../core/i18n/i18n.js';
import * as Platform from '../../core/platform/platform.js';
import * as ProtocolClient from '../../core/protocol_client/protocol_client.js';
import * as Root from '../../core/root/root.js';
import * as SDK from '../../core/sdk/sdk.js';
import * as Bindings from '../../models/bindings/bindings.js';
import * as Extensions from '../../models/extensions/extensions.js';
import * as IssuesManager from '../../models/issues_manager/issues_manager.js';
import * as Logs from '../../models/logs/logs.js';
import * as Persistence from '../../models/persistence/persistence.js';
import * as Workspace from '../../models/workspace/workspace.js';
import * as Snippets from '../../panels/snippets/snippets.js';
import * as Timeline from '../../panels/timeline/timeline.js';
import * as PerfUI from '../../ui/legacy/components/perf_ui/perf_ui.js';
import * as Components from '../../ui/legacy/components/utils/utils.js';
import * as UI from '../../ui/legacy/legacy.js';
import { ExecutionContextSelector } from './ExecutionContextSelector.js';
const UIStrings = {
/**
*@description A message to display prompting the user to reload DevTools if the OS color scheme changes.
*/
theSystempreferredColorSchemeHas: 'The system-preferred color scheme has changed. To apply this change to DevTools, reload.',
/**
*@description Title of item in main
*/
customizeAndControlDevtools: 'Customize and control DevTools',
/**
*@description Title element text content in Main
*/
dockSide: 'Dock side',
/**
*@description Title element title in Main
*@example {Ctrl+Shift+D} PH1
*/
placementOfDevtoolsRelativeToThe: 'Placement of DevTools relative to the page. ({PH1} to restore last position)',
/**
*@description Text to undock the DevTools
*/
undockIntoSeparateWindow: 'Undock into separate window',
/**
*@description Text to dock the DevTools to the bottom of the browser tab
*/
dockToBottom: 'Dock to bottom',
/**
*@description Text to dock the DevTools to the right of the browser tab
*/
dockToRight: 'Dock to right',
/**
*@description Text to dock the DevTools to the left of the browser tab
*/
dockToLeft: 'Dock to left',
/**
*@description Text in Main
*/
focusDebuggee: 'Focus debuggee',
/**
*@description Text in Main
*/
hideConsoleDrawer: 'Hide console drawer',
/**
*@description Text in Main
*/
showConsoleDrawer: 'Show console drawer',
/**
*@description A context menu item in the Main
*/
moreTools: 'More tools',
/**
*@description Text for the viewing the help options
*/
help: 'Help',
};
const str_ = i18n.i18n.registerUIStrings('entrypoints/main/MainImpl.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
export class MainImpl {
_lateInitDonePromise;
constructor() {
MainImpl._instanceForTest = this;
Platform.runOnWindowLoad(() => {
this._loaded();
});
}
static time(label) {
if (Host.InspectorFrontendHost.isUnderTest()) {
return;
}
console.time(label);
}
static timeEnd(label) {
if (Host.InspectorFrontendHost.isUnderTest()) {
return;
}
console.timeEnd(label);
}
async _loaded() {
console.timeStamp('Main._loaded');
await Root.Runtime.appStarted;
Root.Runtime.Runtime.setPlatform(Host.Platform.platform());
const prefs = await new Promise(resolve => {
Host.InspectorFrontendHost.InspectorFrontendHostInstance.getPreferences(resolve);
});
console.timeStamp('Main._gotPreferences');
this._createSettings(prefs);
await this.requestAndRegisterLocaleData();
this._createAppUI();
}
async requestAndRegisterLocaleData() {
// The language setting is only available when the experiment is enabled.
// TODO(crbug.com/1163928): Remove the check when the experiment is gone.
let settingLanguage = 'en-US';
if (Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.LOCALIZED_DEVTOOLS)) {
settingLanguage = Common.Settings.Settings.instance().moduleSetting('language').get();
}
const devToolsLocale = i18n.DevToolsLocale.DevToolsLocale.instance({
create: true,
data: {
navigatorLanguage: navigator.language,
settingLanguage,
lookupClosestDevToolsLocale: i18n.i18n.lookupClosestSupportedDevToolsLocale,
},
});
if (devToolsLocale.locale !== 'en-US') {
// Always load en-US locale data as a fallback. This is important, newly added
// strings won't have a translation. If fetching en-US.json fails, something
// is seriously wrong and the exception should bubble up.
await i18n.i18n.fetchAndRegisterLocaleData('en-US');
}
try {
await i18n.i18n.fetchAndRegisterLocaleData(devToolsLocale.locale);
}
catch (error) {
console.error(error);
// Loading the actual locale data failed, tell DevTools to use 'en-US'.
devToolsLocale.forceFallbackLocale();
}
}
_createSettings(prefs) {
this._initializeExperiments();
let storagePrefix = '';
if (Host.Platform.isCustomDevtoolsFrontend()) {
storagePrefix = '__custom__';
}
else if (!Root.Runtime.Runtime.queryParam('can_dock') && Boolean(Root.Runtime.Runtime.queryParam('debugFrontend')) &&
!Host.InspectorFrontendHost.isUnderTest()) {
storagePrefix = '__bundled__';
}
let localStorage;
if (!Host.InspectorFrontendHost.isUnderTest() && window.localStorage) {
localStorage = new Common.Settings.SettingsStorage(window.localStorage, undefined, undefined, () => window.localStorage.clear(), storagePrefix);
}
else {
localStorage = new Common.Settings.SettingsStorage({}, undefined, undefined, undefined, storagePrefix);
}
const globalStorage = new Common.Settings.SettingsStorage(prefs, Host.InspectorFrontendHost.InspectorFrontendHostInstance.setPreference, Host.InspectorFrontendHost.InspectorFrontendHostInstance.removePreference, Host.InspectorFrontendHost.InspectorFrontendHostInstance.clearPreferences, storagePrefix);
Common.Settings.Settings.instance({ forceNew: true, globalStorage, localStorage });
// @ts-ignore layout test global
self.Common.settings = Common.Settings.Settings.instance();
if (!Host.InspectorFrontendHost.isUnderTest()) {
new Common.Settings.VersionController().updateVersion();
}
}
_initializeExperiments() {
Root.Runtime.experiments.register('applyCustomStylesheet', 'Allow extensions to load custom stylesheets');
Root.Runtime.experiments.register('captureNodeCreationStacks', 'Capture node creation stacks');
Root.Runtime.experiments.register('sourcesPrettyPrint', 'Automatically pretty print in the Sources Panel');
Root.Runtime.experiments.register('backgroundServices', 'Background web platform feature events', true);
Root.Runtime.experiments.register('backgroundServicesNotifications', 'Background services section for Notifications');
Root.Runtime.experiments.register('backgroundServicesPaymentHandler', 'Background services section for Payment Handler');
Root.Runtime.experiments.register('backgroundServicesPushMessaging', 'Background services section for Push Messaging');
// TODO(crbug.com/1161439): remove 'blackboxJSFramesOnTimeline', keep 'ignoreListJSFramesOnTimeline'
Root.Runtime.experiments.register('blackboxJSFramesOnTimeline', 'Ignore List for JavaScript frames on Timeline', true);
Root.Runtime.experiments.register('ignoreListJSFramesOnTimeline', 'Ignore List for JavaScript frames on Timeline', true);
Root.Runtime.experiments.register('cssOverview', 'CSS Overview', undefined, 'https://developer.chrome.com/blog/new-in-devtools-87/#css-overview');
Root.Runtime.experiments.register('emptySourceMapAutoStepping', 'Empty sourcemap auto-stepping');
Root.Runtime.experiments.register('inputEventsOnTimelineOverview', 'Input events on Timeline overview', true);
Root.Runtime.experiments.register('liveHeapProfile', 'Live heap profile', true);
Root.Runtime.experiments.register('protocolMonitor', 'Protocol Monitor', undefined, 'https://developer.chrome.com/blog/new-in-devtools-92/#protocol-monitor');
Root.Runtime.experiments.register('developerResourcesView', 'Show developer resources view');
Root.Runtime.experiments.register('cspViolationsView', 'Show CSP Violations view', undefined, 'https://developer.chrome.com/blog/new-in-devtools-89/#csp');
Root.Runtime.experiments.register('recordCoverageWithPerformanceTracing', 'Record coverage while performance tracing');
Root.Runtime.experiments.register('samplingHeapProfilerTimeline', 'Sampling heap profiler timeline', true);
Root.Runtime.experiments.register('showOptionToNotTreatGlobalObjectsAsRoots', 'Show option to take heap snapshot where globals are not treated as root');
Root.Runtime.experiments.register('sourceDiff', 'Source diff');
Root.Runtime.experiments.register('sourceOrderViewer', 'Source order viewer', undefined, 'https://developer.chrome.com/blog/new-in-devtools-92/#source-order');
Root.Runtime.experiments.register('webauthnPane', 'WebAuthn Pane');
Root.Runtime.experiments.register('keyboardShortcutEditor', 'Enable keyboard shortcut editor', true, 'https://developer.chrome.com/blog/new-in-devtools-88/#keyboard-shortcuts');
// Back-forward cache
Root.Runtime.experiments.register('bfcacheDebugging', 'Enable back-forward cache debugging support');
// Timeline
Root.Runtime.experiments.register('timelineEventInitiators', 'Timeline: event initiators');
Root.Runtime.experiments.register('timelineInvalidationTracking', 'Timeline: invalidation tracking', true);
Root.Runtime.experiments.register('timelineShowAllEvents', 'Timeline: show all events', true);
Root.Runtime.experiments.register('timelineV8RuntimeCallStats', 'Timeline: V8 Runtime Call Stats on Timeline', true);
Root.Runtime.experiments.register('timelineWebGL', 'Timeline: WebGL-based flamechart');
Root.Runtime.experiments.register('timelineReplayEvent', 'Timeline: Replay input events', true);
Root.Runtime.experiments.register('wasmDWARFDebugging', 'WebAssembly Debugging: Enable DWARF support', undefined, 'https://developer.chrome.com/blog/wasm-debugging-2020/');
// Dual-screen
Root.Runtime.experiments.register('dualScreenSupport', 'Emulation: Support dual screen mode', undefined, 'https://developer.chrome.com/blog/new-in-devtools-89#dual-screen');
Root.Runtime.experiments.setEnabled('dualScreenSupport', true);
// Advanced Perceptual Contrast Algorithm.
Root.Runtime.experiments.register('APCA', 'Enable new Advanced Perceptual Contrast Algorithm (APCA) replacing previous contrast ratio and AA/AAA guidelines', undefined, 'https://developer.chrome.com/blog/new-in-devtools-89/#apca');
// Full Accessibility Tree
Root.Runtime.experiments.register('fullAccessibilityTree', 'Enable full accessibility tree view in the Elements panel', undefined, 'https://developer.chrome.com/blog/new-in-devtools-90/#accesibility-tree');
// Font Editor
Root.Runtime.experiments.register('fontEditor', 'Enable new Font Editor tool within the Styles Pane.', undefined, 'https://developer.chrome.com/blog/new-in-devtools-89/#font');
// Contrast issues reported via the Issues panel.
Root.Runtime.experiments.register('contrastIssues', 'Enable automatic contrast issue reporting via the Issues panel', undefined, 'https://developer.chrome.com/blog/new-in-devtools-90/#low-contrast');
// New cookie features.
Root.Runtime.experiments.register('experimentalCookieFeatures', 'Enable experimental cookie features');
Root.Runtime.experiments.enableExperimentsByDefault([
'sourceOrderViewer',
]);
// Localized DevTools, hide "locale selector" setting behind an experiment.
Root.Runtime.experiments.register(Root.Runtime.ExperimentName.LOCALIZED_DEVTOOLS, 'Enable localized DevTools');
Root.Runtime.experiments.cleanUpStaleExperiments();
const enabledExperiments = Root.Runtime.Runtime.queryParam('enabledExperiments');
if (enabledExperiments) {
Root.Runtime.experiments.setServerEnabledExperiments(enabledExperiments.split(';'));
}
Root.Runtime.experiments.enableExperimentsTransiently([
'backgroundServices',
'backgroundServicesNotifications',
'backgroundServicesPushMessaging',
'backgroundServicesPaymentHandler',
'webauthnPane',
'developerResourcesView',
]);
if (Host.InspectorFrontendHost.isUnderTest()) {
const testParam = Root.Runtime.Runtime.queryParam('test');
if (testParam && testParam.includes('live-line-level-heap-profile.js')) {
Root.Runtime.experiments.enableForTest('liveHeapProfile');
}
}
// TODO(crbug.com/1161439): remove experiment duplication
const isBlackboxJSFramesOnTimelineEnabled = Root.Runtime.experiments.isEnabled('blackboxJSFramesOnTimeline');
Root.Runtime.experiments.setEnabled('ignoreListJSFramesOnTimeline', isBlackboxJSFramesOnTimelineEnabled);
for (const experiment of Root.Runtime.experiments.enabledExperiments()) {
Host.userMetrics.experimentEnabledAtLaunch(experiment.name);
}
}
async _createAppUI() {
MainImpl.time('Main._createAppUI');
// @ts-ignore layout test global
self.UI.viewManager = UI.ViewManager.ViewManager.instance();
// Request filesystems early, we won't create connections until callback is fired. Things will happen in parallel.
// @ts-ignore layout test global
self.Persistence.isolatedFileSystemManager =
Persistence.IsolatedFileSystemManager.IsolatedFileSystemManager.instance();
const defaultThemeSetting = 'systemPreferred';
const themeSetting = Common.Settings.Settings.instance().createSetting('uiTheme', defaultThemeSetting);
UI.UIUtils.initializeUIUtils(document, themeSetting);
if (themeSetting.get() === defaultThemeSetting) {
const darkThemeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
darkThemeMediaQuery.addEventListener('change', () => {
UI.InspectorView.InspectorView.instance().displayReloadRequiredWarning(i18nString(UIStrings.theSystempreferredColorSchemeHas));
});
}
UI.UIUtils.installComponentRootStyles(document.body);
this._addMainEventListeners(document);
const canDock = Boolean(Root.Runtime.Runtime.queryParam('can_dock'));
// @ts-ignore layout test global
self.UI.zoomManager = UI.ZoomManager.ZoomManager.instance({ forceNew: true, win: window, frontendHost: Host.InspectorFrontendHost.InspectorFrontendHostInstance });
// @ts-ignore layout test global
self.UI.inspectorView = UI.InspectorView.InspectorView.instance();
UI.ContextMenu.ContextMenu.initialize();
UI.ContextMenu.ContextMenu.installHandler(document);
// These instances need to be created early so they don't miss any events about requests/issues/etc.
Logs.NetworkLog.NetworkLog.instance();
SDK.FrameManager.FrameManager.instance();
Logs.LogManager.LogManager.instance();
IssuesManager.IssuesManager.IssuesManager.instance({
forceNew: true,
ensureFirst: true,
showThirdPartyIssuesSetting: IssuesManager.Issue.getShowThirdPartyIssuesSetting(),
});
IssuesManager.ContrastCheckTrigger.ContrastCheckTrigger.instance();
// @ts-ignore layout test global
self.SDK.consoleModel = SDK.ConsoleModel.ConsoleModel.instance();
// @ts-ignore layout test global
self.UI.dockController = UI.DockController.DockController.instance({ forceNew: true, canDock });
// @ts-ignore layout test global
self.SDK.multitargetNetworkManager = SDK.NetworkManager.MultitargetNetworkManager.instance({ forceNew: true });
// @ts-ignore layout test global
self.SDK.domDebuggerManager = SDK.DOMDebuggerModel.DOMDebuggerManager.instance({ forceNew: true });
SDK.TargetManager.TargetManager.instance().addEventListener(SDK.TargetManager.Events.SuspendStateChanged, this._onSuspendStateChanged.bind(this));
// @ts-ignore layout test global
self.Workspace.fileManager = Workspace.FileManager.FileManager.instance({ forceNew: true });
// @ts-ignore layout test global
self.Workspace.workspace = Workspace.Workspace.WorkspaceImpl.instance();
// @ts-ignore layout test global
self.Bindings.networkProjectManager = Bindings.NetworkProject.NetworkProjectManager.instance();
// @ts-ignore layout test global
self.Bindings.resourceMapping = Bindings.ResourceMapping.ResourceMapping.instance({
forceNew: true,
targetManager: SDK.TargetManager.TargetManager.instance(),
workspace: Workspace.Workspace.WorkspaceImpl.instance(),
});
new Bindings.PresentationConsoleMessageHelper.PresentationConsoleMessageManager();
// @ts-ignore layout test global
self.Bindings.cssWorkspaceBinding = Bindings.CSSWorkspaceBinding.CSSWorkspaceBinding.instance({
forceNew: true,
targetManager: SDK.TargetManager.TargetManager.instance(),
workspace: Workspace.Workspace.WorkspaceImpl.instance(),
});
// @ts-ignore layout test global
self.Bindings.debuggerWorkspaceBinding = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance({
forceNew: true,
targetManager: SDK.TargetManager.TargetManager.instance(),
workspace: Workspace.Workspace.WorkspaceImpl.instance(),
});
// @ts-ignore layout test global
self.Bindings.breakpointManager = Bindings.BreakpointManager.BreakpointManager.instance({
forceNew: true,
workspace: Workspace.Workspace.WorkspaceImpl.instance(),
targetManager: SDK.TargetManager.TargetManager.instance(),
debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance(),
});
// @ts-ignore layout test global
self.Extensions.extensionServer = Extensions.ExtensionServer.ExtensionServer.instance({ forceNew: true });
new Persistence.FileSystemWorkspaceBinding.FileSystemWorkspaceBinding(Persistence.IsolatedFileSystemManager.IsolatedFileSystemManager.instance(), Workspace.Workspace.WorkspaceImpl.instance());
Persistence.IsolatedFileSystemManager.IsolatedFileSystemManager.instance().addPlatformFileSystem(
// @ts-ignore https://github.com/microsoft/TypeScript/issues/41397
'snippet://', new Snippets.ScriptSnippetFileSystem.SnippetFileSystem());
// @ts-ignore layout test global
self.Persistence.persistence = Persistence.Persistence.PersistenceImpl.instance({
forceNew: true,
workspace: Workspace.Workspace.WorkspaceImpl.instance(),
breakpointManager: Bindings.BreakpointManager.BreakpointManager.instance(),
});
// @ts-ignore layout test global
self.Persistence.networkPersistenceManager =
Persistence.NetworkPersistenceManager.NetworkPersistenceManager.instance({ forceNew: true, workspace: Workspace.Workspace.WorkspaceImpl.instance() });
new ExecutionContextSelector(SDK.TargetManager.TargetManager.instance(), UI.Context.Context.instance());
// @ts-ignore layout test global
self.Bindings.ignoreListManager = Bindings.IgnoreListManager.IgnoreListManager.instance({
forceNew: true,
debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance(),
});
new PauseListener();
const actionRegistryInstance = UI.ActionRegistry.ActionRegistry.instance({ forceNew: true });
// Required for legacy a11y layout tests
// @ts-ignore layout test global
self.UI.actionRegistry = actionRegistryInstance;
// @ts-ignore layout test global
self.UI.shortcutRegistry =
UI.ShortcutRegistry.ShortcutRegistry.instance({ forceNew: true, actionRegistry: actionRegistryInstance });
this._registerMessageSinkListener();
MainImpl.timeEnd('Main._createAppUI');
const appProvider = Common.AppProvider.getRegisteredAppProviders()[0];
if (!appProvider) {
throw new Error('Unable to boot DevTools, as the appprovider is missing');
}
await this._showAppUI(await appProvider.loadAppProvider());
}
async _showAppUI(appProvider) {
MainImpl.time('Main._showAppUI');
const app = appProvider.createApp();
// It is important to kick controller lifetime after apps are instantiated.
UI.DockController.DockController.instance().initialize();
app.presentUI(document);
const toggleSearchNodeAction = UI.ActionRegistry.ActionRegistry.instance().action('elements.toggle-element-search');
// TODO: we should not access actions from other modules.
if (toggleSearchNodeAction) {
Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(Host.InspectorFrontendHostAPI.Events.EnterInspectElementMode, () => {
toggleSearchNodeAction.execute();
}, this);
}
Host.InspectorFrontendHost.InspectorFrontendHostInstance.events.addEventListener(Host.InspectorFrontendHostAPI.Events.RevealSourceLine, this._revealSourceLine, this);
await UI.InspectorView.InspectorView.instance().createToolbars();
Host.InspectorFrontendHost.InspectorFrontendHostInstance.loadCompleted();
const value = Root.Runtime.Runtime.queryParam('loadTimelineFromURL');
if (value !== null) {
Timeline.TimelinePanel.LoadTimelineHandler.instance().handleQueryParam(value);
}
// Allow UI cycles to repaint prior to creating connection.
setTimeout(this._initializeTarget.bind(this), 0);
MainImpl.timeEnd('Main._showAppUI');
}
async _initializeTarget() {
MainImpl.time('Main._initializeTarget');
// We rely on having the early initialization runnables registered in Common when an app loads its
// modules, so that we don't have to exhaustively check the app DevTools is running as to
// start the applicable runnables.
for (const runnableInstanceFunction of Common.Runnable.earlyInitializationRunnables()) {
await runnableInstanceFunction().run();
}
// Used for browser tests.
Host.InspectorFrontendHost.InspectorFrontendHostInstance.readyForTest();
// Asynchronously run the extensions.
setTimeout(this._lateInitialization.bind(this), 100);
MainImpl.timeEnd('Main._initializeTarget');
}
_lateInitialization() {
MainImpl.time('Main._lateInitialization');
Extensions.ExtensionServer.ExtensionServer.instance().initializeExtensions();
const promises = Common.Runnable.lateInitializationRunnables().map(async (lateInitializationLoader) => {
const runnable = await lateInitializationLoader();
return runnable.run();
});
if (Root.Runtime.experiments.isEnabled('liveHeapProfile')) {
const setting = 'memoryLiveHeapProfile';
if (Common.Settings.Settings.instance().moduleSetting(setting).get()) {
promises.push(PerfUI.LiveHeapProfile.LiveHeapProfile.instance().run());
}
else {
const changeListener = async (event) => {
if (!event.data) {
return;
}
Common.Settings.Settings.instance().moduleSetting(setting).removeChangeListener(changeListener);
PerfUI.LiveHeapProfile.LiveHeapProfile.instance().run();
};
Common.Settings.Settings.instance().moduleSetting(setting).addChangeListener(changeListener);
}
}
this._lateInitDonePromise = Promise.all(promises).then(() => undefined);
MainImpl.timeEnd('Main._lateInitialization');
}
lateInitDonePromiseForTest() {
return this._lateInitDonePromise;
}
_registerMessageSinkListener() {
Common.Console.Console.instance().addEventListener(Common.Console.Events.MessageAdded, messageAdded);
function messageAdded(event) {
const message = event.data;
if (message.show) {
Common.Console.Console.instance().show();
}
}
}
_revealSourceLine(event) {
const url = event.data['url'];
const lineNumber = event.data['lineNumber'];
const columnNumber = event.data['columnNumber'];
const uiSourceCode = Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURL(url);
if (uiSourceCode) {
Common.Revealer.reveal(uiSourceCode.uiLocation(lineNumber, columnNumber));
return;
}
function listener(event) {
const uiSourceCode = event.data;
if (uiSourceCode.url() === url) {
Common.Revealer.reveal(uiSourceCode.uiLocation(lineNumber, columnNumber));
Workspace.Workspace.WorkspaceImpl.instance().removeEventListener(Workspace.Workspace.Events.UISourceCodeAdded, listener);
}
}
Workspace.Workspace.WorkspaceImpl.instance().addEventListener(Workspace.Workspace.Events.UISourceCodeAdded, listener);
}
_postDocumentKeyDown(event) {
if (!event.handled) {
UI.ShortcutRegistry.ShortcutRegistry.instance().handleShortcut(event);
}
}
_redispatchClipboardEvent(event) {
const eventCopy = new CustomEvent('clipboard-' + event.type, { bubbles: true });
// @ts-ignore Used in ElementsTreeOutline
eventCopy['original'] = event;
const document = event.target && event.target.ownerDocument;
const target = document ? document.deepActiveElement() : null;
if (target) {
target.dispatchEvent(eventCopy);
}
if (eventCopy.handled) {
event.preventDefault();
}
}
_contextMenuEventFired(event) {
if (event.handled || event.target.classList.contains('popup-glasspane')) {
event.preventDefault();
}
}
_addMainEventListeners(document) {
document.addEventListener('keydown', this._postDocumentKeyDown.bind(this), false);
document.addEventListener('beforecopy', this._redispatchClipboardEvent.bind(this), true);
document.addEventListener('copy', this._redispatchClipboardEvent.bind(this), false);
document.addEventListener('cut', this._redispatchClipboardEvent.bind(this), false);
document.addEventListener('paste', this._redispatchClipboardEvent.bind(this), false);
document.addEventListener('contextmenu', this._contextMenuEventFired.bind(this), true);
}
_onSuspendStateChanged() {
const suspended = SDK.TargetManager.TargetManager.instance().allTargetsSuspended();
UI.InspectorView.InspectorView.instance().onSuspendStateChanged(suspended);
}
static _instanceForTest = null;
}
// @ts-ignore Exported for Tests.js
globalThis.Main = globalThis.Main || {};
// @ts-ignore Exported for Tests.js
globalThis.Main.Main = MainImpl;
let zoomActionDelegateInstance;
export class ZoomActionDelegate {
static instance(opts = { forceNew: null }) {
const { forceNew } = opts;
if (!zoomActionDelegateInstance || forceNew) {
zoomActionDelegateInstance = new ZoomActionDelegate();
}
return zoomActionDelegateInstance;
}
handleAction(context, actionId) {
if (Host.InspectorFrontendHost.InspectorFrontendHostInstance.isHostedMode()) {
return false;
}
switch (actionId) {
case 'main.zoom-in':
Host.InspectorFrontendHost.InspectorFrontendHostInstance.zoomIn();
return true;
case 'main.zoom-out':
Host.InspectorFrontendHost.InspectorFrontendHostInstance.zoomOut();
return true;
case 'main.zoom-reset':
Host.InspectorFrontendHost.InspectorFrontendHostInstance.resetZoom();
return true;
}
return false;
}
}
let searchActionDelegateInstance;
export class SearchActionDelegate {
static instance(opts = { forceNew: null }) {
const { forceNew } = opts;
if (!searchActionDelegateInstance || forceNew) {
searchActionDelegateInstance = new SearchActionDelegate();
}
return searchActionDelegateInstance;
}
handleAction(context, actionId) {
let searchableView = UI.SearchableView.SearchableView.fromElement(document.deepActiveElement());
if (!searchableView) {
const currentPanel = UI.InspectorView.InspectorView.instance().currentPanelDeprecated();
if (currentPanel && currentPanel.searchableView) {
searchableView = currentPanel.searchableView();
}
if (!searchableView) {
return false;
}
}
switch (actionId) {
case 'main.search-in-panel.find':
return searchableView.handleFindShortcut();
case 'main.search-in-panel.cancel':
return searchableView.handleCancelSearchShortcut();
case 'main.search-in-panel.find-next':
return searchableView.handleFindNextShortcut();
case 'main.search-in-panel.find-previous':
return searchableView.handleFindPreviousShortcut();
}
return false;
}
}
let mainMenuItemInstance;
export class MainMenuItem {
_item;
constructor() {
this._item = new UI.Toolbar.ToolbarMenuButton(this._handleContextMenu.bind(this), true);
this._item.element.classList.add('main-menu');
this._item.setTitle(i18nString(UIStrings.customizeAndControlDevtools));
}
static instance(opts = { forceNew: null }) {
const { forceNew } = opts;
if (!mainMenuItemInstance || forceNew) {
mainMenuItemInstance = new MainMenuItem();
}
return mainMenuItemInstance;
}
item() {
return this._item;
}
_handleContextMenu(contextMenu) {
if (UI.DockController.DockController.instance().canDock()) {
const dockItemElement = document.createElement('div');
dockItemElement.classList.add('flex-centered');
dockItemElement.classList.add('flex-auto');
dockItemElement.tabIndex = -1;
UI.ARIAUtils.setAccessibleName(dockItemElement, UIStrings.dockSide);
const titleElement = dockItemElement.createChild('span', 'flex-auto');
titleElement.textContent = i18nString(UIStrings.dockSide);
const toggleDockSideShorcuts = UI.ShortcutRegistry.ShortcutRegistry.instance().shortcutsForAction('main.toggle-dock');
UI.Tooltip.Tooltip.install(titleElement, i18nString(UIStrings.placementOfDevtoolsRelativeToThe, { PH1: toggleDockSideShorcuts[0].title() }));
dockItemElement.appendChild(titleElement);
const dockItemToolbar = new UI.Toolbar.Toolbar('', dockItemElement);
dockItemToolbar.makeBlueOnHover();
const undock = new UI.Toolbar.ToolbarToggle(i18nString(UIStrings.undockIntoSeparateWindow), 'largeicon-undock');
const bottom = new UI.Toolbar.ToolbarToggle(i18nString(UIStrings.dockToBottom), 'largeicon-dock-to-bottom');
const right = new UI.Toolbar.ToolbarToggle(i18nString(UIStrings.dockToRight), 'largeicon-dock-to-right');
const left = new UI.Toolbar.ToolbarToggle(i18nString(UIStrings.dockToLeft), 'largeicon-dock-to-left');
undock.addEventListener(UI.Toolbar.ToolbarButton.Events.MouseDown, event => event.data.consume());
bottom.addEventListener(UI.Toolbar.ToolbarButton.Events.MouseDown, event => event.data.consume());
right.addEventListener(UI.Toolbar.ToolbarButton.Events.MouseDown, event => event.data.consume());
left.addEventListener(UI.Toolbar.ToolbarButton.Events.MouseDown, event => event.data.consume());
undock.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, setDockSide.bind(null, UI.DockController.State.Undocked));
bottom.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, setDockSide.bind(null, UI.DockController.State.DockedToBottom));
right.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, setDockSide.bind(null, UI.DockController.State.DockedToRight));
left.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, setDockSide.bind(null, UI.DockController.State.DockedToLeft));
undock.setToggled(UI.DockController.DockController.instance().dockSide() === UI.DockController.State.Undocked);
bottom.setToggled(UI.DockController.DockController.instance().dockSide() === UI.DockController.State.DockedToBottom);
right.setToggled(UI.DockController.DockController.instance().dockSide() === UI.DockController.State.DockedToRight);
left.setToggled(UI.DockController.DockController.instance().dockSide() === UI.DockController.State.DockedToLeft);
dockItemToolbar.appendToolbarItem(undock);
dockItemToolbar.appendToolbarItem(left);
dockItemToolbar.appendToolbarItem(bottom);
dockItemToolbar.appendToolbarItem(right);
dockItemElement.addEventListener('keydown', event => {
let dir = 0;
if (event.key === 'ArrowLeft') {
dir = -1;
}
else if (event.key === 'ArrowRight') {
dir = 1;
}
else {
return;
}
const buttons = [undock, left, bottom, right];
let index = buttons.findIndex(button => button.element.hasFocus());
index = Platform.NumberUtilities.clamp(index + dir, 0, buttons.length - 1);
buttons[index].element.focus();
event.consume(true);
});
contextMenu.headerSection().appendCustomItem(dockItemElement);
}
const button = this._item.element;
function setDockSide(side) {
UI.DockController.DockController.instance().once("AfterDockSideChanged" /* AfterDockSideChanged */).then(() => {
button.focus();
});
UI.DockController.DockController.instance().setDockSide(side);
contextMenu.discard();
}
if (UI.DockController.DockController.instance().dockSide() === UI.DockController.State.Undocked) {
const mainTarget = SDK.TargetManager.TargetManager.instance().mainTarget();
if (mainTarget && mainTarget.type() === SDK.Target.Type.Frame) {
contextMenu.defaultSection().appendAction('inspector_main.focus-debuggee', i18nString(UIStrings.focusDebuggee));
}
}
contextMenu.defaultSection().appendAction('main.toggle-drawer', UI.InspectorView.InspectorView.instance().drawerVisible() ? i18nString(UIStrings.hideConsoleDrawer) :
i18nString(UIStrings.showConsoleDrawer));
contextMenu.appendItemsAtLocation('mainMenu');
const moreTools = contextMenu.defaultSection().appendSubMenuItem(i18nString(UIStrings.moreTools));
const viewExtensions = UI.ViewManager.getRegisteredViewExtensions();
viewExtensions.sort((extension1, extension2) => {
const title1 = extension1.title();
const title2 = extension2.title();
return title1.localeCompare(title2);
});
for (const viewExtension of viewExtensions) {
const location = viewExtension.location();
const persistence = viewExtension.persistence();
const title = viewExtension.title();
const id = viewExtension.viewId();
if (id === 'issues-pane') {
moreTools.defaultSection().appendItem(title, () => {
Host.userMetrics.issuesPanelOpenedFrom(Host.UserMetrics.IssueOpener.HamburgerMenu);
UI.ViewManager.ViewManager.instance().showView('issues-pane', /* userGesture */ true);
});
continue;
}
if (persistence !== 'closeable') {
continue;
}
if (location !== 'drawer-view' && location !== 'panel') {
continue;
}
moreTools.defaultSection().appendItem(title, () => {
UI.ViewManager.ViewManager.instance().showView(id, true, false);
});
}
const helpSubMenu = contextMenu.footerSection().appendSubMenuItem(i18nString(UIStrings.help));
helpSubMenu.appendItemsAtLocation('mainMenuHelp');
}
}
let settingsButtonProviderInstance;
export class SettingsButtonProvider {
_settingsButton;
constructor() {
const settingsActionId = 'settings.show';
this._settingsButton =
UI.Toolbar.Toolbar.createActionButtonForId(settingsActionId, { showLabel: false, userActionCode: undefined });
}
static instance(opts = { forceNew: null }) {
const { forceNew } = opts;
if (!settingsButtonProviderInstance || forceNew) {
settingsButtonProviderInstance = new SettingsButtonProvider();
}
return settingsButtonProviderInstance;
}
item() {
return this._settingsButton;
}
}
export class PauseListener {
constructor() {
SDK.TargetManager.TargetManager.instance().addModelListener(SDK.DebuggerModel.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
}
_debuggerPaused(event) {
SDK.TargetManager.TargetManager.instance().removeModelListener(SDK.DebuggerModel.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
const debuggerModel = event.data;
const debuggerPausedDetails = debuggerModel.debuggerPausedDetails();
UI.Context.Context.instance().setFlavor(SDK.Target.Target, debuggerModel.target());
Common.Revealer.reveal(debuggerPausedDetails);
}
}
export function sendOverProtocol(method, params) {
return new Promise((resolve, reject) => {
const sendRawMessage = ProtocolClient.InspectorBackend.test.sendRawMessage;
if (!sendRawMessage) {
return reject('Unable to send message to test client');
}
sendRawMessage(method, params, (err, ...results) => {
if (err) {
return reject(err);
}
return resolve(results);
});
});
}
let reloadActionDelegateInstance;
export class ReloadActionDelegate {
static instance(opts = { forceNew: null }) {
const { forceNew } = opts;
if (!reloadActionDelegateInstance || forceNew) {
reloadActionDelegateInstance = new ReloadActionDelegate();
}
return reloadActionDelegateInstance;
}
handleAction(context, actionId) {
switch (actionId) {
case 'main.debug-reload':
Components.Reload.reload();
return true;
}
return false;
}
}
new MainImpl();