chrome-devtools-frontend 1.0.1548870 → 1.0.1549484

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 (188) hide show
  1. package/docs/contributing/settings-experiments-features.md +35 -0
  2. package/docs/styleguide/ux/patterns.md +27 -0
  3. package/eslint.config.mjs +1 -0
  4. package/front_end/Tests.js +2 -0
  5. package/front_end/core/host/InspectorFrontendHost.ts +26 -558
  6. package/front_end/core/host/InspectorFrontendHostAPI.ts +6 -3
  7. package/front_end/core/host/InspectorFrontendHostStub.ts +558 -0
  8. package/front_end/core/host/ResourceLoader.ts +9 -23
  9. package/front_end/core/host/UserMetrics.ts +4 -4
  10. package/front_end/core/root/DevToolsContext.ts +4 -0
  11. package/front_end/core/root/Runtime.ts +10 -0
  12. package/front_end/core/sdk/CSSMatchedStyles.ts +2 -2
  13. package/front_end/core/sdk/CSSModel.ts +24 -24
  14. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +11 -11
  15. package/front_end/core/sdk/CSSQuery.ts +1 -1
  16. package/front_end/core/sdk/CSSRule.ts +2 -2
  17. package/front_end/core/sdk/CSSStyleDeclaration.ts +1 -1
  18. package/front_end/core/sdk/CSSStyleSheetHeader.ts +1 -1
  19. package/front_end/core/sdk/DOMModel.ts +3 -0
  20. package/front_end/core/sdk/NetworkManager.ts +29 -31
  21. package/front_end/core/sdk/NetworkRequest.ts +4 -0
  22. package/front_end/core/sdk/OverlayModel.ts +2 -2
  23. package/front_end/core/sdk/PageResourceLoader.ts +63 -37
  24. package/front_end/core/sdk/SourceMap.ts +6 -0
  25. package/front_end/core/sdk/SourceMapCache.ts +21 -0
  26. package/front_end/core/sdk/SourceMapManager.ts +7 -6
  27. package/front_end/core/sdk/SourceMapScopesInfo.ts +6 -2
  28. package/front_end/core/sdk/TargetManager.ts +14 -2
  29. package/front_end/core/sdk/sdk-meta.ts +13 -0
  30. package/front_end/entrypoints/formatter_worker/FormatterActions.ts +1 -0
  31. package/front_end/entrypoints/formatter_worker/ScopeParser.ts +1 -1
  32. package/front_end/entrypoints/main/MainImpl.ts +13 -3
  33. package/front_end/foundation/Universe.ts +1 -1
  34. package/front_end/generated/Deprecation.ts +18 -4
  35. package/front_end/generated/InspectorBackendCommands.ts +33 -31
  36. package/front_end/generated/SupportedCSSProperties.js +41 -41
  37. package/front_end/generated/protocol-mapping.d.ts +12 -0
  38. package/front_end/generated/protocol-proxy-api.d.ts +11 -0
  39. package/front_end/generated/protocol.ts +70 -35
  40. package/front_end/models/ai_assistance/AiConversation.ts +5 -4
  41. package/front_end/models/ai_assistance/ChangeManager.ts +4 -4
  42. package/front_end/models/ai_assistance/ConversationHandler.ts +0 -15
  43. package/front_end/models/ai_assistance/agents/AiAgent.ts +9 -6
  44. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +135 -3
  45. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +24 -0
  46. package/front_end/models/bindings/CompilerScriptMapping.ts +43 -0
  47. package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +19 -0
  48. package/front_end/models/bindings/ResourceMapping.ts +73 -0
  49. package/front_end/models/bindings/ResourceScriptMapping.ts +50 -0
  50. package/front_end/models/issues_manager/GenericIssue.ts +17 -0
  51. package/front_end/models/issues_manager/descriptions/genericNavigationEntryMarkedSkippable.md +7 -0
  52. package/front_end/models/javascript_metadata/NativeFunctions.js +7 -3
  53. package/front_end/models/source_map_scopes/FunctionCodeResolver.snapshot.txt +98 -0
  54. package/front_end/models/source_map_scopes/FunctionCodeResolver.ts +270 -0
  55. package/front_end/models/source_map_scopes/source_map_scopes.ts +2 -0
  56. package/front_end/models/workspace/UISourceCode.ts +51 -44
  57. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +76 -34
  58. package/front_end/panels/ai_assistance/aiAssistancePanel.css +1 -0
  59. package/front_end/panels/ai_assistance/components/ChatView.ts +23 -11
  60. package/front_end/panels/application/AppManifestView.ts +3 -2
  61. package/front_end/panels/application/FrameDetailsView.ts +5 -6
  62. package/front_end/panels/application/ServiceWorkersView.ts +2 -2
  63. package/front_end/panels/application/TrustTokensTreeElement.ts +2 -6
  64. package/front_end/panels/application/components/PermissionsPolicySection.ts +201 -157
  65. package/front_end/panels/application/components/ProtocolHandlersView.ts +117 -80
  66. package/front_end/panels/application/components/ServiceWorkerRouterView.ts +47 -41
  67. package/front_end/panels/application/components/StorageMetadataView.ts +31 -34
  68. package/front_end/panels/application/components/TrustTokensView.ts +76 -68
  69. package/front_end/panels/console/ConsoleView.ts +3 -2
  70. package/front_end/panels/console/ConsoleViewMessage.ts +6 -4
  71. package/front_end/panels/console/console-meta.ts +0 -13
  72. package/front_end/panels/developer_resources/DeveloperResourcesView.ts +3 -1
  73. package/front_end/panels/elements/CSSRuleValidator.ts +7 -7
  74. package/front_end/panels/elements/CSSRuleValidatorHelper.ts +2 -2
  75. package/front_end/panels/elements/ElementsTreeElement.ts +16 -13
  76. package/front_end/panels/elements/ElementsTreeOutline.ts +2 -1
  77. package/front_end/panels/elements/LayoutPane.ts +12 -10
  78. package/front_end/panels/elements/StylePropertyTreeElement.ts +12 -12
  79. package/front_end/panels/elements/components/AdornerManager.ts +3 -3
  80. package/front_end/panels/elements/components/StylePropertyEditor.ts +6 -6
  81. package/front_end/panels/linear_memory_inspector/components/LinearMemoryHighlightChipList.ts +27 -49
  82. package/front_end/panels/linear_memory_inspector/components/LinearMemoryInspector.ts +15 -11
  83. package/front_end/panels/media/PlayerListView.ts +100 -73
  84. package/front_end/panels/media/playerListView.css +5 -0
  85. package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +3 -3
  86. package/front_end/panels/network/RequestConditionsDrawer.ts +5 -5
  87. package/front_end/panels/network/components/DirectSocketConnectionView.ts +17 -0
  88. package/front_end/panels/network/resourceChunkView.css +4 -0
  89. package/front_end/panels/security/CookieControlsView.ts +1 -1
  90. package/front_end/panels/sensors/LocationsSettingsTab.ts +1 -1
  91. package/front_end/panels/settings/FrameworkIgnoreListSettingsTab.ts +1 -1
  92. package/front_end/panels/settings/KeybindsSettingsTab.ts +1 -1
  93. package/front_end/panels/settings/SettingsScreen.ts +6 -6
  94. package/front_end/panels/settings/WorkspaceSettingsTab.ts +1 -1
  95. package/front_end/panels/settings/emulation/DevicesSettingsTab.ts +1 -1
  96. package/front_end/panels/snippets/SnippetsQuickOpen.ts +4 -2
  97. package/front_end/panels/sources/CSSPlugin.ts +1 -1
  98. package/front_end/panels/sources/FilteredUISourceCodeListProvider.ts +13 -5
  99. package/front_end/panels/sources/GoToLineQuickOpen.ts +4 -2
  100. package/front_end/panels/sources/NavigatorView.ts +2 -2
  101. package/front_end/panels/sources/OpenFileQuickOpen.ts +7 -8
  102. package/front_end/panels/sources/OutlineQuickOpen.ts +6 -3
  103. package/front_end/panels/sources/ProfilePlugin.ts +21 -12
  104. package/front_end/panels/sources/UISourceCodeFrame.ts +0 -1
  105. package/front_end/panels/sources/filteredUISourceCodeListProvider.css +41 -0
  106. package/front_end/panels/timeline/TimelinePanel.ts +17 -18
  107. package/front_end/panels/timeline/TimelineSelectorStatsView.ts +3 -3
  108. package/front_end/panels/timeline/components/insights/SlowCSSSelector.ts +2 -2
  109. package/front_end/panels/timeline/docs/flame_chart_migration.md +11 -16
  110. package/front_end/panels/utils/utils.ts +17 -3
  111. package/front_end/panels/whats_new/ReleaseNoteText.ts +10 -20
  112. package/front_end/panels/whats_new/resources/WNDT.md +8 -8
  113. package/front_end/third_party/chromium/README.chromium +1 -1
  114. package/front_end/third_party/puppeteer/third_party/mitt/README.chromium +1 -0
  115. package/front_end/third_party/puppeteer/third_party/parsel/README.chromium +1 -0
  116. package/front_end/third_party/puppeteer/third_party/rxjs/README.chromium +1 -0
  117. package/front_end/ui/components/adorners/Adorner.ts +1 -1
  118. package/front_end/ui/components/annotations/AnnotationRepository.ts +98 -0
  119. package/front_end/ui/components/annotations/AnnotationType.ts +10 -0
  120. package/front_end/ui/components/annotations/annotations.ts +6 -0
  121. package/front_end/ui/components/buttons/Button.ts +1 -1
  122. package/front_end/ui/components/buttons/FloatingButton.ts +1 -1
  123. package/front_end/ui/components/chrome_link/ChromeLink.ts +1 -1
  124. package/front_end/ui/components/dialogs/ButtonDialog.ts +1 -1
  125. package/front_end/ui/components/dialogs/Dialog.ts +1 -1
  126. package/front_end/ui/components/dialogs/ShortcutDialog.ts +1 -0
  127. package/front_end/ui/components/diff_view/DiffView.ts +1 -1
  128. package/front_end/ui/components/expandable_list/ExpandableList.ts +1 -1
  129. package/front_end/ui/components/highlighting/HighlightElement.ts +1 -0
  130. package/front_end/ui/components/highlighting/MarkupHighlight.ts +162 -0
  131. package/front_end/ui/components/highlighting/highlighting.ts +7 -0
  132. package/front_end/ui/components/icon_button/FileSourceIcon.ts +1 -1
  133. package/front_end/ui/components/icon_button/Icon.ts +4 -2
  134. package/front_end/ui/components/icon_button/IconButton.ts +1 -1
  135. package/front_end/ui/components/issue_counter/IssueCounter.ts +1 -1
  136. package/front_end/ui/components/issue_counter/IssueLinkIcon.ts +1 -1
  137. package/front_end/ui/components/legacy_wrapper/LegacyWrapper.ts +1 -1
  138. package/front_end/ui/components/linkifier/LinkifierImpl.ts +1 -1
  139. package/front_end/ui/components/list/List.ts +184 -0
  140. package/front_end/ui/components/list/list.css +90 -0
  141. package/front_end/ui/components/{cards/cards.ts → list/lists.ts} +3 -3
  142. package/front_end/ui/components/markdown_view/CodeBlock.ts +1 -1
  143. package/front_end/ui/components/markdown_view/MarkdownImage.ts +1 -1
  144. package/front_end/ui/components/markdown_view/MarkdownLink.ts +1 -1
  145. package/front_end/ui/components/markdown_view/MarkdownView.ts +1 -1
  146. package/front_end/ui/components/menus/Menu.ts +1 -1
  147. package/front_end/ui/components/menus/SelectMenu.ts +1 -1
  148. package/front_end/ui/components/node_text/NodeText.ts +1 -1
  149. package/front_end/ui/components/panel_feedback/FeedbackButton.ts +1 -1
  150. package/front_end/ui/components/panel_feedback/PanelFeedback.ts +1 -1
  151. package/front_end/ui/components/panel_feedback/PreviewToggle.ts +1 -1
  152. package/front_end/ui/components/panel_introduction_steps/PanelIntroductionSteps.ts +1 -1
  153. package/front_end/ui/components/report_view/ReportView.ts +1 -1
  154. package/front_end/ui/components/request_link_icon/RequestLinkIcon.ts +1 -1
  155. package/front_end/ui/components/settings/SettingCheckbox.ts +1 -1
  156. package/front_end/ui/components/settings/SettingDeprecationWarning.ts +1 -1
  157. package/front_end/ui/components/snackbars/Snackbar.ts +1 -1
  158. package/front_end/ui/components/spinners/Spinner.ts +1 -1
  159. package/front_end/ui/components/srgb_overlay/SrgbOverlay.ts +1 -1
  160. package/front_end/ui/components/suggestion_input/SuggestionInput.ts +1 -0
  161. package/front_end/ui/components/survey_link/SurveyLink.ts +1 -1
  162. package/front_end/ui/components/switch/SwitchImpl.ts +1 -1
  163. package/front_end/ui/components/text_editor/TextEditor.ts +1 -0
  164. package/front_end/ui/components/text_prompt/TextPrompt.ts +1 -1
  165. package/front_end/ui/components/tooltips/Tooltip.ts +1 -1
  166. package/front_end/ui/components/tree_outline/TreeOutline.ts +1 -1
  167. package/front_end/ui/kit/kit.ts +5 -0
  168. package/front_end/ui/legacy/TabbedPane.ts +98 -0
  169. package/front_end/ui/legacy/UIUtils.ts +0 -184
  170. package/front_end/ui/legacy/ViewManager.ts +23 -8
  171. package/front_end/ui/legacy/ViewRegistration.ts +21 -22
  172. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +5 -4
  173. package/front_end/ui/legacy/components/perf_ui/LineLevelProfile.ts +73 -35
  174. package/front_end/ui/legacy/components/perf_ui/LiveHeapProfile.ts +11 -2
  175. package/front_end/ui/legacy/components/quick_open/CommandMenu.ts +12 -13
  176. package/front_end/ui/legacy/components/quick_open/FilteredListWidget.ts +7 -16
  177. package/front_end/ui/legacy/components/quick_open/HelpQuickOpen.ts +5 -6
  178. package/front_end/ui/legacy/components/quick_open/filteredListWidget.css +18 -65
  179. package/front_end/ui/legacy/components/source_frame/JSONView.ts +2 -1
  180. package/front_end/ui/legacy/tabbedPane.css +10 -0
  181. package/front_end/ui/visual_logging/KnownContextValues.ts +3 -0
  182. package/inspector_overlay/README.md +3 -3
  183. package/mcp/HostBindings.ts +310 -0
  184. package/mcp/mcp.ts +17 -0
  185. package/mcp/tsconfig.json +6 -1
  186. package/package.json +26 -24
  187. /package/front_end/ui/{components → kit}/cards/Card.ts +0 -0
  188. /package/front_end/ui/{components → kit}/cards/card.css +0 -0
