chrome-devtools-frontend 1.0.1697595 → 1.0.1698733

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/.agents/skills/version-control/SKILL.md +21 -9
  2. package/.stylelintignore +2 -0
  3. package/front_end/core/common/VersionController.ts +5 -1
  4. package/front_end/core/platform/HostRuntime.ts +12 -0
  5. package/front_end/core/platform/api/HostRuntime.ts +13 -0
  6. package/front_end/core/platform/browser/HostRuntime.ts +34 -0
  7. package/front_end/core/platform/node/HostRuntime.ts +40 -0
  8. package/front_end/core/sdk/AnimationModel.ts +21 -99
  9. package/front_end/core/sdk/CSSModel.ts +4 -2
  10. package/front_end/core/sdk/CSSPropertyParser.ts +4 -4
  11. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +4 -44
  12. package/front_end/core/sdk/Connections.ts +6 -1
  13. package/front_end/core/sdk/ConsoleModel.ts +1 -12
  14. package/front_end/core/sdk/DOMModel.ts +3 -51
  15. package/front_end/core/sdk/DebuggerModel.ts +9 -8
  16. package/front_end/core/sdk/NetworkRequest.ts +1 -1
  17. package/front_end/core/sdk/PageFunctions.ts +187 -0
  18. package/front_end/core/sdk/Resource.ts +1 -1
  19. package/front_end/core/sdk/RuntimeModel.ts +1 -20
  20. package/front_end/core/sdk/Script.ts +21 -0
  21. package/front_end/core/sdk/SourceMap.ts +15 -2
  22. package/front_end/core/sdk/SourceMapCache.ts +13 -10
  23. package/front_end/core/sdk/SourceMapManager.ts +11 -9
  24. package/front_end/core/sdk/SourceMapScopeChainEntry.ts +59 -17
  25. package/front_end/core/sdk/SourceMapScopesInfo.ts +8 -2
  26. package/front_end/entrypoints/heap_snapshot_worker/ContextAnalyzer.ts +635 -0
  27. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +26 -12
  28. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshotLoader.ts +16 -2
  29. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshotWorkerDispatcher.ts +4 -4
  30. package/front_end/entrypoints/heap_snapshot_worker/heap_snapshot_worker.ts +2 -0
  31. package/front_end/entrypoints/shell/shell.ts +1 -1
  32. package/front_end/generated/InspectorBackendCommands.ts +1 -1
  33. package/front_end/generated/protocol.ts +8 -2
  34. package/front_end/models/ai_assistance/DOMHelpers.ts +95 -0
  35. package/front_end/models/ai_assistance/EvaluateAction.ts +5 -42
  36. package/front_end/models/ai_assistance/ExtensionScope.ts +2 -31
  37. package/front_end/models/ai_assistance/agents/AiAgent.ts +2 -1
  38. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +27 -2
  39. package/front_end/models/ai_assistance/ai_assistance.ts +6 -4
  40. package/front_end/models/ai_assistance/contexts/DOMNodeContext.ts +10 -7
  41. package/front_end/models/ai_assistance/contexts/FileContext.ts +2 -10
  42. package/front_end/models/ai_assistance/skills/performance.md +4 -3
  43. package/front_end/models/ai_assistance/tools/GetSourceContent.ts +3 -2
  44. package/front_end/models/ai_assistance/tools/{GetFunctionCode.ts → GetTraceFunctionCode.ts} +26 -13
  45. package/front_end/models/ai_assistance/tools/{GetResourceContent.ts → GetTraceResourceContent.ts} +31 -11
  46. package/front_end/models/ai_assistance/tools/ListSources.ts +21 -14
  47. package/front_end/models/ai_assistance/tools/Tool.ts +2 -2
  48. package/front_end/models/ai_assistance/tools/ToolRegistry.ts +6 -6
  49. package/front_end/models/bindings/CompilerScriptMapping.ts +3 -10
  50. package/front_end/models/bindings/DebuggerLanguagePlugins.ts +48 -17
  51. package/front_end/models/bindings/ResourceScriptMapping.ts +2 -2
  52. package/front_end/models/bindings/StylesSourceMapping.ts +1 -1
  53. package/front_end/models/comment_manager/CD4ABridge.ts +55 -12
  54. package/front_end/models/comment_manager/CommentManager.ts +46 -91
  55. package/front_end/models/comment_manager/CommentThread.ts +145 -0
  56. package/front_end/models/comment_manager/comment_manager.ts +2 -0
  57. package/front_end/models/elements/DOMChanges.ts +238 -0
  58. package/front_end/models/elements/elements.ts +2 -0
  59. package/front_end/models/emulation/DeviceModeModel.ts +53 -0
  60. package/front_end/models/extensions/ExtensionAPI.ts +8 -6
  61. package/front_end/models/extensions/ExtensionEndpoint.ts +11 -8
  62. package/front_end/models/extensions/HostUrlPattern.ts +4 -3
  63. package/front_end/models/extensions/LanguageExtensionEndpoint.ts +3 -2
  64. package/front_end/models/extensions/RecorderExtensionEndpoint.ts +2 -1
  65. package/front_end/models/formatter/FormatterWorkerPool.ts +4 -6
  66. package/front_end/models/heap_snapshot/HeapSnapshotModel.ts +55 -0
  67. package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +18 -14
  68. package/front_end/models/issues_manager/IssuesManager.ts +5 -0
  69. package/front_end/models/issues_manager/WebInstallIssue.ts +63 -0
  70. package/front_end/models/issues_manager/descriptions/webInstallManifestMissingId.md +3 -0
  71. package/front_end/models/issues_manager/descriptions/webInstallManifestMissingNameOrShortName.md +3 -0
  72. package/front_end/models/issues_manager/descriptions/webInstallManifestParsingOrNetworkError.md +3 -0
  73. package/front_end/models/issues_manager/descriptions/webInstallNoManifest.md +3 -0
  74. package/front_end/models/issues_manager/descriptions/webInstallStartUrlInvalid.md +3 -0
  75. package/front_end/models/issues_manager/issues_manager.ts +2 -0
  76. package/front_end/models/workspace/UISourceCode.ts +20 -0
  77. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +7 -7
  78. package/front_end/panels/ai_assistance/components/AIv2MarkdownRenderer.ts +4 -10
  79. package/front_end/panels/ai_assistance/components/MarkdownRendererWithCodeBlock.ts +25 -5
  80. package/front_end/panels/browser_debugger/ObjectEventListenersSidebarPane.ts +2 -3
  81. package/front_end/panels/common/CommentThreadWidget.ts +221 -0
  82. package/front_end/{ui/comments → panels/common}/CommentsOverlayWidget.ts +117 -28
  83. package/front_end/{ui/comments → panels/common}/CommentsStatusBarPill.ts +5 -5
  84. package/front_end/panels/common/ExtensionServer.ts +2 -1
  85. package/front_end/panels/common/commentThreadWidget.css +173 -0
  86. package/front_end/{ui/comments → panels/common}/commentsOverlay.css +8 -1
  87. package/front_end/{ui/comments/comments-meta.ts → panels/common/common-meta.ts} +11 -11
  88. package/front_end/panels/common/common.ts +3 -0
  89. package/front_end/panels/elements/AdoptedStyleSheetTreeElement.ts +3 -3
  90. package/front_end/panels/elements/ElementsPanel.ts +5 -1
  91. package/front_end/panels/elements/ElementsTreeElement.ts +102 -21
  92. package/front_end/panels/elements/ElementsTreeOutline.ts +326 -91
  93. package/front_end/panels/elements/EventListenersWidget.ts +0 -1
  94. package/front_end/panels/elements/PropertiesWidget.ts +11 -10
  95. package/front_end/panels/elements/PropertyRenderer.ts +29 -25
  96. package/front_end/panels/elements/StylePropertyTreeElement.ts +6 -6
  97. package/front_end/panels/elements/elementsTreeOutline.css +7 -1
  98. package/front_end/panels/emulation/DeviceModeToolbar.ts +2 -3
  99. package/front_end/panels/event_listeners/EventListenersView.ts +235 -302
  100. package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorController.ts +6 -7
  101. package/front_end/panels/linear_memory_inspector/components/linearMemoryInspector.css +5 -1
  102. package/front_end/panels/linear_memory_inspector/linear_memory_inspector-meta.ts +1 -1
  103. package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +10 -2
  104. package/front_end/panels/network/NetworkConfigView.ts +141 -116
  105. package/front_end/panels/network/NetworkPanel.ts +7 -4
  106. package/front_end/panels/network/RequestHeadersView.ts +1 -1
  107. package/front_end/panels/network/forward/BackendLinking.ts +5 -2
  108. package/front_end/panels/recorder/stepView.css +1 -0
  109. package/front_end/panels/security/SecurityPanel.ts +5 -5
  110. package/front_end/panels/security/SecurityPanelSidebar.ts +2 -11
  111. package/front_end/panels/settings/BackendLinkingSettingsTab.ts +7 -2
  112. package/front_end/panels/sources/DebuggerPlugin.ts +1 -1
  113. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +11 -16
  114. package/front_end/panels/sources/sources-meta.ts +1 -1
  115. package/front_end/panels/timeline/TimelineTreeView.ts +11 -1
  116. package/front_end/panels/timeline/overlays/OverlaysImpl.ts +0 -3
  117. package/front_end/third_party/chromium/README.chromium +1 -1
  118. package/front_end/ui/comments/CommentOverlayManager.ts +89 -42
  119. package/front_end/ui/comments/comments.ts +0 -4
  120. package/front_end/ui/legacy/Treeoutline.ts +4 -0
  121. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +15 -8
  122. package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +4 -0
  123. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  124. package/package.json +5 -5
