chrome-devtools-frontend 1.0.1672557 → 1.0.1675430

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 (177) hide show
  1. package/.agents/skills/devtools-ux-writing-refactor/SKILL.md +26 -9
  2. package/front_end/core/common/ParsedURL.ts +5 -1
  3. package/front_end/core/common/SettingRegistration.ts +30 -34
  4. package/front_end/core/common/Settings.ts +4 -64
  5. package/front_end/core/host/UserMetrics.ts +127 -117
  6. package/front_end/core/protocol_client/PuppeteerDevToolsConnection.ts +42 -9
  7. package/front_end/core/root/Runtime.ts +14 -0
  8. package/front_end/core/sdk/NetworkManager.ts +0 -35
  9. package/front_end/core/sdk/SourceMap.ts +1 -19
  10. package/front_end/core/sdk/SourceMapManager.ts +75 -48
  11. package/front_end/core/sdk/SourceMapScopesInfo.ts +0 -62
  12. package/front_end/core/sdk/TargetManager.ts +18 -0
  13. package/front_end/devtools_compatibility.js +1 -1
  14. package/front_end/entrypoints/main/MainImpl.ts +1 -0
  15. package/front_end/foundation/Universe.ts +44 -29
  16. package/front_end/generated/InspectorBackendCommands.ts +4 -3
  17. package/front_end/generated/SupportedCSSProperties.ts +16 -1
  18. package/front_end/generated/protocol-mapping.d.ts +8 -0
  19. package/front_end/generated/protocol-proxy-api.d.ts +6 -0
  20. package/front_end/generated/protocol.ts +16 -2
  21. package/front_end/models/ai_assistance/AiSetting.ts +66 -3
  22. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +15 -5
  23. package/front_end/models/bindings/CompilerScriptMapping.ts +1 -1
  24. package/front_end/models/emulation/DeviceModeModel.ts +82 -102
  25. package/front_end/models/emulation/EmulatedDevices.ts +18 -66
  26. package/front_end/models/javascript_metadata/NativeFunctions.js +4 -4
  27. package/front_end/models/persistence/AutomaticFileSystemManager.ts +2 -2
  28. package/front_end/models/persistence/IsolatedFileSystemManager.ts +20 -29
  29. package/front_end/models/trace/ModelImpl.ts +5 -0
  30. package/front_end/models/trace/Processor.ts +5 -0
  31. package/front_end/models/trace/handlers/LayoutShiftsHandler.ts +7 -1
  32. package/front_end/models/trace/handlers/MetaHandler.ts +8 -4
  33. package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +11 -0
  34. package/front_end/models/workspace/FileManager.ts +13 -6
  35. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +11 -10
  36. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +3 -45
  37. package/front_end/panels/application/BackgroundServiceView.ts +42 -40
  38. package/front_end/panels/application/KeyValueStorageItemsView.ts +1 -0
  39. package/front_end/panels/application/WebMCPView.ts +13 -5
  40. package/front_end/panels/application/components/AdsView.ts +24 -1
  41. package/front_end/panels/application/components/adsView.css +27 -21
  42. package/front_end/panels/autofill/AutofillView.ts +12 -12
  43. package/front_end/panels/autofill/autofill-meta.ts +2 -2
  44. package/front_end/panels/common/ExtensionServer.ts +7 -1
  45. package/front_end/panels/common/common.ts +0 -1
  46. package/front_end/panels/console/ConsoleInsightTeaser.ts +7 -6
  47. package/front_end/panels/console/ConsoleViewMessage.ts +1 -1
  48. package/front_end/panels/elements/ClassesPaneWidget.ts +2 -2
  49. package/front_end/panels/elements/ElementsTreeElement.ts +602 -327
  50. package/front_end/panels/elements/ElementsTreeOutline.ts +1 -1
  51. package/front_end/panels/elements/StylesSidebarPane.ts +1 -1
  52. package/front_end/panels/elements/components/AdornerManager.ts +1 -0
  53. package/front_end/panels/emulation/AdvancedApp.ts +3 -3
  54. package/front_end/panels/emulation/DeviceModeToolbar.ts +2 -11
  55. package/front_end/panels/emulation/DeviceModeView.ts +234 -75
  56. package/front_end/panels/emulation/InspectedPagePlaceholder.ts +1 -1
  57. package/front_end/panels/emulation/deviceModeView.css +4 -21
  58. package/front_end/panels/emulation/emulation-meta.ts +4 -30
  59. package/front_end/panels/emulation/emulation.ts +0 -3
  60. package/front_end/panels/explain/components/ConsoleInsight.ts +11 -7
  61. package/front_end/panels/js_timeline/js_timeline-meta.ts +8 -8
  62. package/front_end/panels/layer_viewer/LayerDetailsView.ts +30 -30
  63. package/front_end/panels/layer_viewer/LayerTreeOutline.ts +6 -6
  64. package/front_end/panels/layer_viewer/LayerViewHost.ts +1 -1
  65. package/front_end/panels/layer_viewer/Layers3DView.ts +11 -11
  66. package/front_end/panels/layer_viewer/PaintProfilerView.ts +8 -8
  67. package/front_end/panels/layer_viewer/TransformController.ts +3 -3
  68. package/front_end/panels/layer_viewer/layer_viewer-meta.ts +11 -11
  69. package/front_end/panels/layers/LayersPanel.ts +2 -2
  70. package/front_end/panels/layers/layers-meta.ts +2 -2
  71. package/front_end/panels/lighthouse/LighthouseController.ts +3 -7
  72. package/front_end/panels/mobile_throttling/CPUThrottlingSelector.ts +313 -0
  73. package/front_end/panels/mobile_throttling/NetworkPanelIndicator.ts +0 -10
  74. package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +21 -10
  75. package/front_end/panels/mobile_throttling/ThrottlingManager.ts +1 -58
  76. package/front_end/panels/mobile_throttling/mobile_throttling.ts +2 -9
  77. package/front_end/panels/network/NetworkConfigView.ts +1 -71
  78. package/front_end/panels/network/networkConfigView.css +1 -2
  79. package/front_end/panels/profiler/HeapDetachedElementsDataGrid.ts +3 -3
  80. package/front_end/panels/profiler/HeapDetachedElementsView.ts +5 -5
  81. package/front_end/panels/profiler/HeapProfileView.ts +32 -32
  82. package/front_end/panels/profiler/HeapProfilerPanel.ts +2 -2
  83. package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +33 -37
  84. package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +26 -27
  85. package/front_end/panels/profiler/HeapSnapshotView.ts +48 -48
  86. package/front_end/panels/profiler/IsolateSelector.ts +10 -10
  87. package/front_end/panels/profiler/ModuleUIStrings.ts +25 -25
  88. package/front_end/panels/profiler/ProfileLauncherView.ts +6 -6
  89. package/front_end/panels/profiler/ProfilesPanel.ts +6 -6
  90. package/front_end/panels/profiler/WritableProfileHeader.ts +6 -6
  91. package/front_end/panels/profiler/profiler-meta.ts +7 -7
  92. package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +7 -0
  93. package/front_end/panels/recorder/RecorderPanel.ts +1 -1
  94. package/front_end/panels/settings/AISettingsTab.ts +27 -23
  95. package/front_end/panels/settings/emulation/DevicesSettingsTab.ts +1 -2
  96. package/front_end/panels/timeline/TimelineFlameChartNetworkDataProvider.ts +12 -17
  97. package/front_end/panels/timeline/TimelinePanel.ts +20 -35
  98. package/front_end/panels/timeline/components/LiveMetricsView.ts +27 -6
  99. package/front_end/panels/timeline/components/NetworkTrackWidget.ts +1 -1
  100. package/front_end/panels/timeline/components/components.ts +0 -4
  101. package/front_end/panels/timeline/components/liveMetricsView.css +7 -0
  102. package/front_end/third_party/chromium/README.chromium +1 -1
  103. package/front_end/third_party/source-map-scopes-codec/package/CONTRIBUTING.md +0 -0
  104. package/front_end/third_party/source-map-scopes-codec/package/LICENSE +0 -0
  105. package/front_end/third_party/source-map-scopes-codec/package/README.md +0 -0
  106. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts +0 -0
  107. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts.map +1 -1
  108. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts +0 -0
  109. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts.map +0 -0
  110. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts +0 -0
  111. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts.map +0 -0
  112. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts +0 -0
  113. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts.map +0 -0
  114. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts +0 -0
  115. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts.map +0 -0
  116. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts +0 -0
  117. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts.map +0 -0
  118. package/front_end/third_party/source-map-scopes-codec/package/deno.json +1 -1
  119. package/front_end/third_party/source-map-scopes-codec/package/package.json +1 -1
  120. package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js +2 -0
  121. package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js.map +1 -1
  122. package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.ts +2 -0
  123. package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js +0 -0
  124. package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js.map +0 -0
  125. package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.ts +0 -0
  126. package/front_end/third_party/source-map-scopes-codec/package/src/codec.js +0 -0
  127. package/front_end/third_party/source-map-scopes-codec/package/src/codec.js.map +0 -0
  128. package/front_end/third_party/source-map-scopes-codec/package/src/codec.ts +0 -0
  129. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js +0 -0
  130. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js.map +0 -0
  131. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.ts +0 -0
  132. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js +0 -0
  133. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js.map +0 -0
  134. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.ts +0 -0
  135. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js +0 -0
  136. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js.map +0 -0
  137. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.ts +0 -0
  138. package/front_end/third_party/source-map-scopes-codec/package/src/mod.js +0 -0
  139. package/front_end/third_party/source-map-scopes-codec/package/src/mod.js.map +0 -0
  140. package/front_end/third_party/source-map-scopes-codec/package/src/mod.ts +0 -0
  141. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.js +0 -0
  142. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.js.map +0 -0
  143. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.ts +0 -0
  144. package/front_end/third_party/source-map-scopes-codec/package/src/util.js +0 -0
  145. package/front_end/third_party/source-map-scopes-codec/package/src/util.js.map +0 -0
  146. package/front_end/third_party/source-map-scopes-codec/package/src/util.ts +0 -0
  147. package/front_end/third_party/source-map-scopes-codec/package/src/vlq.js +0 -0
  148. package/front_end/third_party/source-map-scopes-codec/package/src/vlq.js.map +0 -0
  149. package/front_end/third_party/source-map-scopes-codec/package/src/vlq.ts +0 -0
  150. package/front_end/ui/comments/CommentAnchorResolver.ts +132 -0
  151. package/front_end/ui/comments/comments.ts +9 -0
  152. package/front_end/ui/components/dialogs/ShortcutDialog.ts +2 -0
  153. package/front_end/ui/components/settings/SettingCheckbox.ts +4 -12
  154. package/front_end/ui/components/settings/settingCheckbox.css +0 -7
  155. package/front_end/ui/legacy/Treeoutline.ts +14 -14
  156. package/front_end/ui/legacy/UIUtils.ts +2 -47
  157. package/front_end/ui/legacy/Widget.ts +10 -2
  158. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +40 -0
  159. package/front_end/ui/legacy/components/settings_ui/SettingsUI.ts +1 -1
  160. package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -0
  161. package/front_end/ui/lit/Directives.ts +80 -0
  162. package/front_end/ui/lit/lit.ts +1 -0
  163. package/front_end/ui/lit/render.ts +8 -0
  164. package/front_end/ui/settings/SettingUIRegistration.ts +4 -0
  165. package/front_end/ui/visual_logging/Debugging.ts +1 -5
  166. package/front_end/ui/visual_logging/KnownContextValues.ts +3 -0
  167. package/front_end/ui/visual_logging/LoggingConfig.ts +21 -0
  168. package/front_end/ui/visual_logging/visual_logging.ts +9 -0
  169. package/mcp/mcp.ts +1 -0
  170. package/package.json +1 -1
  171. package/front_end/panels/common/ThrottlingUtils.ts +0 -51
  172. package/front_end/panels/emulation/DeviceModeWrapper.ts +0 -248
  173. package/front_end/panels/mobile_throttling/MobileThrottlingSelector.ts +0 -92
  174. package/front_end/panels/timeline/components/CPUThrottlingSelector.ts +0 -235
  175. package/front_end/panels/timeline/components/NetworkThrottlingSelector.ts +0 -245
  176. package/front_end/panels/timeline/components/cpuThrottlingSelector.css +0 -30
  177. package/front_end/panels/timeline/components/networkThrottlingSelector.css +0 -24
@@ -2,6 +2,7 @@
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
4
  /* eslint-disable @devtools/no-lit-render-outside-of-view */
5
+ /* eslint-disable @devtools/no-imperative-dom-api */
5
6
 
