chrome-devtools-frontend 1.0.1701636 → 1.0.1702515

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 (78) hide show
  1. package/eslint.config.mjs +3 -1
  2. package/front_end/core/host/UserMetricsEnums.ts +2 -1
  3. package/front_end/core/root/ExperimentNames.ts +1 -0
  4. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +2 -7
  5. package/front_end/devtools_compatibility.js +2 -1
  6. package/front_end/entrypoints/main/MainImpl.ts +8 -0
  7. package/front_end/generated/InspectorBackendCommands.ts +3 -3
  8. package/front_end/generated/protocol.ts +0 -3
  9. package/front_end/models/ai_assistance/AiAgent2.ts +13 -1
  10. package/front_end/models/ai_assistance/AiConversation.ts +1 -1
  11. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +13 -19
  12. package/front_end/models/change_tracker/ChangeTracker.ts +5 -64
  13. package/front_end/models/comment_manager/CommentManager.ts +3 -5
  14. package/front_end/models/comment_manager/CommentThread.ts +30 -13
  15. package/front_end/models/issues_manager/CookieDeprecationMetadataIssue.ts +6 -7
  16. package/front_end/models/issues_manager/DeprecationIssue.ts +1 -1
  17. package/front_end/models/issues_manager/MarkdownIssueDescription.ts +14 -5
  18. package/front_end/models/issues_manager/SRIMessageSignatureIssue.ts +2 -4
  19. package/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantRead.md +0 -1
  20. package/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantReadOptOut.md +5 -0
  21. package/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantSet.md +0 -1
  22. package/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantSetOptOut.md +5 -0
  23. package/front_end/models/issues_manager/descriptions/deprecation.md +1 -1
  24. package/front_end/models/issues_manager/descriptions/sriValidationFailedIntegrityMismatch.md +2 -0
  25. package/front_end/models/persistence/NetworkPersistenceManager.ts +14 -2
  26. package/front_end/panels/common/CommentThreadWidget.ts +29 -10
  27. package/front_end/panels/common/CommentsOverlayWidget.ts +50 -14
  28. package/front_end/panels/common/commentThreadWidget.css +11 -0
  29. package/front_end/panels/elements/StylePropertiesSection.ts +10 -0
  30. package/front_end/panels/elements/StylePropertyTreeElement.ts +1 -1
  31. package/front_end/panels/elements/StylesSidebarPane.ts +101 -49
  32. package/front_end/panels/elements/components/CSSQuery.ts +1 -1
  33. package/front_end/panels/elements/components/cssQuery.css +4 -0
  34. package/front_end/panels/elements/elements.ts +0 -1
  35. package/front_end/panels/elements/stylesSidebarPane.css +6 -0
  36. package/front_end/panels/sources/ResourceOriginPlugin.ts +8 -3
  37. package/front_end/panels/sources/ScopeChainSidebarPane.ts +3 -4
  38. package/front_end/panels/sources/TabbedEditorContainer.ts +339 -126
  39. package/front_end/panels/sources/UISourceCodeFrame.ts +9 -0
  40. package/front_end/third_party/chromium/README.chromium +1 -1
  41. package/front_end/third_party/chromium/client-variations/ClientVariations.js +25 -96
  42. package/front_end/third_party/codemirror.next/chunk/angular.js +1 -1
  43. package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
  44. package/front_end/third_party/codemirror.next/chunk/codemirror.js.map +1 -1
  45. package/front_end/third_party/codemirror.next/chunk/cpp.js +1 -1
  46. package/front_end/third_party/codemirror.next/chunk/cpp.js.map +1 -1
  47. package/front_end/third_party/codemirror.next/chunk/java.js +1 -1
  48. package/front_end/third_party/codemirror.next/chunk/java.js.map +1 -1
  49. package/front_end/third_party/codemirror.next/chunk/legacy.js +1 -1
  50. package/front_end/third_party/codemirror.next/chunk/less.js +1 -1
  51. package/front_end/third_party/codemirror.next/chunk/less.js.map +1 -1
  52. package/front_end/third_party/codemirror.next/chunk/markdown.js +1 -1
  53. package/front_end/third_party/codemirror.next/chunk/markdown.js.map +1 -1
  54. package/front_end/third_party/codemirror.next/chunk/php.js +1 -1
  55. package/front_end/third_party/codemirror.next/chunk/php.js.map +1 -1
  56. package/front_end/third_party/codemirror.next/chunk/python.js +1 -1
  57. package/front_end/third_party/codemirror.next/chunk/python.js.map +1 -1
  58. package/front_end/third_party/codemirror.next/chunk/sass.js +1 -1
  59. package/front_end/third_party/codemirror.next/chunk/sass.js.map +1 -1
  60. package/front_end/third_party/codemirror.next/chunk/svelte.js +1 -1
  61. package/front_end/third_party/codemirror.next/chunk/svelte.js.map +1 -1
  62. package/front_end/third_party/codemirror.next/chunk/vue.js +1 -1
  63. package/front_end/third_party/codemirror.next/chunk/wast.js +1 -1
  64. package/front_end/third_party/codemirror.next/chunk/wast.js.map +1 -1
  65. package/front_end/third_party/codemirror.next/chunk/xml.js +1 -1
  66. package/front_end/third_party/codemirror.next/chunk/xml.js.map +1 -1
  67. package/front_end/third_party/codemirror.next/codemirror.next.js +1 -1
  68. package/front_end/third_party/codemirror.next/package.json +4 -1
  69. package/front_end/third_party/codemirror.next/rebuild.sh +1 -1
  70. package/front_end/ui/comments/CommentOverlayManager.ts +11 -10
  71. package/front_end/ui/components/markdown_view/MarkdownPlaceholderLitRenderer.ts +117 -0
  72. package/front_end/ui/components/markdown_view/markdown_view.ts +2 -0
  73. package/front_end/ui/legacy/Treeoutline.ts +28 -19
  74. package/front_end/ui/legacy/UIUtils.ts +1 -1
  75. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +228 -343
  76. package/front_end/ui/legacy/components/object_ui/objectPropertiesSection.css +2 -27
  77. package/mcp/mcp.ts +1 -0
  78. package/package.json +1 -1
