blob: 1244460d37967acd5c71db269d146e06a4e3c1d3 [file] [log] [blame]
Jan Scheffler35199b92021-03-17 09:51:151// Copyright 2021 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Blink Reformat4c46d092018-04-07 15:32:375/*
6 * Copyright (C) IBM Corp. 2009 All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following disclaimer
16 * in the documentation and/or other materials provided with the
17 * distribution.
18 * * Neither the name of IBM Corp. nor the names of its
19 * contributors may be used to endorse or promote products derived from
20 * this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
Tim van der Lippe8987f8f2020-01-03 15:03:1634
Tim van der Lippe021c7572021-04-19 10:49:4335import * as Common from '../../core/common/common.js';
36import * as Host from '../../core/host/host.js';
37import * as i18n from '../../core/i18n/i18n.js';
38import * as Platform from '../../core/platform/platform.js';
39import * as SDK from '../../core/sdk/sdk.js';
40import * as ObjectUI from '../../ui/legacy/components/object_ui/object_ui.js';
Kriti Sapraae8f17e2021-08-18 10:28:0241// eslint-disable-next-line rulesdir/es_modules_import
42import objectValueStyles from '../../ui/legacy/components/object_ui/objectValue.css.js';
Tim van der Lippe339ad262021-04-21 12:23:3643import * as Components from '../../ui/legacy/components/utils/utils.js';
Tim van der Lippe021c7572021-04-19 10:49:4344import * as UI from '../../ui/legacy/legacy.js';
Kriti Sapraae8f17e2021-08-18 10:28:0245
46import watchExpressionsSidebarPaneStyles from './watchExpressionsSidebarPane.css.js';
47
Tim van der Lippe229a54f2021-05-14 16:59:0548import type * as Protocol from '../../generated/protocol.js';
Tim van der Lippefbbf9812020-02-13 14:43:4649
Paul Lewis39944952020-01-22 15:45:1850import {UISourceCodeFrame} from './UISourceCodeFrame.js';
51
Simon Zünd697fb0b2021-03-01 10:12:4252const UIStrings = {
Vidal Guillermo Diazleal Ortega83edb472021-02-16 18:39:3253 /**
54 *@description A context menu item in the Watch Expressions Sidebar Pane of the Sources panel
55 */
56 addWatchExpression: 'Add watch expression',
57 /**
58 *@description Tooltip/screen reader label of a button in the Sources panel that refreshes all watch expressions.
59 */
60 refreshWatchExpressions: 'Refresh watch expressions',
61 /**
62 *@description Empty element text content in Watch Expressions Sidebar Pane of the Sources panel
63 */
64 noWatchExpressions: 'No watch expressions',
65 /**
66 *@description A context menu item in the Watch Expressions Sidebar Pane of the Sources panel
67 */
68 deleteAllWatchExpressions: 'Delete all watch expressions',
69 /**
70 *@description A context menu item in the Watch Expressions Sidebar Pane of the Sources panel
71 */
72 addPropertyPathToWatch: 'Add property path to watch',
73 /**
74 *@description A context menu item in the Watch Expressions Sidebar Pane of the Sources panel
75 */
76 deleteWatchExpression: 'Delete watch expression',
77 /**
78 *@description Value element text content in Watch Expressions Sidebar Pane of the Sources panel
79 */
80 notAvailable: '<not available>',
81 /**
82 *@description A context menu item in the Watch Expressions Sidebar Pane of the Sources panel and Network pane request.
83 */
84 copyValue: 'Copy value',
85};
Tim van der Lippe021c7572021-04-19 10:49:4386const str_ = i18n.i18n.registerUIStrings('panels/sources/WatchExpressionsSidebarPane.ts', UIStrings);
Vidal Guillermo Diazleal Ortega83edb472021-02-16 18:39:3287const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
Jan Scheffler35199b92021-03-17 09:51:1588let watchExpressionsSidebarPaneInstance: WatchExpressionsSidebarPane;
Andres Olivaresfd431fb2020-12-10 15:30:0489
Jan Scheffler35199b92021-03-17 09:51:1590export class WatchExpressionsSidebarPane extends UI.ThrottledWidget.ThrottledWidget implements
91 UI.ActionRegistration.ActionDelegate, UI.Toolbar.ItemsProvider, UI.ContextMenu.Provider {
Jan Schefflera222c632021-08-13 12:46:1592 private watchExpressions: WatchExpression[];
93 private emptyElement!: HTMLElement;
94 private readonly watchExpressionsSetting: Common.Settings.Setting<string[]>;
95 private readonly addButton: UI.Toolbar.ToolbarButton;
96 private readonly refreshButton: UI.Toolbar.ToolbarButton;
97 private readonly treeOutline: ObjectUI.ObjectPropertiesSection.ObjectPropertiesSectionsTreeOutline;
98 private readonly expandController: ObjectUI.ObjectPropertiesSection.ObjectPropertiesSectionsTreeExpandController;
99 private readonly linkifier: Components.Linkifier.Linkifier;
Jan Scheffler35199b92021-03-17 09:51:15100 private constructor() {
Blink Reformat4c46d092018-04-07 15:32:37101 super(true);
Blink Reformat4c46d092018-04-07 15:32:37102
Simon Zünd0243c602020-03-10 06:51:42103 // TODO(szuend): Replace with a Set once the web test
Tim van der Lippe021c7572021-04-19 10:49:43104 // panels/sources/debugger-ui/watch-expressions-preserve-expansion.js is either converted
Jan Scheffler35199b92021-03-17 09:51:15105 // to an e2e test or no longer accesses this variable directly.
Jan Schefflera222c632021-08-13 12:46:15106 this.watchExpressions = [];
107 this.watchExpressionsSetting =
Sigurd Schneider8641b422021-07-16 06:13:35108 Common.Settings.Settings.instance().createLocalSetting<string[]>('watchExpressions', []);
Blink Reformat4c46d092018-04-07 15:32:37109
Jan Schefflera222c632021-08-13 12:46:15110 this.addButton = new UI.Toolbar.ToolbarButton(i18nString(UIStrings.addWatchExpression), 'largeicon-add');
111 this.addButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, _event => {
112 this.addButtonClicked();
Tim van der Lippe37a35ff2020-03-03 13:49:02113 });
Jan Schefflera222c632021-08-13 12:46:15114 this.refreshButton =
Vidal Guillermo Diazleal Ortega83edb472021-02-16 18:39:32115 new UI.Toolbar.ToolbarButton(i18nString(UIStrings.refreshWatchExpressions), 'largeicon-refresh');
Jan Schefflera222c632021-08-13 12:46:15116 this.refreshButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, this.update, this);
Blink Reformat4c46d092018-04-07 15:32:37117
118 this.contentElement.classList.add('watch-expressions');
Jan Schefflera222c632021-08-13 12:46:15119 this.contentElement.addEventListener('contextmenu', this.contextMenu.bind(this), false);
120 this.treeOutline = new ObjectUI.ObjectPropertiesSection.ObjectPropertiesSectionsTreeOutline();
Kriti Sapraae8f17e2021-08-18 10:28:02121
Jan Schefflera222c632021-08-13 12:46:15122 this.treeOutline.setShowSelectionOnKeyboardFocus(/* show */ true);
123 this.expandController =
124 new ObjectUI.ObjectPropertiesSection.ObjectPropertiesSectionsTreeExpandController(this.treeOutline);
Blink Reformat4c46d092018-04-07 15:32:37125
Tim van der Lipped1a00aa2020-08-19 16:03:56126 UI.Context.Context.instance().addFlavorChangeListener(SDK.RuntimeModel.ExecutionContext, this.update, this);
127 UI.Context.Context.instance().addFlavorChangeListener(SDK.DebuggerModel.CallFrame, this.update, this);
Jan Schefflera222c632021-08-13 12:46:15128 this.linkifier = new Components.Linkifier.Linkifier();
Blink Reformat4c46d092018-04-07 15:32:37129 this.update();
130 }
131
Jan Scheffler35199b92021-03-17 09:51:15132 static instance(): WatchExpressionsSidebarPane {
Andres Olivaresfd431fb2020-12-10 15:30:04133 if (!watchExpressionsSidebarPaneInstance) {
134 watchExpressionsSidebarPaneInstance = new WatchExpressionsSidebarPane();
135 }
136 return watchExpressionsSidebarPaneInstance;
137 }
138
Jan Scheffler35199b92021-03-17 09:51:15139 toolbarItems(): UI.Toolbar.ToolbarItem[] {
Jan Schefflera222c632021-08-13 12:46:15140 return [this.addButton, this.refreshButton];
Blink Reformat4c46d092018-04-07 15:32:37141 }
142
Jan Scheffler35199b92021-03-17 09:51:15143 focus(): void {
Jack Lynch5db2a3e2019-11-05 19:12:31144 if (this.hasFocus()) {
145 return;
146 }
Jan Schefflera222c632021-08-13 12:46:15147 if (this.watchExpressions.length > 0) {
148 this.treeOutline.forceSelect();
Jack Lynch5db2a3e2019-11-05 19:12:31149 }
150 }
151
Jan Scheffler35199b92021-03-17 09:51:15152 hasExpressions(): boolean {
Jan Schefflera222c632021-08-13 12:46:15153 return Boolean(this.watchExpressionsSetting.get().length);
Blink Reformat4c46d092018-04-07 15:32:37154 }
155
Jan Schefflera222c632021-08-13 12:46:15156 private saveExpressions(): void {
Blink Reformat4c46d092018-04-07 15:32:37157 const toSave = [];
Jan Schefflera222c632021-08-13 12:46:15158 for (let i = 0; i < this.watchExpressions.length; i++) {
159 const expression = this.watchExpressions[i].expression();
Sigurd Schneider8641b422021-07-16 06:13:35160 if (expression) {
161 toSave.push(expression);
Tim van der Lippe1d6e57a2019-09-30 11:55:34162 }
Blink Reformat4c46d092018-04-07 15:32:37163 }
164
Jan Schefflera222c632021-08-13 12:46:15165 this.watchExpressionsSetting.set(toSave);
Blink Reformat4c46d092018-04-07 15:32:37166 }
167
Jan Schefflera222c632021-08-13 12:46:15168 private async addButtonClicked(): Promise<void> {
Paul Lewis75c7d0d2020-03-19 12:17:26169 await UI.ViewManager.ViewManager.instance().showView('sources.watch');
Jan Schefflera222c632021-08-13 12:46:15170 this.emptyElement.classList.add('hidden');
171 this.createWatchExpression(null).startEditing();
Blink Reformat4c46d092018-04-07 15:32:37172 }
173
Sigurd Schneider8641b422021-07-16 06:13:35174 doUpdate(): Promise<void> {
Jan Schefflera222c632021-08-13 12:46:15175 this.linkifier.reset();
Blink Reformat4c46d092018-04-07 15:32:37176 this.contentElement.removeChildren();
Jan Schefflera222c632021-08-13 12:46:15177 this.treeOutline.removeChildren();
178 this.watchExpressions = [];
179 this.emptyElement = (this.contentElement.createChild('div', 'gray-info-message') as HTMLElement);
180 this.emptyElement.textContent = i18nString(UIStrings.noWatchExpressions);
181 this.emptyElement.tabIndex = -1;
182 const watchExpressionStrings = this.watchExpressionsSetting.get();
Jack Lynch338317a2020-08-19 21:59:49183 if (watchExpressionStrings.length) {
Jan Schefflera222c632021-08-13 12:46:15184 this.emptyElement.classList.add('hidden');
Jack Lynch338317a2020-08-19 21:59:49185 }
Blink Reformat4c46d092018-04-07 15:32:37186 for (let i = 0; i < watchExpressionStrings.length; ++i) {
187 const expression = watchExpressionStrings[i];
Tim van der Lippe1d6e57a2019-09-30 11:55:34188 if (!expression) {
Blink Reformat4c46d092018-04-07 15:32:37189 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:34190 }
Blink Reformat4c46d092018-04-07 15:32:37191
Jan Schefflera222c632021-08-13 12:46:15192 this.createWatchExpression(expression);
Blink Reformat4c46d092018-04-07 15:32:37193 }
194 return Promise.resolve();
195 }
196
Jan Schefflera222c632021-08-13 12:46:15197 private createWatchExpression(expression: string|null): WatchExpression {
198 this.contentElement.appendChild(this.treeOutline.element);
199 const watchExpression = new WatchExpression(expression, this.expandController, this.linkifier);
200 watchExpression.addEventListener(WatchExpression.Events.ExpressionUpdated, this.watchExpressionUpdated, this);
201 this.treeOutline.appendChild(watchExpression.treeElement());
202 this.watchExpressions.push(watchExpression);
Blink Reformat4c46d092018-04-07 15:32:37203 return watchExpression;
204 }
205
Jan Schefflera222c632021-08-13 12:46:15206 private watchExpressionUpdated(event: Common.EventTarget.EventTargetEvent): void {
Jan Scheffler35199b92021-03-17 09:51:15207 const watchExpression = (event.data as WatchExpression);
Blink Reformat4c46d092018-04-07 15:32:37208 if (!watchExpression.expression()) {
Jan Schefflera222c632021-08-13 12:46:15209 Platform.ArrayUtilities.removeElement(this.watchExpressions, watchExpression);
210 this.treeOutline.removeChild(watchExpression.treeElement());
211 this.emptyElement.classList.toggle('hidden', Boolean(this.watchExpressions.length));
212 if (this.watchExpressions.length === 0) {
213 this.treeOutline.element.remove();
Jack Lynch5db2a3e2019-11-05 19:12:31214 }
Blink Reformat4c46d092018-04-07 15:32:37215 }
216
Jan Schefflera222c632021-08-13 12:46:15217 this.saveExpressions();
Blink Reformat4c46d092018-04-07 15:32:37218 }
219
Jan Schefflera222c632021-08-13 12:46:15220 private contextMenu(event: MouseEvent): void {
Tim van der Lippefbbf9812020-02-13 14:43:46221 const contextMenu = new UI.ContextMenu.ContextMenu(event);
Jan Schefflera222c632021-08-13 12:46:15222 this.populateContextMenu(contextMenu, event);
Blink Reformat4c46d092018-04-07 15:32:37223 contextMenu.show();
224 }
225
Jan Schefflera222c632021-08-13 12:46:15226 private populateContextMenu(contextMenu: UI.ContextMenu.ContextMenu, event: MouseEvent): void {
Blink Reformat4c46d092018-04-07 15:32:37227 let isEditing = false;
Jan Schefflera222c632021-08-13 12:46:15228 for (const watchExpression of this.watchExpressions) {
Tim van der Lippe0ad77da2020-10-01 16:38:00229 isEditing = isEditing || watchExpression.isEditing();
Tim van der Lippe1d6e57a2019-09-30 11:55:34230 }
Blink Reformat4c46d092018-04-07 15:32:37231
Tim van der Lippe1d6e57a2019-09-30 11:55:34232 if (!isEditing) {
Jan Schefflera222c632021-08-13 12:46:15233 contextMenu.debugSection().appendItem(i18nString(UIStrings.addWatchExpression), this.addButtonClicked.bind(this));
Blink Reformat4c46d092018-04-07 15:32:37234 }
235
Jan Schefflera222c632021-08-13 12:46:15236 if (this.watchExpressions.length > 1) {
Changhao Han8eb616e2021-08-11 05:45:27237 contextMenu.debugSection().appendItem(
Jan Schefflera222c632021-08-13 12:46:15238 i18nString(UIStrings.deleteAllWatchExpressions), this.deleteAllButtonClicked.bind(this));
Changhao Han8eb616e2021-08-11 05:45:27239 }
240
Jan Schefflera222c632021-08-13 12:46:15241 const treeElement = this.treeOutline.treeElementFromEvent(event);
Jack Lynch5db2a3e2019-11-05 19:12:31242 if (!treeElement) {
Blink Reformat4c46d092018-04-07 15:32:37243 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34244 }
Jack Lynch5db2a3e2019-11-05 19:12:31245 const currentWatchExpression =
Jan Schefflera222c632021-08-13 12:46:15246 this.watchExpressions.find(watchExpression => treeElement.hasAncestorOrSelf(watchExpression.treeElement()));
Tim van der Lippe0ad77da2020-10-01 16:38:00247 if (currentWatchExpression) {
Jan Schefflera222c632021-08-13 12:46:15248 currentWatchExpression.populateContextMenu(contextMenu, event);
Tim van der Lippe0ad77da2020-10-01 16:38:00249 }
Blink Reformat4c46d092018-04-07 15:32:37250 }
251
Jan Schefflera222c632021-08-13 12:46:15252 private deleteAllButtonClicked(): void {
253 this.watchExpressions = [];
254 this.saveExpressions();
Blink Reformat4c46d092018-04-07 15:32:37255 this.update();
256 }
257
Jan Schefflera222c632021-08-13 12:46:15258 private async focusAndAddExpressionToWatch(expression: string): Promise<void> {
Benedikt Meurer61f1eef2021-03-17 10:38:29259 await UI.ViewManager.ViewManager.instance().showView('sources.watch');
Jan Schefflera222c632021-08-13 12:46:15260 this.createWatchExpression(expression);
261 this.saveExpressions();
Jack Lynch338317a2020-08-19 21:59:49262 this.update();
PhistucK065e1362018-05-05 09:51:09263 }
264
Jan Scheffler35199b92021-03-17 09:51:15265 handleAction(_context: UI.Context.Context, _actionId: string): boolean {
Tim van der Lipped1a00aa2020-08-19 16:03:56266 const frame = UI.Context.Context.instance().flavor(UISourceCodeFrame);
Tim van der Lippe1d6e57a2019-09-30 11:55:34267 if (!frame) {
Blink Reformat4c46d092018-04-07 15:32:37268 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34269 }
Blink Reformat4c46d092018-04-07 15:32:37270 const text = frame.textEditor.text(frame.textEditor.selection());
Jan Schefflera222c632021-08-13 12:46:15271 this.focusAndAddExpressionToWatch(text);
Blink Reformat4c46d092018-04-07 15:32:37272 return true;
273 }
274
Jan Scheffler35199b92021-03-17 09:51:15275 appendApplicableItems(event: Event, contextMenu: UI.ContextMenu.ContextMenu, target: Object): void {
Tim van der Lippefbbf9812020-02-13 14:43:46276 if (target instanceof ObjectUI.ObjectPropertiesSection.ObjectPropertyTreeElement && !target.property.synthetic) {
PhistucK065e1362018-05-05 09:51:09277 contextMenu.debugSection().appendItem(
Jan Schefflera222c632021-08-13 12:46:15278 i18nString(UIStrings.addPropertyPathToWatch), () => this.focusAndAddExpressionToWatch(target.path()));
PhistucK065e1362018-05-05 09:51:09279 }
280
Tim van der Lipped1a00aa2020-08-19 16:03:56281 const frame = UI.Context.Context.instance().flavor(UISourceCodeFrame);
Tim van der Lippe1d6e57a2019-09-30 11:55:34282 if (!frame || frame.textEditor.selection().isEmpty()) {
Blink Reformat4c46d092018-04-07 15:32:37283 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34284 }
Blink Reformat4c46d092018-04-07 15:32:37285
286 contextMenu.debugSection().appendAction('sources.add-to-watch');
287 }
Kriti Sapraae8f17e2021-08-18 10:28:02288 wasShown(): void {
289 super.wasShown();
290 this.treeOutline.registerCSSFiles([watchExpressionsSidebarPaneStyles]);
291 this.registerCSSFiles([watchExpressionsSidebarPaneStyles, objectValueStyles]);
292 }
Tim van der Lippe8987f8f2020-01-03 15:03:16293}
Blink Reformat4c46d092018-04-07 15:32:37294
Tim van der Lippefbbf9812020-02-13 14:43:46295export class WatchExpression extends Common.ObjectWrapper.ObjectWrapper {
Jan Schefflera222c632021-08-13 12:46:15296 private treeElementInternal!: UI.TreeOutline.TreeElement;
297 private nameElement!: Element;
298 private valueElement!: Element;
299 private expressionInternal: string|null;
300 private readonly expandController: ObjectUI.ObjectPropertiesSection.ObjectPropertiesSectionsTreeExpandController;
301 private element: HTMLDivElement;
302 private editing: boolean;
303 private linkifier: Components.Linkifier.Linkifier;
304 private textPrompt?: ObjectUI.ObjectPropertiesSection.ObjectPropertyPrompt;
305 private result?: SDK.RemoteObject.RemoteObject|null;
306 private preventClickTimeout?: number;
Jan Scheffler35199b92021-03-17 09:51:15307 constructor(
308 expression: string|null,
309 expandController: ObjectUI.ObjectPropertiesSection.ObjectPropertiesSectionsTreeExpandController,
310 linkifier: Components.Linkifier.Linkifier) {
Blink Reformat4c46d092018-04-07 15:32:37311 super();
Tim van der Lippe0ad77da2020-10-01 16:38:00312
Jan Schefflera222c632021-08-13 12:46:15313 this.expressionInternal = expression;
314 this.expandController = expandController;
315 this.element = document.createElement('div');
316 this.element.classList.add('watch-expression');
317 this.element.classList.add('monospace');
318 this.editing = false;
319 this.linkifier = linkifier;
Blink Reformat4c46d092018-04-07 15:32:37320
Jan Schefflera222c632021-08-13 12:46:15321 this.createWatchExpression();
Blink Reformat4c46d092018-04-07 15:32:37322 this.update();
323 }
324
Jan Scheffler35199b92021-03-17 09:51:15325 treeElement(): UI.TreeOutline.TreeElement {
Jan Schefflera222c632021-08-13 12:46:15326 return this.treeElementInternal;
Blink Reformat4c46d092018-04-07 15:32:37327 }
328
Jan Scheffler35199b92021-03-17 09:51:15329 expression(): string|null {
Jan Schefflera222c632021-08-13 12:46:15330 return this.expressionInternal;
Blink Reformat4c46d092018-04-07 15:32:37331 }
332
Jan Scheffler35199b92021-03-17 09:51:15333 update(): void {
Tim van der Lipped1a00aa2020-08-19 16:03:56334 const currentExecutionContext = UI.Context.Context.instance().flavor(SDK.RuntimeModel.ExecutionContext);
Jan Schefflera222c632021-08-13 12:46:15335 if (currentExecutionContext && this.expressionInternal) {
Blink Reformat4c46d092018-04-07 15:32:37336 currentExecutionContext
337 .evaluate(
338 {
Jan Schefflera222c632021-08-13 12:46:15339 expression: this.expressionInternal,
Sigurd Schneider8641b422021-07-16 06:13:35340 objectGroup: WatchExpression.watchObjectGroupId,
Blink Reformat4c46d092018-04-07 15:32:37341 includeCommandLineAPI: false,
342 silent: true,
343 returnByValue: false,
Tim van der Lippe0ad77da2020-10-01 16:38:00344 generatePreview: false,
345 allowUnsafeEvalBlockedByCSP: undefined,
346 disableBreaks: undefined,
347 replMode: undefined,
348 throwOnSideEffect: undefined,
349 timeout: undefined,
Blink Reformat4c46d092018-04-07 15:32:37350 },
351 /* userGesture */ false,
352 /* awaitPromise */ false)
Tim van der Lippe0ad77da2020-10-01 16:38:00353 .then(result => {
354 if ('object' in result) {
Jan Schefflera222c632021-08-13 12:46:15355 this.createWatchExpression(result.object, result.exceptionDetails);
Sigurd Schneider53dc6482021-06-30 11:22:02356 } else {
Jan Schefflera222c632021-08-13 12:46:15357 this.createWatchExpression();
Tim van der Lippe0ad77da2020-10-01 16:38:00358 }
359 });
Sigurd Schneider53dc6482021-06-30 11:22:02360 } else {
Jan Schefflera222c632021-08-13 12:46:15361 this.createWatchExpression();
Blink Reformat4c46d092018-04-07 15:32:37362 }
363 }
364
Jan Scheffler35199b92021-03-17 09:51:15365 startEditing(): void {
Jan Schefflera222c632021-08-13 12:46:15366 this.editing = true;
367 this.treeElementInternal.setDisableSelectFocus(true);
368 this.element.removeChildren();
369 const newDiv = this.element.createChild('div');
370 newDiv.textContent = this.nameElement.textContent;
371 this.textPrompt = new ObjectUI.ObjectPropertiesSection.ObjectPropertyPrompt();
372 this.textPrompt.renderAsBlock();
373 const proxyElement = (this.textPrompt.attachAndStartEditing(newDiv, this.finishEditing.bind(this)) as HTMLElement);
374 this.treeElementInternal.listItemElement.classList.add('watch-expression-editing');
375 this.treeElementInternal.collapse();
Blink Reformat4c46d092018-04-07 15:32:37376 proxyElement.classList.add('watch-expression-text-prompt-proxy');
Jan Schefflera222c632021-08-13 12:46:15377 proxyElement.addEventListener('keydown', this.promptKeyDown.bind(this), false);
378 const selection = this.element.getComponentSelection();
Tim van der Lippe0ad77da2020-10-01 16:38:00379 if (selection) {
380 selection.selectAllChildren(newDiv);
381 }
Blink Reformat4c46d092018-04-07 15:32:37382 }
383
Jan Scheffler35199b92021-03-17 09:51:15384 isEditing(): boolean {
Jan Schefflera222c632021-08-13 12:46:15385 return Boolean(this.editing);
Blink Reformat4c46d092018-04-07 15:32:37386 }
387
Jan Schefflera222c632021-08-13 12:46:15388 private finishEditing(event: Event, canceled?: boolean): void {
Tim van der Lippe1d6e57a2019-09-30 11:55:34389 if (event) {
Blink Reformat4c46d092018-04-07 15:32:37390 event.consume(canceled);
Tim van der Lippe1d6e57a2019-09-30 11:55:34391 }
Blink Reformat4c46d092018-04-07 15:32:37392
Jan Schefflera222c632021-08-13 12:46:15393 this.editing = false;
394 this.treeElementInternal.setDisableSelectFocus(false);
395 this.treeElementInternal.listItemElement.classList.remove('watch-expression-editing');
396 if (this.textPrompt) {
397 this.textPrompt.detach();
398 const newExpression = canceled ? this.expressionInternal : this.textPrompt.text();
399 this.textPrompt = undefined;
400 this.element.removeChildren();
401 this.updateExpression(newExpression);
Tim van der Lippe0ad77da2020-10-01 16:38:00402 }
Blink Reformat4c46d092018-04-07 15:32:37403 }
404
Jan Schefflera222c632021-08-13 12:46:15405 private dblClickOnWatchExpression(event: Event): void {
Blink Reformat4c46d092018-04-07 15:32:37406 event.consume();
Tim van der Lippe1d6e57a2019-09-30 11:55:34407 if (!this.isEditing()) {
Blink Reformat4c46d092018-04-07 15:32:37408 this.startEditing();
Tim van der Lippe1d6e57a2019-09-30 11:55:34409 }
Blink Reformat4c46d092018-04-07 15:32:37410 }
411
Jan Schefflera222c632021-08-13 12:46:15412 private updateExpression(newExpression: string|null): void {
413 if (this.expressionInternal) {
414 this.expandController.stopWatchSectionsWithId(this.expressionInternal);
Tim van der Lippe1d6e57a2019-09-30 11:55:34415 }
Jan Schefflera222c632021-08-13 12:46:15416 this.expressionInternal = newExpression;
Blink Reformat4c46d092018-04-07 15:32:37417 this.update();
Tim van der Lippe8987f8f2020-01-03 15:03:16418 this.dispatchEventToListeners(WatchExpression.Events.ExpressionUpdated, this);
Blink Reformat4c46d092018-04-07 15:32:37419 }
420
Jan Schefflera222c632021-08-13 12:46:15421 private deleteWatchExpression(event: Event): void {
Blink Reformat4c46d092018-04-07 15:32:37422 event.consume(true);
Jan Schefflera222c632021-08-13 12:46:15423 this.updateExpression(null);
Blink Reformat4c46d092018-04-07 15:32:37424 }
425
Jan Schefflera222c632021-08-13 12:46:15426 private createWatchExpression(
427 result?: SDK.RemoteObject.RemoteObject, exceptionDetails?: Protocol.Runtime.ExceptionDetails): void {
428 this.result = result || null;
Blink Reformat4c46d092018-04-07 15:32:37429
Jan Schefflera222c632021-08-13 12:46:15430 this.element.removeChildren();
431 const oldTreeElement = this.treeElementInternal;
432 this.createWatchExpressionTreeElement(result, exceptionDetails);
Jack Lynch5db2a3e2019-11-05 19:12:31433 if (oldTreeElement && oldTreeElement.parent) {
434 const root = oldTreeElement.parent;
435 const index = root.indexOfChild(oldTreeElement);
436 root.removeChild(oldTreeElement);
Jan Schefflera222c632021-08-13 12:46:15437 root.insertChild(this.treeElementInternal, index);
Jack Lynch5db2a3e2019-11-05 19:12:31438 }
Jan Schefflera222c632021-08-13 12:46:15439 this.treeElementInternal.select();
Jack Lynch5db2a3e2019-11-05 19:12:31440 }
441
Jan Schefflera222c632021-08-13 12:46:15442 private createWatchExpressionHeader(
Jan Scheffler35199b92021-03-17 09:51:15443 expressionValue?: SDK.RemoteObject.RemoteObject, exceptionDetails?: Protocol.Runtime.ExceptionDetails): Element {
Jan Schefflera222c632021-08-13 12:46:15444 const headerElement = this.element.createChild('div', 'watch-expression-header');
Tim van der Lippefbbf9812020-02-13 14:43:46445 const deleteButton = UI.Icon.Icon.create('smallicon-cross', 'watch-expression-delete-button');
Vidal Guillermo Diazleal Ortega83edb472021-02-16 18:39:32446 UI.Tooltip.Tooltip.install(deleteButton, i18nString(UIStrings.deleteWatchExpression));
Jan Schefflera222c632021-08-13 12:46:15447 deleteButton.addEventListener('click', this.deleteWatchExpression.bind(this), false);
Blink Reformat4c46d092018-04-07 15:32:37448
Jack Lynch5db2a3e2019-11-05 19:12:31449 const titleElement = headerElement.createChild('div', 'watch-expression-title tree-element-title');
Jack Lynche1767de2020-04-22 02:43:55450 titleElement.appendChild(deleteButton);
Jan Schefflera222c632021-08-13 12:46:15451 this.nameElement =
452 ObjectUI.ObjectPropertiesSection.ObjectPropertiesSection.createNameElement(this.expressionInternal);
Tim van der Lipped7cfd142021-01-07 12:17:24453 if (Boolean(exceptionDetails) || !expressionValue) {
Jan Schefflera222c632021-08-13 12:46:15454 this.valueElement = document.createElement('span');
455 this.valueElement.classList.add('watch-expression-error');
456 this.valueElement.classList.add('value');
Blink Reformat4c46d092018-04-07 15:32:37457 titleElement.classList.add('dimmed');
Jan Schefflera222c632021-08-13 12:46:15458 this.valueElement.textContent = i18nString(UIStrings.notAvailable);
Philip Pfaffe7426b002020-11-30 15:59:22459 if (exceptionDetails !== undefined && exceptionDetails.exception !== undefined &&
460 exceptionDetails.exception.description !== undefined) {
Jan Schefflera222c632021-08-13 12:46:15461 UI.Tooltip.Tooltip.install(this.valueElement as HTMLElement, exceptionDetails.exception.description);
Philip Pfaffe7426b002020-11-30 15:59:22462 }
Blink Reformat4c46d092018-04-07 15:32:37463 } else {
Tim van der Lippefbbf9812020-02-13 14:43:46464 const propertyValue =
465 ObjectUI.ObjectPropertiesSection.ObjectPropertiesSection.createPropertyValueWithCustomSupport(
Jan Schefflera222c632021-08-13 12:46:15466 expressionValue, Boolean(exceptionDetails), false /* showPreview */, titleElement, this.linkifier);
467 this.valueElement = propertyValue.element;
Blink Reformat4c46d092018-04-07 15:32:37468 }
Tim van der Lippef49e2322020-05-01 15:03:09469 const separatorElement = document.createElement('span');
470 separatorElement.classList.add('watch-expressions-separator');
Blink Reformat4c46d092018-04-07 15:32:37471 separatorElement.textContent = ': ';
Jan Schefflera222c632021-08-13 12:46:15472 titleElement.append(this.nameElement, separatorElement, this.valueElement);
Blink Reformat4c46d092018-04-07 15:32:37473
Jack Lynch5db2a3e2019-11-05 19:12:31474 return headerElement;
475 }
Blink Reformat4c46d092018-04-07 15:32:37476
Jan Schefflera222c632021-08-13 12:46:15477 private createWatchExpressionTreeElement(
Jan Scheffler35199b92021-03-17 09:51:15478 expressionValue?: SDK.RemoteObject.RemoteObject, exceptionDetails?: Protocol.Runtime.ExceptionDetails): void {
Jan Schefflera222c632021-08-13 12:46:15479 const headerElement = this.createWatchExpressionHeader(expressionValue, exceptionDetails);
Jack Lynch5db2a3e2019-11-05 19:12:31480
481 if (!exceptionDetails && expressionValue && expressionValue.hasChildren && !expressionValue.customPreview()) {
482 headerElement.classList.add('watch-expression-object-header');
Jan Schefflera222c632021-08-13 12:46:15483 this.treeElementInternal = new ObjectUI.ObjectPropertiesSection.RootElement(expressionValue, this.linkifier);
484 this.expandController.watchSection(
485 (this.expressionInternal as string),
486 (this.treeElementInternal as ObjectUI.ObjectPropertiesSection.RootElement));
487 this.treeElementInternal.toggleOnClick = false;
488 this.treeElementInternal.listItemElement.addEventListener('click', this.onSectionClick.bind(this), false);
489 this.treeElementInternal.listItemElement.addEventListener('dblclick', this.dblClickOnWatchExpression.bind(this));
Jack Lynch5db2a3e2019-11-05 19:12:31490 } else {
Jan Schefflera222c632021-08-13 12:46:15491 headerElement.addEventListener('dblclick', this.dblClickOnWatchExpression.bind(this));
492 this.treeElementInternal = new UI.TreeOutline.TreeElement();
Jack Lynch5db2a3e2019-11-05 19:12:31493 }
Jan Schefflera222c632021-08-13 12:46:15494 this.treeElementInternal.title = this.element;
495 this.treeElementInternal.listItemElement.classList.add('watch-expression-tree-item');
496 this.treeElementInternal.listItemElement.addEventListener('keydown', event => {
Tim van der Lippebcd6b5c2021-01-13 12:31:51497 if (event.key === 'Enter' && !this.isEditing()) {
Jack Lynch5db2a3e2019-11-05 19:12:31498 this.startEditing();
499 event.consume(true);
500 }
501 });
Blink Reformat4c46d092018-04-07 15:32:37502 }
503
Jan Schefflera222c632021-08-13 12:46:15504 private onSectionClick(event: Event): void {
Blink Reformat4c46d092018-04-07 15:32:37505 event.consume(true);
Jan Scheffler35199b92021-03-17 09:51:15506 const mouseEvent = (event as MouseEvent);
Tim van der Lippe0ad77da2020-10-01 16:38:00507 if (mouseEvent.detail === 1) {
Jan Schefflera222c632021-08-13 12:46:15508 this.preventClickTimeout = window.setTimeout(handleClick.bind(this), 333);
509 } else if (this.preventClickTimeout !== undefined) {
510 window.clearTimeout(this.preventClickTimeout);
511 this.preventClickTimeout = undefined;
Blink Reformat4c46d092018-04-07 15:32:37512 }
513
Jan Scheffler35199b92021-03-17 09:51:15514 function handleClick(this: WatchExpression): void {
Jan Schefflera222c632021-08-13 12:46:15515 if (!this.treeElementInternal) {
Blink Reformat4c46d092018-04-07 15:32:37516 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34517 }
Blink Reformat4c46d092018-04-07 15:32:37518
Jan Schefflera222c632021-08-13 12:46:15519 if (this.treeElementInternal.expanded) {
520 this.treeElementInternal.collapse();
521 } else if (!this.editing) {
522 this.treeElementInternal.expand();
Tim van der Lippe1d6e57a2019-09-30 11:55:34523 }
Blink Reformat4c46d092018-04-07 15:32:37524 }
525 }
526
Jan Schefflera222c632021-08-13 12:46:15527 private promptKeyDown(event: KeyboardEvent): void {
Tim van der Lippebcd6b5c2021-01-13 12:31:51528 if (event.key === 'Enter' || isEscKey(event)) {
Jan Schefflera222c632021-08-13 12:46:15529 this.finishEditing(event, isEscKey(event));
Tim van der Lippe1d6e57a2019-09-30 11:55:34530 }
Blink Reformat4c46d092018-04-07 15:32:37531 }
532
Jan Schefflera222c632021-08-13 12:46:15533 populateContextMenu(contextMenu: UI.ContextMenu.ContextMenu, event: Event): void {
Blink Reformat4c46d092018-04-07 15:32:37534 if (!this.isEditing()) {
535 contextMenu.editSection().appendItem(
Jan Schefflera222c632021-08-13 12:46:15536 i18nString(UIStrings.deleteWatchExpression), this.updateExpression.bind(this, null));
Blink Reformat4c46d092018-04-07 15:32:37537 }
538
Jan Schefflera222c632021-08-13 12:46:15539 if (!this.isEditing() && this.result && (this.result.type === 'number' || this.result.type === 'string')) {
Tim van der Lippefbbf9812020-02-13 14:43:46540 contextMenu.clipboardSection().appendItem(
Jan Schefflera222c632021-08-13 12:46:15541 i18nString(UIStrings.copyValue), this.copyValueButtonClicked.bind(this));
Tim van der Lippe1d6e57a2019-09-30 11:55:34542 }
Blink Reformat4c46d092018-04-07 15:32:37543
Sigurd Schneider090c3b62020-11-10 10:26:49544 const target = UI.UIUtils.deepElementFromEvent(event);
Jan Schefflera222c632021-08-13 12:46:15545 if (target && this.valueElement.isSelfOrAncestor(target) && this.result) {
546 contextMenu.appendApplicableItems(this.result);
Tim van der Lippe1d6e57a2019-09-30 11:55:34547 }
Blink Reformat4c46d092018-04-07 15:32:37548 }
549
Jan Schefflera222c632021-08-13 12:46:15550 private copyValueButtonClicked(): void {
551 Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(this.valueElement.textContent);
Blink Reformat4c46d092018-04-07 15:32:37552 }
Jan Scheffler35199b92021-03-17 09:51:15553
Sigurd Schneider8641b422021-07-16 06:13:35554 private static readonly watchObjectGroupId = 'watch-group';
Tim van der Lippe8987f8f2020-01-03 15:03:16555}
Blink Reformat4c46d092018-04-07 15:32:37556
Jan Scheffler35199b92021-03-17 09:51:15557export namespace WatchExpression {
558 // TODO(crbug.com/1167717): Make this a const enum again
559 // eslint-disable-next-line rulesdir/const_enum
560 export const Events = {
561 ExpressionUpdated: Symbol('ExpressionUpdated'),
562 };
563}