chrome-devtools-frontend 1.0.1682249 → 1.0.1684555

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 (103) hide show
  1. package/AUTHORS +1 -0
  2. package/front_end/core/sdk/ServiceWorkerCacheModel.ts +0 -7
  3. package/front_end/core/sdk/StorageBucketsModel.ts +0 -6
  4. package/front_end/entrypoints/inspector_main/InspectorMain.ts +2 -1
  5. package/front_end/entrypoints/inspector_main/inspector_main-meta.ts +1 -5
  6. package/front_end/entrypoints/main/MainImpl.ts +6 -4
  7. package/front_end/entrypoints/main/main-meta.ts +9 -51
  8. package/front_end/foundation/Universe.ts +7 -0
  9. package/front_end/generated/InspectorBackendCommands.ts +12 -22
  10. package/front_end/generated/protocol-mapping.d.ts +9 -59
  11. package/front_end/generated/protocol-proxy-api.d.ts +7 -47
  12. package/front_end/generated/protocol.ts +105 -330
  13. package/front_end/models/ai_assistance/AiAgent2.ts +12 -4
  14. package/front_end/models/ai_assistance/AiConversation.ts +25 -7
  15. package/front_end/models/ai_assistance/agents/AiAgent.ts +11 -19
  16. package/front_end/models/ai_assistance/agents/StorageAgent.ts +6 -6
  17. package/front_end/models/ai_assistance/ai_assistance.ts +4 -0
  18. package/front_end/models/ai_assistance/tools/GetLighthouseAudits.ts +12 -6
  19. package/front_end/models/ai_assistance/tools/GetStorageValues.ts +1 -1
  20. package/front_end/models/ai_assistance/tools/ListStorageKeys.ts +1 -1
  21. package/front_end/models/ai_assistance/tools/RunLighthouse.ts +5 -8
  22. package/front_end/models/ai_assistance/tools/Tool.ts +19 -6
  23. package/front_end/models/issues_manager/DOMIssuesManager.ts +144 -0
  24. package/front_end/models/issues_manager/ElementAccessibilityIssue.ts +13 -1
  25. package/front_end/models/issues_manager/GenericIssue.ts +14 -2
  26. package/front_end/models/issues_manager/IssuesManager.ts +0 -1
  27. package/front_end/models/issues_manager/issues_manager.ts +2 -0
  28. package/front_end/models/javascript_metadata/NativeFunctions.js +8 -0
  29. package/front_end/models/trace/Processor.ts +1 -0
  30. package/front_end/panels/ai_assistance/ExternalHandler.ts +89 -0
  31. package/front_end/panels/ai_assistance/ai_assistance.ts +1 -0
  32. package/front_end/panels/application/BackgroundServiceModel.ts +4 -3
  33. package/front_end/panels/application/IndexedDBModel.ts +0 -7
  34. package/front_end/panels/console/ConsoleView.ts +17 -16
  35. package/front_end/panels/console/ConsoleViewMessage.ts +4 -1
  36. package/front_end/panels/console/console-meta.ts +4 -19
  37. package/front_end/panels/elements/ElementIssueUtils.ts +10 -2
  38. package/front_end/panels/elements/ElementsPanel.ts +8 -3
  39. package/front_end/panels/elements/ElementsTreeElement.ts +82 -161
  40. package/front_end/panels/elements/ElementsTreeOutline.ts +26 -105
  41. package/front_end/panels/elements/StandaloneStylesContainer.ts +5 -11
  42. package/front_end/panels/elements/StylePropertyTreeElement.ts +2 -0
  43. package/front_end/panels/elements/StylesContainer.ts +1 -0
  44. package/front_end/panels/elements/StylesSidebarPane.ts +174 -151
  45. package/front_end/panels/network/RequestPayloadView.ts +5 -2
  46. package/front_end/panels/security/SecurityPanelSidebar.ts +0 -32
  47. package/front_end/panels/settings/KeybindsSettingsTab.ts +5 -2
  48. package/front_end/panels/sources/SourcesPanel.ts +6 -3
  49. package/front_end/panels/timeline/components/BreadcrumbsUI.ts +2 -6
  50. package/front_end/panels/timeline/components/CWVMetrics.ts +9 -10
  51. package/front_end/panels/timeline/components/DetailsView.ts +12 -16
  52. package/front_end/panels/timeline/components/ExportTraceOptions.ts +13 -13
  53. package/front_end/panels/timeline/components/FieldSettingsDialog.ts +19 -19
  54. package/front_end/panels/timeline/components/IgnoreListSetting.ts +7 -9
  55. package/front_end/panels/timeline/components/InteractionBreakdown.ts +3 -3
  56. package/front_end/panels/timeline/components/LayoutShiftDetails.ts +13 -13
  57. package/front_end/panels/timeline/components/LiveMetricsView.ts +64 -64
  58. package/front_end/panels/timeline/components/MetricCard.ts +25 -25
  59. package/front_end/panels/timeline/components/NetworkRequestDetails.ts +22 -22
  60. package/front_end/panels/timeline/components/NetworkRequestTooltip.ts +9 -9
  61. package/front_end/panels/timeline/components/OriginMap.ts +7 -7
  62. package/front_end/panels/timeline/components/RelatedInsightChips.ts +2 -2
  63. package/front_end/panels/timeline/components/SidebarAnnotationsTab.ts +19 -20
  64. package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +1 -1
  65. package/front_end/panels/timeline/components/TimelineSummary.ts +2 -2
  66. package/front_end/panels/timeline/components/Utils.ts +2 -6
  67. package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +6 -9
  68. package/front_end/panels/timeline/components/insights/Checklist.ts +2 -2
  69. package/front_end/panels/timeline/components/insights/Table.ts +1 -1
  70. package/front_end/third_party/chromium/README.chromium +1 -1
  71. package/front_end/ui/comments/CommentAnchorResolver.ts +94 -0
  72. package/front_end/ui/comments/CommentOverlayManager.ts +16 -32
  73. package/front_end/ui/components/text_editor/config.ts +2 -1
  74. package/front_end/ui/legacy/DockController.ts +4 -1
  75. package/front_end/ui/legacy/InspectorView.ts +3 -1
  76. package/front_end/ui/legacy/KeyboardShortcut.ts +4 -7
  77. package/front_end/ui/legacy/SearchableView.ts +2 -1
  78. package/front_end/ui/legacy/ShortcutRegistry.ts +6 -3
  79. package/front_end/ui/legacy/UIUtils.ts +10 -6
  80. package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +23 -24
  81. package/front_end/ui/legacy/components/perf_ui/BrickBreaker.ts +2 -2
  82. package/front_end/ui/legacy/components/perf_ui/FilmStripView.ts +6 -6
  83. package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +14 -15
  84. package/front_end/ui/legacy/components/perf_ui/GCActionDelegate.ts +1 -1
  85. package/front_end/ui/legacy/components/perf_ui/NetworkPriorities.ts +5 -5
  86. package/front_end/ui/legacy/components/perf_ui/OverviewGrid.ts +5 -5
  87. package/front_end/ui/legacy/components/perf_ui/PieChart.ts +1 -1
  88. package/front_end/ui/legacy/components/perf_ui/perf_ui-meta.ts +4 -6
  89. package/front_end/ui/legacy/components/source_frame/FontView.ts +2 -2
  90. package/front_end/ui/legacy/components/source_frame/ImageView.ts +13 -13
  91. package/front_end/ui/legacy/components/source_frame/JSONView.ts +1 -1
  92. package/front_end/ui/legacy/components/source_frame/PreviewFactory.ts +2 -2
  93. package/front_end/ui/legacy/components/source_frame/ResourceSourceFrame.ts +1 -1
  94. package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +15 -18
  95. package/front_end/ui/legacy/components/source_frame/XMLView.ts +1 -1
  96. package/front_end/ui/legacy/components/source_frame/source_frame-meta.ts +10 -10
  97. package/front_end/ui/legacy/theme_support/ThemeSupport.ts +5 -2
  98. package/front_end/ui/settings/ConsoleSettings.ts +32 -0
  99. package/front_end/ui/settings/InspectorMainSettings.ts +7 -0
  100. package/front_end/ui/settings/MainSettings.ts +80 -0
  101. package/front_end/ui/settings/settings.ts +4 -0
  102. package/front_end/ui/visual_logging/KnownContextValues.ts +8 -0
  103. package/package.json +1 -1