@@ -1,7 +1,6 @@
1
1
  // Copyright 2020 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
  /*
7
6
  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
@@ -66,6 +65,7 @@ export interface ObjectPropertySearchResult extends UI.TreeOutline.TreeSearchRes
66
65
  range: TextUtils.TextRange.SourceRange;
67
66
  }
68
67
  const {widget, widgetRef} = UI.Widget;
68
+ const {ifExpanded} = UI.TreeOutline;
69
69
  const {ref, repeat, ifDefined, classMap} = Directives;
70
70
  const UIStrings = {
71
71
  /**
@@ -147,21 +147,12 @@ const UIStrings = {
147
147
  /**
148
148
  * @description Tooltip text for the button to open a memory buffer object in the Memory inspector panel.
149
149
  */
150
- openInMemoryInpector: 'Open in Memory inspector panel',
150
+ openInMemoryInspector: 'Open in Memory inspector panel',
151
151
  } as const;
152
152
  const str_ = i18n.i18n.registerUIStrings('ui/legacy/components/object_ui/ObjectPropertiesSection.ts', UIStrings);
153
153
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
154
154
  export const EXPANDABLE_MAX_DEPTH = 100;
155
155
 
156
- // TODO(crbug.com/457388389): This cache is a temporary workaround for the <devtools-tree> migration.
157
- // It can be removed once the entire ObjectPropertiesSection is fully migrated to Lit and
158
- // the legacy TreeOutline/TreeElement dependencies are removed.
159
- const topLevelNodesCache = new WeakMap<ObjectTreeNodeBase, {
160
- nodes: UI.TreeOutline.TreeElement[],
161
- listener: () => void,
162
- linkifier?: Components.Linkifier.Linkifier,
163
- }>();
164
-
165
156
  interface NodeChildren {
166
157
  properties?: ObjectTreeNode[];
167
158
  internalProperties?: ObjectTreeNode[];
@@ -502,8 +493,6 @@ export abstract class ObjectTreeNodeBase extends Common.ObjectWrapper.ObjectWrap
502
493
  }
503
494
 