6
7
  /*
7
8
  * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
@@ -40,6 +41,7 @@ import * as Common from '../../core/common/common.js';
40
41
  import * as Host from '../../core/host/host.js';
41
42
  import * as i18n from '../../core/i18n/i18n.js';
42
43
  import * as Platform from '../../core/platform/platform.js';
44
+ import * as Root from '../../core/root/root.js';
43
45
  import * as SDK from '../../core/sdk/sdk.js';
44
46
  import * as TextUtils from '../../core/text_utils/text_utils.js';
45
47
  import * as Protocol from '../../generated/protocol.js';
@@ -244,6 +246,14 @@ const UIStrings = {
244
246
  * @description ARIA label for an elements tree adorner
245
247
  */
246
248
  stopForceOpenPopover: 'Stop keeping this popover open',
249
+ /**
250
+ * @description ARIA label for an elements tree adorner
251
+ */
252
+ forceShowInterest: 'Trigger interest on this element',
253
+ /**
254
+ * @description ARIA label for an elements tree adorner
255
+ */
256
+ stopForceShowInterest: 'Cancel interest on this element',
247
257
  /**
248
258
  * @description Label of the adorner for flex elements in the Elements panel
249
259
  */
@@ -426,6 +436,7 @@ export interface ViewInput {
426
436
  flexAdornerActive: boolean;
427
437
  gridAdornerActive: boolean;
428
438
  popoverAdornerActive: boolean;
439
+ interestAdornerActive: boolean;
429
440
 
430
441
  adProvenance?: Protocol.Network.AdProvenance;
431
442
  target?: SDK.Target.Target;
@@ -438,6 +449,7 @@ export interface ViewInput {
438
449
  showGridLanesAdorner: boolean;
439
450
  showMediaAdorner: boolean;
440
451
  showPopoverAdorner: boolean;
452
+ showInterestAdorner: boolean;
441
453
  showTopLayerAdorner: boolean;
442
454
  isSubgrid: boolean;
443
455
 
@@ -453,6 +465,7 @@ export interface ViewInput {
453
465
  onGridAdornerClick: (e: Event) => void;
454
466
  onMediaAdornerClick: (e: Event) => void;
455
467
  onPopoverAdornerClick: (e: Event) => void;
468
+ onInterestAdornerClick: (e: Event) => void;
456
469
  onScrollSnapAdornerClick: (e: Event) => void;
457
470
  onTopLayerAdornerClick: (e: Event) => void;
458
471
  onViewSourceAdornerClick: () => void;
@@ -562,7 +575,7 @@ function renderTitle(
562
575
  return openingTag;
563
576
  }
564
577
 
565
- if (ElementsTreeElement.canShowInlineText(node)) {
578
+ if (ElementsTreeWidget.canShowInlineText(node)) {
566
579
  const firstChild = node.firstChild;
567
580
  if (!firstChild) {
568
581
  throw new Error('ElementsTreeElement._nodeTitleInfo expects node.firstChild to be defined.');
@@ -749,6 +762,7 @@ function renderLinkifiedValue(value: string, node: SDK.DOMModel.DOMNode): Lit.Te
749
762
  text: value,
750
763
  preventClick: true,
751
764
  showColumnNumber: false,
765
+ bypassURLTrimming: true,
752
766
  onRef: link => {
753
767
  ImagePreviewPopover.setImageUrl(link, rewrittenHref);
754
768
  },
@@ -977,9 +991,9 @@ function maybeRenderAdAdorner(input: ViewInput): Lit.TemplateResult|typeof nothi
977
991
  export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLElement): void => {
978
992
  const hasAdorners = !!input.adProvenance || input.showContainerAdorner || input.showFlexAdorner ||
979
993
  input.showGridAdorner || input.showGridLanesAdorner || input.showMediaAdorner || input.showPopoverAdorner ||
980
- input.showTopLayerAdorner || input.showViewSourceAdorner || input.showScrollAdorner ||
981
- input.showScrollSnapAdorner || input.showSlotAdorner || input.showStartingStyleAdorner ||
982
- input.showCustomElementAdorner;
994
+ input.showInterestAdorner || input.showTopLayerAdorner || input.showViewSourceAdorner ||
995
+ input.showScrollAdorner || input.showScrollSnapAdorner || input.showSlotAdorner ||
996
+ input.showStartingStyleAdorner || input.showCustomElementAdorner;
983
997
  const gutterContainerClasses = {
984
998
  'has-decorations': input.decorations.length || input.descendantDecorations.length,
985
999
  'gutter-container': true,
@@ -1121,6 +1135,20 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
1121
1135
  ${adornerRef()}>
1122
1136
  <span>${ElementsComponents.AdornerManager.RegisteredAdorners.POPOVER}</span>
1123
1137
  </devtools-adorner>`: nothing}
1138
+ ${input.showInterestAdorner ? html`<devtools-adorner
1139
+ class=clickable
1140
+ role=button
1141
+ toggleable=true
1142
+ tabindex=0
1143
+ .name=${ElementsComponents.AdornerManager.RegisteredAdorners.INTEREST}
1144
+ jslog=${VisualLogging.adorner(ElementsComponents.AdornerManager.RegisteredAdorners.INTEREST).track({ click: true })}
1145
+ active=${input.interestAdornerActive}
1146
+ aria-label=${input.interestAdornerActive ? i18nString(UIStrings.stopForceShowInterest) : i18nString(UIStrings.forceShowInterest)}
1147
+ @click=${input.onInterestAdornerClick}
1148
+ @keydown=${handleAdornerKeydown(input.onInterestAdornerClick)}
1149
+ ${adornerRef()}>
1150
+ <span>${ElementsComponents.AdornerManager.RegisteredAdorners.INTEREST}</span>
1151
+ </devtools-adorner>`: nothing}
1124
1152
  ${input.showTopLayerAdorner ? html`<devtools-adorner
1125
1153
  class=clickable
1126
1154
  role=button
@@ -1210,16 +1238,16 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
1210
1238
  // clang-format on
1211
1239
  };
1212
1240
 
1213
- export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1241
+ export class ElementsTreeWidget extends UI.Widget.Widget {
1242
+ treeElement: ElementsTreeElement&{treeOutline: ElementsTreeOutline | null};
1214
1243
  nodeInternal: SDK.DOMModel.DOMNode;
1215
- override treeOutline: ElementsTreeOutline|null;
1216
1244
 
1217
1245
  private searchQuery: string|null;
1218
1246
  #expandedChildrenLimit: number;
1219
1247
  private readonly decorationsThrottler: Common.Throttler.Throttler;
1220
1248
  private inClipboard: boolean;
1221
1249
  #hovered: boolean;
1222
- private editing: EditorHandles|null;
1250
+ editing: EditorHandles|null;
1223
1251
  #editorRef?: TextEditor.TextEditor.TextEditor;
1224
1252
  // True while the Edit as HTML editor's own context menu is open, so that the
1225
1253
  // focusout caused by the menu taking focus does not commit the edit.
@@ -1231,13 +1259,12 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1231
1259
  #nodeElementToIssue = new Map<Element, IssuesManager.Issue.Issue[]>();
1232
1260
  #highlights: Range[] = [];
1233
1261
 
1234
- readonly tagTypeContext: TagTypeContext;
1235
-
1236
1262
  #adornersThrottler = new Common.Throttler.Throttler(100);
1237
1263
  #containerAdornerActive = false;
1238
1264
  #flexAdornerActive = false;
1239
1265
  #gridAdornerActive = false;
1240
1266
  #popoverAdornerActive = false;
1267
+ #interestAdornerActive = false;
1241
1268
 
1242
1269
  #scrollSnapAdornerActive = false;
1243
1270
  #startingStyleAdornerActive = false;
@@ -1248,26 +1275,20 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1248
1275
  #decorationsTooltip = '';
1249
1276
 
1250
1277
  static #adTooltipIdCounter = 0;
1251
- #adTooltipId = `ad-tooltip-${++ElementsTreeElement.#adTooltipIdCounter}`;
1278
+ #adTooltipId = `ad-tooltip-${++ElementsTreeWidget.#adTooltipIdCounter}`;
1252
1279
 
1253
1280
  #updateRecord: Elements.ElementUpdateRecord.ElementUpdateRecord|null = null;
1254
1281
 
1255
1282
  // Used to add the content to TreeElement's title element.
1256
1283
  // Relied on by web tests.
1257
- #contentElement?: HTMLElement;
1258
1284
 
1259
- constructor(node: SDK.DOMModel.DOMNode, isClosingTag?: boolean) {
1260
- // The title will be updated in onattach.
1285
+ constructor(treeElement: ElementsTreeElement) {
1261
1286
  super();
1287
+ this.treeElement = treeElement as ElementsTreeElement & {treeOutline: ElementsTreeOutline | null};
1288
+ const node = treeElement.node();
1289
+ const isClosingTag = treeElement.isClosingTag();
1262
1290
  this.nodeInternal = node;
1263
- this.treeOutline = null;
1264
- this.listItemElement.setAttribute(
1265
- 'jslog', `${VisualLogging.treeItem().parent('elementsTreeOutline').track({
1266
- keydown: 'ArrowUp|ArrowDown|ArrowLeft|ArrowRight|Backspace|Delete|Enter|Space|Home|End',
1267
- resize: true,
1268
- drag: true,
1269
- click: true,
1270
- })}`);
1291
+ this.treeElement.treeOutline = null;
1271
1292
 
1272
1293
  this.searchQuery = null;
1273
1294
  this.#expandedChildrenLimit = InitialChildrenLimit;
@@ -1278,30 +1299,10 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1278
1299
 
1279
1300
  this.editing = null;
1280
1301
 
1281
- if (isClosingTag) {
1282
- this.tagTypeContext = {tagType: TagType.CLOSING};
1283
- } else {
1284
- this.tagTypeContext = {
1285
- tagType: TagType.OPENING,
1286
- canAddAttributes: this.nodeInternal.nodeType() === Node.ELEMENT_NODE,
1287
- };
1302
+ if (!isClosingTag) {
1288
1303
  void this.#updateAdorners();
1289
1304
  }
1290
1305
  this.expandAllButtonElement = null;
1291
- this.performUpdate();
1292
-
1293
- if (this.nodeInternal.retained && !this.isClosingTag()) {
1294
- this.setLeadingIcons([
1295
- html`<devtools-icon class="extra-small" name="small-status-dot" style="color:var(--icon-error); vertical-align:middle"></devtools-icon>`,
1296
- ]);
1297
- this.listItemNode.classList.add('detached-elements-detached-node');
1298
- this.listItemNode.style.setProperty('display', '-webkit-box');
1299
- this.listItemNode.setAttribute('title', 'Retained Node');
1300
- }
1301
-
1302
- if (this.nodeInternal.detached && !this.isClosingTag()) {
1303
- this.listItemNode.setAttribute('title', 'Detached Tree Node');
1304
- }
1305
1306
  }
1306
1307
 
1307
1308
  static animateOnDOMUpdate(treeElement: ElementsTreeElement): void {
@@ -1322,7 +1323,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1322
1323
  }
1323
1324
 
1324
1325
  static canShowInlineText(node: SDK.DOMModel.DOMNode): boolean {
1325
- if (node.contentDocument() || node.templateContent() || ElementsTreeElement.visibleShadowRoots(node).length ||
1326
+ if (node.contentDocument() || node.templateContent() || ElementsTreeWidget.visibleShadowRoots(node).length ||
1326
1327
  node.hasPseudoElements()) {
1327
1328
  return false;
1328
1329
  }
@@ -1357,60 +1358,72 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1357
1358
  }
1358
1359
  }
1359
1360
 
1360
- // ClearNode param is used to clean DOM after in-place editing..
1361
- performUpdate(clearNode = false): void {
1361
+ #clearDOMNextUpdate = false;
1362
+
1363
+ override performUpdate(): void {
1362
1364
  // Skip updating when in-place editing (not HTML editing indicated by the
1363
1365
  // editorState) is happening. Doing an update would break editing
1364
1366
  // (crbug.com/515639787).
1365
1367
  if (this.editing && !this.#editorState) {
1366
1368
  return;
1367
1369
  }
1370
+ if (this.#clearDOMNextUpdate) {
1371
+ this.#clearDOMNextUpdate = false;
1372
+ Lit.render(Lit.nothing, this.contentElement, {host: this});
1373
+ }
1374
+ const isClosingTag = this.treeElement.isClosingTag();
1368
1375
  const output: ViewOutput = {};
1369
1376
  DEFAULT_VIEW({
1370
- node: !clearNode ? this.nodeInternal : null,
1371
- isClosingTag: this.isClosingTag(),
1372
- expanded: this.expanded,
1373
- isExpandable: this.isExpandable(),
1374
- isXMLMimeType: Boolean(this.treeOutline?.isXMLMimeType),
1377
+ node: this.nodeInternal,
1378
+ isClosingTag,
1379
+ expanded: this.treeElement.expanded,
1380
+ isExpandable: this.treeElement.isExpandable(),
1381
+ isXMLMimeType: Boolean(this.treeElement.treeOutline?.isXMLMimeType),
1375
1382
  updateRecord: this.#updateRecord,
1376
1383
  onHighlightSearchResults: () => this.#highlightSearchResults(),
1377
- onExpand: () => this.expand(),
1384
+ onExpand: () => this.treeElement.expand(),
1378
1385
 
1379
1386
  containerAdornerActive: this.#containerAdornerActive,
1380
1387
  adProvenance: this.nodeInternal.adProvenance(),
1381
1388
  adTooltipId: this.#adTooltipId,
1382
1389
  target: this.nodeInternal.domModel().target(),
1383
- showContainerAdorner: Boolean(this.#layout?.containerType) && !this.isClosingTag(),
1390
+ showContainerAdorner: Boolean(this.#layout?.containerType) && !isClosingTag,
1384
1391
  containerType: this.#layout?.containerType,
1385
- showFlexAdorner: Boolean(this.#layout?.isFlex) && !this.isClosingTag(),
1392
+ showFlexAdorner: Boolean(this.#layout?.isFlex) && !isClosingTag,
1386
1393
  flexAdornerActive: this.#flexAdornerActive,
1387
- showGridAdorner: Boolean(this.#layout?.isGrid) && !this.isClosingTag(),
1388
- showGridLanesAdorner: Boolean(this.#layout?.isGridLanes) && !this.isClosingTag(),
1389
- showMediaAdorner: this.node().isMediaNode() && !this.isClosingTag(),
1390
- showPopoverAdorner:
1391
- Boolean(this.node().attributes().find(attr => attr.name === 'popover')) && !this.isClosingTag(),
1392
- showTopLayerAdorner: this.node().topLayerIndex() !== -1 && !this.isClosingTag(),
1394
+ showGridAdorner: Boolean(this.#layout?.isGrid) && !isClosingTag,
1395
+ showGridLanesAdorner: Boolean(this.#layout?.isGridLanes) && !isClosingTag,
1396
+ showMediaAdorner: this.node().isMediaNode() && !isClosingTag,
1397
+ showPopoverAdorner: Boolean(this.node().attributes().find(attr => attr.name === 'popover')) && !isClosingTag,
1398
+ showInterestAdorner: Boolean(Root.Runtime.hostConfig.devToolsAllowInterestForcing?.enabled) &&
1399
+ Boolean(this.node().attributes().find(attr =>
1400
+ attr.name === 'interesttarget' || attr.name === 'interestfor')) &&
1401
+ !isClosingTag,
1402
+ showTopLayerAdorner: this.node().topLayerIndex() !== -1 && !isClosingTag,
1393
1403
  gridAdornerActive: this.#gridAdornerActive,
1394
1404
  popoverAdornerActive: this.#popoverAdornerActive,
1405
+ interestAdornerActive: this.#interestAdornerActive,
1395
1406
  isSubgrid: Boolean(this.#layout?.isSubgrid),
1396
- showViewSourceAdorner: this.nodeInternal.isRootNode() && isOpeningTag(this.tagTypeContext),
1407
+ showViewSourceAdorner: this.nodeInternal.isRootNode() && isOpeningTag(this.treeElement.tagTypeContext),
1397
1408
  showScrollAdorner: ((this.node().nodeName() === 'HTML' && this.node().ownerDocument?.isScrollable()) ||
1398
1409
  (this.node().nodeName() !== '#document' && this.node().isScrollable())) &&
1399
- !this.isClosingTag(),
1410
+ !isClosingTag,
1400
1411
  decorations: this.#decorations,
1401
- descendantDecorations: this.expanded ? [] : this.#descendantDecorations,
1412
+ descendantDecorations: this.treeElement.expanded ? [] : this.#descendantDecorations,
1402
1413
  decorationsTooltip: this.#decorationsTooltip,
1403
1414
  indent: this.computeLeftIndent(),
1404
- showScrollSnapAdorner: Boolean(this.#layout?.hasScroll) && !this.isClosingTag(),
1415
+ showScrollSnapAdorner: Boolean(this.#layout?.hasScroll) && !isClosingTag,
1405
1416
  scrollSnapAdornerActive: this.#scrollSnapAdornerActive,
1406
- showSlotAdorner: Boolean(this.nodeInternal.assignedSlot) && !this.isClosingTag(),
1407
- showCustomElementAdorner: this.node().isCustomElement() && !this.isClosingTag(),
1408
- onCustomElementAdornerClick:
1409
- this.treeOutline?.disableEdits ? () => {} : (event: Event) => void this.#onCustomElementAdornerClick(event),
1410
- showStartingStyleAdorner: this.nodeInternal.affectedByStartingStyles() && !this.isClosingTag(),
1417
+ showSlotAdorner: Boolean(this.nodeInternal.assignedSlot) && !isClosingTag,
1418
+ showCustomElementAdorner: this.node().isCustomElement() && !isClosingTag,
1419
+ onCustomElementAdornerClick: this.treeElement.treeOutline?.disableEdits ?
1420
+ () => {} :
1421
+ (event: Event) => void this.#onCustomElementAdornerClick(event),
1422
+ showStartingStyleAdorner: this.nodeInternal.affectedByStartingStyles() && !isClosingTag,
1411
1423
  startingStyleAdornerActive: this.#startingStyleAdornerActive,
1412
- onStartingStyleAdornerClick:
1413
- this.treeOutline?.disableEdits ? () => {} : (event: Event) => this.#onStartingStyleAdornerClick(event),
1424
+ onStartingStyleAdornerClick: this.treeElement.treeOutline?.disableEdits ?
1425
+ () => {} :
1426
+ (event: Event) => this.#onStartingStyleAdornerClick(event),
1414
1427
  onSlotAdornerClick:
1415
1428
  () => {
1416
1429
  if (this.nodeInternal.assignedSlot) {
@@ -1421,36 +1434,45 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1421
1434
  }
1422
1435
  },
1423
1436
  topLayerIndex: this.node().topLayerIndex(),
1424
- onViewSourceAdornerClick: this.treeOutline?.disableEdits ? () => {} : this.revealHTMLInSources.bind(this),
1437
+ onViewSourceAdornerClick: this.treeElement.treeOutline?.disableEdits ? () => {} :
1438
+ this.revealHTMLInSources.bind(this),
1425
1439
  onGutterClick: this.showContextMenu.bind(this),
1426
- onContainerAdornerClick: this.treeOutline?.disableEdits ? () => {} :
1427
- (event: Event) => this.#onContainerAdornerClick(event),
1428
- onFlexAdornerClick: this.treeOutline?.disableEdits ? () => {} : (event: Event) => this.#onFlexAdornerClick(event),
1429
- onGridAdornerClick: this.treeOutline?.disableEdits ? () => {} : (event: Event) => this.#onGridAdornerClick(event),
1430
- onMediaAdornerClick: this.treeOutline?.disableEdits ? () => {} :
1431
- (event: Event) => this.#onMediaAdornerClick(event),
1432
- onPopoverAdornerClick: this.treeOutline?.disableEdits ? () => {} :
1433
- (event: Event) => this.#onPopoverAdornerClick(event),
1434
- onScrollSnapAdornerClick:
1435
- this.treeOutline?.disableEdits ? () => {} : (event: Event) => this.#onScrollSnapAdornerClick(event),
1436
- onTopLayerAdornerClick: this.treeOutline?.disableEdits ? () => {} :
1437
- () => {
1438
- if (!this.treeOutline) {
1439
- return;
1440
- }
1441
- this.treeOutline.revealInTopLayer(this.node());
1442
- },
1440
+ onContainerAdornerClick: this.treeElement.treeOutline?.disableEdits ?
1441
+ () => {} :
1442
+ (event: Event) => this.#onContainerAdornerClick(event),
1443
+ onFlexAdornerClick:
1444
+ this.treeElement.treeOutline?.disableEdits ? () => {} : (event: Event) => this.#onFlexAdornerClick(event),
1445
+ onGridAdornerClick:
1446
+ this.treeElement.treeOutline?.disableEdits ? () => {} : (event: Event) => this.#onGridAdornerClick(event),
1447
+ onMediaAdornerClick:
1448
+ this.treeElement.treeOutline?.disableEdits ? () => {} : (event: Event) => this.#onMediaAdornerClick(event),
1449
+ onPopoverAdornerClick:
1450
+ this.treeElement.treeOutline?.disableEdits ? () => {} : (event: Event) => this.#onPopoverAdornerClick(event),
1451
+ onInterestAdornerClick:
1452
+ this.treeElement.treeOutline?.disableEdits ? () => {} : (event: Event) => this.#onInterestAdornerClick(event),
1453
+ onScrollSnapAdornerClick: this.treeElement.treeOutline?.disableEdits ?
1454
+ () => {} :
1455
+ (event: Event) => this.#onScrollSnapAdornerClick(event),
1456
+ onTopLayerAdornerClick: this.treeElement.treeOutline?.disableEdits ?
1457
+ () => {} :
1458
+ () => {
1459
+ if (!this.treeElement.treeOutline) {
1460
+ return;
1461
+ }
1462
+ this.treeElement.treeOutline.revealInTopLayer(this.node());
1463
+ },
1443
1464
  isHovered: this.#hovered,
1444
- isSelected: this.selected,
1465
+ isSelected: this.treeElement.selected,
1445
1466
  canInspect: this.node().canInspectNode(),
1446
- showAiButton: Boolean(this.#hovered || this.selected) && this.node().nodeType() === Node.ELEMENT_NODE &&
1447
- this.isAiButtonEnabled() && (this.treeOutline as ElementsTreeOutline)?.showAIButton,
1467
+ showAiButton: Boolean(this.#hovered || this.treeElement.selected) &&
1468
+ this.node().nodeType() === Node.ELEMENT_NODE && this.isAiButtonEnabled() &&
1469
+ (this.treeElement.treeOutline as ElementsTreeOutline)?.showAIButton,
1448
1470
  aiButtonTitle: this.isAiButtonEnabled() ?
1449
1471
  UI.ActionRegistry.ActionRegistry.instance().getAction('freestyler.elements-floating-button').title() :
1450
1472
  undefined,
1451
1473
  onAiButtonClick: (ev: Event) => {
1452
1474
  ev.stopPropagation();
1453
- this.select(true, false);
1475
+ this.treeElement.select(true, false);
1454
1476
  const action = UI.ActionRegistry.ActionRegistry.instance().getAction('freestyler.elements-floating-button');
1455
1477
  if (action) {
1456
1478
  void action.execute();
@@ -1459,15 +1481,52 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1459
1481
  editorState: this.#editorState,
1460
1482
  editorWidth: this.#editorWidth,
1461
1483
  },
1462
- output, this.listItemElement);
1484
+ output, this.contentElement);
1463
1485
 
1464
- this.#contentElement = output.contentElement;
1465
1486
  this.#editorRef = output.editorRef;
1466
1487
  if (this.#updateRecord) {
1467
1488
  this.#updateRecord = null;
1468
1489
  }
1469
1490
  }
1470
1491
 
1492
+ async #onCustomElementAdornerClick(event: Event): Promise<void> {
1493
+ event.stopPropagation();
1494
+ const node = this.node();
1495
+ const object = await node.resolveToObject('');
1496
+ if (!object) {
1497
+ return;
1498
+ }
1499
+ let constructorObject: SDK.RemoteObject.RemoteObject|null = null;
1500
+ try {
1501
+ const result = await object.callFunction(function(this: Element): unknown {
1502
+ const selector = this.getAttribute('is') || this.tagName.toLowerCase();
1503
+ return (typeof customElements !== 'undefined' && customElements.get(selector)) || this.constructor;
1504
+ });
1505
+ constructorObject = result.object;
1506
+ } finally {
1507
+ object.release();
1508
+ }
1509
+ if (!constructorObject) {
1510
+ return;
1511
+ }
1512
+ try {
1513
+ if (constructorObject.type === 'function') {
1514
+ const functionDetails =
1515
+ await SDK.RemoteObject.RemoteFunction.objectAsFunction(constructorObject).targetFunctionDetails();
1516
+ if (functionDetails?.location) {
1517
+ const uiLocation =
1518
+ await Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().rawLocationToUILocation(
1519
+ functionDetails.location);
1520
+ if (uiLocation) {
1521
+ void Common.Revealer.reveal(uiLocation);
1522
+ }
1523
+ }
1524
+ }
1525
+ } finally {
1526
+ constructorObject.release();
1527
+ }
1528
+ }
1529
+
1471
1530
  #onContainerAdornerClick(event: Event): void {
1472
1531
  event.stopPropagation();
1473
1532
  const node = this.node();
@@ -1542,14 +1601,14 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1542
1601
 
1543
1602
  highlightAttribute(attributeName: string): void {
1544
1603
  // If the attribute is not found, we highlight the tag name instead.
1545
- let animationElement = this.listItemElement.querySelector('.webkit-html-tag-name') ?? this.listItemElement;
1604
+ let animationElement = this.contentElement.querySelector('.webkit-html-tag-name') ?? this.element;
1546
1605
 
1547
1606
  if (this.nodeInternal.getAttribute(attributeName) !== undefined) {
1548
- const tag = this.listItemElement.getElementsByClassName('webkit-html-tag')[0];
1549
- const attributes = tag.getElementsByClassName('webkit-html-attribute');
1607
+ const tag = this.contentElement.querySelector('.webkit-html-tag');
1608
+ const attributes = tag?.getElementsByClassName('webkit-html-attribute') ?? [];
1550
1609
  for (const attribute of attributes) {
1551
1610
  const attributeElement = attribute.getElementsByClassName('webkit-html-attribute-name')[0];
1552
- if (attributeElement.textContent === attributeName) {
1611
+ if (attributeElement?.textContent === attributeName) {
1553
1612
  animationElement = attributeElement;
1554
1613
  break;
1555
1614
  }
@@ -1558,10 +1617,6 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1558
1617
  UI.UIUtils.runCSSAnimationOnce(animationElement, DOM_UPDATE_ANIMATION_CLASS_NAME);
1559
1618
  }
1560
1619
 
1561
- isClosingTag(): boolean {
1562
- return !isOpeningTag(this.tagTypeContext);
1563
- }
1564
-
1565
1620
  isDisplayContents(): boolean {
1566
1621
  return Boolean(this.#layout?.isContents);
1567
1622
  }
@@ -1570,7 +1625,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1570
1625
  return this.nodeInternal;
1571
1626
  }
1572
1627
 
1573
- isEditing(): boolean {
1628
+ get isEditing(): boolean {
1574
1629
  return Boolean(this.editing);
1575
1630
  }
1576
1631
 
@@ -1591,7 +1646,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1591
1646
  return;
1592
1647
  }
1593
1648
  this.inClipboard = inClipboard;
1594
- this.listItemElement.classList.toggle('in-clipboard', inClipboard);
1649
+ this.requestUpdate();
1595
1650
  }
1596
1651
 
1597
1652
  get hovered(): boolean {
@@ -1604,15 +1659,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1604
1659
  }
1605
1660
 
1606
1661
  this.#hovered = isHovered;
1607
-
1608
- if (this.listItemElement) {
1609
- if (isHovered) {
1610
- this.listItemElement.classList.add('hovered');
1611
- } else {
1612
- this.listItemElement.classList.remove('hovered');
1613
- }
1614
- this.performUpdate();
1615
- }
1662
+ this.requestUpdate();
1616
1663
  }
1617
1664
 
1618
1665
  addIssue(newIssue: IssuesManager.Issue.Issue): void {
@@ -1642,7 +1689,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1642
1689
  }
1643
1690
 
1644
1691
  #highlightViolatingAttr(name: string, issue: IssuesManager.Issue.Issue): void {
1645
- const tag = this.listItemElement.getElementsByClassName('webkit-html-tag')[0];
1692
+ const tag = this.contentElement.querySelectorAll('.webkit-html-tag')[0];
1646
1693
  const attributes = tag.getElementsByClassName('webkit-html-attribute');
1647
1694
  for (const attribute of attributes) {
1648
1695
  if (attribute.getElementsByClassName('webkit-html-attribute-name')[0].textContent === name) {
@@ -1654,7 +1701,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1654
1701
  }
1655
1702
 
1656
1703
  #highlightTagAsViolating(issue: IssuesManager.Issue.Issue): void {
1657
- const tagElement = this.listItemElement.getElementsByClassName('webkit-html-tag-name')[0];
1704
+ const tagElement = this.contentElement.querySelectorAll('.webkit-html-tag-name')[0];
1658
1705
  tagElement.classList.add('violating-element');
1659
1706
  this.#updateNodeElementToIssue(tagElement, issue);
1660
1707
  }
@@ -1666,7 +1713,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1666
1713
  this.#nodeElementToIssue.set(nodeElement, issues);
1667
1714
  }
1668
1715
  issues.push(issue);
1669
- this.treeOutline?.updateNodeElementToIssue(nodeElement, issues);
1716
+ this.treeElement.treeOutline?.updateNodeElementToIssue(nodeElement, issues);
1670
1717
  }
1671
1718
 
1672
1719
  removeIssue(issue: IssuesManager.Issue.Issue): void {
@@ -1692,7 +1739,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1692
1739
  }
1693
1740
 
1694
1741
  #undoHighlightViolatingAttr(name: string, issue: IssuesManager.Issue.Issue): void {
1695
- const violatingAttributes = this.listItemElement.querySelectorAll('.webkit-html-attribute-name.violating-element');
1742
+ const violatingAttributes = this.contentElement.querySelectorAll('.webkit-html-attribute-name.violating-element');
1696
1743
  for (const attributeElement of violatingAttributes) {
1697
1744
  if (attributeElement.textContent === name) {
1698
1745
  this.#removeFromNodeElementToIssue(attributeElement, issue);
@@ -1704,7 +1751,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1704
1751
  }
1705
1752
 
1706
1753
  #undoHighlightTagAsViolating(issue: IssuesManager.Issue.Issue): void {
1707
- const tagElement = this.listItemElement.getElementsByClassName('webkit-html-tag-name')[0];
1754
+ const tagElement = this.contentElement.querySelectorAll('.webkit-html-tag-name')[0];
1708
1755
  if (!tagElement) {
1709
1756
  return;
1710
1757
  }
@@ -1727,7 +1774,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1727
1774
  } else {
1728
1775
  this.#nodeElementToIssue.set(nodeElement, issues);
1729
1776
  }
1730
- this.treeOutline?.updateNodeElementToIssue(nodeElement, issues);
1777
+ this.treeElement.treeOutline?.updateNodeElementToIssue(nodeElement, issues);
1731
1778
  }
1732
1779
 
1733
1780
  expandedChildrenLimit(): number {
@@ -1739,13 +1786,13 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1739
1786
  }
1740
1787
 
1741
1788
  onTopLayerIndexChanged(): void {
1742
- this.performUpdate();
1789
+ this.requestUpdate();
1743
1790
  }
1744
1791
 
1745
- override onbind(): void {
1746
- this.performUpdate();
1747
- if (this.treeOutline && !this.isClosingTag()) {
1748
- this.treeOutline.treeElementByNode.set(this.nodeInternal, this);
1792
+ onbind(): void {
1793
+ this.requestUpdate();
1794
+ if (this.treeElement.treeOutline && !this.treeElement.isClosingTag()) {
1795
+ this.treeElement.treeOutline.treeElementByNode.set(this.nodeInternal, this.treeElement);
1749
1796
  this.nodeInternal.addEventListener(
1750
1797
  SDK.DOMModel.DOMNodeEvents.TOP_LAYER_INDEX_CHANGED, this.onTopLayerIndexChanged, this);
1751
1798
  this.nodeInternal.addEventListener(
@@ -1792,9 +1839,11 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1792
1839
  showGridLanesAdorner: false,
1793
1840
  showMediaAdorner: false,
1794
1841
  showPopoverAdorner: false,
1842
+ showInterestAdorner: false,
1795
1843
  showTopLayerAdorner: false,
1796
1844
  gridAdornerActive: false,
1797
1845
  popoverAdornerActive: false,
1846
+ interestAdornerActive: false,
1798
1847
  isSubgrid: false,
1799
1848
  showViewSourceAdorner: false,
1800
1849
  showScrollAdorner: false,
@@ -1815,6 +1864,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1815
1864
  onGridAdornerClick: () => {},
1816
1865
  onMediaAdornerClick: () => {},
1817
1866
  onPopoverAdornerClick: () => {},
1867
+ onInterestAdornerClick: () => {},
1818
1868
  onScrollSnapAdornerClick: () => {},
1819
1869
  onTopLayerAdornerClick: () => {},
1820
1870
  isHovered: false,
@@ -1829,16 +1879,17 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1829
1879
  editorState: null,
1830
1880
  editorWidth: null,
1831
1881
  },
1832
- {}, this.listItemElement);
1882
+ {}, this.contentElement);
1833
1883
  }
1834
1884
 
1835
- override onunbind(): void {
1885
+ onunbind(): void {
1836
1886
  if (this.editing) {
1837
1887
  this.editing.cancel();
1838
1888
  }
1839
1889
  this.clearView();
1840
- if (this.treeOutline && this.treeOutline.treeElementByNode.get(this.nodeInternal) === this) {
1841
- this.treeOutline.treeElementByNode.delete(this.nodeInternal);
1890
+ if (this.treeElement.treeOutline &&
1891
+ this.treeElement.treeOutline.treeElementByNode.get(this.nodeInternal) === this.treeElement) {
1892
+ this.treeElement.treeOutline.treeElementByNode.delete(this.nodeInternal);
1842
1893
  }
1843
1894
  this.nodeInternal.removeEventListener(
1844
1895
  SDK.DOMModel.DOMNodeEvents.TOP_LAYER_INDEX_CHANGED, this.onTopLayerIndexChanged, this);
@@ -1869,22 +1920,22 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1869
1920
 
1870
1921
  #onPersistentContainerQueryOverlayStateChanged(event: Common.EventTarget.EventTargetEvent<{enabled: boolean}>): void {
1871
1922
  this.#containerAdornerActive = event.data.enabled;
1872
- this.performUpdate();
1923
+ this.requestUpdate();
1873
1924
  }
1874
1925
 
1875
1926
  #onPersistentFlexContainerOverlayStateChanged(event: Common.EventTarget.EventTargetEvent<{enabled: boolean}>): void {
1876
1927
  this.#flexAdornerActive = event.data.enabled;
1877
- this.performUpdate();
1928
+ this.requestUpdate();
1878
1929
  }
1879
1930
 
1880
1931
  #onPersistentGridOverlayStateChanged(event: Common.EventTarget.EventTargetEvent<{enabled: boolean}>): void {
1881
1932
  this.#gridAdornerActive = event.data.enabled;
1882
- this.performUpdate();
1933
+ this.requestUpdate();
1883
1934
  }
1884
1935
 
1885
1936
  #onPersistentScrollSnapOverlayStateChanged(event: Common.EventTarget.EventTargetEvent<{enabled: boolean}>): void {
1886
1937
  this.#scrollSnapAdornerActive = event.data.enabled;
1887
- this.performUpdate();
1938
+ this.requestUpdate();
1888
1939
  }
1889
1940
 
1890
1941
  #onScrollSnapAdornerClick(event: Event): void {
@@ -1902,75 +1953,63 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1902
1953
  }
1903
1954
  }
1904
1955
 
1905
- override onattach(): void {
1956
+ onattach(): void {
1906
1957
  if (this.#hovered) {
1907
- this.listItemElement.classList.add('hovered');
1908
- this.performUpdate();
1958
+ this.element.classList.add('hovered');
1959
+ this.requestUpdate();
1909
1960
  }
1910
1961
 
1911
- this.updateTitle();
1912
- this.listItemElement.draggable = true;
1962
+ this.treeElement.updateTitle();
1963
+ this.element.draggable = true;
1913
1964
  }
1914
1965
 
1915
- override async onpopulate(): Promise<void> {
1916
- if (this.treeOutline) {
1917
- return await this.treeOutline.populateTreeElement(this);
1966
+ async onpopulate(): Promise<void> {
1967
+ if (this.treeElement.treeOutline) {
1968
+ return await this.treeElement.treeOutline.populateTreeElement(this.treeElement);
1918
1969
  }
1919
1970
  }
1920
1971
 
1921
- override async expandRecursively(): Promise<void> {
1922
- await this.nodeInternal.getSubtree(100, true);
1923
- await super.expandRecursively(Number.MAX_VALUE);
1924
- }
1925
-
1926
- override onexpand(): void {
1927
- if (this.isClosingTag()) {
1972
+ onexpand(): void {
1973
+ if (this.treeElement.isClosingTag()) {
1928
1974
  return;
1929
1975
  }
1930
1976
 
1931
- this.updateTitle();
1977
+ this.treeElement.updateTitle();
1932
1978
  }
1933
1979
 
1934
- override oncollapse(): void {
1935
- if (this.isClosingTag()) {
1980
+ oncollapse(): void {
1981
+ if (this.treeElement.isClosingTag()) {
1936
1982
  return;
1937
1983
  }
1938
1984
 
1939
- this.updateTitle();
1985
+ this.treeElement.updateTitle();
1940
1986
  }
1941
1987
 
1942
- override select(omitFocus?: boolean, selectedByUser?: boolean): boolean {
1943
- if (this.editing) {
1988
+ onselect(selectedByUser?: boolean): boolean {
1989
+ if (!this.treeElement.treeOutline) {
1944
1990
  return false;
1945
1991
  }
1946
- return super.select(omitFocus, selectedByUser);
1947
- }
1948
-
1949
- override onselect(selectedByUser?: boolean): boolean {
1950
- if (!this.treeOutline) {
1951
- return false;
1952
- }
1953
- this.treeOutline.suppressRevealAndSelect = true;
1954
- this.treeOutline.selectDOMNode(this.nodeInternal, selectedByUser);
1992
+ this.treeElement.treeOutline.suppressRevealAndSelect = true;
1993
+ this.treeElement.treeOutline.selectDOMNode(this.nodeInternal, selectedByUser);
1955
1994
  if (selectedByUser) {
1956
1995
  this.nodeInternal.highlight();
1957
1996
  Host.userMetrics.actionTaken(Host.UserMetrics.Action.ChangeInspectedNodeInElementsPanel);
1958
1997
  }
1959
- this.performUpdate();
1960
- this.treeOutline.suppressRevealAndSelect = false;
1998
+ this.requestUpdate();
1999
+ this.treeElement.treeOutline.suppressRevealAndSelect = false;
1961
2000
  return true;
1962
2001
  }
1963
2002
 
1964
- override ondelete(): boolean {
1965
- if (!this.treeOutline) {
2003
+ ondelete(): boolean {
2004
+ if (!this.treeElement.treeOutline) {
1966
2005
  return false;
1967
2006
  }
1968
- const startTagTreeElement = this.treeOutline.findTreeElement(this.nodeInternal);
1969
- startTagTreeElement ? (void startTagTreeElement.remove()) : (void this.remove());
2007
+ const startTagTreeElement = this.treeElement.treeOutline.findTreeElement(this.nodeInternal);
2008
+ startTagTreeElement ? (void (startTagTreeElement as ElementsTreeElement).remove()) : (void this.remove());
1970
2009
  return true;
1971
2010
  }
1972
2011
 
1973
- override onenter(): boolean {
2012
+ onenter(): boolean {
1974
2013
  // On Enter or Return start editing the first attribute
1975
2014
  // or create a new attribute on the selected element.
1976
2015
  if (this.editing) {
@@ -1983,29 +2022,17 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
1983
2022
  return true;
1984
2023
  }
1985
2024
 
1986
- override selectOnMouseDown(event: MouseEvent): void {
1987
- super.selectOnMouseDown(event);
1988
-
1989
- if (this.editing) {
1990
- return;
1991
- }
1992
-
1993
- // Prevent selecting the nearest word on double click.
1994
- if (event.detail >= 2) {
1995
- event.preventDefault();
1996
- }
1997
- }
1998
-
1999
- override ondblclick(event: Event): boolean {
2000
- if (this.editing || this.isClosingTag()) {
2025
+ ondblclick(event: Event): boolean {
2026
+ if (this.editing || this.treeElement.isClosingTag()) {
2001
2027
  return false;
2002
2028
  }
2003
- if (this.startEditingTarget((event.target as Element))) {
2029
+ const target = (event.composedPath()[0] || event.target) as Element;
2030
+ if (this.startEditingTarget(target)) {
2004
2031
  return false;
2005
2032
  }
2006
2033
 
2007
- if (this.isExpandable() && !this.expanded) {
2008
- this.expand();
2034
+ if (this.treeElement.isExpandable() && !this.treeElement.expanded) {
2035
+ this.treeElement.expand();
2009
2036
  }
2010
2037
  return false;
2011
2038
  }
@@ -2031,7 +2058,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2031
2058
  }
2032
2059
 
2033
2060
  private startEditingTarget(eventTarget: Element): boolean {
2034
- if (!this.treeOutline || this.treeOutline.selectedDOMNode() !== this.nodeInternal) {
2061
+ if (!this.treeElement.treeOutline || this.treeElement.treeOutline.selectedDOMNode() !== this.nodeInternal) {
2035
2062
  return false;
2036
2063
  }
2037
2064
 
@@ -2053,19 +2080,19 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2053
2080
 
2054
2081
  const tagName = eventTarget.enclosingNodeOrSelfWithClass('webkit-html-tag-name');
2055
2082
  if (tagName) {
2056
- return this.startEditingTagName(tagName);
2083
+ return this.treeElement.startEditingTagName(tagName);
2057
2084
  }
2058
2085
 
2059
2086
  const newAttribute = eventTarget.enclosingNodeOrSelfWithClass('add-attribute');
2060
2087
  if (newAttribute) {
2061
- return this.addNewAttribute();
2088
+ return this.treeElement.addNewAttribute();
2062
2089
  }
2063
2090
 
2064
2091
  return false;
2065
2092
  }
2066
2093
 
2067
2094
  private showContextMenu(event: Event): void {
2068
- this.treeOutline && void this.treeOutline.showContextMenu(this, event);
2095
+ this.treeElement.treeOutline && void this.treeElement.treeOutline.showContextMenu(this.treeElement, event);
2069
2096
  }
2070
2097
 
2071
2098
  private revealHTMLInSources(): void {
@@ -2081,8 +2108,9 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2081
2108
 
2082
2109
  async populateTagContextMenu(contextMenu: UI.ContextMenu.ContextMenu, event: Event): Promise<void> {
2083
2110
  // Add attribute-related actions.
2084
- const treeElement =
2085
- this.isClosingTag() && this.treeOutline ? this.treeOutline.findTreeElement(this.nodeInternal) : this;
2111
+ const treeElement = this.treeElement.isClosingTag() && this.treeElement.treeOutline ?
2112
+ this.treeElement.treeOutline.findTreeElement(this.nodeInternal) as ElementsTreeElement | null :
2113
+ this.treeElement;
2086
2114
  if (!treeElement) {
2087
2115
  return;
2088
2116
  }
@@ -2090,7 +2118,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2090
2118
  i18nString(UIStrings.addAttribute), treeElement.addNewAttribute.bind(treeElement),
2091
2119
  {jslogContext: 'add-attribute'});
2092
2120
 
2093
- const target = (event.target as Element);
2121
+ const target = (event.composedPath()[0] || event.target) as Element;
2094
2122
  const attribute = target.enclosingNodeOrSelfWithClass('webkit-html-attribute');
2095
2123
  const newAttribute = target.enclosingNodeOrSelfWithClass('add-attribute');
2096
2124
  if (attribute && !newAttribute) {
@@ -2099,7 +2127,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2099
2127
  {jslogContext: 'edit-attribute'});
2100
2128
  }
2101
2129
  await this.populateNodeContextMenu(contextMenu);
2102
- ElementsTreeElement.populateForcedPseudoStateItems(contextMenu, treeElement.node());
2130
+ ElementsTreeWidget.populateForcedPseudoStateItems(contextMenu, treeElement.node());
2103
2131
  this.populateScrollIntoView(contextMenu);
2104
2132
  contextMenu.viewSection().appendItem(i18nString(UIStrings.focus), async () => {
2105
2133
  await this.nodeInternal.focus();
@@ -2107,7 +2135,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2107
2135
  }
2108
2136
 
2109
2137
  populatePseudoElementContextMenu(contextMenu: UI.ContextMenu.ContextMenu): void {
2110
- if (this.childCount() !== 0) {
2138
+ if (this.treeElement.childCount() !== 0) {
2111
2139
  this.populateExpandRecursively(contextMenu);
2112
2140
  }
2113
2141
 
@@ -2115,9 +2143,9 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2115
2143
  }
2116
2144
 
2117
2145
  private populateExpandRecursively(contextMenu: UI.ContextMenu.ContextMenu): void {
2118
- contextMenu.viewSection().appendItem(
2119
- i18nString(UIStrings.expandRecursively), this.expandRecursively.bind(this),
2120
- {jslogContext: 'expand-recursively'});
2146
+ contextMenu.viewSection().appendItem(i18nString(UIStrings.expandRecursively),
2147
+ this.treeElement.expandRecursively.bind(this.treeElement),
2148
+ {jslogContext: 'expand-recursively'});
2121
2149
  }
2122
2150
 
2123
2151
  private populateScrollIntoView(contextMenu: UI.ContextMenu.ContextMenu): void {
@@ -2130,10 +2158,11 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2130
2158
  return UI.ActionRegistry.ActionRegistry.instance().hasAction('freestyler.elements-floating-button');
2131
2159
  }
2132
2160
 
2133
- async populateTextContextMenu(contextMenu: UI.ContextMenu.ContextMenu, textNode: Element): Promise<void> {
2161
+ async populateTextContextMenu(contextMenu: UI.ContextMenu.ContextMenu, textNode: Node): Promise<void> {
2134
2162
  if (!this.editing) {
2135
- contextMenu.editSection().appendItem(
2136
- i18nString(UIStrings.editText), this.startEditingTextNode.bind(this, textNode), {jslogContext: 'edit-text'});
2163
+ contextMenu.editSection().appendItem(i18nString(UIStrings.editText),
2164
+ this.startEditingTextNode.bind(this, textNode as Element),
2165
+ {jslogContext: 'edit-text'});
2137
2166
  }
2138
2167
  return await this.populateNodeContextMenu(contextMenu);
2139
2168
  }
@@ -2150,7 +2179,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2150
2179
 
2151
2180
  const createShortcut = UI.KeyboardShortcut.KeyboardShortcut.shortcutToString.bind(null);
2152
2181
  const modifier = UI.KeyboardShortcut.Modifiers.CtrlOrMeta.value;
2153
- const treeOutline = this.treeOutline;
2182
+ const treeOutline = this.treeElement.treeOutline;
2154
2183
  if (!treeOutline) {
2155
2184
  return;
2156
2185
  }
@@ -2353,8 +2382,10 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2353
2382
  menuItem.setShortcut(createShortcut('V', modifier));
2354
2383
 
2355
2384
  menuItem = contextMenu.debugSection().appendCheckboxItem(
2356
- i18nString(UIStrings.hideElement), treeOutline.toggleHideElement.bind(treeOutline, this.nodeInternal),
2357
- {checked: treeOutline.isToggledToHidden(this.nodeInternal), jslogContext: 'elements.hide-element'});
2385
+ i18nString(UIStrings.hideElement), treeOutline.toggleHideElement.bind(treeOutline, this.nodeInternal), {
2386
+ checked: treeOutline.isToggledToHidden(this.nodeInternal),
2387
+ jslogContext: 'elements.hide-element',
2388
+ });
2358
2389
  menuItem.setShortcut(
2359
2390
  UI.ShortcutRegistry.ShortcutRegistry.instance().shortcutTitleForAction('elements.hide-element') || '');
2360
2391
 
@@ -2364,12 +2395,13 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2364
2395
  }
2365
2396
 
2366
2397
  this.populateExpandRecursively(contextMenu);
2367
- contextMenu.viewSection().appendItem(i18nString(UIStrings.collapseChildren), this.collapseChildren.bind(this),
2398
+ contextMenu.viewSection().appendItem(i18nString(UIStrings.collapseChildren),
2399
+ this.treeElement.collapseChildren.bind(this.treeElement),
2368
2400
  {jslogContext: 'collapse-children'});
2369
2401
  contextMenu.viewSection().appendItem(i18nString(UIStrings.switchToAccessibilityTree),
2370
2402
  () => ElementsPanel.instance().toggleAccessibilityTree(),
2371
2403
  {jslogContext: 'switch-to-accessibility-tree'});
2372
- const deviceModeWrapperAction = new Emulation.DeviceModeWrapper.ActionDelegate();
2404
+ const deviceModeWrapperAction = new Emulation.DeviceModeView.ActionDelegate();
2373
2405
  contextMenu.viewSection().appendItem(
2374
2406
  i18nString(UIStrings.captureNodeScreenshot),
2375
2407
  deviceModeWrapperAction.handleAction.bind(
@@ -2387,7 +2419,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2387
2419
  }
2388
2420
 
2389
2421
  async populateProcessingElementContextMenu(contextMenu: UI.ContextMenu.ContextMenu): Promise<void> {
2390
- const treeOutline = this.treeOutline;
2422
+ const treeOutline = this.treeElement.treeOutline;
2391
2423
  if (!treeOutline) {
2392
2424
  return;
2393
2425
  }
@@ -2405,20 +2437,20 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2405
2437
  }
2406
2438
 
2407
2439
  private startEditing(): boolean|undefined {
2408
- if (!this.treeOutline || this.treeOutline.selectedDOMNode() !== this.nodeInternal) {
2440
+ if (!this.treeElement.treeOutline || this.treeElement.treeOutline.selectedDOMNode() !== this.nodeInternal) {
2409
2441
  return;
2410
2442
  }
2411
2443
 
2412
- const listItem = this.listItemElement;
2444
+ const listItem = this.element;
2413
2445
 
2414
- if (isOpeningTag(this.tagTypeContext) && this.tagTypeContext.canAddAttributes) {
2446
+ if (isOpeningTag(this.treeElement.tagTypeContext) && this.treeElement.tagTypeContext.canAddAttributes) {
2415
2447
  const attribute = listItem.getElementsByClassName('webkit-html-attribute')[0];
2416
2448
  if (attribute) {
2417
2449
  return this.startEditingAttribute(
2418
2450
  attribute, attribute.getElementsByClassName('webkit-html-attribute-value')[0]);
2419
2451
  }
2420
2452
 
2421
- return this.addNewAttribute();
2453
+ return this.treeElement.addNewAttribute();
2422
2454
  }
2423
2455
 
2424
2456
  if (this.nodeInternal.nodeType() === Node.TEXT_NODE) {
@@ -2429,22 +2461,22 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2429
2461
  }
2430
2462
 
2431
2463
  if (this.nodeInternal.nodeType() === Node.PROCESSING_INSTRUCTION_NODE) {
2432
- return this.startEditingProcessingInstructionValue();
2464
+ return this.treeElement.startEditingProcessingInstructionValue();
2433
2465
  }
2434
2466
 
2435
2467
  return;
2436
2468
  }
2437
2469
 
2438
- private startEditingProcessingInstructionValue(): boolean|undefined {
2470
+ startEditingProcessingInstructionValue(): boolean|undefined {
2439
2471
  const processingInstructionValue =
2440
- this.listItemElement.getElementsByClassName('webkit-html-processing-instruction-value')[0];
2472
+ this.contentElement.querySelectorAll('.webkit-html-processing-instruction-value')[0];
2441
2473
  if (processingInstructionValue) {
2442
2474
  return this.startEditingTextNode(processingInstructionValue);
2443
2475
  }
2444
2476
  return;
2445
2477
  }
2446
2478
 
2447
- private addNewAttribute(): boolean {
2479
+ addNewAttribute(): boolean {
2448
2480
  // Cannot just convert the textual html into an element without
2449
2481
  // a parent node. Use a temporary span container for the HTML.
2450
2482
  const container = document.createDocumentFragment();
@@ -2455,14 +2487,14 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2455
2487
  attr.style.marginRight = '2px'; // overrides the .editing margin rule
2456
2488
  attr.setAttribute('jslog', `${VisualLogging.value('new-attribute').track({change: true, resize: true})}`);
2457
2489
 
2458
- const tag = this.listItemElement.getElementsByClassName('webkit-html-tag')[0];
2490
+ const tag = this.contentElement.querySelectorAll('.webkit-html-tag')[0];
2459
2491
  this.insertInLastAttributePosition(tag, attr);
2460
2492
  attr.scrollIntoViewIfNeeded(true);
2461
2493
  return this.startEditingAttribute(attr, attr);
2462
2494
  }
2463
2495
 
2464
2496
  triggerEditAttribute(attributeName: string): boolean|undefined {
2465
- const attributeElements = this.listItemElement.getElementsByClassName('webkit-html-attribute-name');
2497
+ const attributeElements = this.contentElement.querySelectorAll('.webkit-html-attribute-name');
2466
2498
  for (let i = 0, len = attributeElements.length; i < len; ++i) {
2467
2499
  if (attributeElements[i].textContent === attributeName) {
2468
2500
  for (let elem: (ChildNode|null) = attributeElements[i].nextSibling; elem; elem = elem.nextSibling) {
@@ -2480,7 +2512,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2480
2512
  }
2481
2513
 
2482
2514
  private startEditingAttribute(attribute: Element, elementForSelection: Element): boolean {
2483
- console.assert(this.listItemElement.isAncestor(attribute));
2515
+ console.assert(this.element.isAncestor(attribute));
2484
2516
 
2485
2517
  if (UI.UIUtils.isBeingEdited(attribute)) {
2486
2518
  return true;
@@ -2549,7 +2581,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2549
2581
 
2550
2582
  this.updateEditorHandles(attribute, config);
2551
2583
 
2552
- const componentSelection = this.listItemElement.getComponentSelection();
2584
+ const componentSelection = this.element.getComponentSelection();
2553
2585
  componentSelection?.selectAllChildren(elementForSelection);
2554
2586
 
2555
2587
  return true;
@@ -2574,15 +2606,15 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2574
2606
  const config = new UI.InplaceEditor.Config(
2575
2607
  this.textNodeEditingCommitted.bind(this, textNode), this.editingCancelled.bind(this), null);
2576
2608
  this.updateEditorHandles(textNodeElement, config);
2577
- const componentSelection = this.listItemElement.getComponentSelection();
2609
+ const componentSelection = this.element.getComponentSelection();
2578
2610
  componentSelection?.selectAllChildren(textNodeElement);
2579
2611
 
2580
2612
  return true;
2581
2613
  }
2582
2614
 
2583
- private startEditingTagName(tagNameElement?: Element): boolean {
2615
+ startEditingTagName(tagNameElement?: Element): boolean {
2584
2616
  if (!tagNameElement) {
2585
- tagNameElement = this.listItemElement.getElementsByClassName('webkit-html-tag-name')[0];
2617
+ tagNameElement = this.contentElement.querySelectorAll('.webkit-html-tag-name')[0];
2586
2618
  if (!tagNameElement) {
2587
2619
  return false;
2588
2620
  }
@@ -2614,7 +2646,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2614
2646
  };
2615
2647
 
2616
2648
  function editingCommitted(
2617
- this: ElementsTreeElement,
2649
+ this: ElementsTreeWidget,
2618
2650
  element: Element,
2619
2651
  newTagName: string,
2620
2652
  oldText: string|null,
@@ -2629,7 +2661,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2629
2661
  this.tagNameEditingCommitted(element, newTagName, oldText, tagName, moveDirection);
2630
2662
  }
2631
2663
 
2632
- function editingCancelled(this: ElementsTreeElement, element: Element, tagName: string|null): void {
2664
+ function editingCancelled(this: ElementsTreeWidget, element: Element, tagName: string|null): void {
2633
2665
  if (!tagNameElement) {
2634
2666
  return;
2635
2667
  }
@@ -2644,7 +2676,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2644
2676
  const config =
2645
2677
  new UI.InplaceEditor.Config<string|null>(editingCommitted.bind(this), editingCancelled.bind(this), tagName);
2646
2678
  this.updateEditorHandles(tagNameElement, config);
2647
- const componentSelection = this.listItemElement.getComponentSelection();
2679
+ const componentSelection = this.element.getComponentSelection();
2648
2680
  componentSelection?.selectAllChildren(tagNameElement);
2649
2681
  return true;
2650
2682
  }
@@ -2673,8 +2705,8 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2673
2705
  }
2674
2706
 
2675
2707
  // Hide children item.
2676
- if (this.childrenListElement) {
2677
- this.childrenListElement.style.display = 'none';
2708
+ if (this.treeElement.childrenListElement) {
2709
+ this.treeElement.childrenListElement.style.display = 'none';
2678
2710
  }
2679
2711
  const initialValue = convertUnicodeCharsToHTMLEntities(maybeInitialValue).text;
2680
2712
  // Append editor.
@@ -2756,41 +2788,43 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2756
2788
  }),
2757
2789
  ],
2758
2790
  });
2759
- this.performUpdate();
2791
+ this.requestUpdate();
2760
2792
  resize.call(this);
2761
- this.#editorRef?.focus();
2762
2793
  this.editing = {commit: commit.bind(this), cancel: dispose.bind(this), resize: resize.bind(this)};
2763
- this.treeOutline?.setMultilineEditing(this.editing);
2794
+ (this.treeElement.treeOutline as ElementsTreeOutline | null)?.setMultilineEditing(this.editing);
2795
+ await this.updateComplete;
2796
+ this.#editorRef?.focus();
2764
2797
 
2765
- function resize(this: ElementsTreeElement): void {
2766
- if (this.treeOutline) {
2767
- this.#editorWidth = this.treeOutline.visibleWidth() - this.computeLeftIndent() - 30;
2768
- this.performUpdate();
2798
+ function resize(this: ElementsTreeWidget): void {
2799
+ if (this.treeElement.treeOutline) {
2800
+ this.#editorWidth =
2801
+ (this.treeElement.treeOutline as ElementsTreeOutline).visibleWidth() - this.computeLeftIndent() - 30;
2802
+ this.requestUpdate();
2769
2803
  }
2770
2804
  }
2771
2805
 
2772
- function commit(this: ElementsTreeElement): void {
2806
+ function commit(this: ElementsTreeWidget): void {
2773
2807
  if (this.#editorRef) {
2774
2808
  commitCallback(initialValue, this.#editorRef.editor.state.doc.toString());
2775
2809
  }
2776
2810
  dispose.call(this);
2777
2811
  }
2778
2812
 
2779
- function dispose(this: ElementsTreeElement): void {
2813
+ function dispose(this: ElementsTreeWidget): void {
2780
2814
  if (!this.#editorRef) {
2781
2815
  return;
2782
2816
  }
2783
2817
  this.editing = null;
2784
2818
  this.#editorState = null;
2785
- this.performUpdate();
2819
+ this.requestUpdate();
2786
2820
  // Unhide children item.
2787
- if (this.childrenListElement) {
2788
- this.childrenListElement.style.removeProperty('display');
2821
+ if (this.treeElement.childrenListElement) {
2822
+ this.treeElement.childrenListElement.style.removeProperty('display');
2789
2823
  }
2790
2824
 
2791
- if (this.treeOutline) {
2792
- this.treeOutline.setMultilineEditing(null);
2793
- this.treeOutline.focus();
2825
+ if (this.treeElement.treeOutline) {
2826
+ (this.treeElement.treeOutline as ElementsTreeOutline).setMultilineEditing(null);
2827
+ this.treeElement.treeOutline.focus();
2794
2828
  }
2795
2829
 
2796
2830
  disposeCallback();
@@ -2806,9 +2840,9 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2806
2840
  ): void {
2807
2841
  this.editing = null;
2808
2842
 
2809
- const treeOutline = this.treeOutline;
2843
+ const treeOutline = this.treeElement.treeOutline;
2810
2844
 
2811
- function moveToNextAttributeIfNeeded(this: ElementsTreeElement, error?: string|null): void {
2845
+ function moveToNextAttributeIfNeeded(this: ElementsTreeWidget, error?: string|null): void {
2812
2846
  if (error) {
2813
2847
  this.editingCancelled(element, attributeName);
2814
2848
  }
@@ -2818,7 +2852,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2818
2852
  }
2819
2853
 
2820
2854
  if (treeOutline) {
2821
- treeOutline.runPendingUpdates();
2855
+ (treeOutline as ElementsTreeOutline).runPendingUpdates();
2822
2856
  treeOutline.focus();
2823
2857
  }
2824
2858
 
@@ -2831,12 +2865,12 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2831
2865
 
2832
2866
  if (moveDirection === 'backward') {
2833
2867
  if (i === 0) {
2834
- this.startEditingTagName();
2868
+ this.treeElement.startEditingTagName();
2835
2869
  } else {
2836
2870
  this.triggerEditAttribute(attributes[i - 1].name);
2837
2871
  }
2838
2872
  } else if (i === attributes.length - 1) {
2839
- this.addNewAttribute();
2873
+ this.treeElement.addNewAttribute();
2840
2874
  } else {
2841
2875
  this.triggerEditAttribute(attributes[i + 1].name);
2842
2876
  }
@@ -2856,9 +2890,9 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2856
2890
  }
2857
2891
  } else if (moveDirection === 'forward') {
2858
2892
  if (!Platform.StringUtilities.isWhitespace(newText)) {
2859
- this.addNewAttribute();
2893
+ this.treeElement.addNewAttribute();
2860
2894
  } else {
2861
- this.startEditingTagName();
2895
+ this.treeElement.startEditingTagName();
2862
2896
  }
2863
2897
  }
2864
2898
  }
@@ -2869,7 +2903,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2869
2903
  return;
2870
2904
  }
2871
2905
 
2872
- this.updateTitle();
2906
+ this.treeElement.updateTitle();
2873
2907
  moveToNextAttributeIfNeeded.call(this);
2874
2908
  }
2875
2909
 
@@ -2893,14 +2927,14 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2893
2927
  moveToNextAttributeIfNeeded.call(self);
2894
2928
  }
2895
2929
 
2896
- function moveToNextAttributeIfNeeded(this: ElementsTreeElement): void {
2930
+ function moveToNextAttributeIfNeeded(this: ElementsTreeWidget): void {
2897
2931
  if (this.nodeInternal.nodeType() === Node.PROCESSING_INSTRUCTION_NODE) {
2898
- this.startEditingProcessingInstructionValue();
2932
+ this.treeElement.startEditingProcessingInstructionValue();
2899
2933
  return;
2900
2934
  }
2901
2935
 
2902
2936
  if (moveDirection !== 'forward') {
2903
- this.addNewAttribute();
2937
+ this.treeElement.addNewAttribute();
2904
2938
  return;
2905
2939
  }
2906
2940
 
@@ -2908,7 +2942,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2908
2942
  if (attributes.length > 0) {
2909
2943
  this.triggerEditAttribute(attributes[0].name);
2910
2944
  } else {
2911
- this.addNewAttribute();
2945
+ this.treeElement.addNewAttribute();
2912
2946
  }
2913
2947
  }
2914
2948
 
@@ -2918,8 +2952,8 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2918
2952
  return;
2919
2953
  }
2920
2954
 
2921
- const treeOutline = this.treeOutline;
2922
- const wasExpanded = this.expanded;
2955
+ const treeOutline = this.treeElement.treeOutline;
2956
+ const wasExpanded = this.treeElement.expanded;
2923
2957
 
2924
2958
  this.nodeInternal.setNodeName(newText, (error, newNode) => {
2925
2959
  if (error || !newNode) {
@@ -2931,18 +2965,21 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2931
2965
  }
2932
2966
 
2933
2967
  Badges.UserBadges.instance().recordAction(Badges.BadgeAction.DOM_ELEMENT_OR_ATTRIBUTE_EDITED);
2934
- const newTreeItem = treeOutline.selectNodeAfterEdit(wasExpanded, error, newNode);
2935
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
2936
- // @ts-expect-error
2937
- moveToNextAttributeIfNeeded.call(newTreeItem);
2968
+ const newTreeItem =
2969
+ (treeOutline as ElementsTreeOutline).selectNodeAfterEdit(wasExpanded, error, newNode) as ElementsTreeElement |
2970
+ null;
2971
+ if (newTreeItem) {
2972
+ moveToNextAttributeIfNeeded.call(newTreeItem.widget);
2973
+ }
2938
2974
  });
2939
2975
  }
2940
2976
 
2941
2977
  private textNodeEditingCommitted(textNode: SDK.DOMModel.DOMNode, _element: Element, newText: string): void {
2942
2978
  this.editing = null;
2943
2979
 
2944
- function callback(this: ElementsTreeElement): void {
2945
- this.updateTitle();
2980
+ function callback(this: ElementsTreeWidget): void {
2981
+ this.#clearDOMNextUpdate = true;
2982
+ this.treeElement.updateTitle();
2946
2983
  }
2947
2984
  textNode.setNodeValue(newText, callback.bind(this));
2948
2985
  }
@@ -2951,7 +2988,8 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2951
2988
  this.editing = null;
2952
2989
 
2953
2990
  // Need to restore attributes structure.
2954
- this.updateTitle();
2991
+ this.#clearDOMNextUpdate = true;
2992
+ this.treeElement.updateTitle();
2955
2993
  }
2956
2994
 
2957
2995
  private distinctClosingTagElement(): Element|null {
@@ -2959,15 +2997,15 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2959
2997
 
2960
2998
  // For an expanded element, it will be the last element with class "close"
2961
2999
  // in the child element list.
2962
- if (this.expanded) {
2963
- const closers = this.childrenListElement.querySelectorAll('.close');
3000
+ if (this.treeElement.expanded) {
3001
+ const closers = this.treeElement.childrenListElement.querySelectorAll('.close');
2964
3002
  return closers[closers.length - 1];
2965
3003
  }
2966
3004
 
2967
3005
  // Remaining cases are single line non-expanded elements with a closing
2968
3006
  // tag, or HTML elements without a closing tag (such as <br>). Return
2969
3007
  // null in the case where there isn't a closing tag.
2970
- const tags = this.listItemElement.getElementsByClassName('webkit-html-tag');
3008
+ const tags = this.contentElement.querySelectorAll('.webkit-html-tag');
2971
3009
  return tags.length === 1 ? null : tags[tags.length - 1];
2972
3010
  }
2973
3011
 
@@ -2977,11 +3015,10 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2977
3015
  if (this.editing) {
2978
3016
  return;
2979
3017
  }
2980
- this.performUpdate(/* clearNode= */ true);
2981
3018
  this.#updateRecord = updateRecord ?? null;
2982
3019
  if (this.nodeInternal.nodeType() === Node.DOCUMENT_FRAGMENT_NODE && this.nodeInternal.isInShadowTree() &&
2983
3020
  this.nodeInternal.shadowRootType()) {
2984
- this.childrenListElement.classList.add('shadow-root');
3021
+ this.treeElement.childrenListElement.classList.add('shadow-root');
2985
3022
  let depth = 4;
2986
3023
  for (let node: (SDK.DOMModel.DOMNode|null) = (this.nodeInternal as SDK.DOMModel.DOMNode | null); depth && node;
2987
3024
  node = node.parentNode) {
@@ -2990,16 +3027,12 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2990
3027
  }
2991
3028
  }
2992
3029
  if (!depth) {
2993
- this.childrenListElement.classList.add('shadow-root-deep');
3030
+ this.treeElement.childrenListElement.classList.add('shadow-root-deep');
2994
3031
  } else {
2995
- this.childrenListElement.classList.add('shadow-root-depth-' + depth);
3032
+ this.treeElement.childrenListElement.classList.add('shadow-root-depth-' + depth);
2996
3033
  }
2997
3034
  }
2998
3035
  this.performUpdate();
2999
- if (this.#contentElement) {
3000
- // fixme: we probably do not need a title element in the new tree outline.
3001
- this.title = this.#contentElement;
3002
- }
3003
3036
  this.updateDecorations();
3004
3037
 
3005
3038
  // If there is an issue with this node, make sure to update it.
@@ -3011,7 +3044,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
3011
3044
  }
3012
3045
 
3013
3046
  private computeLeftIndent(): number {
3014
- let treeElement: (UI.TreeOutline.TreeElement|null) = this.parent;
3047
+ let treeElement: (UI.TreeOutline.TreeElement|null) = this.treeElement.parent;
3015
3048
  let depth = 0;
3016
3049
  while (treeElement !== null) {
3017
3050
  depth++;
@@ -3019,15 +3052,15 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
3019
3052
  }
3020
3053
 
3021
3054
  /** Keep it in sync with elementsTreeOutline.css **/
3022
- return 12 * (depth - 2) + (this.isExpandable() && this.isCollapsible() ? 1 : 12);
3055
+ return 12 * (depth - 2) + (this.treeElement.isExpandable() && this.treeElement.isCollapsible() ? 1 : 12);
3023
3056
  }
3024
3057
 
3025
3058
  updateDecorations(): void {
3026
3059
  // Important to keep the entire tree node row as a clickable area for that
3027
3060
  // node.
3028
- this.listItemElement.style.setProperty('--indent', this.computeLeftIndent() + 'px');
3061
+ this.element.style.setProperty('--indent', this.computeLeftIndent() + 'px');
3029
3062
 
3030
- if (this.isClosingTag()) {
3063
+ if (this.treeElement.isClosingTag()) {
3031
3064
  return;
3032
3065
  }
3033
3066
 
@@ -3039,18 +3072,19 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
3039
3072
  }
3040
3073
 
3041
3074
  #updateDecorations(): Promise<void> {
3042
- if (!this.treeOutline) {
3075
+ if (!this.treeElement.treeOutline) {
3043
3076
  return Promise.resolve();
3044
3077
  }
3045
3078
 
3046
3079
  const node = this.nodeInternal;
3047
3080
 
3048
- if (!this.treeOutline.decoratorExtensions) {
3049
- this.treeOutline.decoratorExtensions = getRegisteredDecorators();
3081
+ const outline = this.treeElement.treeOutline as ElementsTreeOutline;
3082
+ if (!outline.decoratorExtensions) {
3083
+ outline.decoratorExtensions = getRegisteredDecorators();
3050
3084
  }
3051
3085
 
3052
3086
  const markerToExtension = new Map<string, MarkerDecoratorRegistration>();
3053
- for (const decoratorExtension of this.treeOutline.decoratorExtensions) {
3087
+ for (const decoratorExtension of (outline.decoratorExtensions || [])) {
3054
3088
  markerToExtension.set(decoratorExtension.marker, decoratorExtension);
3055
3089
  }
3056
3090
 
@@ -3083,13 +3117,13 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
3083
3117
 
3084
3118
  return Promise.all(promises).then(updateDecorationsUI.bind(this));
3085
3119
 
3086
- function updateDecorationsUI(this: ElementsTreeElement): void {
3120
+ function updateDecorationsUI(this: ElementsTreeWidget): void {
3087
3121
  this.#decorations = decorations;
3088
3122
  this.#descendantDecorations = descendantDecorations;
3089
3123
 
3090
3124
  if (!decorations.length && !descendantDecorations.length) {
3091
3125
  this.#decorationsTooltip = '';
3092
- this.performUpdate();
3126
+ this.requestUpdate();
3093
3127
  return;
3094
3128
  }
3095
3129
 
@@ -3097,26 +3131,26 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
3097
3131
  for (const decoration of decorations) {
3098
3132
  tooltip.push(decoration.title);
3099
3133
  }
3100
- if (!this.expanded && descendantDecorations.length) {
3134
+ if (!this.treeElement.expanded && descendantDecorations.length) {
3101
3135
  tooltip.push(i18nString(UIStrings.children));
3102
3136
  for (const decoration of descendantDecorations) {
3103
3137
  tooltip.push(decoration.title);
3104
3138
  }
3105
3139
  }
3106
3140
  this.#decorationsTooltip = tooltip.join('\n');
3107
- this.performUpdate();
3141
+ this.requestUpdate();
3108
3142
  }
3109
3143
  }
3110
3144
 
3111
3145
  async remove(): Promise<void> {
3112
- if (this.treeOutline?.isToggledToHidden(this.nodeInternal)) {
3146
+ if (this.treeElement.treeOutline?.isToggledToHidden(this.nodeInternal)) {
3113
3147
  // Unhide the node before removing. This avoids inconsistent state if the node is restored via undo.
3114
- await this.treeOutline.toggleHideElement(this.nodeInternal);
3148
+ await (this.treeElement.treeOutline as ElementsTreeOutline).toggleHideElement(this.nodeInternal);
3115
3149
  }
3116
3150
  if (this.nodeInternal.pseudoType()) {
3117
3151
  return;
3118
3152
  }
3119
- const parentElement = this.parent;
3153
+ const parentElement = this.treeElement.parent;
3120
3154
  if (!parentElement) {
3121
3155
  return;
3122
3156
  }
@@ -3213,7 +3247,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
3213
3247
  return;
3214
3248
  }
3215
3249
 
3216
- const text = this.listItemElement.textContent || '';
3250
+ const text = this.contentElement.deepTextContent();
3217
3251
  const regexObject = Platform.StringUtilities.createPlainTextSearchRegex(this.searchQuery, 'gi');
3218
3252
 
3219
3253
  const matchRanges = [];
@@ -3229,7 +3263,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
3229
3263
  }
3230
3264
 
3231
3265
  this.#highlights = Highlighting.HighlightManager.HighlightManager.instance().highlightOrderedTextRanges(
3232
- this.listItemElement, matchRanges);
3266
+ this.contentElement, matchRanges);
3233
3267
  }
3234
3268
 
3235
3269
  private editAsHTML(): void {
@@ -3246,7 +3280,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
3246
3280
  }
3247
3281
 
3248
3282
  async #updateAdorners(): Promise<void> {
3249
- if (this.isClosingTag()) {
3283
+ if (this.treeElement.isClosingTag()) {
3250
3284
  return;
3251
3285
  }
3252
3286
  const node = this.node();
@@ -3257,7 +3291,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
3257
3291
  } else {
3258
3292
  this.#layout = null;
3259
3293
  }
3260
- this.performUpdate();
3294
+ this.requestUpdate();
3261
3295
  }
3262
3296
 
3263
3297
  async #onPopoverAdornerClick(event: Event): Promise<void> {
@@ -3272,7 +3306,22 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
3272
3306
  if (this.#popoverAdornerActive) {
3273
3307
  Badges.UserBadges.instance().recordAction(Badges.BadgeAction.MODERN_DOM_BADGE_CLICKED);
3274
3308
  }
3275
- this.performUpdate();
3309
+ this.requestUpdate();
3310
+ }
3311
+
3312
+ async #onInterestAdornerClick(event: Event): Promise<void> {
3313
+ event.stopPropagation();
3314
+ const node = this.node();
3315
+ const nodeId = node.id;
3316
+ if (!nodeId) {
3317
+ return;
3318
+ }
3319
+ await node.domModel().agent.invoke_forceShowInterest({nodeId, enable: !this.#interestAdornerActive});
3320
+ this.#interestAdornerActive = !this.#interestAdornerActive;
3321
+ if (this.#interestAdornerActive) {
3322
+ Badges.UserBadges.instance().recordAction(Badges.BadgeAction.MODERN_DOM_BADGE_CLICKED);
3323
+ }
3324
+ this.requestUpdate();
3276
3325
  }
3277
3326
 
3278
3327
  #onStartingStyleAdornerClick(event: Event): void {
@@ -3289,46 +3338,272 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
3289
3338
  model.forceStartingStyle(node, true);
3290
3339
  }
3291
3340
  this.#startingStyleAdornerActive = !this.#startingStyleAdornerActive;
3292
- this.performUpdate();
3341
+ this.requestUpdate();
3293
3342
  }
3343
+ }
3344
+ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
3345
+ widget: ElementsTreeWidget;
3346
+ widgetWrapper: HTMLElement;
3347
+ nodeInternal: SDK.DOMModel.DOMNode;
3348
+ tagTypeContext: TagTypeContext;
3294
3349
 
3295
- async #onCustomElementAdornerClick(event: Event): Promise<void> {
3296
- event.stopPropagation();
3297
- const node = this.node();
3298
- const object = await node.resolveToObject('');
3299
- if (!object) {
3300
- return;
3350
+ constructor(node: SDK.DOMModel.DOMNode, isClosingTag?: boolean) {
3351
+ super();
3352
+ this.nodeInternal = node;
3353
+ this.listItemElement.setAttribute(
3354
+ 'jslog', `${VisualLogging.treeItem().parent('elementsTreeOutline').track({
3355
+ keydown: 'ArrowUp|ArrowDown|ArrowLeft|ArrowRight|Backspace|Delete|Enter|Space|Home|End',
3356
+ resize: true,
3357
+ drag: true,
3358
+ click: true,
3359
+ })}`);
3360
+
3361
+ if (isClosingTag) {
3362
+ this.tagTypeContext = {tagType: TagType.CLOSING};
3363
+ } else {
3364
+ this.tagTypeContext = {
3365
+ tagType: TagType.OPENING,
3366
+ canAddAttributes: this.nodeInternal.nodeType() === Node.ELEMENT_NODE,
3367
+ };
3301
3368
  }
3302
- let constructorObject: SDK.RemoteObject.RemoteObject|null = null;
3303
- try {
3304
- const result = await object.callFunction(function(this: Element): unknown {
3305
- const selector = this.getAttribute('is') || this.tagName.toLowerCase();
3306
- return (typeof customElements !== 'undefined' && customElements.get(selector)) || this.constructor;
3307
- });
3308
- constructorObject = result.object;
3309
- } finally {
3310
- object.release();
3369
+ this.widgetWrapper = document.createElement('div');
3370
+ this.widgetWrapper.style.display = 'contents';
3371
+ this.title = this.widgetWrapper;
3372
+ this.widget = new ElementsTreeWidget(this);
3373
+ this.widget.element.classList.remove('vbox', 'flex-auto');
3374
+ this.widget.element.style.display = 'contents';
3375
+ this.widget.markAsRoot();
3376
+ this.widget.show(this.widgetWrapper);
3377
+
3378
+ if (this.nodeInternal.retained && !this.isClosingTag()) {
3379
+ this.setLeadingIcons([
3380
+ html`<devtools-icon class="extra-small" name="small-status-dot" style="color:var(--icon-error); vertical-align:middle"></devtools-icon>`,
3381
+ ]);
3382
+ this.listItemNode.classList.add('detached-elements-detached-node');
3383
+ this.listItemNode.style.setProperty('display', '-webkit-box');
3384
+ this.listItemNode.setAttribute('title', 'Retained Node');
3311
3385
  }
3312
- if (!constructorObject) {
3386
+
3387
+ if (this.nodeInternal.detached && !this.isClosingTag()) {
3388
+ this.listItemNode.setAttribute('title', 'Detached Tree Node');
3389
+ }
3390
+ }
3391
+
3392
+ highlightSearchResults(searchQuery: string): void {
3393
+ this.widget.highlightSearchResults(searchQuery);
3394
+ }
3395
+ hideSearchHighlights(): void {
3396
+ this.widget.hideSearchHighlights();
3397
+ }
3398
+ copyStyles(): Promise<void> {
3399
+ return this.widget.copyStyles();
3400
+ }
3401
+ addIssue(issue: IssuesManager.Issue.Issue): void {
3402
+ this.widget.addIssue(issue);
3403
+ }
3404
+ get issuesByNodeElement(): Map<Element, IssuesManager.Issue.Issue[]> {
3405
+ return this.widget.issuesByNodeElement;
3406
+ }
3407
+ removeIssue(issue: IssuesManager.Issue.Issue): void {
3408
+ this.widget.removeIssue(issue);
3409
+ }
3410
+ setInClipboard(inClipboard: boolean): void {
3411
+ this.widget.setInClipboard(inClipboard);
3412
+ if (this.listItemElement) {
3413
+ this.listItemElement.classList.toggle('in-clipboard', inClipboard);
3414
+ }
3415
+ }
3416
+ get isEditing(): boolean {
3417
+ return this.widget.isEditing;
3418
+ }
3419
+ expandedChildrenLimit(): number {
3420
+ return this.widget.expandedChildrenLimit();
3421
+ }
3422
+
3423
+ setExpandedChildrenLimit(limit: number): void {
3424
+ this.widget.setExpandedChildrenLimit(limit);
3425
+ }
3426
+ highlightAttribute(name: string): void {
3427
+ this.widget.highlightAttribute(name);
3428
+ }
3429
+ populateTextContextMenu(contextMenu: UI.ContextMenu.ContextMenu, textNode: Node): Promise<void> {
3430
+ return this.widget.populateTextContextMenu(contextMenu, textNode);
3431
+ }
3432
+ populateTagContextMenu(contextMenu: UI.ContextMenu.ContextMenu, event: Event): Promise<void> {
3433
+ return this.widget.populateTagContextMenu(contextMenu, event);
3434
+ }
3435
+ populateNodeContextMenu(contextMenu: UI.ContextMenu.ContextMenu): Promise<void> {
3436
+ return this.widget.populateNodeContextMenu(contextMenu);
3437
+ }
3438
+ populatePseudoElementContextMenu(contextMenu: UI.ContextMenu.ContextMenu): void {
3439
+ this.widget.populatePseudoElementContextMenu(contextMenu);
3440
+ }
3441
+ populateProcessingElementContextMenu(contextMenu: UI.ContextMenu.ContextMenu): Promise<void> {
3442
+ return this.widget.populateProcessingElementContextMenu(contextMenu);
3443
+ }
3444
+ hasEditableNode(): boolean {
3445
+ return this.widget.hasEditableNode();
3446
+ }
3447
+ toggleEditAsHTML(callback?: ((arg0: boolean) => void), startEditing?: boolean): void {
3448
+ this.widget.toggleEditAsHTML(callback, startEditing);
3449
+ }
3450
+
3451
+ get expandAllButtonElement(): UI.TreeOutline.TreeElement|null {
3452
+ return this.widget.expandAllButtonElement;
3453
+ }
3454
+ set expandAllButtonElement(element: UI.TreeOutline.TreeElement|null) {
3455
+ this.widget.expandAllButtonElement = element;
3456
+ }
3457
+
3458
+ node(): SDK.DOMModel.DOMNode {
3459
+ return this.nodeInternal;
3460
+ }
3461
+
3462
+ isClosingTag(): boolean {
3463
+ return this.tagTypeContext.tagType === TagType.CLOSING;
3464
+ }
3465
+
3466
+ override onattach(): void {
3467
+ this.widget.onattach();
3468
+ }
3469
+
3470
+ override async onpopulate(): Promise<void> {
3471
+ return await this.widget.onpopulate();
3472
+ }
3473
+
3474
+ override async expandRecursively(): Promise<void> {
3475
+ await this.nodeInternal.getSubtree(100, true);
3476
+ await super.expandRecursively(Number.MAX_VALUE);
3477
+ }
3478
+
3479
+ override onexpand(): void {
3480
+ this.widget.onexpand();
3481
+ }
3482
+
3483
+ override oncollapse(): void {
3484
+ this.widget.oncollapse();
3485
+ }
3486
+
3487
+ override select(omitFocus?: boolean, selectedByUser?: boolean): boolean {
3488
+ if (this.widget.editing) {
3489
+ return false;
3490
+ }
3491
+ return super.select(omitFocus, selectedByUser);
3492
+ }
3493
+
3494
+ override onselect(selectedByUser?: boolean): boolean {
3495
+ return this.widget.onselect(selectedByUser);
3496
+ }
3497
+
3498
+ override ondelete(): boolean {
3499
+ return this.widget.ondelete();
3500
+ }
3501
+
3502
+ override onenter(): boolean {
3503
+ return this.widget.onenter();
3504
+ }
3505
+
3506
+ override selectOnMouseDown(event: MouseEvent): void {
3507
+ super.selectOnMouseDown(event);
3508
+
3509
+ if (this.widget.editing) {
3313
3510
  return;
3314
3511
  }
3315
- try {
3316
- if (constructorObject.type === 'function') {
3317
- const functionDetails =
3318
- await SDK.RemoteObject.RemoteFunction.objectAsFunction(constructorObject).targetFunctionDetails();
3319
- if (functionDetails?.location) {
3320
- const uiLocation =
3321
- await Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().rawLocationToUILocation(
3322
- functionDetails.location);
3323
- if (uiLocation) {
3324
- void Common.Revealer.reveal(uiLocation);
3325
- }
3326
- }
3327
- }
3328
- } finally {
3329
- constructorObject.release();
3512
+
3513
+ // Prevent selecting the nearest word on double click.
3514
+ if (event.detail >= 2) {
3515
+ event.preventDefault();
3516
+ }
3517
+ }
3518
+
3519
+ override ondblclick(event: Event): boolean {
3520
+ return this.widget.ondblclick(event);
3521
+ }
3522
+
3523
+ override onbind(): void {
3524
+ this.widget.onbind();
3525
+ }
3526
+
3527
+ override onunbind(): void {
3528
+ this.widget.onunbind();
3529
+ }
3530
+
3531
+ static animateOnDOMUpdate(treeElement: ElementsTreeElement): void {
3532
+ ElementsTreeWidget.animateOnDOMUpdate(treeElement);
3533
+ }
3534
+
3535
+ static visibleShadowRoots(node: SDK.DOMModel.DOMNode): SDK.DOMModel.DOMNode[] {
3536
+ return ElementsTreeWidget.visibleShadowRoots(node);
3537
+ }
3538
+
3539
+ static canShowInlineText(node: SDK.DOMModel.DOMNode): boolean {
3540
+ return ElementsTreeWidget.canShowInlineText(node);
3541
+ }
3542
+
3543
+ static populateForcedPseudoStateItems(contextMenu: UI.ContextMenu.ContextMenu, node: SDK.DOMModel.DOMNode): void {
3544
+ ElementsTreeWidget.populateForcedPseudoStateItems(contextMenu, node);
3545
+ }
3546
+
3547
+ set hovered(isHovered: boolean) {
3548
+ this.widget.hovered = isHovered;
3549
+ if (this.listItemElement) {
3550
+ this.listItemElement.classList.toggle('hovered', isHovered);
3330
3551
  }
3331
3552
  }
3553
+
3554
+ get hovered(): boolean {
3555
+ return this.widget.hovered;
3556
+ }
3557
+
3558
+ updateAdorners(): void {
3559
+ this.widget.updateAdorners();
3560
+ }
3561
+
3562
+ get updateComplete(): Promise<void> {
3563
+ return this.widget.updateComplete;
3564
+ }
3565
+
3566
+ requestUpdate(): void {
3567
+ this.widget.requestUpdate();
3568
+ }
3569
+ updateTitle(updateRecord?: Elements.ElementUpdateRecord.ElementUpdateRecord|null): void {
3570
+ this.widget.updateTitle(updateRecord);
3571
+ }
3572
+
3573
+ triggerEditAttribute(attributeName: string): boolean {
3574
+ return this.widget.triggerEditAttribute(attributeName) || false;
3575
+ }
3576
+
3577
+ editingCancelled(element: Element, tagName: string|null): void {
3578
+ this.widget.editingCancelled(element, tagName);
3579
+ }
3580
+
3581
+ updateDecorations(): void {
3582
+ this.widget.updateDecorations();
3583
+ }
3584
+
3585
+ async remove(): Promise<void> {
3586
+ return await this.widget.remove();
3587
+ }
3588
+
3589
+ addNewAttribute(): boolean {
3590
+ return this.widget.addNewAttribute();
3591
+ }
3592
+ startEditingTagName(tagNameElement?: Element): boolean {
3593
+ return this.widget.startEditingTagName(tagNameElement);
3594
+ }
3595
+
3596
+ startEditingProcessingInstructionValue(): boolean|undefined {
3597
+ return this.widget.startEditingProcessingInstructionValue();
3598
+ }
3599
+
3600
+ isDisplayContents(): boolean {
3601
+ return this.widget.isDisplayContents();
3602
+ }
3603
+
3604
+ performUpdate(): void {
3605
+ this.widget.performUpdate();
3606
+ }
3332
3607
  }
3333
3608
 
3334
3609
  export const InitialChildrenLimit = 500;