@@ -10,6 +10,7 @@ import * as Common from '../../core/common/common.js';
10
10
  import * as i18n from '../../core/i18n/i18n.js';
11
11
  import * as Platform from '../../core/platform/platform.js';
12
12
  import * as Geometry from '../../models/geometry/geometry.js';
13
+ import * as Annotations from '../../ui/components/annotations/annotations.js';
13
14
  import * as Buttons from '../../ui/components/buttons/buttons.js';
14
15
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
15
16
  import * as IconButton from '../components/icon_button/icon_button.js';
@@ -53,6 +54,10 @@ const UIStrings = {
53
54
  * @description Indicates that a tab contains a preview feature (i.e., a beta / experimental feature).
54
55
  */
55
56
  previewFeature: 'Preview feature',
57
+ /**
58
+ * @description Indicates that a tab contains annotation(s).
59
+ */
60
+ panelContainsAnnotation: 'This panel has one or more annotations',
56
61
  /**
57
62
  * @description Text to move a tab forwar.
58
63
  */
@@ -121,6 +126,11 @@ export class TabbedPane extends Common.ObjectWrapper.eventMixin<EventTypes, type
121
126
  this.currentDevicePixelRatio = window.devicePixelRatio;
122
127
  ZoomManager.instance().addEventListener(ZoomManagerEvents.ZOOM_CHANGED, this.zoomChanged, this);
123
128
  this.makeTabSlider();
129
+
130
+ if (Annotations.AnnotationRepository.annotationsEnabled()) {
131
+ Annotations.AnnotationRepository.instance().addEventListener(
132
+ Annotations.Events.ANNOTATION_ADDED, this.#onAnnotationAdded, this);
133
+ }
124
134
  }
125
135
 
126
136
  setAccessibleName(name: string): void {
@@ -555,6 +565,36 @@ export class TabbedPane extends Common.ObjectWrapper.eventMixin<EventTypes, type
555
565
  this.performUpdate();
556
566
  }
557
567
 
568
+ updateTabAnnotationIcons(): void {
569
+ if (!Annotations.AnnotationRepository.annotationsEnabled()) {
570
+ return;
571
+ }
572
+
573
+ const annotations = Annotations.AnnotationRepository.instance();
574
+ if (!annotations) {
575
+ return;
576
+ }
577
+
578
+ for (const tab of this.tabs) {
579
+ let primaryType = -1;
580
+ let secondaryType = -1;
581
+ switch (tab.id) {
582
+ case 'elements':
583
+ primaryType = Annotations.AnnotationType.ELEMENT_NODE;
584
+ secondaryType = Annotations.AnnotationType.STYLE_RULE;
585
+ break;
586
+ case 'network':
587
+ primaryType = Annotations.AnnotationType.NETWORK_REQUEST;
588
+ secondaryType = Annotations.AnnotationType.NETWORK_REQUEST_SUBPANEL_HEADERS;
589
+ break;
590
+ }
591
+
592
+ const showTabAnnotationIcon = annotations.getAnnotationsByType(primaryType).length > 0 ||
593
+ annotations.getAnnotationsByType(secondaryType).length > 0;
594
+ this.setTabAnnotationIcon(tab.id, showTabAnnotationIcon);
595
+ }
596
+ }
597
+
558
598
  override performUpdate(): void {
559
599
  if (!this.isShowing()) {
560
600
  return;
@@ -583,6 +623,7 @@ export class TabbedPane extends Common.ObjectWrapper.eventMixin<EventTypes, type
583
623
  this.updateWidths();
584
624
  this.updateTabsDropDown();
585
625
  this.updateTabSlider();
626
+ this.updateTabAnnotationIcons();
586
627
  }
587
628
 
588
629
  private adjustToolbarWidth(): void {
@@ -939,6 +980,17 @@ export class TabbedPane extends Common.ObjectWrapper.eventMixin<EventTypes, type
939
980
  this.automaticReorder = automatic;
940
981
  }
941
982
 
983
+ setTabAnnotationIcon(id: string, iconVisible: boolean): void {
984
+ const tab = this.tabsById.get(id);
985
+ if (tab) {
986
+ tab.tabAnnotationIcon = iconVisible;
987
+ }
988
+ }
989
+
990
+ #onAnnotationAdded(): void {
991
+ this.updateTabAnnotationIcons();
992
+ }
993
+
942
994
  private keyDown(event: KeyboardEvent): void {
943
995
  if (!this.currentTab) {
944
996
  return;
@@ -1009,6 +1061,7 @@ export interface EventTypes {
1009
1061
  export class TabbedPaneTab {
1010
1062
  closeable: boolean;
1011
1063
  previewFeature = false;
1064
+ #tabAnnotationIcon = false;
1012
1065
  private readonly tabbedPane: TabbedPane;
1013
1066
  #id: string;
1014
1067
  #title: string;
@@ -1064,6 +1117,32 @@ export class TabbedPaneTab {
1064
1117
  return this.#jslogContext ?? (this.#id === 'console-view' ? 'console' : this.#id);
1065
1118
  }
1066
1119
 
1120
+ get tabAnnotationIcon(): boolean {
1121
+ return this.#tabAnnotationIcon;
1122
+ }
1123
+
1124
+ set tabAnnotationIcon(iconVisible: boolean) {
1125
+ if (this.#tabAnnotationIcon === iconVisible) {
1126
+ return;
1127
+ }
1128
+ this.#tabAnnotationIcon = iconVisible;
1129
+ if (!this.#tabElement) {
1130
+ return;
1131
+ }
1132
+ const iconElement = this.#tabElement.querySelector('.ai-icon');
1133
+ if (iconVisible) {
1134
+ if (!iconElement) {
1135
+ const closeButton = this.#tabElement.querySelector('.close-button');
1136
+ this.#tabElement.insertBefore(this.createTabAnnotationIcon(), closeButton);
1137
+ }
1138
+ } else {
1139
+ iconElement?.remove();
1140
+ }
1141
+ this.#tabElement.classList.toggle('ai', iconVisible);
1142
+ delete this.measuredWidth;
1143
+ this.tabbedPane.requestUpdate();
1144
+ }
1145
+
1067
1146
  isCloseable(): boolean {
1068
1147
  return this.closeable;
1069
1148
  }
@@ -1204,6 +1283,12 @@ export class TabbedPaneTab {
1204
1283
  tabElement.classList.add('preview');
1205
1284
  }
1206
1285
 
1286
+ if (this.tabAnnotationIcon) {
1287
+ const tabAnnotationIcon = this.createTabAnnotationIcon();
1288
+ tabElement.appendChild(tabAnnotationIcon);
1289
+ tabElement.classList.add('ai');
1290
+ }
1291
+
1207
1292
  if (this.closeable) {
1208
1293
  const closeIcon = this.createCloseIconButton();
1209
1294
  tabElement.appendChild(closeIcon);
@@ -1230,6 +1315,19 @@ export class TabbedPaneTab {
1230
1315
  return tabElement as HTMLElement;
1231
1316
  }
1232
1317
 
1318
+ private createTabAnnotationIcon(): HTMLDivElement {
1319
+ // TODO(finnur): Replace the ai-icon with the squiggly svg once it becomes available.
1320
+ const iconContainer = document.createElement('div');
1321
+ iconContainer.classList.add('ai-icon');
1322
+ const tabAnnotationIcon = new IconButton.Icon.Icon();
1323
+ tabAnnotationIcon.name = 'smart-assistant';
1324
+ tabAnnotationIcon.classList.add('small');
1325
+ iconContainer.appendChild(tabAnnotationIcon);
1326
+ iconContainer.setAttribute('title', i18nString(UIStrings.panelContainsAnnotation));
1327
+ iconContainer.setAttribute('aria-label', i18nString(UIStrings.panelContainsAnnotation));
1328
+ return iconContainer;
1329
+ }
1330
+
1233
1331
  private createCloseIconButton(): Buttons.Button.Button {
1234
1332
  const closeButton = new Buttons.Button.Button();
1235
1333
  closeButton.data = {
@@ -41,7 +41,6 @@ import * as Host from '../../core/host/host.js';
41
41
  import * as i18n from '../../core/i18n/i18n.js';
42
42
  import * as Platform from '../../core/platform/platform.js';
43
43
  import * as Geometry from '../../models/geometry/geometry.js';
44
- import * as TextUtils from '../../models/text_utils/text_utils.js';
45
44
  import * as Buttons from '../components/buttons/buttons.js';
46
45
  import * as IconButton from '../components/icon_button/icon_button.js';
47
46
  import * as Lit from '../lit/lit.js';
@@ -125,9 +124,6 @@ const UIStrings = {
125
124
  const str_ = i18n.i18n.registerUIStrings('ui/legacy/UIUtils.ts', UIStrings);
126
125
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
127
126
 
128
- export const highlightedSearchResultClassName = 'highlighted-search-result';
129
- export const highlightedCurrentSearchResultClassName = 'current-search-result';
130
-
131
127
  export function installDragHandle(
132
128
  element: Element, elementDragStart: ((arg0: MouseEvent) => boolean)|null, elementDrag: (arg0: MouseEvent) => void,
133
129
  elementDragEnd: ((arg0: MouseEvent) => void)|null, cursor: string|null, hoverCursor?: string|null,
@@ -698,17 +694,6 @@ export class ElementFocusRestorer {
698
694
  }
699
695
  }
700
696
 
701
- export function highlightSearchResult(
702
- element: Element, offset: number, length: number, domChanges?: HighlightChange[]): Element|null {
703
- const result = highlightSearchResults(element, [new TextUtils.TextRange.SourceRange(offset, length)], domChanges);
704
- return result.length ? result[0] : null;
705
- }
706
-
707
- export function highlightSearchResults(
708
- element: Element, resultRanges: TextUtils.TextRange.SourceRange[], changes?: HighlightChange[]): Element[] {
709
- return highlightRangesWithStyleClass(element, resultRanges, highlightedSearchResultClassName, changes);
710
- }
711
-
712
697
  export function runCSSAnimationOnce(element: Element, className: string): void {
713
698
  function animationEndCallback(): void {
714
699
  element.classList.remove(className);
@@ -725,166 +710,6 @@ export function runCSSAnimationOnce(element: Element, className: string): void {
725
710
  element.classList.add(className);
726
711
  }
727
712
 
728
- export function highlightRangesWithStyleClass(
729
- element: Element, resultRanges: TextUtils.TextRange.SourceRange[], styleClass: string,
730
- changes?: HighlightChange[]): Element[] {
731
- changes = changes || [];
732
- const highlightNodes: Element[] = [];
733
- const textNodes = element.childTextNodes();
734
- const lineText = textNodes
735
- .map(function(node) {
736
- return node.textContent;
737
- })
738
- .join('');
739
- const ownerDocument = element.ownerDocument;
740
-
741
- if (textNodes.length === 0) {
742
- return highlightNodes;
743
- }
744
-
745
- const nodeRanges: TextUtils.TextRange.SourceRange[] = [];
746
- let rangeEndOffset = 0;
747
- for (const textNode of textNodes) {
748
- const range =
749
- new TextUtils.TextRange.SourceRange(rangeEndOffset, textNode.textContent ? textNode.textContent.length : 0);
750
- rangeEndOffset = range.offset + range.length;
751
- nodeRanges.push(range);
752
- }
753
-
754
- let startIndex = 0;
755
- for (let i = 0; i < resultRanges.length; ++i) {
756
- const startOffset = resultRanges[i].offset;
757
- const endOffset = startOffset + resultRanges[i].length;
758
-
759
- while (startIndex < textNodes.length &&
760
- nodeRanges[startIndex].offset + nodeRanges[startIndex].length <= startOffset) {
761
- startIndex++;
762
- }
763
- let endIndex = startIndex;
764
- while (endIndex < textNodes.length && nodeRanges[endIndex].offset + nodeRanges[endIndex].length < endOffset) {
765
- endIndex++;
766
- }
767
- if (endIndex === textNodes.length) {
768
- break;
769
- }
770
-
771
- const highlightNode = ownerDocument.createElement('span');
772
- highlightNode.className = styleClass;
773
- highlightNode.textContent = lineText.substring(startOffset, endOffset);
774
-
775
- const lastTextNode = textNodes[endIndex];
776
- const lastText = lastTextNode.textContent || '';
777
- lastTextNode.textContent = lastText.substring(endOffset - nodeRanges[endIndex].offset);
778
- changes.push({
779
- node: (lastTextNode as Element),
780
- type: 'changed',
781
- oldText: lastText,
782
- newText: lastTextNode.textContent,
783
- nextSibling: undefined,
784
- parent: undefined,
785
- });
786
-
787
- if (startIndex === endIndex && lastTextNode.parentElement) {
788
- lastTextNode.parentElement.insertBefore(highlightNode, lastTextNode);
789
- changes.push({
790
- node: highlightNode,
791
- type: 'added',
792
- nextSibling: lastTextNode,
793
- parent: lastTextNode.parentElement,
794
- oldText: undefined,
795
- newText: undefined,
796
- });
797
- highlightNodes.push(highlightNode);
798
-
799
- const prefixNode =
800
- ownerDocument.createTextNode(lastText.substring(0, startOffset - nodeRanges[startIndex].offset));
801
- lastTextNode.parentElement.insertBefore(prefixNode, highlightNode);
802
- changes.push({
803
- node: prefixNode,
804
- type: 'added',
805
- nextSibling: highlightNode,
806
- parent: lastTextNode.parentElement,
807
- oldText: undefined,
808
- newText: undefined,
809
- });
810
- } else {
811
- const firstTextNode = textNodes[startIndex];
812
- const firstText = firstTextNode.textContent || '';
813
- const anchorElement = firstTextNode.nextSibling;
814
-
815
- if (firstTextNode.parentElement) {
816
- firstTextNode.parentElement.insertBefore(highlightNode, anchorElement);
817
- changes.push({
818
- node: highlightNode,
819
- type: 'added',
820
- nextSibling: anchorElement || undefined,
821
- parent: firstTextNode.parentElement,
822
- oldText: undefined,
823
- newText: undefined,
824
- });
825
- highlightNodes.push(highlightNode);
826
- }
827
-
828
- firstTextNode.textContent = firstText.substring(0, startOffset - nodeRanges[startIndex].offset);
829
- changes.push({
830
- node: (firstTextNode as Element),
831
- type: 'changed',
832
- oldText: firstText,
833
- newText: firstTextNode.textContent,
834
- nextSibling: undefined,
835
- parent: undefined,
836
- });
837
-
838
- for (let j = startIndex + 1; j < endIndex; j++) {
839
- const textNode = textNodes[j];
840
- const text = textNode.textContent;
841
- textNode.textContent = '';
842
- changes.push({
843
- node: (textNode as Element),
844
- type: 'changed',
845
- oldText: text || undefined,
846
- newText: textNode.textContent,
847
- nextSibling: undefined,
848
- parent: undefined,
849
- });
850
- }
851
- }
852
- startIndex = endIndex;
853
- nodeRanges[startIndex].offset = endOffset;
854
- nodeRanges[startIndex].length = lastTextNode.textContent.length;
855
- }
856
- return highlightNodes;
857
- }
858
-
859
- /** Used in chromium/src/third_party/blink/web_tests/http/tests/devtools/components/utilities-highlight-results.js **/
860
- export function applyDomChanges(domChanges: HighlightChange[]): void {
861
- for (let i = 0, size = domChanges.length; i < size; ++i) {
862
- const entry = domChanges[i];
863
- switch (entry.type) {
864
- case 'added':
865
- entry.parent?.insertBefore(entry.node, entry.nextSibling ?? null);
866
- break;
867
- case 'changed':
868
- entry.node.textContent = entry.newText ?? null;
869
- break;
870
- }
871
- }
872
- }
873
-
874
- export function revertDomChanges(domChanges: HighlightChange[]): void {
875
- for (let i = domChanges.length - 1; i >= 0; --i) {
876
- const entry = domChanges[i];
877
- switch (entry.type) {
878
- case 'added':
879
- entry.node.remove();
880
- break;
881
- case 'changed':
882
- entry.node.textContent = entry.oldText ?? null;
883
- break;
884
- }
885
- }
886
- }
887
-
888
713
  export function measurePreferredSize(element: Element, containerElement?: Element|null): Geometry.Size {
889
714
  const oldParent = element.parentElement;
890
715
  const oldNextSibling = element.nextSibling;
@@ -1802,15 +1627,6 @@ export interface Options {
1802
1627
  expand?: boolean;
1803
1628
  }
1804
1629
 
1805
- export interface HighlightChange {
1806
- node: Element|Text;
1807
- type: string;
1808
- oldText?: string;
1809
- newText?: string;
1810
- nextSibling?: Node;
1811
- parent?: Node;
1812
- }
1813
-
1814
1630
  export const isScrolledToBottom = (element: Element): boolean => {
1815
1631
  // This code works only for 0-width border.
1816
1632
  // The scrollTop, clientHeight and scrollHeight are computed in double values internally.
@@ -10,6 +10,7 @@ import * as Host from '../../core/host/host.js';
10
10
  import * as i18n from '../../core/i18n/i18n.js';
11
11
  import * as Platform from '../../core/platform/platform.js';
12
12
  import * as Root from '../../core/root/root.js';
13
+ import type * as Foundation from '../../foundation/foundation.js';
13
14
  import * as IconButton from '../components/icon_button/icon_button.js';
14
15
  import * as VisualLogging from '../visual_logging/visual_logging.js';
15
16
 
@@ -52,10 +53,12 @@ export const defaultOptionsForTabs = {
52
53
 
53
54
  export class PreRegisteredView implements View {
54
55
  private readonly viewRegistration: ViewRegistration;
56
+ private readonly universe?: Foundation.Universe.Universe;
55
57
  private widgetPromise: Promise<Widget>|null;
56
58
 
57
- constructor(viewRegistration: ViewRegistration) {
59
+ constructor(viewRegistration: ViewRegistration, universe?: Foundation.Universe.Universe) {
58
60
  this.viewRegistration = viewRegistration;
61
+ this.universe = universe;
59
62
  this.widgetPromise = null;
60
63
  }
61
64
 
@@ -124,7 +127,10 @@ export class PreRegisteredView implements View {
124
127
 
125
128
  widget(): Promise<Widget> {
126
129
  if (this.widgetPromise === null) {
127
- this.widgetPromise = this.viewRegistration.loadView();
130
+ if (!this.universe) {
131
+ throw new Error('Creating views via ViewManager requires a Foundation.Universe');
132
+ }
133
+ this.widgetPromise = this.viewRegistration.loadView(this.universe);
128
134
  }
129
135
  return this.widgetPromise;
130
136
  }
@@ -168,7 +174,11 @@ export class ViewManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
168
174
  private readonly locationNameByViewId = new Map<string, string>();
169
175
  private readonly locationOverrideSetting: Common.Settings.Setting<Record<string, string>>;
170
176
 
171
- private constructor() {
177
+ private readonly preRegisteredViews: PreRegisteredView[] = [];
178
+
179
+ // TODO(crbug.com/458180550): Pass the universe unconditionally once tests no longer rely
180
+ // on `instance()` to create ViewManagers lazily in after/afterEach blocks.
181
+ private constructor(universe?: Foundation.Universe.Universe) {
172
182
  super();
173
183
 
174
184
  // Read override setting for location
@@ -180,9 +190,9 @@ export class ViewManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
180
190
 
181
191
  const viewsByLocation = new Map<ViewLocationValues|'none', PreRegisteredView[]>();
182
192
  for (const view of getRegisteredViewExtensions()) {
183
- const location = view.location() || 'none';
193
+ const location = view.location || 'none';
184
194
  const views = viewsByLocation.get(location) || [];
185
- views.push(view);
195
+ views.push(new PreRegisteredView(view, universe));
186
196
  viewsByLocation.set(location, views);
187
197
  }
188
198
 
@@ -209,6 +219,7 @@ export class ViewManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
209
219
  throw new Error(`Invalid view ID '${viewId}'`);
210
220
  }
211
221
  this.views.set(viewId, view);
222
+ this.preRegisteredViews.push(view);
212
223
  // Use the preferred user location if available
213
224
  const locationName = preferredExtensionLocations[viewId] || location;
214
225
  this.locationNameByViewId.set(viewId, locationName as string);
@@ -217,10 +228,11 @@ export class ViewManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
217
228
 
218
229
  static instance(opts: {
219
230
  forceNew: boolean|null,
231
+ universe?: Foundation.Universe.Universe,
220
232
  } = {forceNew: null}): ViewManager {
221
- const {forceNew} = opts;
233
+ const {forceNew, universe} = opts;
222
234
  if (!viewManagerInstance || forceNew) {
223
- viewManagerInstance = new ViewManager();
235
+ viewManagerInstance = new ViewManager(universe);
224
236
  }
225
237
 
226
238
  return viewManagerInstance;
@@ -241,6 +253,10 @@ export class ViewManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
241
253
  return toolbar;
242
254
  }
243
255
 
256
+ getRegisteredViewExtensions(): PreRegisteredView[] {
257
+ return this.preRegisteredViews;
258
+ }
259
+
244
260
  locationNameForViewId(viewId: string): string {
245
261
  const locationName = this.locationNameByViewId.get(viewId);
246
262
  if (!locationName) {
@@ -1004,7 +1020,6 @@ class StackLocation extends Location implements ViewLocation {
1004
1020
  export {
1005
1021
  getLocalizedViewLocationCategory,
1006
1022
  getRegisteredLocationResolvers,
1007
- getRegisteredViewExtensions,
1008
1023
  maybeRemoveViewExtension,
1009
1024
  registerLocationResolver,
1010
1025
  registerViewExtension,
@@ -5,9 +5,9 @@
5
5
  import * as i18n from '../../core/i18n/i18n.js';
6
6
  import type * as Platform from '../../core/platform/platform.js';
7
7
  import * as Root from '../../core/root/root.js';
8
+ import type * as Foundation from '../../foundation/foundation.js';
8
9
 
9
10
  import type {ViewLocationResolver} from './View.js';
10
- import {PreRegisteredView} from './ViewManager.js';
11
11
  import type {Widget} from './Widget.js';
12
12
 
13
13
  const UIStrings = {
@@ -43,8 +43,6 @@ const UIStrings = {
43
43
  const str_ = i18n.i18n.registerUIStrings('ui/legacy/ViewRegistration.ts', UIStrings);
44
44
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
45
45
 
46
- const registeredViewExtensions: PreRegisteredView[] = [];
47
-
48
46
  export const enum ViewPersistence {
49
47
  CLOSEABLE = 'closeable',
50
48
  PERMANENT = 'permanent',
@@ -115,7 +113,11 @@ export interface ViewRegistration {
115
113
  /**
116
114
  * Returns an instance of the class that wraps the view.
117
115
  * The common pattern for implementing this function is loading the module with the wrapping 'Widget'
118
- * lazily loaded. As an example:
116
+ * lazily loaded.
117
+ * The DevTools universe is passed along, allowing `loadView` to retrieve necessary dependencies.
118
+ * Prefer passing individual dependencies one by one instead of forwarding the full universe. This
119
+ * makes testing easier.
120
+ * As an example:
119
121
  *
120
122
  * ```js
121
123
  * let loadedElementsModule;
@@ -129,15 +131,16 @@ export interface ViewRegistration {
129
131
  * }
130
132
  * UI.ViewManager.registerViewExtension({
131
133
  * <...>
132
- * async loadView() {
134
+ * async loadView(universe) {
133
135
  * const Elements = await loadElementsModule();
134
- * return Elements.ElementsPanel.ElementsPanel.instance();
136
+ * const pageResourceLoader = universe.context.get(SDK.PageResourceLoader.PageResourceLoader);
137
+ * return new Elements.ElementsPanel.ElementsPanel(pageResourceLoader);
135
138
  * },
136
139
  * <...>
137
140
  * });
138
141
  * ```
139
142
  */
140
- loadView: () => Promise<Widget>;
143
+ loadView: (universe: Foundation.Universe.Universe) => Promise<Widget>;
141
144
  /**
142
145
  * Used to sort the views that appear in a shared location.
143
146
  */
@@ -160,28 +163,25 @@ export interface ViewRegistration {
160
163
  featurePromotionId?: string;
161
164
  }
162
165
 
163
- const viewIdSet = new Set<string>();
166
+ const registeredViewExtensions = new Map<string, ViewRegistration>();
167
+
164
168
  export function registerViewExtension(registration: ViewRegistration): void {
165
169
  const viewId = registration.id;
166
- if (viewIdSet.has(viewId)) {
170
+ if (registeredViewExtensions.has(viewId)) {
167
171
  throw new Error(`Duplicate view id '${viewId}'`);
168
172
  }
169
- viewIdSet.add(viewId);
170
- registeredViewExtensions.push(new PreRegisteredView(registration));
173
+ registeredViewExtensions.set(viewId, registration);
171
174
  }
172
175
 
173
- export function getRegisteredViewExtensions(): PreRegisteredView[] {
174
- return registeredViewExtensions.filter(
175
- view => Root.Runtime.Runtime.isDescriptorEnabled({experiment: view.experiment(), condition: view.condition()}));
176
+ export function getRegisteredViewExtensions(): ViewRegistration[] {
177
+ return registeredViewExtensions.values()
178
+ .filter(
179
+ view => Root.Runtime.Runtime.isDescriptorEnabled({experiment: view.experiment, condition: view.condition}))
180
+ .toArray();
176
181
  }
177
182
 
178
183
  export function maybeRemoveViewExtension(viewId: string): boolean {
179
- const viewIndex = registeredViewExtensions.findIndex(view => view.viewId() === viewId);
180
- if (viewIndex < 0 || !viewIdSet.delete(viewId)) {
181
- return false;
182
- }
183
- registeredViewExtensions.splice(viewIndex, 1);
184
- return true;
184
+ return registeredViewExtensions.delete(viewId);
185
185
  }
186
186
 
187
187
  const registeredLocationResolvers: LocationResolverRegistration[] = [];
@@ -202,10 +202,9 @@ export function getRegisteredLocationResolvers(): LocationResolverRegistration[]
202
202
  }
203
203
 
204
204
  export function resetViewRegistration(): void {
205
- registeredViewExtensions.length = 0;
205
+ registeredViewExtensions.clear();
206
206
  registeredLocationResolvers.length = 0;
207
207
  viewLocationNameSet.clear();
208
- viewIdSet.clear();
209
208
  }
210
209
 
211
210
  export const enum ViewLocationCategory {
@@ -37,6 +37,7 @@ import * as SDK from '../../../../core/sdk/sdk.js';
37
37
  import type * as Protocol from '../../../../generated/protocol.js';
38
38
  import * as TextUtils from '../../../../models/text_utils/text_utils.js';
39
39
  import * as uiI18n from '../../../../ui/i18n/i18n.js';
40
+ import * as Highlighting from '../../../components/highlighting/highlighting.js';
40
41
  import * as TextEditor from '../../../components/text_editor/text_editor.js';
41
42
  import {Directives, html, type LitTemplate, nothing, render} from '../../../lit/lit.js';
42
43
  import * as VisualLogging from '../../../visual_logging/visual_logging.js';
@@ -992,7 +993,7 @@ export const TREE_ELEMENT_DEFAULT_VIEW: TreeElementView = (input, output, target
992
993
  export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
993
994
  property: ObjectTreeNode;
994
995
  override toggleOnClick: boolean;
995
- private highlightChanges: UI.UIUtils.HighlightChange[];
996
+ private highlightChanges: Highlighting.HighlightChange[];
996
997
  private linkifier: Components.Linkifier.Linkifier|undefined;
997
998
  private readonly maxNumPropertiesToShow: number;
998
999
  readOnly!: boolean;
@@ -1115,7 +1116,7 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1115
1116
  }
1116
1117
 
1117
1118
  setSearchRegex(regex: RegExp, additionalCssClassName?: string): boolean {
1118
- let cssClasses = UI.UIUtils.highlightedSearchResultClassName;
1119
+ let cssClasses = Highlighting.highlightedSearchResultClassName;
1119
1120
  if (additionalCssClassName) {
1120
1121
  cssClasses += ' ' + additionalCssClassName;
1121
1122
  }
@@ -1144,7 +1145,7 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1144
1145
  match = regex.exec(content);
1145
1146
  }
1146
1147
  if (ranges.length) {
1147
- UI.UIUtils.highlightRangesWithStyleClass(element, ranges, cssClassName, this.highlightChanges);
1148
+ Highlighting.highlightRangesWithStyleClass(element, ranges, cssClassName, this.highlightChanges);
1148
1149
  }
1149
1150
  }
1150
1151
 
@@ -1171,7 +1172,7 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
1171
1172
  }
1172
1173
 
1173
1174
  revertHighlightChanges(): void {
1174
- UI.UIUtils.revertDomChanges(this.highlightChanges);
1175
+ Highlighting.revertDomChanges(this.highlightChanges);
1175
1176
  this.highlightChanges = [];
1176
1177
  }
1177
1178