504
495
  setFilter(filter: {includeNullOrUndefinedValues: boolean, regex: RegExp|null}|null): void {
505
- this.filter = filter;
506
- this.dispatchEventToListeners(ObjectTreeNodeBase.Events.FILTER_CHANGED);
507
496
  this.#walk().forEach(c => {
508
497
  c.filter = filter;
509
498
  c.dispatchEventToListeners(ObjectTreeNodeBase.Events.FILTER_CHANGED);
@@ -766,11 +755,11 @@ class ArrayGroupTreeNode extends ObjectTreeNodeBase {
766
755
 
767
756
  export class ObjectTreeNode extends ObjectTreeNodeBase {
768
757
  #path?: string;
758
+ showAllChildren: boolean = false;
769
759
  constructor(
770
760
  readonly property: SDK.RemoteObject.RemoteObjectProperty,
771
761
  parent: ObjectTreeNodeBase|undefined,
772
762
  options: ObjectTreeOptions,
773
- readonly nonSyntheticParent?: SDK.RemoteObject.RemoteObject|undefined,
774
763
  ) {
775
764
  super(parent, options);
776
765
  }
@@ -1084,8 +1073,8 @@ export function getMemoryIcon(object: SDK.RemoteObject.RemoteObject, expression?
1084
1073
  void Common.Revealer.reveal(new SDK.RemoteObject.LinearMemoryInspectable(object, expression));
1085
1074
  }}
1086
1075
  jslog=${VisualLogging.action('open-memory-inspector').track({click: true})}
1087
- title=${i18nString(UIStrings.openInMemoryInpector)}
1088
- aria-label=${i18nString(UIStrings.openInMemoryInpector)}></devtools-icon>`;
1076
+ title=${i18nString(UIStrings.openInMemoryInspector)}
1077
+ aria-label=${i18nString(UIStrings.openInMemoryInspector)}></devtools-icon>`;
1089
1078
  // clang-format on
1090
1079
  }
1091
1080
 
@@ -1253,13 +1242,21 @@ export const enum ObjectPropertiesMode {
1253
1242
  OWN_AND_INTERNAL_AND_INHERITED = 1, // Own, internal, and inherited properties
1254
1243
  }
1255
1244
 
1245
+ export interface ContextMenuHandlers {
1246
+ expandRecursively: (node: ObjectTreeNodeBase) => void;
1247
+ collapseChildren: (node: ObjectTreeNodeBase) => void;
1248
+ sortPropertiesAlphabetically: (node: ObjectTreeNodeBase) => void;
1249
+ onShowAllToggled: (node: ObjectTreeNodeBase) => void;
1250
+ }
1251
+
1252
+ interface StateHandlers extends ContextMenuHandlers {
1253
+ onShowAllProperties: (node: ObjectTreeNode) => void;
1254
+ onExpand: (node: ObjectTreeNodeBase, expanded: boolean) => void;
1255
+ }
1256
+
1256
1257
  export function populateObjectTreeContextMenu(contextMenu: UI.ContextMenu.ContextMenu,
1257
- objectOrProperty: ObjectTree|ObjectTreeNode, handlers: {
1258
- expandRecursively: (node: ObjectTreeNodeBase) => void,
1259
- collapseChildren: (node: ObjectTreeNodeBase) => void,
1260
- sortPropertiesAlphabetically: (node: ObjectTreeNodeBase) => void,
1261
- onShowAllToggled: (node: ObjectTreeNodeBase) => void,
1262
- }): void {
1258
+ objectOrProperty: ObjectTree|ObjectTreeNode,
1259
+ handlers: ContextMenuHandlers): void {
1263
1260
  contextMenu.appendApplicableItems(objectOrProperty);
1264
1261
  if (objectOrProperty instanceof ObjectTreeNode && objectOrProperty.property.symbol) {
1265
1262
  contextMenu.appendApplicableItems(objectOrProperty.property.symbol);
@@ -1314,14 +1311,13 @@ export function populateObjectTreeContextMenu(contextMenu: UI.ContextMenu.Contex
1314
1311
  {checked: objectOrProperty.includeNullOrUndefinedValues, jslogContext: 'show-all'});
1315
1312
  }
1316
1313
 
1317
- interface ObjectTreeViewInput {
1314
+ interface ObjectTreeViewInput extends StateHandlers {
1318
1315
  renderAsSubtree: boolean;
1319
1316
  objectTree?: ObjectTree;
1320
1317
  linkifier?: Components.Linkifier.Linkifier;
1321
- emptyPlaceholder?: string;
1318
+ emptyPlaceholder?: LitTemplate;
1322
1319
  skipProto: boolean;
1323
1320
  skipGettersAndSetters: boolean;
1324
- onExpand: (expanded: boolean) => void;
1325
1321
  }
1326
1322
  type ObjectTreeView = (input: ObjectTreeViewInput, output: object, target: HTMLElement) => void;
1327
1323
  const OBJECT_TREE_DEFAULT_VIEW: ObjectTreeView = (input, output, target) => {
@@ -1330,50 +1326,20 @@ const OBJECT_TREE_DEFAULT_VIEW: ObjectTreeView = (input, output, target) => {
1330
1326
  render(nothing, target);
1331
1327
  return;
1332
1328
  }
1333
- const classes = input.renderAsSubtree ? ['source-code', 'object-properties-section'] : [];
1334
- let entry = topLevelNodesCache.get(objectTree);
1335
- if (!entry || entry.linkifier !== input.linkifier || (!entry.nodes.length && objectTree.children)) {
1336
- if (entry) {
1337
- objectTree.removeEventListener(ObjectTreeNodeBase.Events.CHILDREN_CHANGED, entry.listener);
1338
- }
1339
- const nodes = Array.from(ObjectPropertyTreeElement.createNodes(
1340
- objectTree, input.skipProto, input.skipGettersAndSetters, input.linkifier, input.emptyPlaceholder));
1341
- const listener = (): void => {
1342
- topLevelNodesCache.delete(objectTree);
1343
- objectTree.removeEventListener(ObjectTreeNodeBase.Events.CHILDREN_CHANGED, listener);
1344
- };
1345
- entry = {linkifier: input.linkifier, nodes, listener};
1346
- topLevelNodesCache.set(objectTree, entry);
1347
- objectTree.addEventListener(ObjectTreeNodeBase.Events.CHILDREN_CHANGED, listener);
1348
- }
1349
1329
 
1350
- render(entry.nodes.map(node => html`<devtools-tree-wrapper .treeElement=${node}></devtools-tree-wrapper>`), target, {
1351
- container: {
1352
- classes,
1353
- interceptedListeners: {
1354
- expand: (e: Event) => input.onExpand((e as UI.TreeOutline.TreeViewElement.ExpandEvent).detail.expanded),
1355
- },
1356
- },
1330
+ const nodes = Array.from(ObjectPropertyTreeElement.createNodes(
1331
+ objectTree, input, input.skipProto, input.skipGettersAndSetters, input.linkifier, input.emptyPlaceholder));
1332
+ nodes.forEach(UI.UIUtils.HTMLElementWithLightDOMTemplate.patchLitTemplate);
1333
+
1334
+ render(nodes, target, {
1335
+ container: {classes: input.renderAsSubtree ? ['source-code', 'object-properties-section'] : []},
1357
1336
  });
1358
1337
  };
1359
1338
 
1360
- async function populateChildrenIfNeeded(node: ObjectTreeNodeBase): Promise<void> {
1361
- const children = await node.populateChildrenIfNeeded();
1362
- if (!children.arrayRanges) {
1363
- return;
1364
- }
1365
- if (children.arrayRanges.length === 1) {
1366
- await populateChildrenIfNeeded(children.arrayRanges[0]);
1367
- } else {
1368
- await Promise.all(
1369
- children.arrayRanges.filter(child => child.singular).map(child => populateChildrenIfNeeded(child)));
1370
- }
1371
- }
1372
-
1373
1339
  export class ObjectTreeWidget extends UI.Widget.Widget {
1374
1340
  #objectTree: ObjectTree|undefined = undefined;
1375
1341
  #linkifier: Components.Linkifier.Linkifier|undefined = undefined;
1376
- #emptyPlaceholder?: string;
1342
+ #emptyPlaceholder?: LitTemplate;
1377
1343
  #renderAsSubtree = false;
1378
1344
  #skipProto = false;
1379
1345
  #skipGettersAndSetters = false;
@@ -1384,9 +1350,77 @@ export class ObjectTreeWidget extends UI.Widget.Widget {
1384
1350
  this.#view = view;
1385
1351
  }
1386
1352
 
1387
- onExpand = (expanded: boolean): void => {
1388
- if (this.#objectTree) {
1389
- this.#objectTree.expanded = expanded;
1353
+ async #populateChildrenIfNeeded(node: ObjectTreeNodeBase): Promise<void> {
1354
+ const isFirstPopulation = !node.children;
1355
+ const children = await node.populateChildrenIfNeeded();
1356
+
1357
+ if (isFirstPopulation) {
1358
+ const entriesProperty = children.internalProperties?.find(({property}) => property.name === '[[Entries]]');
1359
+ if (entriesProperty) {
1360
+ entriesProperty.expanded = true;
1361
+ }
1362
+
1363
+ for (const property of children.properties ?? []) {
1364
+ const canShowProperty = property.property.getter || !property.property.isAccessorProperty();
1365
+ if (canShowProperty) {
1366
+ if (property.property.name === 'memories' && property.object?.className === 'Memories') {
1367
+ property.expanded = true;
1368
+ }
1369
+ }
1370
+ }
1371
+ }
1372
+
1373
+ for (const child of node.treeNodeChildren()) {
1374
+ child.removeEventListener(ObjectTreeNodeBase.Events.FILTER_CHANGED, this.requestUpdate, this);
1375
+ child.removeEventListener(ObjectTreeNodeBase.Events.EXPANDED_CHANGED, this.requestUpdate, this);
1376
+ child.removeEventListener(ObjectTreeNodeBase.Events.VALUE_CHANGED, this.requestUpdate, this);
1377
+ child.removeEventListener(ObjectTreeNodeBase.Events.CHILDREN_CHANGED, this.requestUpdate, this);
1378
+ child.addEventListener(ObjectTreeNodeBase.Events.FILTER_CHANGED, this.requestUpdate, this);
1379
+ child.addEventListener(ObjectTreeNodeBase.Events.EXPANDED_CHANGED, this.requestUpdate, this);
1380
+ child.addEventListener(ObjectTreeNodeBase.Events.VALUE_CHANGED, this.requestUpdate, this);
1381
+ child.addEventListener(ObjectTreeNodeBase.Events.CHILDREN_CHANGED, this.requestUpdate, this);
1382
+ if (child.expanded) {
1383
+ await this.#populateChildrenIfNeeded(child);
1384
+ }
1385
+ }
1386
+
1387
+ if (!children.arrayRanges) {
1388
+ return;
1389
+ }
1390
+ if (children.arrayRanges.length === 1) {
1391
+ await this.#populateChildrenIfNeeded(children.arrayRanges[0]);
1392
+ } else {
1393
+ await Promise.all(
1394
+ children.arrayRanges.filter(child => child.singular).map(child => this.#populateChildrenIfNeeded(child)));
1395
+ }
1396
+ }
1397
+
1398
+ onExpand = (node: ObjectTreeNodeBase, expanded: boolean): void => {
1399
+ if (node.expanded !== expanded) {
1400
+ node.expanded = expanded;
1401
+ this.requestUpdate();
1402
+ }
1403
+ };
1404
+ expandRecursively = (node: ObjectTreeNodeBase): void => {
1405
+ void node.expandRecursively(EXPANDABLE_MAX_DEPTH);
1406
+ this.requestUpdate();
1407
+ };
1408
+ collapseChildren = (node: ObjectTreeNodeBase): void => {
1409
+ node.collapseRecursively();
1410
+ this.requestUpdate();
1411
+ };
1412
+ sortPropertiesAlphabetically = (node: ObjectTreeNodeBase): void => {
1413
+ node.sortPropertiesAlphabetically = !node.sortPropertiesAlphabetically;
1414
+ this.requestUpdate();
1415
+ };
1416
+ onShowAllToggled = (node: ObjectTreeNodeBase): void => {
1417
+ node.includeNullOrUndefinedValues = !node.includeNullOrUndefinedValues;
1418
+ this.requestUpdate();
1419
+ };
1420
+ onShowAllProperties = (node: ObjectTreeNode): void => {
1421
+ if (!node.showAllChildren) {
1422
+ node.showAllChildren = true;
1423
+ this.requestUpdate();
1390
1424
  }
1391
1425
  };
1392
1426
 
@@ -1436,11 +1470,11 @@ export class ObjectTreeWidget extends UI.Widget.Widget {
1436
1470
  this.requestUpdate();
1437
1471
  }
1438
1472
 
1439
- get emptyPlaceholder(): string|undefined {
1473
+ get emptyPlaceholder(): LitTemplate|undefined {
1440
1474
  return this.#emptyPlaceholder;
1441
1475
  }
1442
1476
 
1443
- set emptyPlaceholder(val: string) {
1477
+ set emptyPlaceholder(val: LitTemplate) {
1444
1478
  if (val === this.#emptyPlaceholder) {
1445
1479
  return;
1446
1480
  }
@@ -1462,7 +1496,7 @@ export class ObjectTreeWidget extends UI.Widget.Widget {
1462
1496
 
1463
1497
  override async performUpdate(): Promise<void> {
1464
1498
  if (this.#objectTree?.expanded) {
1465
- await populateChildrenIfNeeded(this.#objectTree);
1499
+ await this.#populateChildrenIfNeeded(this.#objectTree);
1466
1500
  }
1467
1501
  this.#view(this, {}, this.contentElement);
1468
1502
  }
@@ -1484,7 +1518,7 @@ export class ObjectTreeWidget extends UI.Widget.Widget {
1484
1518
  export function renderObjectTree(
1485
1519
  objectTree: ObjectTree,
1486
1520
  linkifier?: Components.Linkifier.Linkifier,
1487
- emptyPlaceholder?: string,
1521
+ emptyPlaceholder?: LitTemplate,
1488
1522
  ): LitTemplate|DirectiveResult {
1489
1523
  return html`<ul role="group" ${
1490
1524
  widget(ObjectTreeWidget, {objectTree, linkifier, emptyPlaceholder, renderAsSubtree: true})} ${
@@ -1840,21 +1874,40 @@ export class ObjectPropertyWidget extends UI.Widget.Widget {
1840
1874
  }
1841
1875
 
1842
1876
  set property(property: ObjectTreeNode) {
1843
- if (this.#property) {
1844
- this.#property.removeEventListener(ObjectTreeNodeBase.Events.VALUE_CHANGED, this.requestUpdate, this);
1845
- this.#property.removeEventListener(ObjectTreeNodeBase.Events.CHILDREN_CHANGED, this.requestUpdate, this);
1846
- this.#property.removeEventListener(ObjectTreeNodeBase.Events.FILTER_CHANGED, this.requestUpdate, this);
1877
+ if (property === this.#property) {
1878
+ return;
1847
1879
  }
1848
- this.#search?.removeEventListener(UI.TreeOutline.TreeSearch.Events.SEARCH_CHANGED, this.requestUpdate, this);
1880
+ this.#removePropertyListeners();
1849
1881
  this.#property = property;
1850
- this.#property.addEventListener(ObjectTreeNodeBase.Events.VALUE_CHANGED, this.requestUpdate, this);
1851
- this.#property.addEventListener(ObjectTreeNodeBase.Events.CHILDREN_CHANGED, this.requestUpdate, this);
1852
- this.#property.addEventListener(ObjectTreeNodeBase.Events.FILTER_CHANGED, this.requestUpdate, this);
1853
1882
  this.#search = property.search;
1854
- this.#search?.addEventListener(UI.TreeOutline.TreeSearch.Events.SEARCH_CHANGED, this.requestUpdate, this);
1883
+ this.#addPropertyListeners();
1855
1884
  this.requestUpdate();
1856
1885
  }
1857
1886
 
1887
+ #addPropertyListeners(): void {
1888
+ this.#property?.addEventListener(ObjectTreeNodeBase.Events.VALUE_CHANGED, this.requestUpdate, this);
1889
+ this.#property?.addEventListener(ObjectTreeNodeBase.Events.CHILDREN_CHANGED, this.requestUpdate, this);
1890
+ this.#property?.addEventListener(ObjectTreeNodeBase.Events.FILTER_CHANGED, this.requestUpdate, this);
1891
+ this.#search?.addEventListener(UI.TreeOutline.TreeSearch.Events.SEARCH_CHANGED, this.requestUpdate, this);
1892
+ }
1893
+
1894
+ #removePropertyListeners(): void {
1895
+ this.#property?.removeEventListener(ObjectTreeNodeBase.Events.VALUE_CHANGED, this.requestUpdate, this);
1896
+ this.#property?.removeEventListener(ObjectTreeNodeBase.Events.CHILDREN_CHANGED, this.requestUpdate, this);
1897
+ this.#property?.removeEventListener(ObjectTreeNodeBase.Events.FILTER_CHANGED, this.requestUpdate, this);
1898
+ this.#search?.removeEventListener(UI.TreeOutline.TreeSearch.Events.SEARCH_CHANGED, this.requestUpdate, this);
1899
+ }
1900
+
1901
+ override onDetach(): void {
1902
+ this.#removePropertyListeners();
1903
+ }
1904
+
1905
+ override wasShown(): void {
1906
+ super.wasShown();
1907
+ this.#removePropertyListeners();
1908
+ this.#addPropertyListeners();
1909
+ }
1910
+
1858
1911
  get expanded(): boolean {
1859
1912
  return this.#expanded;
1860
1913
  }
@@ -1934,94 +1987,88 @@ export class ObjectPropertyWidget extends UI.Widget.Widget {
1934
1987
  }
1935
1988
  }
1936
1989
 
1937
- class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1938
- property: ObjectTreeNode;
1939
- override toggleOnClick: boolean;
1940
- private linkifier: Components.Linkifier.Linkifier|undefined;
1941
- private readonly maxNumPropertiesToShow: number;
1942
- readonly #widget: ObjectPropertyWidget;
1943
- constructor(property: ObjectTreeNode, linkifier?: Components.Linkifier.Linkifier) {
1944
- // Pass an empty title, the title gets made later in onattach.
1945
- super();
1990
+ class ObjectPropertyTreeElement {
1991
+ static #render(property: ObjectTreeNode, linkifier: Components.Linkifier.Linkifier|undefined,
1992
+ handlers: StateHandlers): LitTemplate {
1993
+ const onContextMenu = (e: Event): void => {
1994
+ const contextMenu = new UI.ContextMenu.ContextMenu(e);
1995
+ populateObjectTreeContextMenu(contextMenu, property, handlers);
1996
+ void contextMenu.show();
1997
+ };
1946
1998
 
1947
- this.#widget = new ObjectPropertyWidget();
1948
- this.#widget.markAsRoot();
1949
- this.property = property;
1950
- this.hidden = property.isFiltered;
1951
- this.property.addEventListener(ObjectTreeNodeBase.Events.VALUE_CHANGED, this.#updateValue, this);
1952
- this.property.addEventListener(ObjectTreeNodeBase.Events.CHILDREN_CHANGED, this.#updateChildren, this);
1953
- this.property.addEventListener(ObjectTreeNodeBase.Events.FILTER_CHANGED, this.#updateFilter, this);
1954
- this.property.addEventListener(ObjectTreeNodeBase.Events.EXPANDED_CHANGED, this.#onExpandedChanged, this);
1955
- this.toggleOnClick = true;
1956
- this.linkifier = linkifier;
1957
- this.maxNumPropertiesToShow = InitialVisibleChildrenLimit;
1958
- this.listItemElement.addEventListener('contextmenu', this.contextMenuFired.bind(this), false);
1959
- this.listItemElement.dataset.objectPropertyNameForTest = property.name;
1960
- this.updateExpandable();
1961
- this.setExpandRecursively(property.name !== '[[Prototype]]');
1962
- if (property.expanded) {
1963
- this.expand();
1964
- }
1965
- }
1966
-
1967
- static async populate(
1968
- treeElement: UI.TreeOutline.TreeElement,
1969
- value: ObjectTreeNodeBase,
1970
- skipProto: boolean,
1971
- skipGettersAndSetters: boolean,
1972
- linkifier?: Components.Linkifier.Linkifier,
1973
- emptyPlaceholder?: string|null,
1974
- ): Promise<void> {
1975
- await populateChildrenIfNeeded(value);
1976
- ObjectPropertyTreeElement.populateImpl(treeElement, value, skipProto, skipGettersAndSetters, linkifier,
1977
- emptyPlaceholder);
1978
- }
1979
-
1980
- static populateImpl(
1981
- treeElement: UI.TreeOutline.TreeElement,
1982
- value: ObjectTreeNodeBase,
1983
- skipProto: boolean,
1984
- skipGettersAndSetters: boolean,
1985
- linkifier?: Components.Linkifier.Linkifier,
1986
- emptyPlaceholder?: string|null,
1987
- ): void {
1988
- for (const childNode of ObjectPropertyTreeElement.createNodes(
1989
- value, skipProto, skipGettersAndSetters, linkifier, emptyPlaceholder,
1990
- property => treeElement instanceof ObjectPropertyTreeElement &&
1991
- !isDisplayableProperty(property, treeElement.property?.property))) {
1992
- treeElement.appendChild(childNode);
1993
- }
1999
+ const onExpand = (e: UI.TreeOutline.TreeViewElement.ExpandEvent): void => {
2000
+ handlers.onExpand(property, e.detail.expanded);
2001
+ e.consume(true);
2002
+ };
2003
+ const childCount = (property.children?.properties?.length ?? 0) +
2004
+ (property.children?.internalProperties?.length ?? 0) + (property.children?.accessors?.length ?? 0) +
2005
+ (property.children?.arrayRanges?.length ?? 0);
2006
+
2007
+ const showAllChildren = childCount <= InitialVisibleChildrenLimit || property.showAllChildren;
2008
+ const children = (): Iterable<LitTemplate> => {
2009
+ const nodes = ObjectPropertyTreeElement.createNodes(property, handlers, false, false, linkifier, undefined,
2010
+ p => !isDisplayableProperty(p, property.property));
2011
+ return showAllChildren ? nodes : nodes.take(InitialVisibleChildrenLimit);
2012
+ };
2013
+
2014
+ const expandable = property.object && !property.object.customPreview() && property.object.hasChildren &&
2015
+ !property.property.wasThrown;
2016
+
2017
+ // clang-format off
2018
+ return html`<li
2019
+ ?hidden=${property.isFiltered}
2020
+ ?open=${property.expanded}
2021
+ @contextmenu=${onContextMenu}
2022
+ @expand=${onExpand}
2023
+ data-object-property-name-for-test=${property.name}
2024
+ toggle-on-click
2025
+ role=treeitem>
2026
+ ${widget(ObjectPropertyWidget, {property, linkifier, editable: !property.readOnly, expanded: property.expanded})}
2027
+ ${expandable ? html`
2028
+ <ul role=group>
2029
+ ${children()}
2030
+ ${showAllChildren ? nothing : html`
2031
+ <li role=treeitem @select=${() => handlers.onShowAllProperties(property)}>
2032
+ <div
2033
+ class=object-value-calculate-value-button
2034
+ title=${i18nString(UIStrings.showAllD, {PH1: childCount})}>
2035
+ ${i18nString(UIStrings.dots)}
2036
+ </div>
2037
+ </li>`}
2038
+ </ul>` : nothing}
2039
+ </li>`;
2040
+ // clang-format on
1994
2041
  }
1995
2042
 
1996
2043
  static *
1997
2044
  createNodes(
1998
2045
  value: ObjectTreeNodeBase,
2046
+ handlers: StateHandlers,
1999
2047
  skipProto: boolean,
2000
2048
  skipGettersAndSetters: boolean,
2001
2049
  linkifier?: Components.Linkifier.Linkifier,
2002
- emptyPlaceholder?: string|null,
2050
+ emptyPlaceholder?: LitTemplate,
2003
2051
  isNotDisplayablePropertyCallback?: (property: SDK.RemoteObject.RemoteObjectProperty) => boolean,
2004
- ): Generator<UI.TreeOutline.TreeElement> {
2052
+ ): Generator<LitTemplate> {
2005
2053
  const properties = value.children;
2006
2054
  if (!properties) {
2007
2055
  return;
2008
2056
  }
2009
2057
  if (properties.arrayRanges) {
2010
- yield* ArrayGroupingTreeElement.createNodes(properties, linkifier, isNotDisplayablePropertyCallback);
2058
+ yield* ArrayGroupingTreeElement.createNodes(properties, handlers, linkifier, isNotDisplayablePropertyCallback);
2011
2059
  } else {
2012
2060
  yield*
2013
- ObjectPropertyTreeElement.createPropertyNodes(properties, skipProto, skipGettersAndSetters, linkifier,
2014
- emptyPlaceholder, isNotDisplayablePropertyCallback);
2061
+ ObjectPropertyTreeElement.createPropertyNodes(properties, handlers, skipProto, skipGettersAndSetters,
2062
+ linkifier, emptyPlaceholder, isNotDisplayablePropertyCallback);
2015
2063
  }
2016
2064
  }
2017
2065
 
2018
2066
  static *
2019
- createPropertyNodes({properties, internalProperties, accessors, arrayRanges}: NodeChildren, skipProto: boolean,
2020
- skipGettersAndSetters: boolean, linkifier?: Components.Linkifier.Linkifier,
2021
- emptyPlaceholder?: string|null,
2067
+ createPropertyNodes({properties, internalProperties, accessors, arrayRanges}: NodeChildren,
2068
+ handlers: StateHandlers, skipProto: boolean, skipGettersAndSetters: boolean,
2069
+ linkifier?: Components.Linkifier.Linkifier, emptyPlaceholder?: LitTemplate,
2022
2070
  isNotDisplayablePropertyCallback?:
2023
- (property: SDK.RemoteObject.RemoteObjectProperty) => boolean):
2024
- Generator<UI.TreeOutline.TreeElement> {
2071
+ (property: SDK.RemoteObject.RemoteObjectProperty) => boolean): Generator<LitTemplate> {
2025
2072
  let empty = true;
2026
2073
  // Arrays with large numbers of elements are paginated into arrayRanges.
2027
2074
  // If we have array ranges, the object is not empty.
@@ -2033,11 +2080,8 @@ class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
2033
2080
 
2034
2081
  const entriesProperty = internalProperties?.find(({property}) => property.name === '[[Entries]]');
2035
2082
  if (entriesProperty) {
2036
- const treeElement = new ObjectPropertyTreeElement(entriesProperty, linkifier);
2037
- treeElement.setExpandable(true);
2038
- treeElement.expand();
2083
+ yield ObjectPropertyTreeElement.#render(entriesProperty, linkifier, handlers);
2039
2084
  empty = false;
2040
- yield treeElement;
2041
2085
  }
2042
2086
 
2043
2087
  for (const property of properties ?? []) {
@@ -2047,172 +2091,32 @@ class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
2047
2091
 
2048
2092
  const canShowProperty = property.property.getter || !property.property.isAccessorProperty();
2049
2093
  if (canShowProperty) {
2050
- const element = new ObjectPropertyTreeElement(property, linkifier);
2051
- if (property.property.name === 'memories' && property.object?.className === 'Memories') {
2052
- element.updateExpandable();
2053
- if (element.isExpandable()) {
2054
- element.expand();
2055
- }
2056
- }
2094
+ yield ObjectPropertyTreeElement.#render(property, linkifier, handlers);
2057
2095
  empty = false;
2058
- yield element;
2059
2096
  }
2060
2097
  }
2061
2098
 
2062
- for (const accessor of accessors ?? []) {
2063
- yield new ObjectPropertyTreeElement(accessor, linkifier);
2099
+ if (!skipGettersAndSetters) {
2100
+ for (const accessor of accessors ?? []) {
2101
+ yield ObjectPropertyTreeElement.#render(accessor, linkifier, handlers);
2102
+ }
2064
2103
  }
2065
2104
 
2066
2105
  for (const property of internalProperties ?? []) {
2067
- const treeElement = new ObjectPropertyTreeElement(property, linkifier);
2068
2106
  if (property.property.name === '[[Entries]]') {
2069
2107
  continue;
2070
2108
  }
2071
2109
  if (property.property.name === '[[Prototype]]' && skipProto) {
2072
2110
  continue;
2073
2111
  }
2112
+ yield ObjectPropertyTreeElement.#render(property, linkifier, handlers);
2074
2113
  empty = false;
2075
- yield treeElement;
2076
2114
  }
2077
2115
 
2078
2116
  if (empty) {
2079
- const title = document.createElement('div');
2080
- title.classList.add('gray-info-message');
2081
- title.textContent = emptyPlaceholder || i18nString(UIStrings.noProperties);
2082
- const infoElement = new UI.TreeOutline.TreeElement(title);
2083
- yield infoElement;
2084
- }
2085
- }
2086
-
2087
- static populateWithProperties(treeNode: UI.TreeOutline.TreeElement, children: NodeChildren, skipProto: boolean,
2088
- skipGettersAndSetters: boolean, linkifier?: Components.Linkifier.Linkifier,
2089
- emptyPlaceholder?: string|null): void {
2090
- for (const childNode of this.createPropertyNodes(
2091
- children, skipProto, skipGettersAndSetters, linkifier, emptyPlaceholder,
2092
- property => treeNode instanceof ObjectPropertyTreeElement &&
2093
- !isDisplayableProperty(property, treeNode.property?.property))) {
2094
- treeNode.appendChild(childNode);
2095
- }
2096
- }
2097
-
2098
- // This is called by layout tests
2099
- startEditing(): void {
2100
- this.#widget.startEditing();
2101
- }
2102
-
2103
- // This is called by layout tests
2104
- get editing(): boolean {
2105
- return this.#widget.editing;
2106
- }
2107
-
2108
- get editable(): boolean {
2109
- return this.#widget.editable;
2110
- }
2111
-
2112
- set editable(val: boolean) {
2113
- this.#widget.editable = val;
2114
- }
2115
-
2116
- // This is called by layout tests
2117
- async applyExpression(expression: string): Promise<void> {
2118
- await this.property.setValue(expression);
2119
- }
2120
-
2121
- private showAllPropertiesElementSelected(element: UI.TreeOutline.TreeElement): boolean {
2122
- this.removeChild(element);
2123
- this.children().forEach(x => {
2124
- x.hidden = false;
2125
- });
2126
- return false;
2127
- }
2128
-
2129
- private createShowAllPropertiesButton(): void {
2130
- const element = document.createElement('div');
2131
- element.classList.add('object-value-calculate-value-button');
2132
- element.textContent = i18nString(UIStrings.dots);
2133
- UI.Tooltip.Tooltip.install(element, i18nString(UIStrings.showAllD, {PH1: this.childCount()}));
2134
- const children = this.children();
2135
- for (let i = this.maxNumPropertiesToShow; i < this.childCount(); ++i) {
2136
- children[i].hidden = true;
2137
- }
2138
- const showAllPropertiesButton = new UI.TreeOutline.TreeElement(element);
2139
- showAllPropertiesButton.onselect = this.showAllPropertiesElementSelected.bind(this, showAllPropertiesButton);
2140
- this.appendChild(showAllPropertiesButton);
2141
- }
2142
-
2143
- override async onpopulate(): Promise<void> {
2144
- this.removeChildren();
2145
-
2146
- if (this.property.object) {
2147
- await ObjectPropertyTreeElement.populate(this, this.property, false, false, this.linkifier);
2148
- if (this.childCount() > this.maxNumPropertiesToShow) {
2149
- this.createShowAllPropertiesButton();
2150
- }
2151
- }
2152
- }
2153
-
2154
- override onattach(): void {
2155
- this.updateExpandable();
2156
- this.#widget.show(this.listItemElement);
2157
- this.#widget.property = this.property;
2158
- this.#widget.linkifier = this.linkifier;
2159
- this.#widget.editable = !this.property.readOnly;
2160
- }
2161
-
2162
- override onexpand(): void {
2163
- this.property.expanded = true;
2164
- this.#widget.expanded = true;
2165
- }
2166
-
2167
- override oncollapse(): void {
2168
- this.property.expanded = false;
2169
- this.#widget.expanded = false;
2170
- }
2171
-
2172
- #updateValue(): void {
2173
- this.updateExpandable();
2174
- }
2175
-
2176
- #updateChildren(): void {
2177
- this.removeChildren();
2178
- void this.onpopulate();
2179
- }
2180
-
2181
- #updateFilter(): void {
2182
- this.hidden = this.property.isFiltered;
2183
- }
2184
-
2185
- #onExpandedChanged(event: Common.EventTarget.EventTargetEvent<boolean>): void {
2186
- const expanded = event.data;
2187
- if (expanded) {
2188
- this.expand();
2189
- } else {
2190
- this.collapse();
2191
- }
2192
- }
2193
-
2194
- private contextMenuFired(event: Event): void {
2195
- const contextMenu = new UI.ContextMenu.ContextMenu(event);
2196
- populateObjectTreeContextMenu(contextMenu, this.property, {
2197
- expandRecursively: () => this.expandRecursively(EXPANDABLE_MAX_DEPTH),
2198
- collapseChildren: () => this.collapseChildren(),
2199
- sortPropertiesAlphabetically: node => {
2200
- node.sortPropertiesAlphabetically = !node.sortPropertiesAlphabetically;
2201
- },
2202
- onShowAllToggled: node => {
2203
- node.includeNullOrUndefinedValues = !node.includeNullOrUndefinedValues;
2204
- },
2205
- });
2206
-
2207
- void contextMenu.show();
2208
- }
2209
-
2210
- private updateExpandable(): void {
2211
- if (this.property.object) {
2212
- this.setExpandable(!this.property.object.customPreview() && this.property.object.hasChildren &&
2213
- !this.property.property.wasThrown);
2214
- } else {
2215
- this.setExpandable(false);
2117
+ yield html`<li role=treeitem>
2118
+ <div class=gray-info-message>${emptyPlaceholder || i18nString(UIStrings.noProperties)}</div>
2119
+ </li>`;
2216
2120
  }
2217
2121
  }
2218
2122
  }
@@ -2350,75 +2254,56 @@ function buildArrayFragment(
2350
2254
  return result;
2351
2255
  }
2352
2256
 
2353
- class ArrayGroupingTreeElement extends UI.TreeOutline.TreeElement {
2354
- override toggleOnClick: boolean;
2355
- private readonly linkifier: Components.Linkifier.Linkifier|undefined;
2356
- readonly #child: ArrayGroupTreeNode;
2357
- constructor(child: ArrayGroupTreeNode, linkifier?: Components.Linkifier.Linkifier) {
2358
- super(Platform.StringUtilities.sprintf('[%d … %d]', child.range.fromIndex, child.range.toIndex), true);
2359
- this.#child = child;
2360
- this.#child.addEventListener(ObjectTreeNodeBase.Events.CHILDREN_CHANGED, this.onpopulate, this);
2361
- this.#child.addEventListener(ObjectTreeNodeBase.Events.EXPANDED_CHANGED, this.#onExpandedChanged, this);
2362
- this.toggleOnClick = true;
2363
- this.linkifier = linkifier;
2364
- if (child.expanded) {
2365
- this.expand();
2366
- }
2367
- }
2368
-
2369
- #onExpandedChanged(event: Common.EventTarget.EventTargetEvent<boolean>): void {
2370
- const expanded = event.data;
2371
- if (expanded) {
2372
- this.expand();
2373
- } else {
2374
- this.collapse();
2375
- }
2257
+ class ArrayGroupingTreeElement {
2258
+ static #render(child: ArrayGroupTreeNode, linkifier: Components.Linkifier.Linkifier|undefined,
2259
+ handlers: StateHandlers): LitTemplate {
2260
+ const onExpand = (e: UI.TreeOutline.TreeViewElement.ExpandEvent): void => {
2261
+ handlers.onExpand(child, e.detail.expanded);
2262
+ e.consume(true);
2263
+ };
2264
+
2265
+ // clang-format off
2266
+ return html`<li
2267
+ class=object-properties-section-name
2268
+ role=treeitem
2269
+ toggle-on-click
2270
+ ?open=${child.expanded}
2271
+ @expand=${onExpand}>
2272
+ ${Platform.StringUtilities.sprintf('[%d … %d]', child.range.fromIndex, child.range.toIndex)}
2273
+ <ul role=group>
2274
+ ${ifExpanded(() => ObjectPropertyTreeElement.createNodes(child, handlers, false, false, linkifier))}
2275
+ </ul>
2276
+ </li>`;
2277
+ // clang-format on
2376
2278
  }
2377
2279
 
2378
2280
  static *
2379
- createNodes(children: NodeChildren, linkifier?: Components.Linkifier.Linkifier,
2281
+ createNodes(children: NodeChildren, handlers: StateHandlers, linkifier?: Components.Linkifier.Linkifier,
2380
2282
  isNotDisplayablePropertyCallback?: (property: SDK.RemoteObject.RemoteObjectProperty) => boolean):
2381
- Generator<UI.TreeOutline.TreeElement> {
2283
+ Generator<LitTemplate> {
2382
2284
  if (!children.arrayRanges) {
2383
2285
  return;
2384
2286
  }
2385
2287
  if (children.arrayRanges.length === 1) {
2386
2288
  yield*
2387
- ObjectPropertyTreeElement.createNodes(children.arrayRanges[0], false, false, linkifier, null,
2289
+ ObjectPropertyTreeElement.createNodes(children.arrayRanges[0], handlers, false, false, linkifier, undefined,
2388
2290
  isNotDisplayablePropertyCallback);
2389
2291
  } else {
2390
2292
  for (const child of children.arrayRanges) {
2391
2293
  if (child.singular) {
2392
2294
  yield*
2393
- ObjectPropertyTreeElement.createNodes(child, false, false, linkifier, null,
2295
+ ObjectPropertyTreeElement.createNodes(child, handlers, false, false, linkifier, undefined,
2394
2296
  isNotDisplayablePropertyCallback);
2395
2297
  } else {
2396
- yield new ArrayGroupingTreeElement(child, linkifier);
2298
+ yield ArrayGroupingTreeElement.#render(child, linkifier, handlers);
2397
2299
  }
2398
2300
  }
2399
2301
  }
2400
2302
 
2401
2303
  yield*
2402
- ObjectPropertyTreeElement.createPropertyNodes(children, false, false, linkifier, null,
2304
+ ObjectPropertyTreeElement.createPropertyNodes(children, handlers, false, false, linkifier, undefined,
2403
2305
  isNotDisplayablePropertyCallback);
2404
2306
  }
2405
-
2406
- override onexpand(): void {
2407
- this.#child.expanded = true;
2408
- }
2409
-
2410
- override oncollapse(): void {
2411
- this.#child.expanded = false;
2412
- }
2413
-
2414
- override async onpopulate(): Promise<void> {
2415
- this.removeChildren();
2416
- await ObjectPropertyTreeElement.populate(this, this.#child, false, false, this.linkifier);
2417
- }
2418
-
2419
- override onattach(): void {
2420
- this.listItemElement.classList.add('object-properties-section-name');
2421
- }
2422
2307
  }
2423
2308
 
2424
2309
  interface ExpandableTextViewInput {