blob: 03ce9724eab4a647c9298df7c985597b121abe64 [file] [log] [blame]
// 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) 2008 Apple Inc. All Rights Reserved.
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
* 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 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 ObjectUI from '../object_ui/object_ui.js';
import * as Recorder from '../recorder/recorder.js';
import * as Snippets from '../snippets/snippets.js';
import * as UI from '../ui/legacy/legacy.js';
import * as Workspace from '../workspace/workspace.js';
import {CallStackSidebarPane} from './CallStackSidebarPane.js';
import {DebuggerPausedMessage} from './DebuggerPausedMessage.js';
import {NavigatorView} from './NavigatorView.js'; // eslint-disable-line no-unused-vars
import {ContentScriptsNavigatorView, FilesNavigatorView, NetworkNavigatorView, OverridesNavigatorView, RecordingsNavigatorView, SnippetsNavigatorView} from './SourcesNavigator.js';
import {Events, SourcesView} from './SourcesView.js';
import {ThreadsSidebarPane} from './ThreadsSidebarPane.js';
import {UISourceCodeFrame} from './UISourceCodeFrame.js';
const UIStrings = {
/**
*@description Text that appears when user drag and drop something (for example, a file) in Sources Panel of the Sources panel
*/
dropWorkspaceFolderHere: 'Drop workspace folder here',
/**
*@description Text to show more options
*/
moreOptions: 'More options',
/**
* @description Tooltip for the the navigator toggle in the Sources panel. Command to open/show the
* sidebar containing the navigator tool.
*/
showNavigator: 'Show navigator',
/**
* @description Tooltip for the the navigator toggle in the Sources panel. Command to close/hide
* the sidebar containing the navigator tool.
*/
hideNavigator: 'Hide navigator',
/**
* @description Tooltip for the the debugger toggle in the Sources panel. Command to open/show the
* sidebar containing the debugger tool.
*/
showDebugger: 'Show debugger',
/**
* @description Tooltip for the the debugger toggle in the Sources panel. Command to close/hide the
* sidebar containing the debugger tool.
*/
hideDebugger: 'Hide debugger',
/**
*@description Text in Sources Panel of the Sources panel
*/
groupByFolder: 'Group by folder',
/**
*@description Text for pausing the debugger on exceptions
*/
pauseOnExceptions: 'Pause on exceptions',
/**
*@description Text in Sources Panel of the Sources panel
*/
dontPauseOnExceptions: 'Don\'t pause on exceptions',
/**
*@description Tooltip text that appears when hovering over the largeicon play button in the Sources Panel of the Sources panel
*/
resumeWithAllPausesBlockedForMs: 'Resume with all pauses blocked for 500 ms',
/**
*@description Tooltip text that appears when hovering over the largeicon terminate execution button in the Sources Panel of the Sources panel
*/
terminateCurrentJavascriptCall: 'Terminate current JavaScript call',
/**
*@description Text in Sources Panel of the Sources panel
*/
pauseOnCaughtExceptions: 'Pause on caught exceptions',
/**
*@description A context menu item in the Sources Panel of the Sources panel
*/
revealInSidebar: 'Reveal in sidebar',
/**
*@description A context menu item in the Sources Panel of the Sources panel when debugging JS code.
* When clicked, the execution is resumed until it reaches the line specified by the right-click that
* opened the context menu.
*/
continueToHere: 'Continue to here',
/**
*@description A context menu item in the Console that stores selection as a temporary global variable
*@example {string} PH1
*/
storeSAsGlobalVariable: 'Store {PH1} as global variable',
/**
*@description A context menu item in the Console, Sources, and Network panel
*@example {string} PH1
*/
copyS: 'Copy {PH1}',
/**
*@description A context menu item in the Sources Panel of the Sources panel
*/
showFunctionDefinition: 'Show function definition',
/**
*@description Text in Sources Panel of the Sources panel
*/
openInSourcesPanel: 'Open in Sources panel',
};
const str_ = i18n.i18n.registerUIStrings('sources/SourcesPanel.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
let sourcesPanelInstance: SourcesPanel;
let wrapperViewInstance: WrapperView;
export class SourcesPanel extends UI.Panel.Panel implements UI.ContextMenu.Provider, SDK.SDKModel.Observer,
UI.View.ViewLocationResolver {
_workspace: Workspace.Workspace.WorkspaceImpl;
_togglePauseAction: UI.ActionRegistration.Action;
_stepOverAction: UI.ActionRegistration.Action;
_stepIntoAction: UI.ActionRegistration.Action;
_stepOutAction: UI.ActionRegistration.Action;
_stepAction: UI.ActionRegistration.Action;
_toggleBreakpointsActiveAction: UI.ActionRegistration.Action;
_debugToolbar: UI.Toolbar.Toolbar;
_debugToolbarDrawer: HTMLDivElement;
_debuggerPausedMessage: DebuggerPausedMessage;
_splitWidget: UI.SplitWidget.SplitWidget;
editorView: UI.SplitWidget.SplitWidget;
_navigatorTabbedLocation: UI.View.TabbedViewLocation;
_sourcesView: SourcesView;
_toggleNavigatorSidebarButton: UI.Toolbar.ToolbarButton;
_toggleDebuggerSidebarButton: UI.Toolbar.ToolbarButton;
_threadsSidebarPane: UI.View.View|null;
_watchSidebarPane: UI.View.View;
_callstackPane: CallStackSidebarPane;
_liveLocationPool: Bindings.LiveLocation.LiveLocationPool;
_lastModificationTime: number;
_paused?: boolean;
_switchToPausedTargetTimeout?: number;
_ignoreExecutionLineEvents?: boolean;
_executionLineLocation?: Bindings.DebuggerWorkspaceBinding.Location|null;
_pauseOnExceptionButton?: UI.Toolbar.ToolbarToggle;
_sidebarPaneStack?: UI.View.ViewLocation;
_tabbedLocationHeader?: Element|null;
_extensionSidebarPanesContainer?: UI.View.ViewLocation;
sidebarPaneView?: UI.Widget.VBox|UI.SplitWidget.SplitWidget;
constructor() {
super('sources');
this.registerRequiredCSS('sources/sourcesPanel.css', {enableLegacyPatching: false});
new UI.DropTarget.DropTarget(
this.element, [UI.DropTarget.Type.Folder], i18nString(UIStrings.dropWorkspaceFolderHere),
this._handleDrop.bind(this));
this._workspace = Workspace.Workspace.WorkspaceImpl.instance();
this._togglePauseAction =
(UI.ActionRegistry.ActionRegistry.instance().action('debugger.toggle-pause') as UI.ActionRegistration.Action);
this._stepOverAction =
(UI.ActionRegistry.ActionRegistry.instance().action('debugger.step-over') as UI.ActionRegistration.Action);
this._stepIntoAction =
(UI.ActionRegistry.ActionRegistry.instance().action('debugger.step-into') as UI.ActionRegistration.Action);
this._stepOutAction =
(UI.ActionRegistry.ActionRegistry.instance().action('debugger.step-out') as UI.ActionRegistration.Action);
this._stepAction =
(UI.ActionRegistry.ActionRegistry.instance().action('debugger.step') as UI.ActionRegistration.Action);
this._toggleBreakpointsActiveAction =
(UI.ActionRegistry.ActionRegistry.instance().action('debugger.toggle-breakpoints-active') as
UI.ActionRegistration.Action);
this._debugToolbar = this._createDebugToolbar();
this._debugToolbarDrawer = this._createDebugToolbarDrawer();
this._debuggerPausedMessage = new DebuggerPausedMessage();
const initialDebugSidebarWidth = 225;
this._splitWidget =
new UI.SplitWidget.SplitWidget(true, true, 'sourcesPanelSplitViewState', initialDebugSidebarWidth);
this._splitWidget.enableShowModeSaving();
this._splitWidget.show(this.element);
// Create scripts navigator
const initialNavigatorWidth = 225;
this.editorView =
new UI.SplitWidget.SplitWidget(true, false, 'sourcesPanelNavigatorSplitViewState', initialNavigatorWidth);
this.editorView.enableShowModeSaving();
this._splitWidget.setMainWidget(this.editorView);
// Create navigator tabbed pane with toolbar.
this._navigatorTabbedLocation = UI.ViewManager.ViewManager.instance().createTabbedLocation(
this._revealNavigatorSidebar.bind(this), 'navigator-view', true);
const tabbedPane = this._navigatorTabbedLocation.tabbedPane();
tabbedPane.setMinimumSize(100, 25);
tabbedPane.element.classList.add('navigator-tabbed-pane');
const navigatorMenuButton = new UI.Toolbar.ToolbarMenuButton(this._populateNavigatorMenu.bind(this), true);
navigatorMenuButton.setTitle(i18nString(UIStrings.moreOptions));
tabbedPane.rightToolbar().appendToolbarItem(navigatorMenuButton);
if (UI.ViewManager.ViewManager.instance().hasViewsForLocation('run-view-sidebar')) {
const navigatorSplitWidget =
new UI.SplitWidget.SplitWidget(false, true, 'sourcePanelNavigatorSidebarSplitViewState');
navigatorSplitWidget.setMainWidget(tabbedPane);
const runViewTabbedPane = UI.ViewManager.ViewManager.instance()
.createTabbedLocation(this._revealNavigatorSidebar.bind(this), 'run-view-sidebar')
.tabbedPane();
navigatorSplitWidget.setSidebarWidget(runViewTabbedPane);
navigatorSplitWidget.installResizer(runViewTabbedPane.headerElement());
this.editorView.setSidebarWidget(navigatorSplitWidget);
} else {
this.editorView.setSidebarWidget(tabbedPane);
}
this._sourcesView = new SourcesView();
this._sourcesView.addEventListener(Events.EditorSelected, this._editorSelected.bind(this));
this._toggleNavigatorSidebarButton = this.editorView.createShowHideSidebarButton(
i18nString(UIStrings.showNavigator), i18nString(UIStrings.hideNavigator));
this._toggleDebuggerSidebarButton = this._splitWidget.createShowHideSidebarButton(
i18nString(UIStrings.showDebugger), i18nString(UIStrings.hideDebugger));
this.editorView.setMainWidget(this._sourcesView);
this._threadsSidebarPane = null;
this._watchSidebarPane = (UI.ViewManager.ViewManager.instance().view('sources.watch') as UI.View.View);
this._callstackPane = CallStackSidebarPane.instance();
Common.Settings.Settings.instance()
.moduleSetting('sidebarPosition')
.addChangeListener(this._updateSidebarPosition.bind(this));
this._updateSidebarPosition();
this._updateDebuggerButtonsAndStatus();
this._pauseOnExceptionEnabledChanged();
Common.Settings.Settings.instance()
.moduleSetting('pauseOnExceptionEnabled')
.addChangeListener(this._pauseOnExceptionEnabledChanged, this);
this._liveLocationPool = new Bindings.LiveLocation.LiveLocationPool();
this._setTarget(UI.Context.Context.instance().flavor(SDK.SDKModel.Target));
Common.Settings.Settings.instance()
.moduleSetting('breakpointsActive')
.addChangeListener(this._breakpointsActiveStateChanged, this);
UI.Context.Context.instance().addFlavorChangeListener(SDK.SDKModel.Target, this._onCurrentTargetChanged, this);
UI.Context.Context.instance().addFlavorChangeListener(SDK.DebuggerModel.CallFrame, this._callFrameChanged, this);
SDK.SDKModel.TargetManager.instance().addModelListener(
SDK.DebuggerModel.DebuggerModel, SDK.DebuggerModel.Events.DebuggerWasEnabled, this._debuggerWasEnabled, this);
SDK.SDKModel.TargetManager.instance().addModelListener(
SDK.DebuggerModel.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
SDK.SDKModel.TargetManager.instance().addModelListener(
SDK.DebuggerModel.DebuggerModel, SDK.DebuggerModel.Events.DebuggerResumed,
event => this._debuggerResumed((event.data as SDK.DebuggerModel.DebuggerModel)));
SDK.SDKModel.TargetManager.instance().addModelListener(
SDK.DebuggerModel.DebuggerModel, SDK.DebuggerModel.Events.GlobalObjectCleared,
event => this._debuggerResumed((event.data as SDK.DebuggerModel.DebuggerModel)));
Extensions.ExtensionServer.ExtensionServer.instance().addEventListener(
Extensions.ExtensionServer.Events.SidebarPaneAdded, this._extensionSidebarPaneAdded, this);
SDK.SDKModel.TargetManager.instance().observeTargets(this);
this._lastModificationTime = window.performance.now();
}
static instance(opts: {
forceNew: boolean|null,
}|undefined = {forceNew: null}): SourcesPanel {
const {forceNew} = opts;
if (!sourcesPanelInstance || forceNew) {
sourcesPanelInstance = new SourcesPanel();
}
return sourcesPanelInstance;
}
static updateResizerAndSidebarButtons(panel: SourcesPanel): void {
panel._sourcesView.leftToolbar().removeToolbarItems();
panel._sourcesView.rightToolbar().removeToolbarItems();
panel._sourcesView.bottomToolbar().removeToolbarItems();
const isInWrapper = WrapperView.isShowing() && !UI.InspectorView.InspectorView.instance().isDrawerMinimized();
if (panel._splitWidget.isVertical() || isInWrapper) {
panel._splitWidget.uninstallResizer(panel._sourcesView.toolbarContainerElement());
} else {
panel._splitWidget.installResizer(panel._sourcesView.toolbarContainerElement());
}
if (!isInWrapper) {
panel._sourcesView.leftToolbar().appendToolbarItem(panel._toggleNavigatorSidebarButton);
if (panel._splitWidget.isVertical()) {
panel._sourcesView.rightToolbar().appendToolbarItem(panel._toggleDebuggerSidebarButton);
} else {
panel._sourcesView.bottomToolbar().appendToolbarItem(panel._toggleDebuggerSidebarButton);
}
}
}
targetAdded(_target: SDK.SDKModel.Target): void {
this._showThreadsIfNeeded();
}
targetRemoved(_target: SDK.SDKModel.Target): void {
}
_showThreadsIfNeeded(): void {
if (ThreadsSidebarPane.shouldBeShown() && !this._threadsSidebarPane) {
this._threadsSidebarPane = (UI.ViewManager.ViewManager.instance().view('sources.threads') as UI.View.View);
if (this._sidebarPaneStack && this._threadsSidebarPane) {
this._sidebarPaneStack.showView(
this._threadsSidebarPane, this._splitWidget.isVertical() ? this._watchSidebarPane : this._callstackPane);
}
}
}
_setTarget(target: SDK.SDKModel.Target|null): void {
if (!target) {
return;
}
const debuggerModel = target.model(SDK.DebuggerModel.DebuggerModel);
if (!debuggerModel) {
return;
}
if (debuggerModel.isPaused()) {
this._showDebuggerPausedDetails(
(debuggerModel.debuggerPausedDetails() as SDK.DebuggerModel.DebuggerPausedDetails));
} else {
this._paused = false;
this._clearInterface();
this._toggleDebuggerSidebarButton.setEnabled(true);
}
}
_onCurrentTargetChanged(event: Common.EventTarget.EventTargetEvent): void {
const target = (event.data as SDK.SDKModel.Target | null);
this._setTarget(target);
}
paused(): boolean {
return this._paused || false;
}
wasShown(): void {
UI.Context.Context.instance().setFlavor(SourcesPanel, this);
super.wasShown();
const wrapper = WrapperView.instance();
if (wrapper && wrapper.isShowing()) {
UI.InspectorView.InspectorView.instance().setDrawerMinimized(true);
SourcesPanel.updateResizerAndSidebarButtons(this);
}
this.editorView.setMainWidget(this._sourcesView);
}
willHide(): void {
super.willHide();
UI.Context.Context.instance().setFlavor(SourcesPanel, null);
if (WrapperView.isShowing()) {
WrapperView.instance()._showViewInWrapper();
UI.InspectorView.InspectorView.instance().setDrawerMinimized(false);
SourcesPanel.updateResizerAndSidebarButtons(this);
}
}
resolveLocation(locationName: string): UI.View.ViewLocation|null {
if (locationName === 'sources.sidebar-top' || locationName === 'sources.sidebar-bottom' ||
locationName === 'sources.sidebar-tabs') {
return this._sidebarPaneStack || null;
}
return this._navigatorTabbedLocation;
}
_ensureSourcesViewVisible(): boolean {
if (WrapperView.isShowing()) {
return true;
}
if (!UI.InspectorView.InspectorView.instance().canSelectPanel('sources')) {
return false;
}
UI.ViewManager.ViewManager.instance().showView('sources');
return true;
}
onResize(): void {
if (Common.Settings.Settings.instance().moduleSetting('sidebarPosition').get() === 'auto') {
this.element.window().requestAnimationFrame(this._updateSidebarPosition.bind(this));
} // Do not force layout.
}
searchableView(): UI.SearchableView.SearchableView {
return this._sourcesView.searchableView();
}
_debuggerPaused(event: Common.EventTarget.EventTargetEvent): void {
const debuggerModel = (event.data as SDK.DebuggerModel.DebuggerModel);
const details = debuggerModel.debuggerPausedDetails();
if (!this._paused) {
this._setAsCurrentPanel();
}
if (UI.Context.Context.instance().flavor(SDK.SDKModel.Target) === debuggerModel.target()) {
this._showDebuggerPausedDetails((details as SDK.DebuggerModel.DebuggerPausedDetails));
} else if (!this._paused) {
UI.Context.Context.instance().setFlavor(SDK.SDKModel.Target, debuggerModel.target());
}
}
_showDebuggerPausedDetails(details: SDK.DebuggerModel.DebuggerPausedDetails): void {
this._paused = true;
this._updateDebuggerButtonsAndStatus();
UI.Context.Context.instance().setFlavor(SDK.DebuggerModel.DebuggerPausedDetails, details);
this._toggleDebuggerSidebarButton.setEnabled(false);
this._revealDebuggerSidebar();
window.focus();
Host.InspectorFrontendHost.InspectorFrontendHostInstance.bringToFront();
}
_debuggerResumed(debuggerModel: SDK.DebuggerModel.DebuggerModel): void {
const target = debuggerModel.target();
if (UI.Context.Context.instance().flavor(SDK.SDKModel.Target) !== target) {
return;
}
this._paused = false;
this._clearInterface();
this._toggleDebuggerSidebarButton.setEnabled(true);
this._switchToPausedTargetTimeout = window.setTimeout(this._switchToPausedTarget.bind(this, debuggerModel), 500);
}
_debuggerWasEnabled(event: Common.EventTarget.EventTargetEvent): void {
const debuggerModel = (event.data as SDK.DebuggerModel.DebuggerModel);
if (UI.Context.Context.instance().flavor(SDK.SDKModel.Target) !== debuggerModel.target()) {
return;
}
this._updateDebuggerButtonsAndStatus();
}
get visibleView(): UI.Widget.Widget|null {
return this._sourcesView.visibleView();
}
showUISourceCode(
uiSourceCode: Workspace.UISourceCode.UISourceCode, lineNumber?: number, columnNumber?: number,
omitFocus?: boolean): void {
if (omitFocus) {
const wrapperShowing = WrapperView.isShowing();
if (!this.isShowing() && !wrapperShowing) {
return;
}
} else {
this._showEditor();
}
this._sourcesView.showSourceLocation(uiSourceCode, lineNumber, columnNumber, omitFocus);
}
_showEditor(): void {
if (WrapperView.isShowing()) {
return;
}
this._setAsCurrentPanel();
}
showUILocation(uiLocation: Workspace.UISourceCode.UILocation, omitFocus?: boolean): void {
this.showUISourceCode(uiLocation.uiSourceCode, uiLocation.lineNumber, uiLocation.columnNumber, omitFocus);
}
_revealInNavigator(uiSourceCode: Workspace.UISourceCode.UISourceCode, skipReveal?: boolean): void {
for (const navigator of registeredNavigatorViews) {
const navigatorView = navigator.navigatorView();
const viewId = navigator.viewId;
if (viewId && navigatorView.acceptProject(uiSourceCode.project())) {
navigatorView.revealUISourceCode(uiSourceCode, true);
if (skipReveal) {
this._navigatorTabbedLocation.tabbedPane().selectTab(viewId);
} else {
UI.ViewManager.ViewManager.instance().showView(viewId);
}
}
}
}
_populateNavigatorMenu(contextMenu: UI.ContextMenu.ContextMenu): void {
const groupByFolderSetting = Common.Settings.Settings.instance().moduleSetting('navigatorGroupByFolder');
contextMenu.appendItemsAtLocation('navigatorMenu');
contextMenu.viewSection().appendCheckboxItem(
i18nString(UIStrings.groupByFolder), () => groupByFolderSetting.set(!groupByFolderSetting.get()),
groupByFolderSetting.get());
}
setIgnoreExecutionLineEvents(ignoreExecutionLineEvents: boolean): void {
this._ignoreExecutionLineEvents = ignoreExecutionLineEvents;
}
updateLastModificationTime(): void {
this._lastModificationTime = window.performance.now();
}
async _executionLineChanged(liveLocation: Bindings.LiveLocation.LiveLocation): Promise<void> {
const uiLocation = await liveLocation.uiLocation();
if (!uiLocation) {
return;
}
if (window.performance.now() - this._lastModificationTime < lastModificationTimeout) {
return;
}
this._sourcesView.showSourceLocation(
uiLocation.uiSourceCode, uiLocation.lineNumber, uiLocation.columnNumber, undefined, true);
}
_lastModificationTimeoutPassedForTest(): void {
lastModificationTimeout = Number.MIN_VALUE;
}
_updateLastModificationTimeForTest(): void {
lastModificationTimeout = Number.MAX_VALUE;
}
async _callFrameChanged(): Promise<void> {
const callFrame = UI.Context.Context.instance().flavor(SDK.DebuggerModel.CallFrame);
if (!callFrame) {
return;
}
if (this._executionLineLocation) {
this._executionLineLocation.dispose();
}
this._executionLineLocation =
await Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().createCallFrameLiveLocation(
callFrame.location(), this._executionLineChanged.bind(this), this._liveLocationPool);
}
_pauseOnExceptionEnabledChanged(): void {
const enabled = Common.Settings.Settings.instance().moduleSetting('pauseOnExceptionEnabled').get();
const button = (this._pauseOnExceptionButton as UI.Toolbar.ToolbarToggle);
button.setToggled(enabled);
button.setTitle(enabled ? i18nString(UIStrings.pauseOnExceptions) : i18nString(UIStrings.dontPauseOnExceptions));
this._debugToolbarDrawer.classList.toggle('expanded', enabled);
}
async _updateDebuggerButtonsAndStatus(): Promise<void> {
const currentTarget = UI.Context.Context.instance().flavor(SDK.SDKModel.Target);
const currentDebuggerModel = currentTarget ? currentTarget.model(SDK.DebuggerModel.DebuggerModel) : null;
if (!currentDebuggerModel) {
this._togglePauseAction.setEnabled(false);
this._stepOverAction.setEnabled(false);
this._stepIntoAction.setEnabled(false);
this._stepOutAction.setEnabled(false);
this._stepAction.setEnabled(false);
} else if (this._paused) {
this._togglePauseAction.setToggled(true);
this._togglePauseAction.setEnabled(true);
this._stepOverAction.setEnabled(true);
this._stepIntoAction.setEnabled(true);
this._stepOutAction.setEnabled(true);
this._stepAction.setEnabled(true);
} else {
this._togglePauseAction.setToggled(false);
this._togglePauseAction.setEnabled(!currentDebuggerModel.isPausing());
this._stepOverAction.setEnabled(false);
this._stepIntoAction.setEnabled(false);
this._stepOutAction.setEnabled(false);
this._stepAction.setEnabled(false);
}
const details = currentDebuggerModel ? currentDebuggerModel.debuggerPausedDetails() : null;
await this._debuggerPausedMessage.render(
details, Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance(),
Bindings.BreakpointManager.BreakpointManager.instance());
if (details) {
this._updateDebuggerButtonsAndStatusForTest();
}
}
_updateDebuggerButtonsAndStatusForTest(): void {
}
_clearInterface(): void {
this._updateDebuggerButtonsAndStatus();
UI.Context.Context.instance().setFlavor(SDK.DebuggerModel.DebuggerPausedDetails, null);
if (this._switchToPausedTargetTimeout) {
clearTimeout(this._switchToPausedTargetTimeout);
}
this._liveLocationPool.disposeAll();
}
_switchToPausedTarget(debuggerModel: SDK.DebuggerModel.DebuggerModel): void {
delete this._switchToPausedTargetTimeout;
if (this._paused || debuggerModel.isPaused()) {
return;
}
for (const debuggerModel of SDK.SDKModel.TargetManager.instance().models(SDK.DebuggerModel.DebuggerModel)) {
if (debuggerModel.isPaused()) {
UI.Context.Context.instance().setFlavor(SDK.SDKModel.Target, debuggerModel.target());
break;
}
}
}
_togglePauseOnExceptions(): void {
Common.Settings.Settings.instance()
.moduleSetting('pauseOnExceptionEnabled')
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
// @ts-expect-error
.set(!(this._pauseOnExceptionButton).toggled());
}
_runSnippet(): void {
const uiSourceCode = this._sourcesView.currentUISourceCode();
if (uiSourceCode) {
Snippets.ScriptSnippetFileSystem.evaluateScriptSnippet(uiSourceCode);
}
}
_toggleRecording(): void {
const uiSourceCode = this._sourcesView.currentUISourceCode();
if (!uiSourceCode) {
return;
}
const target = UI.Context.Context.instance().flavor(SDK.SDKModel.Target);
if (!target) {
return;
}
const recorderModel = target.model(Recorder.RecorderModel.RecorderModel);
if (!recorderModel) {
return;
}
recorderModel.toggleRecording(uiSourceCode);
}
_editorSelected(event: Common.EventTarget.EventTargetEvent): void {
const uiSourceCode = (event.data as Workspace.UISourceCode.UISourceCode);
if (this.editorView.mainWidget() &&
Common.Settings.Settings.instance().moduleSetting('autoRevealInNavigator').get()) {
this._revealInNavigator(uiSourceCode, true);
}
}
_togglePause(): boolean {
const target = UI.Context.Context.instance().flavor(SDK.SDKModel.Target);
if (!target) {
return true;
}
const debuggerModel = target.model(SDK.DebuggerModel.DebuggerModel);
if (!debuggerModel) {
return true;
}
if (this._paused) {
this._paused = false;
debuggerModel.resume();
} else {
// Make sure pauses didn't stick skipped.
debuggerModel.pause();
}
this._clearInterface();
return true;
}
_prepareToResume(): SDK.DebuggerModel.DebuggerModel|null {
if (!this._paused) {
return null;
}
this._paused = false;
this._clearInterface();
const target = UI.Context.Context.instance().flavor(SDK.SDKModel.Target);
return target ? target.model(SDK.DebuggerModel.DebuggerModel) : null;
}
_longResume(_event: Common.EventTarget.EventTargetEvent): void {
const debuggerModel = this._prepareToResume();
if (debuggerModel) {
debuggerModel.skipAllPausesUntilReloadOrTimeout(500);
debuggerModel.resume();
}
}
_terminateExecution(_event: Common.EventTarget.EventTargetEvent): void {
const debuggerModel = this._prepareToResume();
if (debuggerModel) {
debuggerModel.runtimeModel().terminateExecution();
debuggerModel.resume();
}
}
_stepOver(): boolean {
const debuggerModel = this._prepareToResume();
if (debuggerModel) {
debuggerModel.stepOver();
}
return true;
}
_stepInto(): boolean {
const debuggerModel = this._prepareToResume();
if (debuggerModel) {
debuggerModel.stepInto();
}
return true;
}
_stepIntoAsync(): boolean {
const debuggerModel = this._prepareToResume();
if (debuggerModel) {
debuggerModel.scheduleStepIntoAsync();
}
return true;
}
_stepOut(): boolean {
const debuggerModel = this._prepareToResume();
if (debuggerModel) {
debuggerModel.stepOut();
}
return true;
}
async _continueToLocation(uiLocation: Workspace.UISourceCode.UILocation): Promise<void> {
const executionContext = UI.Context.Context.instance().flavor(SDK.RuntimeModel.ExecutionContext);
if (!executionContext) {
return;
}
// Always use 0 column.
const rawLocations =
await Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().uiLocationToRawLocations(
uiLocation.uiSourceCode, uiLocation.lineNumber, 0);
const rawLocation = rawLocations.find(location => location.debuggerModel === executionContext.debuggerModel);
if (rawLocation && this._prepareToResume()) {
rawLocation.continueToLocation();
}
}
_toggleBreakpointsActive(): void {
Common.Settings.Settings.instance()
.moduleSetting('breakpointsActive')
.set(!Common.Settings.Settings.instance().moduleSetting('breakpointsActive').get());
}
_breakpointsActiveStateChanged(): void {
const active = Common.Settings.Settings.instance().moduleSetting('breakpointsActive').get();
this._toggleBreakpointsActiveAction.setToggled(!active);
this._sourcesView.toggleBreakpointsActiveState(active);
}
_createDebugToolbar(): UI.Toolbar.Toolbar {
const debugToolbar = new UI.Toolbar.Toolbar('scripts-debug-toolbar');
const longResumeButton =
new UI.Toolbar.ToolbarButton(i18nString(UIStrings.resumeWithAllPausesBlockedForMs), 'largeicon-play');
longResumeButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, this._longResume, this);
const terminateExecutionButton = new UI.Toolbar.ToolbarButton(
i18nString(UIStrings.terminateCurrentJavascriptCall), 'largeicon-terminate-execution');
terminateExecutionButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, this._terminateExecution, this);
debugToolbar.appendToolbarItem(UI.Toolbar.Toolbar.createLongPressActionButton(
this._togglePauseAction, [terminateExecutionButton, longResumeButton], []));
debugToolbar.appendToolbarItem(UI.Toolbar.Toolbar.createActionButton(this._stepOverAction));
debugToolbar.appendToolbarItem(UI.Toolbar.Toolbar.createActionButton(this._stepIntoAction));
debugToolbar.appendToolbarItem(UI.Toolbar.Toolbar.createActionButton(this._stepOutAction));
debugToolbar.appendToolbarItem(UI.Toolbar.Toolbar.createActionButton(this._stepAction));
debugToolbar.appendSeparator();
debugToolbar.appendToolbarItem(UI.Toolbar.Toolbar.createActionButton(this._toggleBreakpointsActiveAction));
this._pauseOnExceptionButton = new UI.Toolbar.ToolbarToggle('', 'largeicon-pause-on-exceptions');
this._pauseOnExceptionButton.addEventListener(
UI.Toolbar.ToolbarButton.Events.Click, this._togglePauseOnExceptions, this);
debugToolbar.appendToolbarItem(this._pauseOnExceptionButton);
return debugToolbar;
}
_createDebugToolbarDrawer(): HTMLDivElement {
const debugToolbarDrawer = document.createElement('div');
debugToolbarDrawer.classList.add('scripts-debug-toolbar-drawer');
const label = i18nString(UIStrings.pauseOnCaughtExceptions);
const setting = Common.Settings.Settings.instance().moduleSetting('pauseOnCaughtException');
debugToolbarDrawer.appendChild(UI.SettingsUI.createSettingCheckbox(label, setting, true));
return debugToolbarDrawer;
}
appendApplicableItems(event: Event, contextMenu: UI.ContextMenu.ContextMenu, target: Object): void {
this._appendUISourceCodeItems(event, contextMenu, target);
this._appendUISourceCodeFrameItems(event, contextMenu, target);
this.appendUILocationItems(contextMenu, target);
this._appendRemoteObjectItems(contextMenu, target);
this._appendNetworkRequestItems(contextMenu, target);
}
_appendUISourceCodeItems(event: Event, contextMenu: UI.ContextMenu.ContextMenu, target: Object): void {
if (!(target instanceof Workspace.UISourceCode.UISourceCode) || !event.target) {
return;
}
const uiSourceCode = (target as Workspace.UISourceCode.UISourceCode);
const eventTarget = (event.target as Node);
if (!uiSourceCode.project().isServiceProject() &&
!eventTarget.isSelfOrDescendant(this._navigatorTabbedLocation.widget().element)) {
contextMenu.revealSection().appendItem(
i18nString(UIStrings.revealInSidebar), this._handleContextMenuReveal.bind(this, uiSourceCode));
}
}
_appendUISourceCodeFrameItems(event: Event, contextMenu: UI.ContextMenu.ContextMenu, target: Object): void {
if (!(target instanceof UISourceCodeFrame)) {
return;
}
if (target.uiSourceCode().contentType().isFromSourceMap() || target.textEditor.selection().isEmpty()) {
return;
}
contextMenu.debugSection().appendAction('debugger.evaluate-selection');
}
appendUILocationItems(contextMenu: UI.ContextMenu.ContextMenu, object: Object): void {
if (!(object instanceof Workspace.UISourceCode.UILocation)) {
return;
}
const uiLocation = (object as Workspace.UISourceCode.UILocation);
const uiSourceCode = uiLocation.uiSourceCode;
if (!Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance()
.scriptsForUISourceCode(uiSourceCode)
.every(script => script.isJavaScript())) {
// Ignore List and 'Continue to here' currently only works for JavaScript debugging.
return;
}
const contentType = uiSourceCode.contentType();
if (contentType.hasScripts()) {
const target = UI.Context.Context.instance().flavor(SDK.SDKModel.Target);
const debuggerModel = target ? target.model(SDK.DebuggerModel.DebuggerModel) : null;
if (debuggerModel && debuggerModel.isPaused()) {
contextMenu.debugSection().appendItem(
i18nString(UIStrings.continueToHere), this._continueToLocation.bind(this, uiLocation));
}
this._callstackPane.appendIgnoreListURLContextMenuItems(contextMenu, uiSourceCode);
}
}
_handleContextMenuReveal(uiSourceCode: Workspace.UISourceCode.UISourceCode): void {
this.editorView.showBoth();
this._revealInNavigator(uiSourceCode);
}
_appendRemoteObjectItems(contextMenu: UI.ContextMenu.ContextMenu, target: Object): void {
if (!(target instanceof SDK.RemoteObject.RemoteObject)) {
return;
}
const indent = Common.Settings.Settings.instance().moduleSetting('textEditorIndent').get();
const remoteObject = (target as SDK.RemoteObject.RemoteObject);
const executionContext = UI.Context.Context.instance().flavor(SDK.RuntimeModel.ExecutionContext);
function getObjectTitle(): string|undefined {
if (remoteObject.type === 'wasm') {
return remoteObject.subtype;
}
if (remoteObject.subtype === 'node') {
return 'outerHTML';
}
return remoteObject.type;
}
const copyContextMenuTitle = getObjectTitle();
contextMenu.debugSection().appendItem(
i18nString(UIStrings.storeSAsGlobalVariable, {PH1: copyContextMenuTitle}),
() => SDK.ConsoleModel.ConsoleModel.instance().saveToTempVariable(executionContext, remoteObject));
// Copy object context menu.
if (remoteObject.type !== 'function') {
const copyDecodedValueHandler = async(): Promise<void> => {
const result = await remoteObject.callFunctionJSON(toStringForClipboard, [{
value: {
subtype: remoteObject.subtype,
indent: indent,
},
}]);
Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(result);
};
contextMenu.clipboardSection().appendItem(
i18nString(UIStrings.copyS, {PH1: copyContextMenuTitle}), copyDecodedValueHandler);
}
if (remoteObject.type === 'function') {
contextMenu.debugSection().appendItem(
i18nString(UIStrings.showFunctionDefinition), this._showFunctionDefinition.bind(this, remoteObject));
}
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function toStringForClipboard(this: Object, data: any): string|undefined {
const subtype = data.subtype;
const indent = data.indent;
if (subtype === 'node') {
return this instanceof Element ? this.outerHTML : undefined;
}
if (subtype && typeof this === 'undefined') {
return String(subtype);
}
try {
return JSON.stringify(this, null, indent);
} catch (error) {
return String(this);
}
}
}
_appendNetworkRequestItems(contextMenu: UI.ContextMenu.ContextMenu, target: Object): void {
if (!(target instanceof SDK.NetworkRequest.NetworkRequest)) {
return;
}
const request = (target as SDK.NetworkRequest.NetworkRequest);
const uiSourceCode = this._workspace.uiSourceCodeForURL(request.url());
if (!uiSourceCode) {
return;
}
const openText = i18nString(UIStrings.openInSourcesPanel);
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const callback: () => any = this.showUILocation.bind(this, uiSourceCode.uiLocation(0, 0));
contextMenu.revealSection().appendItem(openText, callback);
}
_showFunctionDefinition(remoteObject: SDK.RemoteObject.RemoteObject): void {
remoteObject.debuggerModel().functionDetailsPromise(remoteObject).then(this._didGetFunctionDetails.bind(this));
}
async _didGetFunctionDetails(response: {
location: SDK.DebuggerModel.Location|null,
}|null): Promise<void> {
if (!response || !response.location) {
return;
}
const uiLocation =
await Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().rawLocationToUILocation(
response.location);
if (uiLocation) {
this.showUILocation(uiLocation);
}
}
_revealNavigatorSidebar(): void {
this._setAsCurrentPanel();
this.editorView.showBoth(true);
}
_revealDebuggerSidebar(): void {
this._setAsCurrentPanel();
this._splitWidget.showBoth(true);
}
_updateSidebarPosition(): void {
let vertically;
const position = Common.Settings.Settings.instance().moduleSetting('sidebarPosition').get();
if (position === 'right') {
vertically = false;
} else if (position === 'bottom') {
vertically = true;
} else {
vertically = UI.InspectorView.InspectorView.instance().element.offsetWidth < 680;
}
if (this.sidebarPaneView && vertically === !this._splitWidget.isVertical()) {
return;
}
if (this.sidebarPaneView && this.sidebarPaneView.shouldHideOnDetach()) {
return;
} // We can't reparent extension iframes.
if (this.sidebarPaneView) {
this.sidebarPaneView.detach();
}
this._splitWidget.setVertical(!vertically);
this._splitWidget.element.classList.toggle('sources-split-view-vertical', vertically);
SourcesPanel.updateResizerAndSidebarButtons(this);
// Create vertical box with stack.
const vbox = new UI.Widget.VBox();
vbox.element.appendChild(this._debugToolbar.element);
vbox.element.appendChild(this._debugToolbarDrawer);
vbox.setMinimumAndPreferredSizes(minToolbarWidth, 25, minToolbarWidth, 100);
this._sidebarPaneStack =
UI.ViewManager.ViewManager.instance().createStackLocation(this._revealDebuggerSidebar.bind(this));
this._sidebarPaneStack.widget().element.classList.add('overflow-auto');
this._sidebarPaneStack.widget().show(vbox.element);
this._sidebarPaneStack.widget().element.appendChild(this._debuggerPausedMessage.element());
this._sidebarPaneStack.appendApplicableItems('sources.sidebar-top');
if (this._threadsSidebarPane) {
this._sidebarPaneStack.showView(this._threadsSidebarPane);
}
const jsBreakpoints = (UI.ViewManager.ViewManager.instance().view('sources.jsBreakpoints') as UI.View.View);
const scopeChainView = (UI.ViewManager.ViewManager.instance().view('sources.scopeChain') as UI.View.View);
if (this._tabbedLocationHeader) {
this._splitWidget.uninstallResizer(this._tabbedLocationHeader);
this._tabbedLocationHeader = null;
}
if (!vertically) {
// Populate the rest of the stack.
this._sidebarPaneStack.appendView(this._watchSidebarPane);
this._sidebarPaneStack.showView(jsBreakpoints);
this._sidebarPaneStack.showView(scopeChainView);
this._sidebarPaneStack.showView(this._callstackPane);
this._extensionSidebarPanesContainer = this._sidebarPaneStack;
this.sidebarPaneView = vbox;
this._splitWidget.uninstallResizer(this._debugToolbar.gripElementForResize());
} else {
const splitWidget = new UI.SplitWidget.SplitWidget(true, true, 'sourcesPanelDebuggerSidebarSplitViewState', 0.5);
splitWidget.setMainWidget(vbox);
// Populate the left stack.
this._sidebarPaneStack.showView(jsBreakpoints);
this._sidebarPaneStack.showView(this._callstackPane);
const tabbedLocation =
UI.ViewManager.ViewManager.instance().createTabbedLocation(this._revealDebuggerSidebar.bind(this));
splitWidget.setSidebarWidget(tabbedLocation.tabbedPane());
this._tabbedLocationHeader = tabbedLocation.tabbedPane().headerElement();
this._splitWidget.installResizer(this._tabbedLocationHeader);
this._splitWidget.installResizer(this._debugToolbar.gripElementForResize());
tabbedLocation.appendView(scopeChainView);
tabbedLocation.appendView(this._watchSidebarPane);
tabbedLocation.appendApplicableItems('sources.sidebar-tabs');
this._extensionSidebarPanesContainer = tabbedLocation;
this.sidebarPaneView = splitWidget;
}
this._sidebarPaneStack.appendApplicableItems('sources.sidebar-bottom');
const extensionSidebarPanes = Extensions.ExtensionServer.ExtensionServer.instance().sidebarPanes();
for (let i = 0; i < extensionSidebarPanes.length; ++i) {
this._addExtensionSidebarPane(extensionSidebarPanes[i]);
}
this._splitWidget.setSidebarWidget(this.sidebarPaneView);
}
_setAsCurrentPanel(): Promise<void> {
return UI.ViewManager.ViewManager.instance().showView('sources');
}
_extensionSidebarPaneAdded(event: Common.EventTarget.EventTargetEvent): void {
const pane = (event.data as Extensions.ExtensionPanel.ExtensionSidebarPane);
this._addExtensionSidebarPane(pane);
}
_addExtensionSidebarPane(pane: Extensions.ExtensionPanel.ExtensionSidebarPane): void {
if (pane.panelName() === this.name) {
(this._extensionSidebarPanesContainer as UI.View.ViewLocation).appendView(pane);
}
}
sourcesView(): SourcesView {
return this._sourcesView;
}
_handleDrop(dataTransfer: DataTransfer): void {
const items = dataTransfer.items;
if (!items.length) {
return;
}
const entry = items[0].webkitGetAsEntry();
if (!entry.isDirectory) {
return;
}
Host.InspectorFrontendHost.InspectorFrontendHostInstance.upgradeDraggedFileSystemPermissions(entry.filesystem);
}
}
export let lastModificationTimeout = 200;
export const minToolbarWidth = 215;
let uILocationRevealerInstance: UILocationRevealer;
export class UILocationRevealer implements Common.Revealer.Revealer {
static instance(opts: {
forceNew: boolean|null,
} = {forceNew: null}): UILocationRevealer {
const {forceNew} = opts;
if (!uILocationRevealerInstance || forceNew) {
uILocationRevealerInstance = new UILocationRevealer();
}
return uILocationRevealerInstance;
}
reveal(uiLocation: Object, omitFocus?: boolean): Promise<void> {
if (!(uiLocation instanceof Workspace.UISourceCode.UILocation)) {
return Promise.reject(new Error('Internal error: not a ui location'));
}
SourcesPanel.instance().showUILocation(uiLocation, omitFocus);
return Promise.resolve();
}
}
let debuggerLocationRevealerInstance: DebuggerLocationRevealer;
export class DebuggerLocationRevealer implements Common.Revealer.Revealer {
static instance(opts: {
forceNew: boolean|null,
} = {forceNew: null}): DebuggerLocationRevealer {
const {forceNew} = opts;
if (!debuggerLocationRevealerInstance || forceNew) {
debuggerLocationRevealerInstance = new DebuggerLocationRevealer();
}
return debuggerLocationRevealerInstance;
}
async reveal(rawLocation: Object, omitFocus?: boolean): Promise<void> {
if (!(rawLocation instanceof SDK.DebuggerModel.Location)) {
throw new Error('Internal error: not a debugger location');
}
const uiLocation =
await Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().rawLocationToUILocation(
rawLocation);
if (uiLocation) {
SourcesPanel.instance().showUILocation(uiLocation, omitFocus);
}
}
}
let uISourceCodeRevealerInstance: UISourceCodeRevealer;
export class UISourceCodeRevealer implements Common.Revealer.Revealer {
static instance(opts: {
forceNew: boolean|null,
} = {forceNew: null}): UISourceCodeRevealer {
const {forceNew} = opts;
if (!uISourceCodeRevealerInstance || forceNew) {
uISourceCodeRevealerInstance = new UISourceCodeRevealer();
}
return uISourceCodeRevealerInstance;
}
reveal(uiSourceCode: Object, omitFocus?: boolean): Promise<void> {
if (!(uiSourceCode instanceof Workspace.UISourceCode.UISourceCode)) {
return Promise.reject(new Error('Internal error: not a ui source code'));
}
SourcesPanel.instance().showUISourceCode(uiSourceCode, undefined, undefined, omitFocus);
return Promise.resolve();
}
}
let debuggerPausedDetailsRevealerInstance: DebuggerPausedDetailsRevealer;
export class DebuggerPausedDetailsRevealer implements Common.Revealer.Revealer {
static instance(opts: {
forceNew: boolean|null,
} = {forceNew: null}): DebuggerPausedDetailsRevealer {
const {forceNew} = opts;
if (!debuggerPausedDetailsRevealerInstance || forceNew) {
debuggerPausedDetailsRevealerInstance = new DebuggerPausedDetailsRevealer();
}
return debuggerPausedDetailsRevealerInstance;
}
reveal(_object: Object): Promise<void> {
return SourcesPanel.instance()._setAsCurrentPanel();
}
}
let revealingActionDelegateInstance: RevealingActionDelegate;
export class RevealingActionDelegate implements UI.ActionRegistration.ActionDelegate {
static instance(opts: {
forceNew: boolean|null,
} = {forceNew: null}): RevealingActionDelegate {
const {forceNew} = opts;
if (!revealingActionDelegateInstance || forceNew) {
revealingActionDelegateInstance = new RevealingActionDelegate();
}
return revealingActionDelegateInstance;
}
handleAction(context: UI.Context.Context, actionId: string): boolean {
const panel = SourcesPanel.instance();
if (!panel._ensureSourcesViewVisible()) {
return false;
}
switch (actionId) {
case 'debugger.toggle-pause':
panel._togglePause();
return true;
}
return false;
}
}
let debuggingActionDelegateInstance: DebuggingActionDelegate;
export class DebuggingActionDelegate implements UI.ActionRegistration.ActionDelegate {
static instance(opts: {
forceNew: boolean|null,
} = {forceNew: null}): DebuggingActionDelegate {
const {forceNew} = opts;
if (!debuggingActionDelegateInstance || forceNew) {
debuggingActionDelegateInstance = new DebuggingActionDelegate();
}
return debuggingActionDelegateInstance;
}
handleAction(context: UI.Context.Context, actionId: string): boolean {
const panel = SourcesPanel.instance();
switch (actionId) {
case 'debugger.step-over': {
panel._stepOver();
return true;
}
case 'debugger.step-into': {
panel._stepIntoAsync();
return true;
}
case 'debugger.step': {
panel._stepInto();
return true;
}
case 'debugger.step-out': {
panel._stepOut();
return true;
}
case 'debugger.run-snippet': {
panel._runSnippet();
return true;
}
case 'recorder.toggle-recording': {
panel._toggleRecording();
return true;
}
case 'debugger.toggle-breakpoints-active': {
panel._toggleBreakpointsActive();
return true;
}
case 'debugger.evaluate-selection': {
const frame = UI.Context.Context.instance().flavor(UISourceCodeFrame);
if (frame) {
let text = frame.textEditor.text(frame.textEditor.selection());
const executionContext = UI.Context.Context.instance().flavor(SDK.RuntimeModel.ExecutionContext);
if (executionContext) {
const message = SDK.ConsoleModel.ConsoleModel.instance().addCommandMessage(executionContext, text);
text = ObjectUI.JavaScriptREPL.JavaScriptREPL.wrapObjectLiteral(text);
SDK.ConsoleModel.ConsoleModel.instance().evaluateCommandInConsole(
executionContext, message, text, /* useCommandLineAPI */ true);
}
}
return true;
}
}
return false;
}
}
export class WrapperView extends UI.Widget.VBox {
_view: SourcesView;
constructor() {
super();
this.element.classList.add('sources-view-wrapper');
this._view = SourcesPanel.instance()._sourcesView;
}
static instance(): WrapperView {
if (!wrapperViewInstance) {
wrapperViewInstance = new WrapperView();
}
return wrapperViewInstance;
}
static isShowing(): boolean {
return Boolean(wrapperViewInstance) && wrapperViewInstance.isShowing();
}
wasShown(): void {
if (!SourcesPanel.instance().isShowing()) {
this._showViewInWrapper();
} else {
UI.InspectorView.InspectorView.instance().setDrawerMinimized(true);
}
SourcesPanel.updateResizerAndSidebarButtons(SourcesPanel.instance());
}
willHide(): void {
UI.InspectorView.InspectorView.instance().setDrawerMinimized(false);
queueMicrotask(() => {
SourcesPanel.updateResizerAndSidebarButtons(SourcesPanel.instance());
});
}
_showViewInWrapper(): void {
this._view.show(this.element);
}
}
const registeredNavigatorViews: NavigatorViewRegistration[] = [
{
viewId: 'navigator-network',
navigatorView: NetworkNavigatorView.instance,
experiment: undefined,
},
{
viewId: 'navigator-files',
navigatorView: FilesNavigatorView.instance,
experiment: undefined,
},
{
viewId: 'navigator-snippets',
navigatorView: SnippetsNavigatorView.instance,
experiment: undefined,
},
{
viewId: 'navigator-recordings',
navigatorView: RecordingsNavigatorView.instance,
experiment: Root.Runtime.ExperimentName.RECORDER,
},
{
viewId: 'navigator-overrides',
navigatorView: OverridesNavigatorView.instance,
experiment: undefined,
},
{
viewId: 'navigator-contentScripts',
navigatorView: ContentScriptsNavigatorView.instance,
experiment: undefined,
},
];
export interface NavigatorViewRegistration {
navigatorView: () => NavigatorView;
viewId: string;
experiment?: string;
}