chrome-devtools-frontend 1.0.995491 → 1.0.996595

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 (110) hide show
  1. package/AUTHORS +1 -0
  2. package/front_end/core/i18n/locales/af.json +96 -42
  3. package/front_end/core/i18n/locales/am.json +97 -43
  4. package/front_end/core/i18n/locales/ar.json +95 -41
  5. package/front_end/core/i18n/locales/as.json +95 -41
  6. package/front_end/core/i18n/locales/az.json +96 -42
  7. package/front_end/core/i18n/locales/be.json +124 -70
  8. package/front_end/core/i18n/locales/bg.json +96 -42
  9. package/front_end/core/i18n/locales/bn.json +95 -41
  10. package/front_end/core/i18n/locales/bs.json +95 -41
  11. package/front_end/core/i18n/locales/ca.json +96 -42
  12. package/front_end/core/i18n/locales/cs.json +95 -41
  13. package/front_end/core/i18n/locales/cy.json +95 -41
  14. package/front_end/core/i18n/locales/da.json +97 -43
  15. package/front_end/core/i18n/locales/de.json +96 -42
  16. package/front_end/core/i18n/locales/el.json +95 -41
  17. package/front_end/core/i18n/locales/en-GB.json +95 -41
  18. package/front_end/core/i18n/locales/en-US.json +26 -5
  19. package/front_end/core/i18n/locales/en-XL.json +26 -5
  20. package/front_end/core/i18n/locales/es-419.json +95 -41
  21. package/front_end/core/i18n/locales/es.json +101 -47
  22. package/front_end/core/i18n/locales/et.json +95 -41
  23. package/front_end/core/i18n/locales/eu.json +100 -46
  24. package/front_end/core/i18n/locales/fa.json +104 -50
  25. package/front_end/core/i18n/locales/fi.json +95 -41
  26. package/front_end/core/i18n/locales/fil.json +95 -41
  27. package/front_end/core/i18n/locales/fr-CA.json +96 -42
  28. package/front_end/core/i18n/locales/fr.json +95 -41
  29. package/front_end/core/i18n/locales/gl.json +104 -50
  30. package/front_end/core/i18n/locales/gu.json +95 -41
  31. package/front_end/core/i18n/locales/he.json +95 -41
  32. package/front_end/core/i18n/locales/hi.json +98 -44
  33. package/front_end/core/i18n/locales/hr.json +96 -42
  34. package/front_end/core/i18n/locales/hu.json +96 -42
  35. package/front_end/core/i18n/locales/hy.json +95 -41
  36. package/front_end/core/i18n/locales/id.json +97 -43
  37. package/front_end/core/i18n/locales/is.json +95 -41
  38. package/front_end/core/i18n/locales/it.json +96 -42
  39. package/front_end/core/i18n/locales/ja.json +95 -41
  40. package/front_end/core/i18n/locales/ka.json +95 -41
  41. package/front_end/core/i18n/locales/kk.json +98 -44
  42. package/front_end/core/i18n/locales/km.json +95 -41
  43. package/front_end/core/i18n/locales/kn.json +96 -42
  44. package/front_end/core/i18n/locales/ko.json +96 -42
  45. package/front_end/core/i18n/locales/ky.json +97 -43
  46. package/front_end/core/i18n/locales/lo.json +96 -42
  47. package/front_end/core/i18n/locales/lt.json +95 -41
  48. package/front_end/core/i18n/locales/lv.json +95 -41
  49. package/front_end/core/i18n/locales/mk.json +98 -44
  50. package/front_end/core/i18n/locales/ml.json +96 -42
  51. package/front_end/core/i18n/locales/mn.json +96 -42
  52. package/front_end/core/i18n/locales/mr.json +95 -41
  53. package/front_end/core/i18n/locales/ms.json +95 -41
  54. package/front_end/core/i18n/locales/my.json +95 -41
  55. package/front_end/core/i18n/locales/ne.json +100 -46
  56. package/front_end/core/i18n/locales/nl.json +99 -45
  57. package/front_end/core/i18n/locales/no.json +95 -41
  58. package/front_end/core/i18n/locales/or.json +98 -44
  59. package/front_end/core/i18n/locales/pa.json +95 -41
  60. package/front_end/core/i18n/locales/pl.json +95 -41
  61. package/front_end/core/i18n/locales/pt-PT.json +95 -41
  62. package/front_end/core/i18n/locales/pt.json +98 -44
  63. package/front_end/core/i18n/locales/ro.json +96 -42
  64. package/front_end/core/i18n/locales/ru.json +115 -61
  65. package/front_end/core/i18n/locales/si.json +96 -42
  66. package/front_end/core/i18n/locales/sk.json +95 -41
  67. package/front_end/core/i18n/locales/sl.json +95 -41
  68. package/front_end/core/i18n/locales/sq.json +96 -42
  69. package/front_end/core/i18n/locales/sr-Latn.json +96 -42
  70. package/front_end/core/i18n/locales/sr.json +96 -42
  71. package/front_end/core/i18n/locales/sv.json +96 -42
  72. package/front_end/core/i18n/locales/sw.json +97 -43
  73. package/front_end/core/i18n/locales/ta.json +96 -42
  74. package/front_end/core/i18n/locales/te.json +108 -54
  75. package/front_end/core/i18n/locales/th.json +95 -41
  76. package/front_end/core/i18n/locales/tr.json +95 -41
  77. package/front_end/core/i18n/locales/uk.json +95 -41
  78. package/front_end/core/i18n/locales/ur.json +95 -41
  79. package/front_end/core/i18n/locales/uz.json +95 -41
  80. package/front_end/core/i18n/locales/vi.json +104 -50
  81. package/front_end/core/i18n/locales/zh-HK.json +96 -42
  82. package/front_end/core/i18n/locales/zh-TW.json +97 -43
  83. package/front_end/core/i18n/locales/zh.json +99 -45
  84. package/front_end/core/i18n/locales/zu.json +95 -41
  85. package/front_end/core/sdk/CSSMatchedStyles.ts +158 -33
  86. package/front_end/core/sdk/CSSMetadata.ts +1 -8
  87. package/front_end/generated/InspectorBackendCommands.js +33 -2
  88. package/front_end/generated/protocol.ts +42 -7
  89. package/front_end/models/issues_manager/DeprecationIssue.ts +3 -3
  90. package/front_end/panels/changes/ChangesView.ts +25 -10
  91. package/front_end/panels/elements/ElementsPanel.ts +7 -6
  92. package/front_end/panels/elements/StylesSidebarPane.ts +39 -15
  93. package/front_end/panels/elements/stylesSectionTree.css +1 -0
  94. package/front_end/panels/elements/stylesSidebarPane.css +1 -1
  95. package/front_end/panels/lighthouse/LighthouseController.ts +38 -7
  96. package/front_end/panels/lighthouse/LighthousePanel.ts +1 -1
  97. package/front_end/panels/lighthouse/LighthouseStartView.ts +15 -7
  98. package/front_end/panels/lighthouse/LighthouseStartViewFR.ts +77 -21
  99. package/front_end/panels/lighthouse/RadioSetting.ts +12 -6
  100. package/front_end/panels/lighthouse/lighthouseStartView.css +49 -2
  101. package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +1 -0
  102. package/front_end/panels/security/SecurityPanel.ts +2 -2
  103. package/front_end/ui/components/diff_view/diffView.css +2 -0
  104. package/front_end/ui/components/tree_outline/TreeOutline.ts +18 -7
  105. package/front_end/ui/legacy/Toolbar.ts +5 -0
  106. package/front_end/ui/legacy/softDropDownButton.css +4 -0
  107. package/package.json +2 -1
  108. package/scripts/eslint_rules/lib/inline_type_imports.js +158 -0
  109. package/scripts/eslint_rules/tests/inline_type_imports_test.js +106 -0
  110. package/scripts/javascript_natives/index.js +1 -2