@@ -1,7 +1,6 @@
1
1
  // Copyright 2015 The Chromium Authors
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
- /* eslint-disable @devtools/no-imperative-dom-api */
5
4
 
6
5
  import * as Common from '../../core/common/common.js';
7
6
  import * as i18n from '../../core/i18n/i18n.js';
@@ -9,14 +8,18 @@ import type * as Platform from '../../core/platform/platform.js';
9
8
  import * as SDK from '../../core/sdk/sdk.js';
10
9
  import * as Buttons from '../../ui/components/buttons/buttons.js';
11
10
  import * as ObjectUI from '../../ui/legacy/components/object_ui/object_ui.js';
11
+ import objectPropertiesSectionStyles from '../../ui/legacy/components/object_ui/objectPropertiesSection.css.js';
12
12
  import objectValueStyles from '../../ui/legacy/components/object_ui/objectValue.css.js';
13
13
  import * as Components from '../../ui/legacy/components/utils/utils.js';
14
14
  import * as UI from '../../ui/legacy/legacy.js';
15
- import {render} from '../../ui/lit/lit.js';
15
+ import * as Lit from '../../ui/lit/lit.js';
16
16
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
17
17
 
18
18
  import {frameworkEventListeners} from './EventListenersUtils.js';
19
19
  import eventListenersViewStyles from './eventListenersView.css.js';
20
+ const {widget, widgetRef} = UI.Widget;
21
+ const {html, render} = Lit;
22
+ const {repeat} = Lit.Directives;
20
23
 