@@ -58,7 +58,7 @@ import objectValueStyles from '../../ui/legacy/components/object_ui/objectValue.
58
58
  import * as SettingsUI from '../../ui/legacy/components/settings_ui/settings_ui.js';
59
59
  import * as Components from '../../ui/legacy/components/utils/utils.js';
60
60
  import * as UI from '../../ui/legacy/legacy.js';
61
- import * as SettingUIRegistration from '../../ui/settings/settings.js';
61
+ import * as Settings from '../../ui/settings/settings.js';
62
62
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
63
63
  import {AiCodeCompletionSummaryToolbar} from '../common/common.js';
64
64
 
@@ -316,7 +316,7 @@ export class ConsoleView extends UI.Widget.VBox implements
316
316
  private readonly progressToolbarItem: UI.Toolbar.ToolbarItem;
317
317
  private readonly groupSimilarSetting: Common.Settings.Setting<boolean>;
318
318
  private readonly showCorsErrorsSetting: Common.Settings.Setting<boolean>;
319
- private readonly timestampsSetting: Common.Settings.Setting<unknown>;
319
+ private readonly timestampsSetting: Common.Settings.Setting<boolean>;
320
320
  private readonly consoleHistoryAutocompleteSetting: Common.Settings.Setting<boolean>;
321
321
  private selfXssWarningDisabledSetting: Common.Settings.Setting<boolean>;
322
322
  readonly pinPane: ConsolePinPane;
@@ -483,9 +483,10 @@ export class ConsoleView extends UI.Widget.VBox implements
483
483
 
484
484
  const monitoringXHREnabledSetting =
485
485
  Common.Settings.Settings.instance().resolve(SDK.SDKSettings.monitoringXHREnabledSettingDescriptor);
486
- this.timestampsSetting = Common.Settings.Settings.instance().moduleSetting('console-timestamps-enabled');
487
- this.consoleHistoryAutocompleteSetting =
488
- Common.Settings.Settings.instance().moduleSetting('console-history-autocomplete');
486
+ this.timestampsSetting =
487
+ Common.Settings.Settings.instance().resolve(Settings.ConsoleSettings.consoleTimestampsEnabledSettingDescriptor);
488
+ this.consoleHistoryAutocompleteSetting = Common.Settings.Settings.instance().resolve(
489
+ Settings.ConsoleSettings.consoleHistoryAutocompleteSettingDescriptor);
489
490
  this.selfXssWarningDisabledSetting = Common.Settings.Settings.instance().createSetting(
490
491
  'disable-self-xss-warning', false, Common.Settings.SettingStorageType.SYNCED);
491
492
 
@@ -501,29 +502,28 @@ export class ConsoleView extends UI.Widget.VBox implements
501
502
  settingsPane.append(
502
503
  SettingsUI.SettingsUI.createSettingCheckbox(
503
504
  i18nString(UIStrings.networkMessages), this.filter.networkMessagesSetting,
504
- SettingUIRegistration.SettingUIRegistration.resolve(this.filter.networkMessagesSetting.descriptor()).title),
505
+ Settings.SettingUIRegistration.resolve(this.filter.networkMessagesSetting.descriptor()).title),
505
506
  SettingsUI.SettingsUI.createSettingCheckbox(i18nString(UIStrings.logXMLHttpRequests),
506
507
  monitoringXHREnabledSetting),
507
508
  SettingsUI.SettingsUI.createSettingCheckbox(i18nString(UIStrings.preserveLog), preserveConsoleLogSetting,
508
509
  i18nString(UIStrings.doNotClearLogOnPageReload)),