@@ -1020,38 +1020,69 @@ export namespace Audits {
1020
1020
 
1021
1021
  export const enum DeprecationIssueType {
1022
1022
  AuthorizationCoveredByWildcard = 'AuthorizationCoveredByWildcard',
1023
+ BatteryStatusInsecureOrigin = 'BatteryStatusInsecureOrigin',
1024
+ CanRequestURLHTTPContainingNewline = 'CanRequestURLHTTPContainingNewline',
1025
+ ChromeLoadTimesConnectionInfo = 'ChromeLoadTimesConnectionInfo',
1026
+ ChromeLoadTimesFirstPaintAfterLoadTime = 'ChromeLoadTimesFirstPaintAfterLoadTime',
1027
+ ChromeLoadTimesWasAlternateProtocolAvailable = 'ChromeLoadTimesWasAlternateProtocolAvailable',
1023
1028
  CookieWithTruncatingChar = 'CookieWithTruncatingChar',
1024
1029
  CrossOriginAccessBasedOnDocumentDomain = 'CrossOriginAccessBasedOnDocumentDomain',
1025
1030
  CrossOriginWindowAlert = 'CrossOriginWindowAlert',
1026
1031
  CrossOriginWindowConfirm = 'CrossOriginWindowConfirm',
1032
+ CSSSelectorInternalMediaControlsOverlayCastButton = 'CSSSelectorInternalMediaControlsOverlayCastButton',
1033
+ CustomCursorIntersectsViewport = 'CustomCursorIntersectsViewport',
1027
1034
  DeprecationExample = 'DeprecationExample',
1028
1035
  DocumentDomainSettingWithoutOriginAgentClusterHeader = 'DocumentDomainSettingWithoutOriginAgentClusterHeader',
1036
+ EventPath = 'EventPath',
1029
1037
  GeolocationInsecureOrigin = 'GeolocationInsecureOrigin',
1030
1038
  GeolocationInsecureOriginDeprecatedNotRemoved = 'GeolocationInsecureOriginDeprecatedNotRemoved',
1031
1039
  GetUserMediaInsecureOrigin = 'GetUserMediaInsecureOrigin',
1040
+ HostCandidateAttributeGetter = 'HostCandidateAttributeGetter',
1041
+ InsecurePrivateNetworkSubresourceRequest = 'InsecurePrivateNetworkSubresourceRequest',
1032
1042
  LegacyConstraintGoogCpuOveruseDetection = 'LegacyConstraintGoogCpuOveruseDetection',
1033
1043
  LegacyConstraintGoogIPv6 = 'LegacyConstraintGoogIPv6',
1034
1044
  LegacyConstraintGoogScreencastMinBitrate = 'LegacyConstraintGoogScreencastMinBitrate',
1035
1045
  LegacyConstraintGoogSuspendBelowMinBitrate = 'LegacyConstraintGoogSuspendBelowMinBitrate',
1036
1046
  LocalCSSFileExtensionRejected = 'LocalCSSFileExtensionRejected',
1047
+ MediaElementAudioSourceNode = 'MediaElementAudioSourceNode',
1048
+ MediaSourceAbortRemove = 'MediaSourceAbortRemove',
1049
+ MediaSourceDurationTruncatingBuffered = 'MediaSourceDurationTruncatingBuffered',
1050
+ NoSysexWebMIDIWithoutPermission = 'NoSysexWebMIDIWithoutPermission',
1037
1051
  NotificationInsecureOrigin = 'NotificationInsecureOrigin',
1052
+ NotificationPermissionRequestedIframe = 'NotificationPermissionRequestedIframe',
1038
1053
  ObsoleteWebRtcCipherSuite = 'ObsoleteWebRtcCipherSuite',
1054
+ PaymentRequestBasicCard = 'PaymentRequestBasicCard',
1055
+ PaymentRequestShowWithoutGesture = 'PaymentRequestShowWithoutGesture',
1039
1056
  PictureSourceSrc = 'PictureSourceSrc',
1040
1057
  PrefixedCancelAnimationFrame = 'PrefixedCancelAnimationFrame',
1041
1058
  PrefixedRequestAnimationFrame = 'PrefixedRequestAnimationFrame',
1059
+ PrefixedStorageInfo = 'PrefixedStorageInfo',
1060
+ PrefixedVideoDisplayingFullscreen = 'PrefixedVideoDisplayingFullscreen',
1061
+ PrefixedVideoEnterFullscreen = 'PrefixedVideoEnterFullscreen',
1062
+ PrefixedVideoEnterFullScreen = 'PrefixedVideoEnterFullScreen',
1063
+ PrefixedVideoExitFullscreen = 'PrefixedVideoExitFullscreen',
1064
+ PrefixedVideoExitFullScreen = 'PrefixedVideoExitFullScreen',
1065
+ PrefixedVideoSupportsFullscreen = 'PrefixedVideoSupportsFullscreen',
1066
+ RangeExpand = 'RangeExpand',
1067
+ RequestedSubresourceWithEmbeddedCredentials = 'RequestedSubresourceWithEmbeddedCredentials',
1042
1068
  RTCConstraintEnableDtlsSrtpFalse = 'RTCConstraintEnableDtlsSrtpFalse',
1043
1069
  RTCConstraintEnableDtlsSrtpTrue = 'RTCConstraintEnableDtlsSrtpTrue',
1044
1070
  RTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics =
1045
1071
  'RTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics',
1046
1072
  RTCPeerConnectionLegacyCreateWithMediaConstraints = 'RTCPeerConnectionLegacyCreateWithMediaConstraints',
1073
+ RTCPeerConnectionSdpSemanticsPlanB = 'RTCPeerConnectionSdpSemanticsPlanB',
1074
+ RtcpMuxPolicyNegotiate = 'RtcpMuxPolicyNegotiate',
1047
1075
  RTPDataChannel = 'RTPDataChannel',
1076
+ SelectionAddRangeIntersect = 'SelectionAddRangeIntersect',
1048
1077
  SharedArrayBufferConstructedWithoutIsolation = 'SharedArrayBufferConstructedWithoutIsolation',
1078
+ TextToSpeech_DisallowedByAutoplay = 'TextToSpeech_DisallowedByAutoplay',
1049
1079
  Untranslated = 'Untranslated',
1050
1080
  V8SharedArrayBufferConstructedInExtensionWithoutIsolation =
1051
1081
  'V8SharedArrayBufferConstructedInExtensionWithoutIsolation',
1052
1082
  WebCodecsVideoFrameDefaultTimestamp = 'WebCodecsVideoFrameDefaultTimestamp',
1053
1083
  XHRJSONEncodingDetection = 'XHRJSONEncodingDetection',
1054
1084
  XMLHttpRequestSynchronousInNonWorkerOutsideBeforeUnload = 'XMLHttpRequestSynchronousInNonWorkerOutsideBeforeUnload',
1085
+ XRSupportsSession = 'XRSupportsSession',
1055
1086
  }
1056
1087
 
1057
1088
  /**
@@ -5162,6 +5193,8 @@ export namespace Emulation {
5162
5193
  architecture: string;
5163
5194
  model: string;
5164
5195
  mobile: boolean;
5196
+ bitness?: string;
5197
+ wow64?: boolean;
5165
5198
  }
5166
5199
 
5167
5200
  /**
@@ -10200,6 +10233,7 @@ export namespace Page {
10200
10233
  InterestCohort = 'interest-cohort',
10201
10234
  JoinAdInterestGroup = 'join-ad-interest-group',
10202
10235
  KeyboardMap = 'keyboard-map',
10236
+ LocalFonts = 'local-fonts',
10203
10237
  Magnetometer = 'magnetometer',
10204
10238
  Microphone = 'microphone',
10205
10239
  Midi = 'midi',
@@ -11300,15 +11334,16 @@ export namespace Page {
11300
11334
  */
11301
11335
  marginRight?: number;
11302
11336
  /**
11303
- * Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means
11304
- * print all pages.
11337
+ * Paper ranges to print, one based, e.g., '1-5, 8, 11-13'. Pages are
11338
+ * printed in the document order, not in the order specified, and no
11339
+ * more than once.
11340
+ * Defaults to empty string, which implies the entire document is printed.
11341
+ * The page numbers are quietly capped to actual page count of the
11342
+ * document, and ranges beyond the end of the document are ignored.
11343
+ * If this results in no pages to print, an error is reported.
11344
+ * It is an error to specify a range with start greater than end.
11305
11345
  */
11306
11346
  pageRanges?: string;
11307
- /**
11308
- * Whether to silently ignore invalid but successfully parsed page ranges, such as '3-2'.
11309
- * Defaults to false.
11310
- */
11311
- ignoreInvalidPageRanges?: boolean;
11312
11347
  /**
11313
11348
  * HTML template for the print header. Should be valid HTML markup with following
11314
11349
  * classes used to inject printing values into them:
@@ -61,12 +61,12 @@ const UIStrings = {
61
61
  documentDomainSettingWithoutOriginAgentClusterHeader:
62
62
  'Relaxing the same-origin policy by setting `document.domain` is deprecated, and will be disabled by default. To continue using this feature, please opt-out of origin-keyed agent clusters by sending an `Origin-Agent-Cluster: ?0` header along with the HTTP response for the document and frames. See https://developer.chrome.com/blog/immutable-document-domain/ for more details.',
63
63
  /**
64
- *@description TODO(crbug.com/1318853): Description needed for translation
64
+ *@description Warning displayed to developers when the Geolocation API is used from an insecure origin (one that isn't localhost or doesn't use HTTPS) to notify them that this use is no longer supported.
65
65
  */
66
66
  geolocationInsecureOrigin:
67
67
  '`getCurrentPosition()` and `watchPosition()` no longer work on insecure origins. To use this feature, you should consider switching your application to a secure origin, such as HTTPS. See https://goo.gl/rStTGz for more details.',
68
68
  /**
69
- *@description TODO(crbug.com/1318855): Description needed for translation
69
+ *@description Warning displayed to developers when the Geolocation API is used from an insecure origin (one that isn't localhost or doesn't use HTTPS) to notify them that this use is deprecated.
70
70
  */
71
71
  geolocationInsecureOriginDeprecatedNotRemoved:
72
72
  '`getCurrentPosition()` and `watchPosition()` are deprecated on insecure origins. To use this feature, you should consider switching your application to a secure origin, such as HTTPS. See https://goo.gl/rStTGz for more details.',
@@ -110,7 +110,7 @@ const UIStrings = {
110
110
  obsoleteWebRtcCipherSuite:
111
111
  'Your partner is negotiating an obsolete (D)TLS version. Please check with your partner to have this fixed.',
112
112
  /**
113
- *@description TODO(crbug.com/1318868): Description needed for translation
113
+ *@description This issue indicates that a `<source>` element with a `<picture>` parent was using an `src` attribute, which is not valid and is ignored by the browser. The `srcset` attribute should be used instead.
114
114
  */
115
115
  pictureSourceSrc:
116
116
  '`<source src>` with a `<picture>` parent is invalid and therefore ignored. Please use `<source srcset>` instead.',
@@ -6,6 +6,7 @@ import * as Common from '../../core/common/common.js';
6
6
  import * as Host from '../../core/host/host.js';
7
7
  import * as i18n from '../../core/i18n/i18n.js';
8
8
  import * as Root from '../../core/root/root.js';
9
+ import type * as Formatter from '../../models/formatter/formatter.js';
9
10
  import {formatCSSChangesFromDiff} from '../../panels/utils/utils.js';
10
11
  import * as Diff from '../../third_party/diff/diff.js';
11
12
  import * as DiffView from '../../ui/components/diff_view/diff_view.js';
@@ -72,6 +73,7 @@ export class ChangesView extends UI.Widget.VBox {
72
73
  private readonly workspaceDiff: WorkspaceDiff.WorkspaceDiff.WorkspaceDiffImpl;
73
74
  readonly changesSidebar: ChangesSidebar;
74
75
  private selectedUISourceCode: Workspace.UISourceCode.UISourceCode|null;
76
+ #selectedSourceCodeFormattedMapping?: Formatter.ScriptFormatter.FormatterSourceMapping;
75
77
  private readonly diffContainer: HTMLElement;
76
78
  private readonly toolbar: UI.Toolbar.Toolbar;
77
79
  private readonly diffStats: UI.Toolbar.ToolbarText;
@@ -167,16 +169,27 @@ export class ChangesView extends UI.Widget.VBox {
167
169
  if (!this.selectedUISourceCode) {
168
170
  return;
169
171
  }
170
- for (let target: HTMLElement|null = event.target as HTMLElement; target; target = target.parentElement) {
171
- if (target.classList.contains('diff-line-content')) {
172
- const number = target.getAttribute('data-line-number');
173
- if (number) {
174
- // Unfortunately, caretRangeFromPoint is broken in shadow
175
- // roots, which makes determining the character offset more
176
- // work than justified here.
177
- void Common.Revealer.reveal(this.selectedUISourceCode.uiLocation(Number(number) - 1, 0), false);
178
- event.consume(true);
172
+
173
+ for (const target of event.composedPath()) {
174
+ if (!(target instanceof HTMLElement)) {
175
+ continue;
176
+ }
177
+ const selection = target.ownerDocument.getSelection();
178
+ if (selection?.toString()) {
179
+ // We abort source revelation when user has text selection.
180
+ break;
181
+ }
182
+ if (target.classList.contains('diff-line-content') && target.hasAttribute('data-line-number')) {
183
+ let lineNumber = Number(target.dataset.lineNumber) - 1;
184
+ // Unfortunately, caretRangeFromPoint is broken in shadow
185
+ // roots, which makes determining the character offset more
186
+ // work than justified here.
187
+ if (Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.PRECISE_CHANGES) &&
188
+ this.#selectedSourceCodeFormattedMapping) {
189
+ lineNumber = this.#selectedSourceCodeFormattedMapping.formattedToOriginal(lineNumber, 0)[0];
179
190
  }
191
+ void Common.Revealer.reveal(this.selectedUISourceCode.uiLocation(lineNumber, 0), false);
192
+ event.consume(true);
180
193
  break;
181
194
  } else if (target.classList.contains('diff-listing')) {
182
195
  break;
@@ -220,10 +233,12 @@ export class ChangesView extends UI.Widget.VBox {
220
233
  return;
221
234
  }
222
235
  const diffResponse = await this.workspaceDiff.requestDiff(
223
- uiSourceCode, {shouldFormatDiff: Root.Runtime.experiments.isEnabled('preciseChanges')});
236
+ uiSourceCode,
237
+ {shouldFormatDiff: Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.PRECISE_CHANGES)});
224
238
  if (this.selectedUISourceCode !== uiSourceCode) {
225
239
  return;
226
240
  }
241
+ this.#selectedSourceCodeFormattedMapping = diffResponse?.formattedCurrentMapping;
227
242
  this.renderDiffRows(diffResponse?.diff);
228
243
  }
229
244
 
@@ -878,18 +878,19 @@ export class ElementsPanel extends UI.Panel.Panel implements UI.SearchableView.S
878
878
  return node;
879
879
  }
880
880
 
881
- async revealAndSelectNode(node: SDK.DOMModel.DOMNode, focus: boolean, omitHighlight?: boolean): Promise<void> {
881
+ async revealAndSelectNode(nodeToReveal: SDK.DOMModel.DOMNode, focus: boolean, omitHighlight?: boolean):
882
+ Promise<void> {
882
883
  this.omitDefaultSelection = true;
883
884
 
884
- node = Common.Settings.Settings.instance().moduleSetting('showUAShadowDOM').get() ?
885
- node :
886
- this.leaveUserAgentShadowDOM(node);
885
+ const node = Common.Settings.Settings.instance().moduleSetting('showUAShadowDOM').get() ?
886
+ nodeToReveal :
887
+ this.leaveUserAgentShadowDOM(nodeToReveal);
887
888
  if (!omitHighlight) {
888
889
  node.highlightForTwoSeconds();
889
890
  }
890
891
 
891
892
  if (this.accessibilityTreeView) {
892
- void this.accessibilityTreeView.revealAndSelectNode(node);
893
+ void this.accessibilityTreeView.revealAndSelectNode(nodeToReveal);
893
894
  }
894
895
 
895
896
  await UI.ViewManager.ViewManager.instance().showView('elements', false, !focus);
@@ -1029,7 +1030,7 @@ export class ElementsPanel extends UI.Panel.Panel implements UI.SearchableView.S
1029
1030
  };
1030
1031
 
1031
1032
  this.sidebarPaneView = UI.ViewManager.ViewManager.instance().createTabbedLocation(
1032
- () => UI.ViewManager.ViewManager.instance().showView('elements'));
1033
+ () => UI.ViewManager.ViewManager.instance().showView('elements'), 'Styles-pane-sidebar', false, true);
1033
1034
  const tabbedPane = this.sidebarPaneView.tabbedPane();
1034
1035
  if (this.splitMode !== _splitMode.Vertical) {
1035
1036
  this.splitWidget.installResizer(tabbedPane.headerElement());
@@ -859,17 +859,38 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
859
859
  }
860
860
  }
861
861
 
862
+ const customHighlightPseudoRulesets: {
863
+ highlightName: string|null,
864
+ pseudoType: Protocol.DOM.PseudoType,
865
+ pseudoStyles: SDK.CSSStyleDeclaration.CSSStyleDeclaration[],
866
+ }[] = Array.from(matchedStyles.customHighlightPseudoNames()).map(highlightName => {
867
+ return {
868
+ 'highlightName': highlightName,
869
+ 'pseudoType': Protocol.DOM.PseudoType.Highlight,
870
+ 'pseudoStyles': matchedStyles.customHighlightPseudoStyles(highlightName),
871
+ };
872
+ });
873
+
862
874
  let pseudoTypes: Protocol.DOM.PseudoType[] = [];
863
875
  const keys = matchedStyles.pseudoTypes();
864
876
  if (keys.delete(Protocol.DOM.PseudoType.Before)) {
865
877
  pseudoTypes.push(Protocol.DOM.PseudoType.Before);
866
878
  }
867
879
  pseudoTypes = pseudoTypes.concat([...keys].sort());
868
- for (const pseudoType of pseudoTypes) {
880
+
881
+ const otherPseudoRulesets: {
882
+ highlightName: string|null,
883
+ pseudoType: Protocol.DOM.PseudoType,
884
+ pseudoStyles: SDK.CSSStyleDeclaration.CSSStyleDeclaration[],
885
+ }[] = pseudoTypes.map(pseudoType => {
886
+ return {'highlightName': null, 'pseudoType': pseudoType, 'pseudoStyles': matchedStyles.pseudoStyles(pseudoType)};
887
+ });
888
+
889
+ const pseudoRulesets = customHighlightPseudoRulesets.concat(otherPseudoRulesets);
890
+ for (const pseudo of pseudoRulesets) {
869
891
  lastParentNode = null;
870
- const pseudoStyles = matchedStyles.pseudoStyles(pseudoType);
871
- for (let i = 0; i < pseudoStyles.length; ++i) {
872
- const style = pseudoStyles[i];
892
+ for (let i = 0; i < pseudo.pseudoStyles.length; ++i) {
893
+ const style = pseudo.pseudoStyles[i];
873
894
  const parentNode = matchedStyles.isInherited(style) ? matchedStyles.nodeForStyle(style) : null;
874
895
 
875
896
  // Start a new SectionBlock if this is the first rule for this pseudo type, or if this
@@ -877,10 +898,11 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
877
898
  if (i === 0 || parentNode !== lastParentNode) {
878
899
  lastLayers = null;
879
900
  if (parentNode) {
880
- const block = await SectionBlock.createInheritedPseudoTypeBlock(pseudoType, parentNode);
901
+ const block =
902
+ await SectionBlock.createInheritedPseudoTypeBlock(pseudo.pseudoType, pseudo.highlightName, parentNode);
881
903
  blocks.push(block);
882
904
  } else {
883
- const block = SectionBlock.createPseudoTypeBlock(pseudoType);
905
+ const block = SectionBlock.createPseudoTypeBlock(pseudo.pseudoType, pseudo.highlightName);
884
906
  blocks.push(block);
885
907
  }
886
908
  }
@@ -889,9 +911,7 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
889
911
  addLayerSeparator(style);
890
912
  const lastBlock = blocks[blocks.length - 1];
891
913
  this.idleCallbackManager.schedule(() => {
892
- const section = SDK.CSSMetadata.cssMetadata().isHighlightPseudoType(pseudoType) ?
893
- new HighlightPseudoStylePropertiesSection(this, matchedStyles, style, sectionIdx) :
894
- new StylePropertiesSection(this, matchedStyles, style, sectionIdx);
914
+ const section = new HighlightPseudoStylePropertiesSection(this, matchedStyles, style, sectionIdx);
895
915
  sectionIdx++;
896
916
  lastBlock.sections.push(section);
897
917
  });
@@ -1287,19 +1307,23 @@ export class SectionBlock {
1287
1307
  this.sections = [];
1288
1308
  }
1289
1309
 
1290
- static createPseudoTypeBlock(pseudoType: Protocol.DOM.PseudoType): SectionBlock {
1310
+ static createPseudoTypeBlock(pseudoType: Protocol.DOM.PseudoType, pseudoArgument: string|null): SectionBlock {
1291
1311
  const separatorElement = document.createElement('div');
1292
1312
  separatorElement.className = 'sidebar-separator';
1293
- separatorElement.textContent = i18nString(UIStrings.pseudoSElement, {PH1: pseudoType});
1313
+ const pseudoArgumentString = pseudoArgument ? `(${pseudoArgument})` : '';
1314
+ const pseudoTypeString = `${pseudoType}${pseudoArgumentString}`;
1315
+ separatorElement.textContent = i18nString(UIStrings.pseudoSElement, {PH1: pseudoTypeString});
1294
1316
  return new SectionBlock(separatorElement);
1295
1317
  }
1296
1318
 
1297
- static async createInheritedPseudoTypeBlock(pseudoType: Protocol.DOM.PseudoType, node: SDK.DOMModel.DOMNode):
1298
- Promise<SectionBlock> {
1319
+ static async createInheritedPseudoTypeBlock(
1320
+ pseudoType: Protocol.DOM.PseudoType, pseudoArgument: string|null,
1321
+ node: SDK.DOMModel.DOMNode): Promise<SectionBlock> {
1299
1322
  const separatorElement = document.createElement('div');
1300
1323
  separatorElement.className = 'sidebar-separator';
1301
-
1302
- UI.UIUtils.createTextChild(separatorElement, i18nString(UIStrings.inheritedFromSPseudoOf, {PH1: pseudoType}));
1324
+ const pseudoArgumentString = pseudoArgument ? `(${pseudoArgument})` : '';
1325
+ const pseudoTypeString = `${pseudoType}${pseudoArgumentString}`;
1326
+ UI.UIUtils.createTextChild(separatorElement, i18nString(UIStrings.inheritedFromSPseudoOf, {PH1: pseudoTypeString}));
1303
1327
  const link = await Common.Linkifier.Linkifier.linkify(node, {
1304
1328
  preventKeyboardFocus: true,
1305
1329
  tooltip: undefined,
@@ -130,6 +130,7 @@ ol.expanded {
130
130
  content: "";
131
131
  position: absolute;
132
132
  left: -4px;
133
+ top: 0;
133
134
  width: 2px;
134
135
  height: 100%;
135
136
  background-color: var(--color-accent-green);
@@ -226,7 +226,7 @@
226
226
  .sidebar-pane-section-toolbar {
227
227
  position: absolute;
228
228
  right: 0;
229
- bottom: 0;
229
+ bottom: -5px;
230
230
  z-index: 0;
231
231
  }
232
232
 
@@ -113,17 +113,29 @@ const UIStrings = {
113
113
  */
114
114
  runLighthouseInMode: 'Run Lighthouse in navigation, timespan, or snapshot mode',
115
115
  /**
116
- * @description Label of a radio option for a Lighthouse mode that audits a page navigation.
116
+ * @description Label of a radio option for a Lighthouse mode that audits a page navigation. This should be marked as the default radio option.
117
117
  */
118
- navigation: 'Navigation',
118
+ navigation: 'Navigation (Default)',
119
+ /**
120
+ * @description Tooltip description of a radio option for a Lighthouse mode that audits a page navigation.
121
+ */
122
+ navigationTooltip: 'Navigation mode analyzes a page load, exactly like the original Lighthouse reports.',
119
123
  /**
120
124
  * @description Label of a radio option for a Lighthouse mode that audits user interactions over a period of time.
121
125
  */
122
126
  timespan: 'Timespan',
127
+ /**
128
+ * @description Tooltip description of a radio option for a Lighthouse mode that audits user interactions over a period of time.
129
+ */
130
+ timespanTooltip: 'Timespan mode analyzes an arbitrary period of time, typically containing user interactions.',
123
131
  /**
124
132
  * @description Label of a radio option for a Lighthouse mode that audits the current page state.
125
133
  */
126
134
  snapshot: 'Snapshot',
135
+ /**
136
+ * @description Tooltip description of a radio option for a Lighthouse mode that audits the current page state.
137
+ */
138
+ snapshotTooltip: 'Snapshot mode analyzes the page in a particular state, typically after user interactions.',
127
139
  /**
128
140
  *@description Text for the mobile platform, as opposed to desktop
129
141
  */
@@ -364,6 +376,9 @@ export class LighthouseController extends Common.ObjectWrapper.ObjectWrapper<Eve
364
376
  this.dispatchEventToListeners(Events.PageAuditabilityChanged, {helpText});
365
377
 
366
378
  void this.hasImportantResourcesNotCleared().then(warning => {
379
+ if (this.getFlags().mode !== 'navigation') {
380
+ warning = '';
381
+ }
367
382
  this.dispatchEventToListeners(Events.PageWarningsChanged, {warning});
368
383
  });
369
384
  }
@@ -456,11 +471,23 @@ export const RuntimeSettings: RuntimeSetting[] = [
456
471
  flags.mode = value;
457
472
  },
458
473
  options: [
459
- {label: i18nLazyString(UIStrings.navigation), value: 'navigation'},
460
- {label: i18nLazyString(UIStrings.timespan), value: 'timespan'},
461
- {label: i18nLazyString(UIStrings.snapshot), value: 'snapshot'},
474
+ {
475
+ label: i18nLazyString(UIStrings.navigation),
476
+ tooltip: i18nLazyString(UIStrings.navigationTooltip),
477
+ value: 'navigation',
478
+ },
479
+ {
480
+ label: i18nLazyString(UIStrings.timespan),
481
+ tooltip: i18nLazyString(UIStrings.timespanTooltip),
482
+ value: 'timespan',
483
+ },
484
+ {
485
+ label: i18nLazyString(UIStrings.snapshot),
486
+ tooltip: i18nLazyString(UIStrings.snapshotTooltip),
487
+ value: 'snapshot',
488
+ },
462
489
  ],
463
- learnMore: undefined,
490
+ learnMore: 'https://web.dev/lighthouse-user-flows/',
464
491
  },
465
492
  {
466
493
  // This setting is disabled, but we keep it around to show in the UI.
@@ -545,7 +572,11 @@ export interface RuntimeSetting {
545
572
  setting: Common.Settings.Setting<string|boolean>;
546
573
  description: () => Common.UIString.LocalizedString;
547
574
  setFlags: (flags: Flags, value: string|boolean) => void;
548
- options?: {label: () => Common.UIString.LocalizedString, value: string}[];
575
+ options?: {
576
+ label: () => Common.UIString.LocalizedString,
577
+ value: string,
578
+ tooltip?: () => Common.UIString.LocalizedString,
579
+ }[];
549
580
  title?: () => Common.UIString.LocalizedString;
550
581
  learnMore?: string;
551
582
  }
@@ -174,7 +174,7 @@ export class LighthousePanel extends UI.Panel.Panel {
174
174
  return;
175
175
  }
176
176
 
177
- this.startView.updateStartButton();
177
+ this.startView.updateMode();
178
178
 
179
179
  this.unauditableExplanation = evt.data.helpText;
180
180
  this.startView.setUnauditableExplanation(evt.data.helpText);
@@ -44,8 +44,8 @@ export class StartView extends UI.Widget.Widget {
44
44
  protected controller: LighthouseController;
45
45
  private readonly settingsToolbarInternal: UI.Toolbar.Toolbar;
46
46
  protected startButton!: HTMLButtonElement;
47
- private helpText?: Element;
48
- private warningText?: Element;
47
+ protected helpText?: Element;
48
+ protected warningText?: Element;
49
49
  private shouldConfirm?: boolean;
50
50
 
51
51
  constructor(controller: LighthouseController) {
@@ -66,6 +66,17 @@ export class StartView extends UI.Widget.Widget {
66
66
  throw new Error(`${settingName} is not a setting with options`);
67
67
  }
68
68
 
69
+ const labelEl = document.createElement('div');
70
+ labelEl.classList.add('lighthouse-form-section-label');
71
+ labelEl.textContent = label;
72
+
73
+ if (runtimeSetting.learnMore) {
74
+ const link =
75
+ UI.XLink.XLink.create(runtimeSetting.learnMore, i18nString(UIStrings.learnMore), 'lighthouse-learn-more');
76
+ labelEl.append(link);
77
+ }
78
+ parentElement.appendChild(labelEl);
79
+
69
80
  const control = new RadioSetting(
70
81
  runtimeSetting.options, runtimeSetting.setting as Common.Settings.Setting<string>,
71
82
  runtimeSetting.description());
@@ -91,7 +102,7 @@ export class StartView extends UI.Widget.Widget {
91
102
  }
92
103
  }
93
104
 
94
- private populateFormControls(fragment: UI.Fragment.Fragment): void {
105
+ protected populateFormControls(fragment: UI.Fragment.Fragment): void {
95
106
  // Populate the device type
96
107
  const deviceTypeFormElements = fragment.$('device-type-form-elements');
97
108
  this.populateRuntimeSettingAsRadio('lighthouse.device_type', i18nString(UIStrings.device), deviceTypeFormElements);
@@ -157,9 +168,6 @@ export class StartView extends UI.Widget.Widget {
157
168
  </div>
158
169
  </div>
159
170
  <div class="lighthouse-form-section">
160
- <div class="lighthouse-form-section-label">
161
- ${i18nString(UIStrings.device)}
162
- </div>
163
171
  <div class="lighthouse-form-elements" $="device-type-form-elements"></div>
164
172
  </div>
165
173
  </form>
@@ -173,7 +181,7 @@ export class StartView extends UI.Widget.Widget {
173
181
  this.contentElement.style.overflow = 'auto';
174
182
  }
175
183
 
176
- updateStartButton(): void {
184
+ updateMode(): void {
177
185
  // Do nothing in default case.
178
186
  }
179
187