21
24
  const UIStrings = {
22
25
  /**
@@ -51,59 +54,253 @@ const UIStrings = {
51
54
  const str_ = i18n.i18n.registerUIStrings('panels/event_listeners/EventListenersView.ts', UIStrings);
52
55
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
53
56
 
57
+ interface ListenerEntry {
58
+ object: SDK.RemoteObject.RemoteObject;
59
+ listener: SDK.DOMDebuggerModel.EventListener;
60
+ objectTree: ObjectUI.ObjectPropertiesSection.ObjectTree;
61
+ }
62
+
63
+ interface ViewInput {
64
+ togglePassiveListener(listener: SDK.DOMDebuggerModel.EventListener): void;
65
+ removeListener(listener: SDK.DOMDebuggerModel.EventListener): boolean;
66
+ reveal(object: SDK.RemoteObject.RemoteObject): void;
67
+ linkifier: Components.Linkifier.Linkifier;
68
+ listeners: Map<string, ListenerEntry[]>;
69
+ filter?: {showFramework: boolean, showPassive: boolean, showBlocking: boolean};
70
+ }
71
+
72
+ type View = (input: ViewInput, output: object, target: HTMLElement) => void;
73
+
74
+ export const DEFAULT_VIEW: View = (input, output, target) => {
75
+ const types = input.listeners.keys().toArray().sort();
76
+
77
+ const onContextMenu = (event: Event, listener: SDK.DOMDebuggerModel.EventListener,
78
+ object: SDK.RemoteObject.RemoteObject): void => {
79
+ const menu = new UI.ContextMenu.ContextMenu(event);
80
+ if (event.target instanceof HTMLElement && !event.target.closest('.event-listener-tree-subtitle') &&
81
+ event.currentTarget instanceof HTMLElement) {
82
+ const link = event.currentTarget.querySelector('.event-listener-tree-subtitle .devtools-link');
83
+ if (link) {
84
+ menu.appendApplicableItems(link);
85
+ }
86
+ }
87
+ if (object.subtype === 'node') {
88
+ menu.defaultSection().appendItem(i18nString(UIStrings.openInElementsPanel), () => input.reveal(object),
89
+ {jslogContext: 'reveal-in-elements'});
90
+ }
91
+ menu.defaultSection().appendItem(i18nString(UIStrings.deleteEventListener), () => input.removeListener(listener),
92
+ {disabled: !listener.canRemove(), jslogContext: 'delete-event-listener'});
93
+ menu.defaultSection().appendCheckboxItem(i18nString(UIStrings.passive), () => input.togglePassiveListener(listener),
94
+ {
95
+ checked: listener.passive(),
96
+ disabled: !listener.canTogglePassive(),
97
+ jslogContext: 'passive',
98
+ });
99
+ void menu.show();
100
+ };
101
+
102
+ const shouldHide = (listenerOrType: SDK.DOMDebuggerModel.EventListener|string): boolean => {
103
+ if (!input.filter) {
104
+ return false;
105
+ }
106
+ if (typeof listenerOrType === 'string') {
107
+ return input.listeners.get(listenerOrType)?.every(({listener}) => shouldHide(listener)) ?? true;
108
+ }
109
+ const listenerOrigin = listenerOrType.origin();
110
+ if (listenerOrigin === SDK.DOMDebuggerModel.EventListener.Origin.FRAMEWORK_USER && !input.filter.showFramework) {
111
+ return true;
112
+ }
113
+ if (listenerOrigin === SDK.DOMDebuggerModel.EventListener.Origin.FRAMEWORK && input.filter.showFramework) {
114
+ return true;
115
+ }
116
+ if (!input.filter.showPassive && listenerOrType.passive()) {
117
+ return true;
118
+ }
119
+ if (!input.filter.showBlocking && !listenerOrType.passive()) {
120
+ return true;
121
+ }
122
+ return false;
123
+ };
124
+
125
+ const onKeyDown = (event: KeyboardEvent, listener: SDK.DOMDebuggerModel.EventListener,
126
+ object: SDK.RemoteObject.RemoteObject): void => {
127
+ if (event.target !== event.currentTarget) {
128
+ return;
129
+ }
130
+ if (event.key === 'Delete' || event.key === 'Backspace') {
131
+ if (input.removeListener(listener)) {
132
+ event.consume();
133
+ }
134
+ } else if (event.key === 'Enter') {
135
+ input.reveal(object);
136
+ event.consume();
137
+ }
138
+ };
139
+
140
+ const hasVisibleListeners = types.some(type => !shouldHide(type));
141
+
142
+ // clang-format off
143
+ render(html`
144
+ <style>${eventListenersViewStyles}</style>
145
+ ${!hasVisibleListeners ? html`
146
+ <div autofocus class=placeholder><!--emptyHolder-->
147
+ <span class=gray-info-message>${i18nString(UIStrings.noEventListeners)}</span>
148
+ ${widget(UI.EmptyWidget.EmptyWidget, {
149
+ header: i18nString(UIStrings.noEventListeners),
150
+ text: i18nString(UIStrings.eventListenersExplanation),
151
+ })}
152
+ </div>` : html`
153
+ <devtools-tree autofocus class="event-listener-tree monospace" show-selection-on-keyboard-focus .template=${html`
154
+ <ul role=tree>
155
+ <style>${eventListenersViewStyles}</style>
156
+ <style>${objectValueStyles}</style>
157
+ <style>${objectPropertiesSectionStyles}</style>
158
+ ${repeat(types, type => type, type => html`
159
+ <li role=treeitem toggle-on-click aria-label="${type}, event listener" ?hidden=${shouldHide(type)}>
160
+ ${type}
161
+ <ul role=group>
162
+ ${repeat(input.listeners.get(type) ?? [], ({listener}) => listener, ({listener, object, objectTree}) => html`
163
+ <li role=treeitem
164
+ data-origin=${listener.origin()}
165
+ @contextmenu=${(e: Event) => onContextMenu(e, listener, object)}
166
+ @keydown=${(e: KeyboardEvent) => onKeyDown(e, listener, object)}
167
+ ?hidden=${shouldHide(listener)}>
168
+ <span class=event-listener-details>
169
+ ${ObjectUI.ObjectPropertiesSection.renderPropertyValue(
170
+ object, /* wasThrown */ false, /* showPreview */ false, input.linkifier)}
171
+ <devtools-button
172
+ .iconName=${'bin'}
173
+ .variant=${Buttons.Button.Variant.ICON}
174
+ .size=${Buttons.Button.Size.MICRO}
175
+ .jslogContext=${'delete-event-listener'}
176
+ title=${i18nString(UIStrings.deleteEventListener)}
177
+ @click=${(event: Event) => {input.removeListener(listener); event.consume();}}
178
+ ?hidden=${!listener.canRemove()}></devtools-button>
179
+ ${listener.isScrollBlockingType() && listener.canTogglePassive() ? html`
180
+ <button class=event-listener-button
181
+ jslog=${VisualLogging.action('passive').track({click: true})}
182
+ title=${i18nString(UIStrings.toggleWhetherEventListenerIs)}
183
+ @click=${(e: Event) => {input.togglePassiveListener(listener); e.consume();}}>
184
+ ${i18nString(UIStrings.togglePassive)}
185
+ </button>` : Lit.nothing}
186
+ <span class=event-listener-tree-subtitle>
187
+ ${input.linkifier.linkifyRawLocation(
188
+ listener.location(), listener.sourceURL(), /* FIXME template version */
189
+ undefined, {tabStop: true})}
190
+ </span>
191
+ </span>
192
+ <ul role=group ${widget(ObjectUI.ObjectPropertiesSection.ObjectTreeWidget, {objectTree})} ${
193
+ widgetRef(ObjectUI.ObjectPropertiesSection.ObjectTreeWidget, () => {})}></ul>
194
+ </li>`)}
195
+ </ul>
196
+ </li>`)}
197
+ </ul>
198
+ `}></devtools-tree>`}`,
199
+ // clang-format on
200
+ target);
201
+ };
202
+
54
203
  export class EventListenersView extends UI.Widget.VBox {
55
- changeCallback = (): void => {};
56
- enableDefaultTreeFocus = false;
57
- treeOutline: UI.TreeOutline.TreeOutlineInShadow;
58
- emptyHolder: HTMLDivElement;
59
- objects: Array<SDK.RemoteObject.RemoteObject|null> = [];
60
- filter: {showFramework: boolean, showPassive: boolean, showBlocking: boolean}|undefined;
204
+ #objects: Array<SDK.RemoteObject.RemoteObject|null> = [];
205
+ #filter: {showFramework: boolean, showPassive: boolean, showBlocking: boolean}|undefined;
206
+ #view: View;
207
+ #listeners?: Map<string, ListenerEntry[]>;
61
208
  #linkifier = new Components.Linkifier.Linkifier();
62
- readonly #treeItemMap = new Map<string, EventListenersTreeElement>();
63
- constructor(element?: HTMLElement) {
209
+ constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
64
210
  super(element);
65
- this.registerRequiredCSS(eventListenersViewStyles);
66
- this.emptyHolder = this.element.createChild('div', 'placeholder hidden');
67
- this.emptyHolder.createChild('span', 'gray-info-message').textContent = i18nString(UIStrings.noEventListeners);
68
- const emptyWidget = new UI.EmptyWidget.EmptyWidget(i18nString(UIStrings.noEventListeners),
69
- i18nString(UIStrings.eventListenersExplanation));
70
- emptyWidget.show(this.emptyHolder);
211
+ this.#view = view;
212
+ }
71
213
 
72
- this.treeOutline = new UI.TreeOutline.TreeOutlineInShadow();
73
- this.treeOutline.setComparator(EventListenersTreeElement.comparator);
74
- this.treeOutline.element.classList.add('event-listener-tree', 'monospace');
75
- this.treeOutline.setShowSelectionOnKeyboardFocus(true);
76
- this.treeOutline.setFocusable(true);
77
- this.treeOutline.registerRequiredCSS(eventListenersViewStyles, objectValueStyles);
78
- this.element.appendChild(this.treeOutline.element);
214
+ get objects(): Array<SDK.RemoteObject.RemoteObject|null> {
215
+ return this.#objects;
79
216
  }
80
217
 
81
- override focus(): void {
82
- if (!this.enableDefaultTreeFocus) {
218
+ set objects(val: Array<SDK.RemoteObject.RemoteObject|null>) {
219
+ if (this.#objects === val) {
83
220
  return;
84
221
  }
85
- if (!this.emptyHolder.classList.contains('hidden')) {
86
- this.treeOutline.forceSelect();
87
- } else {
88
- this.emptyHolder.focus();
222
+ this.#listeners = undefined;
223
+ this.#objects = val;
224
+ this.requestUpdate();
225
+ }
226
+ get filter(): {showFramework: boolean, showPassive: boolean, showBlocking: boolean}|undefined {
227
+ return this.#filter;
228
+ }
229
+
230
+ set filter(val: {showFramework: boolean, showPassive: boolean, showBlocking: boolean}|undefined) {
231
+ if (this.#filter === val) {
232
+ return;
89
233
  }
234
+ this.#filter = val;
235
+ this.requestUpdate();
90
236
  }
91
237
 
92
238
  override async performUpdate(): Promise<void> {
93
- await this.addObjects(this.objects);
94
- if (this.filter) {
95
- this.showFrameworkListeners(this.filter.showFramework, this.filter.showPassive, this.filter.showBlocking);
239
+ if (!this.#listeners && this.#objects) {
240
+ this.#listeners =
241
+ await EventListenersView.#loadListeners(this.#objects.filter((o): o is NonNullable<typeof o> => !!o));
96
242
  }
243
+ const input: ViewInput = {
244
+ listeners: this.#listeners ?? new Map(),
245
+ filter: this.#filter,
246
+ togglePassiveListener: (listener: SDK.DOMDebuggerModel.EventListener) => {
247
+ void listener.togglePassive().then(() => {
248
+ this.#listeners = undefined;
249
+ this.requestUpdate();
250
+ });
251
+ },
252
+ removeListener: (listener: SDK.DOMDebuggerModel.EventListener) => {
253
+ if (!listener.canRemove()) {
254
+ return false;
255
+ }
256
+ void listener.remove();
257
+ if (this.#listeners) {
258
+ const list = this.#listeners.get(listener.type());
259
+ if (list) {
260
+ const index = list.findIndex(item => item.listener === listener);
261
+ if (index !== -1) {
262
+ list.splice(index, 1);
263
+ if (list.length === 0) {
264
+ this.#listeners.delete(listener.type());
265
+ }
266
+ }
267
+ }
268
+ }
269
+ this.requestUpdate();
270
+ return true;
271
+ },
272
+ reveal: (object: SDK.RemoteObject.RemoteObject) => {
273
+ if (object.subtype === 'node') {
274
+ void Common.Revealer.reveal(object);
275
+ }
276
+ },
277
+ linkifier: this.#linkifier,
278
+ };
279
+ this.#view(input, {}, this.contentElement);
280
+ this.eventListenersArrivedForTest();
97
281
  }
98
282
 
99
- static async #loadListeners(objects: SDK.RemoteObject.RemoteObject[]): Promise<
100
- Map<string, Array<{object: SDK.RemoteObject.RemoteObject, listener: SDK.DOMDebuggerModel.EventListener}>>> {
283
+ static #createObjectTree(listener: SDK.DOMDebuggerModel.EventListener): ObjectUI.ObjectPropertiesSection.ObjectTree {
284
+ const object = SDK.RemoteObject.RemoteObject.fromLocalObject({
285
+ useCapture: listener.useCapture(),
286
+ passive: listener.passive(),
287
+ once: listener.once(),
288
+ ...(typeof listener.handler() !== 'undefined' ? {handler: listener.handler()} : {}),
289
+ });
290
+ const objectTree = new ObjectUI.ObjectPropertiesSection.ObjectTree(object, {
291
+ readOnly: false,
292
+ propertiesMode: ObjectUI.ObjectPropertiesSection.ObjectPropertiesMode.OWN_AND_INTERNAL_AND_INHERITED,
293
+ });
294
+ objectTree.expanded = true;
295
+ return objectTree;
296
+ }
297
+
298
+ static async #loadListeners(objects: SDK.RemoteObject.RemoteObject[]): Promise<Map<string, ListenerEntry[]>> {
101
299
  return Map.groupBy((await Promise.all(objects.map(this.#loadListenersForObject))).flat(),
102
300
  ({listener}) => listener.type());
103
301
  }
104
302
 
105
- static async #loadListenersForObject(object: SDK.RemoteObject.RemoteObject):
106
- Promise<Array<{object: SDK.RemoteObject.RemoteObject, listener: SDK.DOMDebuggerModel.EventListener}>> {
303
+ static async #loadListenersForObject(object: SDK.RemoteObject.RemoteObject): Promise<ListenerEntry[]> {
107
304
  const domDebuggerModel = object.runtimeModel().target().model(SDK.DOMDebuggerModel.DOMDebuggerModel);
108
305
  const [eventListeners, frameworkEventListenersObject] =
109
306
  await Promise.all([domDebuggerModel?.eventListeners(object), frameworkEventListeners(object)]);
@@ -126,7 +323,8 @@ export class EventListenersView extends UI.Widget.VBox {
126
323
  }
127
324
 
128
325
  return [eventListeners, frameworkEventListenersObject.eventListeners].flatMap(
129
- listeners => listeners.map(listener => ({object, listener})));
326
+ listeners => listeners.map(
327
+ listener => ({object, listener, objectTree: EventListenersView.#createObjectTree(listener)})));
130
328
 
131
329
  function isInternalEventListener(this: Array<Platform.Constructor.Constructor<unknown>>): boolean[] {
132
330
  const isInternal = [];
@@ -138,271 +336,6 @@ export class EventListenersView extends UI.Widget.VBox {
138
336
  }
139
337
  }
140
338
 
141
- async addObjects(objects: Array<SDK.RemoteObject.RemoteObject|null>): Promise<void> {
142
- // Remove existing event listeners and reset linkifier first.
143
- const eventTypes = this.treeOutline.rootElement().children();
144
- for (const eventType of eventTypes) {
145
- eventType.removeChildren();
146
- }
147
- this.#linkifier.reset();
148
-
149
- const listeners = await EventListenersView.#loadListeners(objects.filter((o): o is NonNullable<typeof o> => !!o));
150
-
151
- for (const [type, groupedListeners] of listeners) {
152
- const treeItem = this.getOrCreateTreeElementForType(type);
153
- for (const {object, listener} of groupedListeners) {
154
- treeItem.addObjectEventListener(listener, object);
155
- }
156
- }
157
-
158
- this.addEmptyHolderIfNeeded();
159
- this.eventListenersArrivedForTest();
160
- }
161
-
162
- showFrameworkListeners(showFramework: boolean, showPassive: boolean, showBlocking: boolean): void {
163
- const eventTypes = this.treeOutline.rootElement().children();
164
- for (const eventType of eventTypes) {
165
- let hiddenEventType = true;
166
- for (const listenerElement of eventType.children()) {
167
- const objectListenerElement = listenerElement as ObjectEventListenerBar;
168
- const listenerOrigin = objectListenerElement.eventListener().origin();
169
- let hidden = false;
170
- if (listenerOrigin === SDK.DOMDebuggerModel.EventListener.Origin.FRAMEWORK_USER && !showFramework) {
171
- hidden = true;
172
- }
173
- if (listenerOrigin === SDK.DOMDebuggerModel.EventListener.Origin.FRAMEWORK && showFramework) {
174
- hidden = true;
175
- }
176
- if (!showPassive && objectListenerElement.eventListener().passive()) {
177
- hidden = true;
178
- }
179
- if (!showBlocking && !objectListenerElement.eventListener().passive()) {
180
- hidden = true;
181
- }
182
- objectListenerElement.hidden = hidden;
183
- hiddenEventType = hiddenEventType && hidden;
184
- }
185
- eventType.hidden = hiddenEventType;
186
- }
187
- }
188
-
189
- private getOrCreateTreeElementForType(type: string): EventListenersTreeElement {
190
- let treeItem = this.#treeItemMap.get(type);
191
- if (!treeItem) {
192
- treeItem = new EventListenersTreeElement(type, this.#linkifier, this.changeCallback);
193
- this.#treeItemMap.set(type, treeItem);
194
- treeItem.hidden = true;
195
- this.treeOutline.appendChild(treeItem);
196
- }
197
- this.emptyHolder.classList.add('hidden');
198
- return treeItem;
199
- }
200
-
201
- addEmptyHolderIfNeeded(): void {
202
- let allHidden = true;
203
- let firstVisibleChild: UI.TreeOutline.TreeElement|null = null;
204
- for (const eventType of this.treeOutline.rootElement().children()) {
205
- eventType.hidden = !eventType.firstChild();
206
- allHidden = allHidden && eventType.hidden;
207
- if (!firstVisibleChild && !eventType.hidden) {
208
- firstVisibleChild = eventType;
209
- }
210
- }
211
- if (allHidden && this.emptyHolder.classList.contains('hidden')) {
212
- this.emptyHolder.classList.remove('hidden');
213
- }
214
- if (firstVisibleChild) {
215
- firstVisibleChild.select(true /* omitFocus */);
216
- }
217
-
218
- this.treeOutline.setFocusable(Boolean(firstVisibleChild));
219
- }
220
-
221
339
  private eventListenersArrivedForTest(): void {
222
340
  }
223
341
  }
224
-
225
- export class EventListenersTreeElement extends UI.TreeOutline.TreeElement {
226
- override toggleOnClick: boolean;
227
- private readonly linkifier: Components.Linkifier.Linkifier;
228
- private readonly changeCallback: () => void;
229
- constructor(type: string, linkifier: Components.Linkifier.Linkifier, changeCallback: () => void) {
230
- super(type);
231
- this.toggleOnClick = true;
232
- this.linkifier = linkifier;
233
- this.changeCallback = changeCallback;
234
- UI.ARIAUtils.setLabel(this.listItemElement, `${type}, event listener`);
235
- }
236
-
237
- static comparator(element1: UI.TreeOutline.TreeElement, element2: UI.TreeOutline.TreeElement): number {
238
- if (element1.title === element2.title) {
239
- return 0;
240
- }
241
- return element1.title > element2.title ? 1 : -1;
242
- }
243
-
244
- addObjectEventListener(eventListener: SDK.DOMDebuggerModel.EventListener,
245
- object: SDK.RemoteObject.RemoteObject): void {
246
- const treeElement = new ObjectEventListenerBar(eventListener, object, this.linkifier, this.changeCallback);
247
- this.appendChild(treeElement as UI.TreeOutline.TreeElement);
248
- }
249
- }
250
-
251
- export class ObjectEventListenerBar extends UI.TreeOutline.TreeElement {
252
- #eventListener: SDK.DOMDebuggerModel.EventListener;
253
- editable: boolean;
254
- private readonly changeCallback: () => void;
255
- private valueTitle?: Element;
256
- constructor(eventListener: SDK.DOMDebuggerModel.EventListener, object: SDK.RemoteObject.RemoteObject,
257
- linkifier: Components.Linkifier.Linkifier, changeCallback: () => void) {
258
- super('', true);
259
- this.#eventListener = eventListener;
260
- this.editable = false;
261
- this.setTitle(object, linkifier);
262
- this.changeCallback = changeCallback;
263
- }
264
-
265
- override async onpopulate(): Promise<void> {
266
- const properties = [];
267
- const eventListener = this.#eventListener;
268
- const runtimeModel = eventListener.domDebuggerModel().runtimeModel();
269
- properties.push(new ObjectUI.ObjectPropertiesSection.ObjectTreeNode(
270
- runtimeModel.createRemotePropertyFromPrimitiveValue('useCapture', eventListener.useCapture()), undefined, {
271
- readOnly: false,
272
- propertiesMode: ObjectUI.ObjectPropertiesSection.ObjectPropertiesMode.OWN_AND_INTERNAL_AND_INHERITED,
273
- }));
274
- properties.push(new ObjectUI.ObjectPropertiesSection.ObjectTreeNode(
275
- runtimeModel.createRemotePropertyFromPrimitiveValue('passive', eventListener.passive()), undefined, {
276
- readOnly: false,
277
- propertiesMode: ObjectUI.ObjectPropertiesSection.ObjectPropertiesMode.OWN_AND_INTERNAL_AND_INHERITED,
278
- }));
279
- properties.push(new ObjectUI.ObjectPropertiesSection.ObjectTreeNode(
280
- runtimeModel.createRemotePropertyFromPrimitiveValue('once', eventListener.once()), undefined, {
281
- readOnly: false,
282
- propertiesMode: ObjectUI.ObjectPropertiesSection.ObjectPropertiesMode.OWN_AND_INTERNAL_AND_INHERITED,
283
- }));
284
- if (typeof eventListener.handler() !== 'undefined') {
285
- properties.push(new ObjectUI.ObjectPropertiesSection.ObjectTreeNode(
286
- new SDK.RemoteObject.RemoteObjectProperty('handler', eventListener.handler()), undefined, {
287
- readOnly: false,
288
- propertiesMode: ObjectUI.ObjectPropertiesSection.ObjectPropertiesMode.OWN_AND_INTERNAL_AND_INHERITED,
289
- }));
290
- }
291
- ObjectUI.ObjectPropertiesSection.ObjectPropertyTreeElement.populateWithProperties(this, {properties}, true, true,
292
- undefined);
293
- }
294
-
295
- private setTitle(object: SDK.RemoteObject.RemoteObject, linkifier: Components.Linkifier.Linkifier): void {
296
- const title = this.listItemElement.createChild('span', 'event-listener-details');
297
-
298
- const propertyValue = ObjectUI.ObjectPropertiesSection.renderPropertyValue(
299
- object, /* wasThrown */ false, /* showPreview */ false, linkifier, /* isSyntheticProperty */ false,
300
- /* variableName */ undefined, /* includeNullOrUndefined */ undefined, /* useCustomPreview */ false, element => {
301
- this.valueTitle = element;
302
- });
303
- // eslint-disable-next-line @devtools/no-lit-render-outside-of-view
304
- render(propertyValue, title);
305
-
306
- if (this.#eventListener.canRemove()) {
307
- const deleteButton = new Buttons.Button.Button();
308
- deleteButton.data = {
309
- variant: Buttons.Button.Variant.ICON,
310
- size: Buttons.Button.Size.MICRO,
311
- iconName: 'bin',
312
- jslogContext: 'delete-event-listener',
313
- };
314
- UI.Tooltip.Tooltip.install(deleteButton, i18nString(UIStrings.deleteEventListener));
315
- deleteButton.addEventListener('click', event => {
316
- this.removeListener();
317
- event.consume();
318
- }, false);
319
- title.appendChild(deleteButton);
320
- }
321
-
322
- if (this.#eventListener.isScrollBlockingType() && this.#eventListener.canTogglePassive()) {
323
- const passiveButton = title.createChild('button', 'event-listener-button');
324
- passiveButton.textContent = i18nString(UIStrings.togglePassive);
325
- passiveButton.setAttribute('jslog', `${VisualLogging.action('passive').track({click: true})}`);
326
- UI.Tooltip.Tooltip.install(passiveButton, i18nString(UIStrings.toggleWhetherEventListenerIs));
327
- passiveButton.addEventListener('click', event => {
328
- this.togglePassiveListener();
329
- event.consume();
330
- }, false);
331
- title.appendChild(passiveButton);
332
- }
333
-
334
- const subtitle = title.createChild('span', 'event-listener-tree-subtitle');
335
- const linkElement = linkifier.linkifyRawLocation(this.#eventListener.location(), this.#eventListener.sourceURL(),
336
- undefined, {tabStop: true});
337
- subtitle.appendChild(linkElement);
338
-
339
- this.listItemElement.addEventListener('contextmenu', event => {
340
- const menu = new UI.ContextMenu.ContextMenu(event);
341
- if (event.target !== linkElement) {
342
- menu.appendApplicableItems(linkElement);
343
- }
344
- if (object.subtype === 'node') {
345
- menu.defaultSection().appendItem(i18nString(UIStrings.openInElementsPanel),
346
- () => Common.Revealer.reveal(object), {jslogContext: 'reveal-in-elements'});
347
- }
348
- menu.defaultSection().appendItem(
349
- i18nString(UIStrings.deleteEventListener), this.removeListener.bind(this),
350
- {disabled: !this.#eventListener.canRemove(), jslogContext: 'delete-event-listener'});
351
- menu.defaultSection().appendCheckboxItem(i18nString(UIStrings.passive), this.togglePassiveListener.bind(this), {
352
- checked: this.#eventListener.passive(),
353
- disabled: !this.#eventListener.canTogglePassive(),
354
- jslogContext: 'passive',
355
- });
356
- void menu.show();
357
- });
358
- }
359
-
360
- private removeListener(): void {
361
- this.removeListenerBar();
362
- void this.#eventListener.remove();
363
- }
364
-
365
- private togglePassiveListener(): void {
366
- void this.#eventListener.togglePassive().then(() => this.changeCallback());
367
- }
368
-
369
- private removeListenerBar(): void {
370
- const parent = this.parent;
371
- if (!parent) {
372
- return;
373
- }
374
- parent.removeChild(this);
375
- if (!parent.childCount()) {
376
- parent.collapse();
377
- }
378
- let allHidden = true;
379
- for (const child of parent.children()) {
380
- if (!child.hidden) {
381
- allHidden = false;
382
- }
383
- }
384
- parent.hidden = allHidden;
385
- }
386
-
387
- eventListener(): SDK.DOMDebuggerModel.EventListener {
388
- return this.#eventListener;
389
- }
390
-
391
- override onenter(): boolean {
392
- if (this.valueTitle) {
393
- (this.valueTitle as HTMLElement).click();
394
- return true;
395
- }
396
-
397
- return false;
398
- }
399
-
400
- override ondelete(): boolean {
401
- if (this.#eventListener.canRemove()) {
402
- this.removeListener();
403
- return true;
404
- }
405
-
406
- return false;
407
- }
408
- }
@@ -87,7 +87,7 @@ interface SerializableSettings {
87
87
 
88
88
  export class LinearMemoryInspectorController extends SDK.TargetManager.SDKModelObserver<SDK.RuntimeModel.RuntimeModel>
89
89
  implements Common.Revealer.Revealer<SDK.RemoteObject.LinearMemoryInspectable>,
90
- UI.ContextMenu.Provider<ObjectUI.ObjectPropertiesSection.ObjectPropertyTreeElement> {
90
+ UI.ContextMenu.Provider<ObjectUI.ObjectPropertiesSection.ObjectTreeNode> {
91
91
  #paneInstance = LinearMemoryInspectorPane.instance();
92
92
  #bufferIdToRemoteObject = new Map<string, SDK.RemoteObject.RemoteObject>();
93
93
  #bufferIdToHighlightInfo = new Map<string, LinearMemoryInspectorComponents.LinearMemoryViewerUtils.HighlightInfo>();
@@ -315,12 +315,11 @@ export class LinearMemoryInspectorController extends SDK.TargetManager.SDKModelO
315
315
  void UI.ViewManager.ViewManager.instance().showView('linear-memory-inspector', omitFocus);
316
316
  }
317
317
 
318
- appendApplicableItems(
319
- _event: Event, contextMenu: UI.ContextMenu.ContextMenu,
320
- target: ObjectUI.ObjectPropertiesSection.ObjectPropertyTreeElement): void {
321
- if (target.property.object?.isLinearMemoryInspectable()) {
322
- const expression = target.path();
323
- const object = target.property.object;
318
+ appendApplicableItems(_event: Event, contextMenu: UI.ContextMenu.ContextMenu,
319
+ target: ObjectUI.ObjectPropertiesSection.ObjectTreeNode): void {
320
+ if (target.object?.isLinearMemoryInspectable()) {
321
+ const expression = target.path;
322
+ const object = target.object;
324
323
  contextMenu.debugSection().appendItem(
325
324
  i18nString(UIStrings.openInMemoryInspectorPanel),
326
325
  this.reveal.bind(this, new SDK.RemoteObject.LinearMemoryInspectable(object, expression)),
@@ -29,7 +29,11 @@
29
29
  justify-content: center;
30
30
  }
31
31
 
32
- .navigator-widget ~ devtools-linear-memory-inspector-viewer {
32
+ .navigator-widget {
33
+ flex: none;
34
+ }
35
+
36
+ .navigator-widget + devtools-linear-memory-inspector-viewer {
33
37
  margin-top: var(--sys-size-6);
34
38
  }
35
39
 
@@ -52,7 +52,7 @@ UI.ContextMenu.registerProvider({
52
52
  },
53
53
  contextTypes() {
54
54
  return [
55
- ObjectUI.ObjectPropertiesSection.ObjectPropertyTreeElement,
55
+ ObjectUI.ObjectPropertiesSection.ObjectTreeNode,
56
56
  ];
57
57
  },
58
58
  });
@@ -58,6 +58,14 @@ const UIStrings = {
58
58
  * @description Label for a textbox that sets the packet loss percentage for real-time networks in the throttling settings tab.
59
59
  */
60
60
  packetLoss: 'Packet Loss',
61
+ /**
62
+ * @description Label for a textbox that sets the low-tier mobile device CPU throttling in the throttling settings tab.
63
+ */
64
+ calibratedLowTierMobile: 'Low-tier mobile device',
65
+ /**
66
+ * @description Label for a textbox that sets the mid-tier mobile device CPU throttling in the throttling settings tab.
67
+ */
68
+ calibratedMidTierMobile: 'Mid-tier mobile device',
61
69
  /**
62
70
  * @description Label for a textbox that sets the maximum packet queue length for real-time networks in the throttling settings tab.
63
71
  */
@@ -241,11 +249,11 @@ export class CPUThrottlingCard {
241
249
  descriptionEl.textContent = i18nString(UIStrings.cpuCalibrationDescription);
242
250
 
243
251
  this.lowTierMobileDeviceEl = this.element.createChild('div', 'cpu-preset-section');
244
- this.lowTierMobileDeviceEl.append('Low-tier mobile device');
252
+ this.lowTierMobileDeviceEl.append(i18nString(UIStrings.calibratedLowTierMobile));
245
253
  this.lowTierMobileDeviceEl.createChild('div', 'cpu-preset-result');
246
254
 
247
255
  this.midTierMobileDeviceEl = this.element.createChild('div', 'cpu-preset-section');
248
- this.midTierMobileDeviceEl.append('Mid-tier mobile device');
256
+ this.midTierMobileDeviceEl.append(i18nString(UIStrings.calibratedMidTierMobile));
249
257
  this.midTierMobileDeviceEl.createChild('div', 'cpu-preset-result');
250
258
 
251
259
  this.calibrateEl = this.element.createChild('div', 'cpu-preset-section cpu-preset-calibrate');