509
510
  SettingsUI.SettingsUI.createSettingCheckbox(
510
- SettingUIRegistration.SettingUIRegistration.resolve(consoleEagerEvalSetting.descriptor()).title,
511
- consoleEagerEvalSetting, i18nString(UIStrings.eagerlyEvaluateTextInThePrompt)),
511
+ Settings.SettingUIRegistration.resolve(consoleEagerEvalSetting.descriptor()).title, consoleEagerEvalSetting,
512
+ i18nString(UIStrings.eagerlyEvaluateTextInThePrompt)),
512
513
  SettingsUI.SettingsUI.createSettingCheckbox(i18nString(UIStrings.selectedContextOnly),
513
514
  this.filter.filterByExecutionContextSetting,
514
515
  i18nString(UIStrings.onlyShowMessagesFromTheCurrentContext)),
515
516
  SettingsUI.SettingsUI.createSettingCheckbox(
516
- SettingUIRegistration.SettingUIRegistration.resolve(this.consoleHistoryAutocompleteSetting.descriptor())
517
- .title,
517
+ Settings.SettingUIRegistration.resolve(this.consoleHistoryAutocompleteSetting.descriptor()).title,
518
518
  this.consoleHistoryAutocompleteSetting, i18nString(UIStrings.autocompleteFromHistory)),
519
519
  SettingsUI.SettingsUI.createSettingCheckbox(
520
- SettingUIRegistration.SettingUIRegistration.resolve(this.groupSimilarSetting.descriptor()).title,
520
+ Settings.SettingUIRegistration.resolve(this.groupSimilarSetting.descriptor()).title,
521
521
  this.groupSimilarSetting, i18nString(UIStrings.groupSimilarMessagesInConsole)),
522
522
  SettingsUI.SettingsUI.createSettingCheckbox(
523
- SettingUIRegistration.SettingUIRegistration.resolve(userActivationEvalSetting.descriptor()).title,
523
+ Settings.SettingUIRegistration.resolve(userActivationEvalSetting.descriptor()).title,
524
524
  userActivationEvalSetting, i18nString(UIStrings.treatEvaluationAsUserActivation)),
525
525
  SettingsUI.SettingsUI.createSettingCheckbox(
526
- SettingUIRegistration.SettingUIRegistration.resolve(this.showCorsErrorsSetting.descriptor()).title,
526
+ Settings.SettingUIRegistration.resolve(this.showCorsErrorsSetting.descriptor()).title,
527
527
  this.showCorsErrorsSetting, i18nString(UIStrings.showCorsErrorsInConsole)),
528
528
  );
529
529
 
@@ -1870,9 +1870,10 @@ export class ConsoleViewFilter {
1870
1870
  this.filterChanged = filterChangedCallback;
1871
1871
 
1872
1872
  this.messageLevelFiltersSetting = ConsoleViewFilter.levelFilterSetting();
1873
- this.networkMessagesSetting = Common.Settings.Settings.instance().moduleSetting('network-messages');
1874
- this.filterByExecutionContextSetting =
1875
- Common.Settings.Settings.instance().moduleSetting('selected-context-filter-enabled');
1873
+ this.networkMessagesSetting =
1874
+ Common.Settings.Settings.instance().resolve(Settings.ConsoleSettings.networkMessagesSettingDescriptor);
1875
+ this.filterByExecutionContextSetting = Common.Settings.Settings.instance().resolve(
1876
+ Settings.ConsoleSettings.selectedContextFilterEnabledSettingDescriptor);
1876
1877
 
1877
1878
  this.messageLevelFiltersSetting.addChangeListener(this.onFilterChanged.bind(this));
1878
1879
  this.networkMessagesSetting.addChangeListener(this.onFilterChanged.bind(this));
@@ -58,6 +58,7 @@ import objectValueStyles from '../../ui/legacy/components/object_ui/objectValue.
58
58
  import * as Components from '../../ui/legacy/components/utils/utils.js';
59
59
  import * as UI from '../../ui/legacy/legacy.js';
60
60
  import {html, type LitTemplate, nothing, render} from '../../ui/lit/lit.js';
61
+ import * as Settings from '../../ui/settings/settings.js';
61
62
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
62
63
  import * as Elements from '../elements/elements.js';
63
64
 
@@ -1238,7 +1239,9 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
1238
1239
  return;
1239
1240
  }
1240
1241
 
1241
- if (Common.Settings.Settings.instance().moduleSetting('console-timestamps-enabled').get()) {
1242
+ if (Common.Settings.Settings.instance()
1243
+ .resolve(Settings.ConsoleSettings.consoleTimestampsEnabledSettingDescriptor)
1244
+ .get()) {
1242
1245
  if (!this.timestampElement) {
1243
1246
  this.timestampElement = document.createElement('span');
1244
1247
  this.timestampElement.classList.add('console-timestamp');
@@ -270,13 +270,9 @@ UI.ActionRegistration.registerActionExtension({
270
270
  },
271
271
  });
272
272
 
273
- Common.Settings.registerSettingExtension({
273
+ SettingsUI.SettingUIRegistration.register(SettingsUI.ConsoleSettings.networkMessagesSettingDescriptor, {
274
274
  category: Common.Settings.SettingCategory.CONSOLE,
275
- storageType: Common.Settings.SettingStorageType.SYNCED,
276
275
  title: i18nLazyString(UIStrings.networkMessages),
277
- settingName: 'network-messages',
278
- settingType: Common.Settings.SettingType.BOOLEAN,
279
- defaultValue: true,
280
276
  options: [
281
277
  {
282
278
  value: true,
@@ -289,13 +285,9 @@ Common.Settings.registerSettingExtension({
289
285
  ],
290
286
  });
291
287
 
292
- Common.Settings.registerSettingExtension({
288
+ SettingsUI.SettingUIRegistration.register(SettingsUI.ConsoleSettings.selectedContextFilterEnabledSettingDescriptor, {
293
289
  category: Common.Settings.SettingCategory.CONSOLE,
294
- storageType: Common.Settings.SettingStorageType.SYNCED,
295
290
  title: i18nLazyString(UIStrings.selectedContextOnly),
296
- settingName: 'selected-context-filter-enabled',
297
- settingType: Common.Settings.SettingType.BOOLEAN,
298
- defaultValue: false,
299
291
  options: [
300
292
  {
301
293
  value: true,
@@ -308,13 +300,9 @@ Common.Settings.registerSettingExtension({
308
300
  ],
309
301
  });
310
302
 
311
- Common.Settings.registerSettingExtension({
303
+ SettingsUI.SettingUIRegistration.register(SettingsUI.ConsoleSettings.consoleTimestampsEnabledSettingDescriptor, {
312
304
  category: Common.Settings.SettingCategory.CONSOLE,
313
- storageType: Common.Settings.SettingStorageType.SYNCED,
314
305
  title: i18nLazyString(UIStrings.timestamps),
315
- settingName: 'console-timestamps-enabled',
316
- settingType: Common.Settings.SettingType.BOOLEAN,
317
- defaultValue: false,
318
306
  options: [
319
307
  {
320
308
  value: true,
@@ -327,12 +315,9 @@ Common.Settings.registerSettingExtension({
327
315
  ],
328
316
  });
329
317
 
330
- Common.Settings.registerSettingExtension({
318
+ SettingsUI.SettingUIRegistration.register(SettingsUI.ConsoleSettings.consoleHistoryAutocompleteSettingDescriptor, {
331
319
  category: Common.Settings.SettingCategory.CONSOLE,
332
320
  title: i18nLazyString(UIStrings.autocompleteFromHistory),
333
- settingName: 'console-history-autocomplete',
334
- settingType: Common.Settings.SettingType.BOOLEAN,
335
- defaultValue: true,
336
321
  options: [
337
322
  {
338
323
  value: true,
@@ -89,8 +89,12 @@ export interface ElementIssueDetails {
89
89
  export function getElementIssueDetails(issue: IssuesManager.Issue.Issue): ElementIssueDetails|undefined {
90
90
  if (issue instanceof IssuesManager.GenericIssue.GenericIssue) {
91
91
  const issueDetails = issue.details();
92
+ const tooltip = getTooltipFromGenericIssue(issueDetails.errorType);
93
+ if (!tooltip) {
94
+ return undefined;
95
+ }
92
96
  return {
93
- tooltip: getTooltipFromGenericIssue(issueDetails.errorType),
97
+ tooltip,
94
98
  nodeId: issueDetails.violatingNodeId,
95
99
  attribute: issueDetails.violatingNodeAttribute,
96
100
  };
@@ -103,8 +107,12 @@ export function getElementIssueDetails(issue: IssuesManager.Issue.Issue): Elemen
103
107
  nodeId: issueDetails.nodeId,
104
108
  };
105
109
  }
110
+ const tooltip = getTooltipFromElementAccessibilityIssue(issueDetails.elementAccessibilityIssueReason);
111
+ if (!tooltip) {
112
+ return undefined;
113
+ }
106
114
  return {
107
- tooltip: getTooltipFromElementAccessibilityIssue(issueDetails.elementAccessibilityIssueReason),
115
+ tooltip,
108
116
  nodeId: issueDetails.nodeId,
109
117
  };
110
118
  }
@@ -44,6 +44,7 @@ import * as ComputedStyle from '../../models/computed_style/computed_style.js';
44
44
  import * as PanelCommon from '../../panels/common/common.js';
45
45
  import type * as Adorners from '../../ui/components/adorners/adorners.js';
46
46
  import * as UI from '../../ui/legacy/legacy.js';
47
+ import * as SettingsUI from '../../ui/settings/settings.js';
47
48
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
48
49
 
49
50
  import {AccessibilityTreeView} from './AccessibilityTreeView.js';
@@ -227,7 +228,10 @@ export class ElementsPanel extends UI.Panel.Panel implements UI.SearchableView.S
227
228
  return this.#domTreeWidget.getTreeOutlineForTesting();
228
229
  }
229
230
 
230
- constructor(targetManager?: SDK.TargetManager.TargetManager, settings?: Common.Settings.Settings) {
231
+ constructor(
232
+ targetManager?: SDK.TargetManager.TargetManager,
233
+ settings?: Common.Settings.Settings,
234
+ ) {
231
235
  super('elements');
232
236
  this.#targetManager = targetManager ?? SDK.TargetManager.TargetManager.instance();
233
237
  this.#settings = settings ?? Common.Settings.Settings.instance();
@@ -294,7 +298,8 @@ export class ElementsPanel extends UI.Panel.Panel implements UI.SearchableView.S
294
298
 
295
299
  this.metricsWidget = new MetricsSidebarPane(this.#computedStyleModel);
296
300
 
297
- this.#settings.moduleSetting('sidebar-position').addChangeListener(this.updateSidebarPosition.bind(this));
301
+ this.#settings.resolve(SettingsUI.MainSettings.sidebarPositionSettingDescriptor)
302
+ .addChangeListener(this.updateSidebarPosition.bind(this));
298
303
  this.updateSidebarPosition();
299
304
 
300
305
  this.cssStyleTrackerByCSSModel = new Map();
@@ -1180,7 +1185,7 @@ export class ElementsPanel extends UI.Panel.Panel implements UI.SearchableView.S
1180
1185
  return;
1181
1186
  } // We can't reparent extension iframes.
1182
1187
 
1183
- const position = this.#settings.moduleSetting('sidebar-position').get();
1188
+ const position = this.#settings.resolve(SettingsUI.MainSettings.sidebarPositionSettingDescriptor).get();
1184
1189
  let splitMode = SplitMode.HORIZONTAL;
1185
1190
  if (position === 'right' || (position === 'auto' && this.splitWidget.element.offsetWidth > 680)) {
1186
1191
  splitMode = SplitMode.VERTICAL;
@@ -49,7 +49,7 @@ import * as AIAssistance from '../../models/ai_assistance/ai_assistance.js';
49
49
  import * as Badges from '../../models/badges/badges.js';
50
50
  import * as Bindings from '../../models/bindings/bindings.js';
51
51
  import type * as Elements from '../../models/elements/elements.js';
52
- import type * as IssuesManager from '../../models/issues_manager/issues_manager.js';
52
+ import * as IssuesManager from '../../models/issues_manager/issues_manager.js';
53
53
  import * as Workspace from '../../models/workspace/workspace.js';
54
54
  import * as CodeMirror from '../../third_party/codemirror.next/codemirror.next.js';
55
55
  import type * as Adorners from '../../ui/components/adorners/adorners.js';
@@ -73,7 +73,7 @@ import {type ElementsTreeOutline, MappedCharToEntity} from './ElementsTreeOutlin
73
73
  import {ImagePreviewPopover} from './ImagePreviewPopover.js';
74
74
  import {getRegisteredDecorators, type MarkerDecorator, type MarkerDecoratorRegistration} from './MarkerDecorator.js';
75
75
 
76
- const {html, nothing, render, Directives: {ref, repeat}} = Lit;
76
+ const {html, nothing, render, Directives: {classMap, ref, repeat, until}} = Lit;
77
77
  const {animateOn} = UI.UIUtils;
78
78
 
79
79
  const UIStrings = {
@@ -268,6 +268,7 @@ export interface ViewInput {
268
268
  updateRecord: Elements.ElementUpdateRecord.ElementUpdateRecord|null;
269
269
  onHighlightSearchResults: () => void;
270
270
  onExpand: () => void;
271
+ issues?: IssuesManager.Issue.Issue[];
271
272
 
272
273
  containerAdornerActive: boolean;
273
274
  flexAdornerActive: boolean;
@@ -379,10 +380,12 @@ function renderTitle(
379
380
  updateRecord: Elements.ElementUpdateRecord.ElementUpdateRecord|null,
380
381
  onUpdateSearchHighlight: () => void,
381
382
  onExpand: () => void,
383
+ issues?: IssuesManager.Issue.Issue[],
382
384
  ): Lit.LitTemplate {
383
385
  switch (node.nodeType()) {
384
386
  case Node.ATTRIBUTE_NODE:
385
- return renderAttribute({name: node.name as string, value: node.value as string}, updateRecord, true, node);
387
+ return renderAttribute({name: node.name as string, value: node.value as string}, updateRecord, true, node,
388
+ issues);
386
389
 
387
390
  case Node.ELEMENT_NODE: {
388
391
  if (node.pseudoType()) {
@@ -396,10 +399,10 @@ function renderTitle(
396
399
 
397
400
  const tagName = node.nodeNameInCorrectCase();
398
401
  if (isClosingTag) {
399
- return renderTag(node, tagName, true, expanded, true, updateRecord);
402
+ return renderTag(node, tagName, true, expanded, true, updateRecord, issues);
400
403
  }
401
404
 
402
- const openingTag = renderTag(node, tagName, false, expanded, false, updateRecord);
405
+ const openingTag = renderTag(node, tagName, false, expanded, false, updateRecord, issues);
403
406
 
404
407
  if (isExpandable) {
405
408
  if (!expanded) {
@@ -407,7 +410,7 @@ function renderTitle(
407
410
  {clickHandler: onExpand} as
408
411
  ElementsComponents.ElementsTreeExpandButton
409
412
  .ElementsTreeExpandButtonData}></devtools-elements-tree-expand-button><span style="font-size: 0;"
410
- >…</span>\u200B${renderTag(node, tagName, true, expanded, false, updateRecord)}`;
413
+ >…</span>\u200B${renderTag(node, tagName, true, expanded, false, updateRecord, issues)}`;
411
414
  }
412
415
  return openingTag;
413
416
  }
@@ -429,14 +432,13 @@ function renderTitle(
429
432
 
430
433
  return html`${openingTag}<span class="webkit-html-text-node" jslog=${
431
434
  VisualLogging.value('text-node').track({change: true, dblclick: true})} ${
432
- animateOn(
433
- Boolean((updateRecord?.hasChangedChildren() || updateRecord?.isCharDataModified())),
434
- DOM_UPDATE_ANIMATION_CLASS_NAME)} ${renderTextNode}></span>\u200B${
435
- renderTag(node, tagName, true, expanded, false, updateRecord)}`;
435
+ animateOn(Boolean((updateRecord?.hasChangedChildren() || updateRecord?.isCharDataModified())),
436
+ DOM_UPDATE_ANIMATION_CLASS_NAME)} ${renderTextNode}></span>\u200B${
437
+ renderTag(node, tagName, true, expanded, false, updateRecord, issues)}`;
436
438
  }
437
439
 
438
440
  if (isXMLMimeType || !ForbiddenClosingTagElements.has(tagName)) {
439
- return html`${openingTag}${renderTag(node, tagName, true, expanded, false, updateRecord)}`;
441
+ return html`${openingTag}${renderTag(node, tagName, true, expanded, false, updateRecord, issues)}`;
440
442
  }
441
443
  return openingTag;
442
444
  }
@@ -609,9 +611,9 @@ function renderLinkifiedValue(value: string, node: SDK.DOMModel.DOMNode): Lit.Te
609
611
  const relationPromisesCache = new WeakMap<SDK.DOMModel.DOMNode, Map<string, Promise<string|Lit.LitTemplate>>>();
610
612
  const relatedElementsCache = new WeakMap<SDK.DOMModel.DOMNode, Map<string, SDK.DOMModel.DOMNode|null>>();
611
613
 
612
- function renderAttribute(
613
- attr: {name: string, value?: string}, updateRecord: Elements.ElementUpdateRecord.ElementUpdateRecord|null,
614
- isDiff: boolean, node: SDK.DOMModel.DOMNode): Lit.LitTemplate {
614
+ function renderAttribute(attr: {name: string, value?: string},
615
+ updateRecord: Elements.ElementUpdateRecord.ElementUpdateRecord|null, isDiff: boolean,
616
+ node: SDK.DOMModel.DOMNode, issues?: IssuesManager.Issue.Issue[]): Lit.LitTemplate {
615
617
  const name = attr.name;
616
618
  const value = attr.value || '';
617
619
  const forceValue = isDiff;
@@ -716,9 +718,15 @@ function renderAttribute(
716
718
  dblclick: true,
717
719
  });
718
720
 
719
- return html`<span class="webkit-html-attribute" jslog=${jslog}><span class="webkit-html-attribute-name"
721
+ const hasAttributeIssues = Boolean(issues?.some(issue => getElementIssueDetails(issue)?.attribute === name));
722
+ const attributeNameClasses = {
723
+ 'webkit-html-attribute-name': true,
724
+ 'violating-element': hasAttributeIssues,
725
+ };
726
+
727
+ return html`<span class="webkit-html-attribute" jslog=${jslog}><span class=${classMap(attributeNameClasses)}
720
728
  ${animateOn(Boolean(updateRecord?.isAttributeModified(name) && !hasText), DOM_UPDATE_ANIMATION_CLASS_NAME)}>${
721
- linkifyName && relationPromise ? Lit.Directives.until(relationPromise, name) : name}</span>${
729
+ linkifyName && relationPromise ? until(relationPromise, name) : name}</span>${
722
730
  hasText ?
723
731
  html`=\u200B"<span class="webkit-html-attribute-value" ${
724
732
  animateOn(Boolean(updateRecord?.isAttributeModified(name) && hasText),
@@ -726,16 +734,15 @@ function renderAttribute(
726
734
  ${valueType === ValueType.SRC ? renderLinkifiedValue(value, node) : nothing}
727
735
  ${
728
736
  valueType === ValueType.SRCSET ? renderLinkifiedSrcset(Common.Srcset.parseSrcset(value), node) : nothing}
729
- ${linkifyValue && relationPromise ? Lit.Directives.until(relationPromise, value) : nothing}
737
+ ${linkifyValue && relationPromise ? until(relationPromise, value) : nothing}
730
738
  </span>"` :
731
739
  nothing}</span>`;
732
740
  }
733
741
 
734
- function renderTag(
735
- node: SDK.DOMModel.DOMNode, tagName: string, isClosingTag: boolean, expanded: boolean,
736
- isDistinctTreeElement: boolean,
737
- updateRecord: Elements.ElementUpdateRecord.ElementUpdateRecord|null): Lit.LitTemplate {
738
- const classMap = {
742
+ function renderTag(node: SDK.DOMModel.DOMNode, tagName: string, isClosingTag: boolean, expanded: boolean,
743
+ isDistinctTreeElement: boolean, updateRecord: Elements.ElementUpdateRecord.ElementUpdateRecord|null,
744
+ issues?: IssuesManager.Issue.Issue[]): Lit.LitTemplate {
745
+ const tagClasses = {
739
746
  'webkit-html-tag': true,
740
747
  close: isClosingTag && isDistinctTreeElement,
741
748
  };
@@ -757,14 +764,22 @@ function renderTag(
757
764
  });
758
765
 
759
766
  const tagNameClass = isClosingTag ? 'webkit-html-close-tag-name' : 'webkit-html-tag-name';
767
+ const hasTagIssues = !isClosingTag && Boolean(issues?.some(issue => {
768
+ const details = getElementIssueDetails(issue);
769
+ return Boolean(details && !details.attribute);
770
+ }));
771
+ const tagNameClasses = {
772
+ [tagNameClass]: true,
773
+ 'violating-element': hasTagIssues,
774
+ };
760
775
  const tagString = (isClosingTag ? '/' : '') + tagName;
761
776
  const jslog = !isClosingTag ? VisualLogging.value('tag-name').track({change: true, dblclick: true}) : '';
762
777
 
763
778
  return html`<span
764
- class=${Lit.Directives.classMap(classMap)} ${setAriaLabel}
765
- >&lt;<span class=${tagNameClass} jslog=${jslog || nothing} ${
779
+ class=${classMap(tagClasses)} ${setAriaLabel}
780
+ >&lt;<span class=${classMap(tagNameClasses)} jslog=${jslog || nothing} ${
766
781
  animateOn(hasUpdates, DOM_UPDATE_ANIMATION_CLASS_NAME)}>${tagString}</span>${
767
- attributes.map(attr => html` ${renderAttribute(attr, updateRecord, false, node)}`)}&gt;</span>\u200B`;
782
+ attributes.map(attr => html` ${renderAttribute(attr, updateRecord, false, node, issues)}`)}&gt;</span>\u200B`;
768
783
  }
769
784
 
770
785
  function maybeRenderAdAdorner(input: ViewInput): Lit.TemplateResult|typeof nothing {
@@ -848,11 +863,12 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
848
863
  input.updateRecord,
849
864
  input.onHighlightSearchResults,
850
865
  input.onExpand,
866
+ input.issues,
851
867
  )}</span>` : nothing}
852
868
  ${input.isHovered || input.isSelected ? html`
853
869
  <div class="selection fill ${input.editorState ? 'hidden' : ''}" style=${`margin-left: ${-input.indent}px`}></div>
854
870
  ` : nothing}
855
- <div class=${Lit.Directives.classMap(gutterContainerClasses)}
871
+ <div class=${classMap(gutterContainerClasses)}
856
872
  style="left: ${-input.indent}px"
857
873
  @click=${input.onGutterClick}>
858
874
  <devtools-icon name="dots-horizontal"></devtools-icon>
@@ -1078,6 +1094,9 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
1078
1094
  type View = typeof DEFAULT_VIEW;
1079
1095
 
1080
1096
  export class ElementsTreeWidget extends UI.Widget.Widget {
1097
+ static override readonly INJECT = [IssuesManager.DOMIssuesManager.DOMIssuesManager] as const;
1098
+ #domIssuesManager?: IssuesManager.DOMIssuesManager.DOMIssuesManager;
1099
+
1081
1100
  #node!: SDK.DOMModel.DOMNode;
1082
1101
  isClosingTag = false;
1083
1102
  #expanded = false;
@@ -1104,7 +1123,6 @@ export class ElementsTreeWidget extends UI.Widget.Widget {
1104
1123
  revealInTopLayer?: (node: SDK.DOMModel.DOMNode) => void;
1105
1124
  showContextMenu?: (event: Event) => void;
1106
1125
  populateTreeElement?: () => Promise<void>;
1107
- updateNodeElementToIssue?: (nodeElement: Element, issues: IssuesManager.Issue.Issue[]) => void;
1108
1126
  performCopyOrCut?: (isCut: boolean, node: SDK.DOMModel.DOMNode, isElement?: boolean) => void;
1109
1127
  duplicateNode?: (node: SDK.DOMModel.DOMNode) => void;
1110
1128
  pasteNode?: (node: SDK.DOMModel.DOMNode) => void;
@@ -1133,8 +1151,6 @@ export class ElementsTreeWidget extends UI.Widget.Widget {
1133
1151
  #editorState: CodeMirror.EditorState|null = null;
1134
1152
  #editorWidth: number|null = null;
1135
1153
  expandAllButtonElement: UI.TreeOutline.TreeElement|null;
1136
- #elementIssues = new Map<string, IssuesManager.Issue.Issue>();
1137
- #nodeElementToIssue = new Map<Element, IssuesManager.Issue.Issue[]>();
1138
1154
  #highlights: Range[] = [];
1139
1155
 
1140
1156
  #adornersThrottler = new Common.Throttler.Throttler(100);
@@ -1205,8 +1221,28 @@ export class ElementsTreeWidget extends UI.Widget.Widget {
1205
1221
  };
1206
1222
  }
1207
1223
 
1208
- constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
1224
+ get issues(): IssuesManager.Issue.Issue[] {
1225
+ // The widget is currently created for non-widget ElementsTreeElement so
1226
+ // the domIssuesManager can be empty, relying on the manual resolution.
1227
+ if (!this.#domIssuesManager) {
1228
+ const universe = UI.Widget.lookupUniverseForElement(this.contentElement);
1229
+ if (universe) {
1230
+ this.#domIssuesManager = universe.get(IssuesManager.DOMIssuesManager.DOMIssuesManager);
1231
+ if (this.node?.id) {
1232
+ this.#domIssuesManager.subscribeByNodeId(this.node.id, this.#onDOMIssueUpdated);
1233
+ }
1234
+ }
1235
+ }
1236
+ return this.#domIssuesManager?.issuesForNode(this.node) ?? [];
1237
+ }
1238
+
1239
+ constructor(
1240
+ element?: HTMLElement,
1241
+ [domIssuesManager]: UI.Widget.WidgetDependencies<typeof ElementsTreeWidget>|[undefined] = [undefined],
1242
+ view: View = DEFAULT_VIEW,
1243
+ ) {
1209
1244
  super(element);
1245
+ this.#domIssuesManager = domIssuesManager;
1210
1246
  this.#view = view;
1211
1247
 
1212
1248
  this.searchQuery = null;
@@ -1382,6 +1418,7 @@ export class ElementsTreeWidget extends UI.Widget.Widget {
1382
1418
  },
1383
1419
  editorState: this.#editorState,
1384
1420
  editorWidth: this.#editorWidth,
1421
+ issues: this.issues,
1385
1422
  },
1386
1423
  output, this.contentElement);
1387
1424
 
@@ -1560,121 +1597,6 @@ export class ElementsTreeWidget extends UI.Widget.Widget {
1560
1597
  this.requestUpdate();
1561
1598
  }
1562
1599
 
1563
- addIssue(newIssue: IssuesManager.Issue.Issue): void {
1564
- if (this.#elementIssues.has(newIssue.primaryKey())) {
1565
- return;
1566
- }
1567
-
1568
- this.#elementIssues.set(newIssue.primaryKey(), newIssue);
1569
- this.#applyIssueStyleAndTooltip(newIssue);
1570
- }
1571
-
1572
- #applyIssueStyleAndTooltip(issue: IssuesManager.Issue.Issue): void {
1573
- const elementIssueDetails = getElementIssueDetails(issue);
1574
- if (!elementIssueDetails) {
1575
- return;
1576
- }
1577
-
1578
- if (elementIssueDetails.attribute) {
1579
- this.#highlightViolatingAttr(elementIssueDetails.attribute, issue);
1580
- } else {
1581
- this.#highlightTagAsViolating(issue);
1582
- }
1583
- }
1584
-
1585
- get issuesByNodeElement(): Map<Element, IssuesManager.Issue.Issue[]> {
1586
- return this.#nodeElementToIssue;
1587
- }
1588
-
1589
- #highlightViolatingAttr(name: string, issue: IssuesManager.Issue.Issue): void {
1590
- const tag = this.contentElement.querySelectorAll('.webkit-html-tag')[0];
1591
- const attributes = tag.getElementsByClassName('webkit-html-attribute');
1592
- for (const attribute of attributes) {
1593
- if (attribute.getElementsByClassName('webkit-html-attribute-name')[0].textContent === name) {
1594
- const attributeElement = attribute.getElementsByClassName('webkit-html-attribute-name')[0];
1595
- attributeElement.classList.add('violating-element');
1596
- this.#recordAndNotifyIssue(attributeElement, issue);
1597
- }
1598
- }
1599
- }
1600
-
1601
- #highlightTagAsViolating(issue: IssuesManager.Issue.Issue): void {
1602
- const tagElement = this.contentElement.querySelectorAll('.webkit-html-tag-name')[0];
1603
- tagElement.classList.add('violating-element');
1604
- this.#recordAndNotifyIssue(tagElement, issue);
1605
- }
1606
-
1607
- #recordAndNotifyIssue(nodeElement: Element, issue: IssuesManager.Issue.Issue): void {
1608
- let issues = this.#nodeElementToIssue.get(nodeElement);
1609
- if (!issues) {
1610
- issues = [];
1611
- this.#nodeElementToIssue.set(nodeElement, issues);
1612
- }
1613
- issues.push(issue);
1614
- this.updateNodeElementToIssue?.(nodeElement, issues);
1615
- }
1616
-
1617
- removeIssue(issue: IssuesManager.Issue.Issue): void {
1618
- if (!this.#elementIssues.has(issue.primaryKey())) {
1619
- return;
1620
- }
1621
-
1622
- this.#removeIssueStyleAndTooltip(issue);
1623
- this.#elementIssues.delete(issue.primaryKey());
1624
- }
1625
-
1626
- #removeIssueStyleAndTooltip(issue: IssuesManager.Issue.Issue): void {
1627
- const elementIssueDetails = getElementIssueDetails(issue);
1628
- if (!elementIssueDetails) {
1629
- return;
1630
- }
1631
-
1632
- if (elementIssueDetails.attribute) {
1633
- this.#undoHighlightViolatingAttr(elementIssueDetails.attribute, issue);
1634
- } else {
1635
- this.#undoHighlightTagAsViolating(issue);
1636
- }
1637
- }
1638
-
1639
- #undoHighlightViolatingAttr(name: string, issue: IssuesManager.Issue.Issue): void {
1640
- const violatingAttributes = this.contentElement.querySelectorAll('.webkit-html-attribute-name.violating-element');
1641
- for (const attributeElement of violatingAttributes) {
1642
- if (attributeElement.textContent === name) {
1643
- this.#removeFromNodeElementToIssue(attributeElement, issue);
1644
- if (!this.#nodeElementToIssue.has(attributeElement)) {
1645
- attributeElement.classList.remove('violating-element');
1646
- }
1647
- }
1648
- }
1649
- }
1650
-
1651
- #undoHighlightTagAsViolating(issue: IssuesManager.Issue.Issue): void {
1652
- const tagElement = this.contentElement.querySelectorAll('.webkit-html-tag-name')[0];
1653
- if (!tagElement) {
1654
- return;
1655
- }
1656
-
1657
- this.#removeFromNodeElementToIssue(tagElement, issue);
1658
- if (!this.#nodeElementToIssue.has(tagElement)) {
1659
- tagElement.classList.remove('violating-element');
1660
- }
1661
- }
1662
-
1663
- #removeFromNodeElementToIssue(nodeElement: Element, issue: IssuesManager.Issue.Issue): void {
1664
- let issues = this.#nodeElementToIssue.get(nodeElement);
1665
- if (!issues) {
1666
- return;
1667
- }
1668
-
1669
- issues = issues.filter(i => i !== issue);
1670
- if (issues.length === 0) {
1671
- this.#nodeElementToIssue.delete(nodeElement);
1672
- } else {
1673
- this.#nodeElementToIssue.set(nodeElement, issues);
1674
- }
1675
- this.updateNodeElementToIssue?.(nodeElement, issues);
1676
- }
1677
-
1678
1600
  expandedChildrenLimit(): number {
1679
1601
  return this.#expandedChildrenLimit;
1680
1602
  }
@@ -1703,6 +1625,9 @@ export class ElementsTreeWidget extends UI.Widget.Widget {
1703
1625
  this.#onPersistentGridOverlayStateChanged, this);
1704
1626
  this.node.addEventListener(SDK.DOMModel.DOMNodeEvents.SCROLL_SNAP_OVERLAY_STATE_CHANGED,
1705
1627
  this.#onPersistentScrollSnapOverlayStateChanged, this);
1628
+ if (this.#domIssuesManager && this.node.id) {
1629
+ this.#domIssuesManager.subscribeByNodeId(this.node.id, this.#onDOMIssueUpdated);
1630
+ }
1706
1631
  }
1707
1632
  }
1708
1633
 
@@ -1771,6 +1696,7 @@ export class ElementsTreeWidget extends UI.Widget.Widget {
1771
1696
  indent: 0,
1772
1697
  editorState: null,
1773
1698
  editorWidth: null,
1699
+ issues: [],
1774
1700
  },
1775
1701
  {}, this.contentElement);
1776
1702
  }
@@ -1794,8 +1720,15 @@ export class ElementsTreeWidget extends UI.Widget.Widget {
1794
1720
  this.#onPersistentGridOverlayStateChanged, this);
1795
1721
  this.node.removeEventListener(SDK.DOMModel.DOMNodeEvents.SCROLL_SNAP_OVERLAY_STATE_CHANGED,
1796
1722
  this.#onPersistentScrollSnapOverlayStateChanged, this);
1723
+ if (this.#domIssuesManager && this.node.id) {
1724
+ this.#domIssuesManager.unsubscribeByNodeId(this.node.id, this.#onDOMIssueUpdated);
1725
+ }
1797
1726
  }
1798
1727
 
1728
+ #onDOMIssueUpdated = (): void => {
1729
+ this.performUpdate();
1730
+ };
1731
+
1799
1732
  #onScrollableFlagUpdated(): void {
1800
1733
  void this.#updateAdorners();
1801
1734
  }
@@ -2561,11 +2494,6 @@ export class ElementsTreeWidget extends UI.Widget.Widget {
2561
2494
  this.performUpdate();
2562
2495
  this.updateDecorations();
2563
2496
 
2564
- // If there is an issue with this node, make sure to update it.
2565
- for (const issue of this.#elementIssues.values()) {
2566
- this.#applyIssueStyleAndTooltip(issue);
2567
- }
2568
-
2569
2497
  this.#highlightSearchResults();
2570
2498
  }
2571
2499
 
@@ -2859,7 +2787,10 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2859
2787
  };
2860
2788
  }
2861
2789
 
2862
- constructor(node: SDK.DOMModel.DOMNode, isClosingTag?: boolean) {
2790
+ constructor(
2791
+ node: SDK.DOMModel.DOMNode,
2792
+ isClosingTag?: boolean,
2793
+ ) {
2863
2794
  super();
2864
2795
  this.nodeInternal = node;
2865
2796
  this.#isClosingTag = Boolean(isClosingTag);
@@ -2944,15 +2875,6 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
2944
2875
  copyStyles(): Promise<void> {
2945
2876
  return this.widget.copyStyles();
2946
2877
  }
2947
- addIssue(issue: IssuesManager.Issue.Issue): void {
2948
- this.widget.addIssue(issue);
2949
- }
2950
- get issuesByNodeElement(): Map<Element, IssuesManager.Issue.Issue[]> {
2951
- return this.widget.issuesByNodeElement;
2952
- }
2953
- removeIssue(issue: IssuesManager.Issue.Issue): void {
2954
- this.widget.removeIssue(issue);
2955
- }
2956
2878
  setInClipboard(inClipboard: boolean): void {
2957
2879
  this.widget.setInClipboard(inClipboard);
2958
2880
  if (this.listItemElement) {
@@ -3036,7 +2958,6 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
3036
2958
  this.widget.revealInTopLayer = node => outline.revealInTopLayer(node);
3037
2959
  this.widget.showContextMenu = event => void outline.showContextMenu(this, event);
3038
2960
  this.widget.populateTreeElement = async () => await outline.populateTreeElement(this);
3039
- this.widget.updateNodeElementToIssue = (el, issues) => outline.updateNodeElementToIssue(el, issues);
3040
2961
  this.widget.performCopyOrCut = (isCut, node, isElement) => outline.performCopyOrCut(isCut, node, isElement);
3041
2962
  this.widget.duplicateNode = node => outline.duplicateNode(node);
3042
2963
  this.widget.pasteNode = node => outline.pasteNode(node);