chrome-devtools-frontend 1.0.1534717 → 1.0.1536371
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.
- package/docs/contributing/images/issues-nearestslo.png +0 -0
- package/docs/contributing/issues.md +32 -58
- package/eslint.config.mjs +1 -0
- package/front_end/core/common/Console.ts +1 -8
- package/front_end/core/common/ParsedURL.ts +10 -20
- package/front_end/core/common/SegmentedRange.ts +1 -2
- package/front_end/core/common/StringOutputStream.ts +1 -4
- package/front_end/core/host/InspectorFrontendHost.ts +6 -0
- package/front_end/core/host/UserMetrics.ts +5 -1
- package/front_end/core/i18n/i18nImpl.ts +0 -24
- package/front_end/core/protocol_client/CDPConnection.ts +53 -5
- package/front_end/core/protocol_client/protocol_client.ts +2 -0
- package/front_end/core/sdk/AnimationModel.ts +1 -2
- package/front_end/core/sdk/CSSMatchedStyles.ts +2 -2
- package/front_end/core/sdk/CSSModel.ts +1 -1
- package/front_end/core/sdk/CSSProperty.ts +3 -6
- package/front_end/core/sdk/CSSStyleDeclaration.ts +4 -4
- package/front_end/core/sdk/DebuggerModel.ts +1 -2
- package/front_end/core/sdk/EnhancedTracesParser.ts +4 -0
- package/front_end/core/sdk/SourceMap.ts +2 -3
- package/front_end/devtools_compatibility.js +32 -24
- package/front_end/entrypoints/node_app/NodeConnectionsPanel.ts +2 -1
- package/front_end/generated/InspectorBackendCommands.js +1 -2
- package/front_end/generated/SupportedCSSProperties.js +57 -0
- package/front_end/generated/protocol.ts +0 -27
- package/front_end/panels/accessibility/AccessibilityNodeView.ts +18 -17
- package/front_end/panels/accessibility/AccessibilitySidebarView.ts +9 -12
- package/front_end/panels/ai_assistance/PatchWidget.ts +39 -40
- package/front_end/panels/ai_assistance/components/ChatView.ts +5 -4
- package/front_end/panels/ai_assistance/components/ExploreWidget.ts +0 -2
- package/front_end/panels/application/AppManifestView.ts +7 -6
- package/front_end/panels/application/ApplicationPanelSidebar.ts +4 -4
- package/front_end/panels/application/OpenedWindowDetailsView.ts +6 -6
- package/front_end/panels/application/StorageView.ts +9 -8
- package/front_end/panels/application/components/BackForwardCacheView.ts +333 -314
- package/front_end/panels/application/components/ProtocolHandlersView.ts +3 -2
- package/front_end/panels/application/preloading/components/PreloadingDisabledInfobar.ts +2 -1
- package/front_end/panels/autofill/AutofillView.ts +2 -3
- package/front_end/panels/browser_debugger/ObjectEventListenersSidebarPane.ts +8 -8
- package/front_end/panels/changes/CombinedDiffView.ts +13 -14
- package/front_end/panels/common/BadgeNotification.ts +2 -1
- package/front_end/panels/common/GdpSignUpDialog.ts +2 -1
- package/front_end/panels/console/ConsoleInsightTeaser.ts +13 -2
- package/front_end/panels/console/ConsolePinPane.ts +12 -7
- package/front_end/panels/console/ConsoleView.ts +1 -0
- package/front_end/panels/console/consoleView.css +0 -1
- package/front_end/panels/developer_resources/DeveloperResourcesView.ts +9 -9
- package/front_end/panels/elements/ComputedStyleWidget.ts +7 -7
- package/front_end/panels/elements/ElementsTreeOutline.ts +1 -1
- package/front_end/panels/elements/EventListenersWidget.ts +9 -9
- package/front_end/panels/elements/NodeStackTraceWidget.ts +6 -6
- package/front_end/panels/elements/PlatformFontsWidget.ts +5 -5
- package/front_end/panels/elements/PropertiesWidget.ts +8 -8
- package/front_end/panels/layer_viewer/Layers3DView.ts +2 -1
- package/front_end/panels/layer_viewer/PaintProfilerView.ts +3 -3
- package/front_end/panels/network/RequestCookiesView.ts +2 -1
- package/front_end/panels/network/RequestTimingView.ts +2 -1
- package/front_end/panels/network/components/DirectSocketConnectionView.ts +4 -6
- package/front_end/panels/recorder/RecorderController.ts +34 -23
- package/front_end/panels/recorder/components/CreateRecordingView.ts +249 -240
- package/front_end/panels/security/CookieControlsView.ts +74 -67
- package/front_end/panels/security/CookieReportView.ts +18 -16
- package/front_end/panels/security/IPProtectionView.ts +1 -2
- package/front_end/panels/security/SecurityPanel.ts +19 -19
- package/front_end/panels/settings/AISettingsTab.ts +2 -1
- package/front_end/panels/settings/KeybindsSettingsTab.ts +6 -0
- package/front_end/panels/settings/components/SyncSection.ts +2 -1
- package/front_end/panels/sources/DebuggerPausedMessage.ts +4 -3
- package/front_end/panels/sources/ResourceOriginPlugin.ts +3 -2
- package/front_end/panels/sources/SourcesNavigator.ts +2 -1
- package/front_end/panels/sources/TabbedEditorContainer.ts +3 -2
- package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +9 -9
- package/front_end/panels/timeline/TimelineSelectorStatsView.ts +36 -36
- package/front_end/panels/timeline/TimelineUIUtils.ts +3 -2
- package/front_end/panels/timeline/components/DetailsView.ts +5 -4
- package/front_end/panels/timeline/components/FieldSettingsDialog.ts +2 -1
- package/front_end/panels/timeline/components/LiveMetricsView.ts +5 -4
- package/front_end/panels/timeline/components/MetricCompareStrings.ts +25 -24
- package/front_end/panels/timeline/components/SidebarAnnotationsTab.ts +1 -2
- package/front_end/panels/timeline/components/insights/LCPDiscovery.ts +2 -1
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/components/docs/tooltip/basic.ts +1 -1
- package/front_end/ui/components/tooltips/Tooltip.ts +32 -17
- package/front_end/ui/i18n/i18n.ts +31 -0
- package/front_end/ui/legacy/SoftDropDown.ts +1 -12
- package/front_end/ui/legacy/ViewManager.ts +2 -4
- package/front_end/ui/legacy/Widget.ts +33 -17
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +2 -1
- package/front_end/ui/legacy/legacy.ts +0 -2
- package/front_end/ui/visual_logging/KnownContextValues.ts +5 -0
- package/mcp/mcp.ts +1 -0
- package/package.json +1 -1
- package/front_end/ui/components/docs/recorder_create_recording_view/basic.html +0 -20
- package/front_end/ui/components/docs/recorder_create_recording_view/basic.ts +0 -27
- package/front_end/ui/legacy/ThrottledWidget.ts +0 -48
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
|
-
/* eslint-disable @devtools/no-lit-render-outside-of-view */
|
|
6
|
-
|
|
7
5
|
import '../../ui/components/linkifier/linkifier.js';
|
|
8
6
|
import '../../ui/legacy/components/data_grid/data_grid.js';
|
|
9
7
|
|
|
@@ -125,24 +123,9 @@ interface ViewInput {
|
|
|
125
123
|
}
|
|
126
124
|
type View = (input: ViewInput, output: object, target: HTMLElement) => void;
|
|
127
125
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* We store the last event (or array of events) that we renderered. We do
|
|
133
|
-
* this because as the user zooms around the panel this view is updated,
|
|
134
|
-
* however if the set of events that are populating the view is the same as it
|
|
135
|
-
* was the last time, we can bail without doing any re-rendering work.
|
|
136
|
-
* If the user views a single event, this will be set to that single event, but if they are viewing a range of events, this will be set to an array.
|
|
137
|
-
* If it's null, that means we have not rendered yet.
|
|
138
|
-
*/
|
|
139
|
-
#lastStatsSourceEventOrEvents: Trace.Types.Events.RecalcStyle|Trace.Types.Events.RecalcStyle[]|null = null;
|
|
140
|
-
#view: View;
|
|
141
|
-
#timings: SelectorTiming[] = [];
|
|
142
|
-
|
|
143
|
-
constructor(parsedTrace: Trace.TraceModel.ParsedTrace|null, view: View = (input, _, target) => {
|
|
144
|
-
render(
|
|
145
|
-
html`
|
|
126
|
+
const DEFAULT_VIEW: View = (input, _output, target) => {
|
|
127
|
+
render(
|
|
128
|
+
html`
|
|
146
129
|
<devtools-data-grid striped name=${i18nString(UIStrings.selectorStats)}
|
|
147
130
|
@contextmenu=${input.onContextMenu.bind(input)}>
|
|
148
131
|
<table>
|
|
@@ -153,7 +136,7 @@ export class TimelineSelectorStatsView extends UI.Widget.VBox {
|
|
|
153
136
|
</th>
|
|
154
137
|
<th id=${SelectorTimingsKey.InvalidationCount} weight="1.5" sortable hideable>
|
|
155
138
|
<span title=${i18nString(UIStrings.invalidationCountExplanation)}>${
|
|
156
|
-
|
|
139
|
+
i18nString(UIStrings.invalidationCount)}</span>
|
|
157
140
|
</th>
|
|
158
141
|
<th id=${SelectorTimingsKey.MatchAttempts} weight="1" sortable hideable align="right">
|
|
159
142
|
<span title=${i18nString(UIStrings.matchAttemptsExplanation)}>
|
|
@@ -165,7 +148,7 @@ export class TimelineSelectorStatsView extends UI.Widget.VBox {
|
|
|
165
148
|
</th>
|
|
166
149
|
<th id=${SelectorTimingsKey.RejectPercentage} weight="1" sortable hideable align="right">
|
|
167
150
|
<span title=${i18nString(UIStrings.slowPathNonMatchesExplanation)}>${
|
|
168
|
-
|
|
151
|
+
i18nString(UIStrings.slowPathNonMatches)}</span>
|
|
169
152
|
</th>
|
|
170
153
|
<th id=${SelectorTimingsKey.Selector} weight="3" sortable hideable>
|
|
171
154
|
<span title=${i18nString(UIStrings.selectorExplanation)}>
|
|
@@ -177,15 +160,15 @@ export class TimelineSelectorStatsView extends UI.Widget.VBox {
|
|
|
177
160
|
</th>
|
|
178
161
|
</tr>
|
|
179
162
|
${input.timings.map(timing => {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
163
|
+
const nonMatches = timing[SelectorTimingsKey.MatchAttempts] - timing[SelectorTimingsKey.MatchCount];
|
|
164
|
+
const slowPathNonMatches =
|
|
165
|
+
(nonMatches ? 1.0 - timing[SelectorTimingsKey.FastRejectCount] / nonMatches : 0) * 100;
|
|
166
|
+
const styleSheetId = timing[SelectorTimingsKey.StyleSheetId];
|
|
167
|
+
const locations = timing.locations;
|
|
168
|
+
const locationMessage = locations ? null :
|
|
169
|
+
locations === null ? '' :
|
|
170
|
+
i18nString(UIStrings.unableToLinkViaStyleSheetId, {PH1: styleSheetId});
|
|
171
|
+
return html`<tr>
|
|
189
172
|
<td data-value=${timing[SelectorTimingsKey.Elapsed]}>
|
|
190
173
|
${(timing[SelectorTimingsKey.Elapsed] / 1000.0).toFixed(3)}
|
|
191
174
|
</td>
|
|
@@ -201,17 +184,34 @@ export class TimelineSelectorStatsView extends UI.Widget.VBox {
|
|
|
201
184
|
${timing[SelectorTimingsKey.Selector]}
|
|
202
185
|
</td>
|
|
203
186
|
<td data-value=${styleSheetId}>${
|
|
204
|
-
|
|
187
|
+
locations ? html`${locations.map((location, itemIndex) => html`
|
|
205
188
|
<devtools-linkifier .data=${location}></devtools-linkifier
|
|
206
189
|
>${itemIndex !== locations.length - 1 ? ',' : ''}`)}` :
|
|
207
|
-
|
|
190
|
+
locationMessage}
|
|
208
191
|
</td>
|
|
209
192
|
</tr>`;
|
|
210
|
-
|
|
193
|
+
})}
|
|
211
194
|
</table>
|
|
212
195
|
</devtools-data-grid>`,
|
|
213
|
-
|
|
214
|
-
|
|
196
|
+
target);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
export class TimelineSelectorStatsView extends UI.Widget.VBox {
|
|
200
|
+
#selectorLocations: Map<string, Protocol.CSS.SourceRange[]>;
|
|
201
|
+
#parsedTrace: Trace.TraceModel.ParsedTrace|null = null;
|
|
202
|
+
/**
|
|
203
|
+
* We store the last event (or array of events) that we renderered. We do
|
|
204
|
+
* this because as the user zooms around the panel this view is updated,
|
|
205
|
+
* however if the set of events that are populating the view is the same as it
|
|
206
|
+
* was the last time, we can bail without doing any re-rendering work.
|
|
207
|
+
* If the user views a single event, this will be set to that single event, but if they are viewing a range of events, this will be set to an array.
|
|
208
|
+
* If it's null, that means we have not rendered yet.
|
|
209
|
+
*/
|
|
210
|
+
#lastStatsSourceEventOrEvents: Trace.Types.Events.RecalcStyle|Trace.Types.Events.RecalcStyle[]|null = null;
|
|
211
|
+
#view: View;
|
|
212
|
+
#timings: SelectorTiming[] = [];
|
|
213
|
+
|
|
214
|
+
constructor(parsedTrace: Trace.TraceModel.ParsedTrace|null, view: View = DEFAULT_VIEW) {
|
|
215
215
|
super({jslog: `${VisualLogging.pane('selector-stats').track({resize: true})}`});
|
|
216
216
|
this.registerRequiredCSS(timelineSelectorStatsViewStyles);
|
|
217
217
|
|
|
@@ -48,6 +48,7 @@ import * as Tracing from '../../services/tracing/tracing.js';
|
|
|
48
48
|
import * as CodeHighlighter from '../../ui/components/code_highlighter/code_highlighter.js';
|
|
49
49
|
// eslint-disable-next-line @devtools/es-modules-import
|
|
50
50
|
import codeHighlighterStyles from '../../ui/components/code_highlighter/codeHighlighter.css.js';
|
|
51
|
+
import * as uiI18n from '../../ui/i18n/i18n.js';
|
|
51
52
|
import * as PerfUI from '../../ui/legacy/components/perf_ui/perf_ui.js';
|
|
52
53
|
// eslint-disable-next-line @devtools/es-modules-import
|
|
53
54
|
import imagePreviewStyles from '../../ui/legacy/components/utils/imagePreview.css.js';
|
|
@@ -1899,7 +1900,7 @@ export class TimelineUIUtils {
|
|
|
1899
1900
|
const niceNodeLink = createLinkForInvalidationNode(invalidation);
|
|
1900
1901
|
|
|
1901
1902
|
const text = scriptLink ?
|
|
1902
|
-
|
|
1903
|
+
uiI18n.getFormatLocalizedString(
|
|
1903
1904
|
str_, UIStrings.invalidationWithCallFrame, {PH1: niceNodeLink, PH2: scriptLink}) as HTMLElement :
|
|
1904
1905
|
niceNodeLink;
|
|
1905
1906
|
|
|
@@ -2207,7 +2208,7 @@ export class TimelineUIUtils {
|
|
|
2207
2208
|
PH1: i18n.TimeUtilities.millisToString(durationMilli, true),
|
|
2208
2209
|
PH2: i18n.TimeUtilities.millisToString(offsetMilli, true),
|
|
2209
2210
|
});
|
|
2210
|
-
return
|
|
2211
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.emptyPlaceholder, {PH1: durationText});
|
|
2211
2212
|
}
|
|
2212
2213
|
|
|
2213
2214
|
static quadWidth(quad: number[]): number {
|
|
@@ -7,6 +7,7 @@ import * as i18n from '../../../core/i18n/i18n.js';
|
|
|
7
7
|
import * as Platform from '../../../core/platform/platform.js';
|
|
8
8
|
import type * as Protocol from '../../../generated/protocol.js';
|
|
9
9
|
import * as Trace from '../../../models/trace/trace.js';
|
|
10
|
+
import * as uiI18n from '../../../ui/i18n/i18n.js';
|
|
10
11
|
import * as UI from '../../../ui/legacy/legacy.js';
|
|
11
12
|
|
|
12
13
|
// *********************************************************************
|
|
@@ -86,8 +87,8 @@ export function buildWarningElementsForEvent(
|
|
|
86
87
|
const forcedReflowLink = UI.XLink.XLink.create(
|
|
87
88
|
'https://developers.google.com/web/fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing#avoid-forced-synchronous-layouts',
|
|
88
89
|
i18nString(UIStrings.forcedReflow), undefined, undefined, 'forced-reflow');
|
|
89
|
-
span.appendChild(
|
|
90
|
-
str_, UIStrings.sIsALikelyPerformanceBottleneck, {PH1: forcedReflowLink}));
|
|
90
|
+
span.appendChild(
|
|
91
|
+
uiI18n.getFormatLocalizedString(str_, UIStrings.sIsALikelyPerformanceBottleneck, {PH1: forcedReflowLink}));
|
|
91
92
|
break;
|
|
92
93
|
}
|
|
93
94
|
case 'IDLE_CALLBACK_OVER_TIME': {
|
|
@@ -103,7 +104,7 @@ export function buildWarningElementsForEvent(
|
|
|
103
104
|
case 'LONG_TASK': {
|
|
104
105
|
const longTaskLink = UI.XLink.XLink.create(
|
|
105
106
|
'https://web.dev/optimize-long-tasks/', i18nString(UIStrings.longTask), undefined, undefined, 'long-tasks');
|
|
106
|
-
span.appendChild(
|
|
107
|
+
span.appendChild(uiI18n.getFormatLocalizedString(
|
|
107
108
|
str_, UIStrings.sTookS,
|
|
108
109
|
{PH1: longTaskLink, PH2: i18n.TimeUtilities.millisToString((duration || 0), true)}));
|
|
109
110
|
break;
|
|
@@ -111,7 +112,7 @@ export function buildWarningElementsForEvent(
|
|
|
111
112
|
case 'LONG_INTERACTION': {
|
|
112
113
|
const longInteractionINPLink = UI.XLink.XLink.create(
|
|
113
114
|
'https://web.dev/inp', i18nString(UIStrings.longInteractionINP), undefined, undefined, 'long-interaction');
|
|
114
|
-
span.appendChild(
|
|
115
|
+
span.appendChild(uiI18n.getFormatLocalizedString(
|
|
115
116
|
str_, UIStrings.sIsLikelyPoorPageResponsiveness, {PH1: longInteractionINPLink}));
|
|
116
117
|
break;
|
|
117
118
|
}
|
|
@@ -11,6 +11,7 @@ import * as Buttons from '../../../ui/components/buttons/buttons.js';
|
|
|
11
11
|
import * as Dialogs from '../../../ui/components/dialogs/dialogs.js';
|
|
12
12
|
import * as ComponentHelpers from '../../../ui/components/helpers/helpers.js';
|
|
13
13
|
import * as Input from '../../../ui/components/input/input.js';
|
|
14
|
+
import * as uiI18n from '../../../ui/i18n/i18n.js';
|
|
14
15
|
import * as UI from '../../../ui/legacy/legacy.js';
|
|
15
16
|
import * as Lit from '../../../ui/lit/lit.js';
|
|
16
17
|
import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
|
|
@@ -331,7 +332,7 @@ export class FieldSettingsDialog extends HTMLElement {
|
|
|
331
332
|
#render = (): void => {
|
|
332
333
|
const linkEl =
|
|
333
334
|
UI.XLink.XLink.create('https://developer.chrome.com/docs/crux', i18n.i18n.lockedString('Chrome UX Report'));
|
|
334
|
-
const descriptionEl =
|
|
335
|
+
const descriptionEl = uiI18n.getFormatLocalizedString(str_, UIStrings.fetchAggregated, {PH1: linkEl});
|
|
335
336
|
|
|
336
337
|
// clang-format off
|
|
337
338
|
const output = html`
|
|
@@ -25,6 +25,7 @@ import * as LegacyWrapper from '../../../ui/components/legacy_wrapper/legacy_wra
|
|
|
25
25
|
import type * as Menus from '../../../ui/components/menus/menus.js';
|
|
26
26
|
import * as RenderCoordinator from '../../../ui/components/render_coordinator/render_coordinator.js';
|
|
27
27
|
import type * as Settings from '../../../ui/components/settings/settings.js';
|
|
28
|
+
import * as uiI18n from '../../../ui/i18n/i18n.js';
|
|
28
29
|
import * as UI from '../../../ui/legacy/legacy.js';
|
|
29
30
|
import * as Lit from '../../../ui/lit/lit.js';
|
|
30
31
|
import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
|
|
@@ -629,8 +630,8 @@ export class LiveMetricsView extends LegacyWrapper.LegacyWrapper.WrappableCompon
|
|
|
629
630
|
<div class="device-toolbar-description">${md(i18nString(UIStrings.useDeviceToolbar))}</div>
|
|
630
631
|
${fieldEnabled ? html`
|
|
631
632
|
<ul class="environment-recs-list">
|
|
632
|
-
<li>${
|
|
633
|
-
<li>${
|
|
633
|
+
<li>${uiI18n.getFormatLocalizedString(str_, UIStrings.device, {PH1: deviceRecEl})}</li>
|
|
634
|
+
<li>${uiI18n.getFormatLocalizedString(str_, UIStrings.network, {PH1: networkRecEl})}</li>
|
|
634
635
|
</ul>
|
|
635
636
|
` : nothing}
|
|
636
637
|
<div class="environment-option">
|
|
@@ -839,7 +840,7 @@ export class LiveMetricsView extends LegacyWrapper.LegacyWrapper.WrappableCompon
|
|
|
839
840
|
dateEl.classList.add('collection-period-range');
|
|
840
841
|
dateEl.textContent = range || i18nString(UIStrings.notEnoughData);
|
|
841
842
|
|
|
842
|
-
const message =
|
|
843
|
+
const message = uiI18n.getFormatLocalizedString(str_, UIStrings.collectionPeriod, {
|
|
843
844
|
PH1: dateEl,
|
|
844
845
|
});
|
|
845
846
|
|
|
@@ -862,7 +863,7 @@ export class LiveMetricsView extends LegacyWrapper.LegacyWrapper.WrappableCompon
|
|
|
862
863
|
|
|
863
864
|
const linkEl =
|
|
864
865
|
UI.XLink.XLink.create('https://developer.chrome.com/docs/crux', i18n.i18n.lockedString('Chrome UX Report'));
|
|
865
|
-
const messageEl =
|
|
866
|
+
const messageEl = uiI18n.getFormatLocalizedString(str_, UIStrings.seeHowYourLocalMetricsCompare, {PH1: linkEl});
|
|
866
867
|
|
|
867
868
|
return html`
|
|
868
869
|
<div class="field-data-message">${messageEl}</div>
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
5
|
import * as i18n from '../../../core/i18n/i18n.js';
|
|
6
|
+
import * as uiI18n from '../../../ui/i18n/i18n.js';
|
|
6
7
|
|
|
7
8
|
import type {MetricRating} from './Utils.js';
|
|
8
9
|
|
|
@@ -185,40 +186,40 @@ export function renderCompareText(
|
|
|
185
186
|
};
|
|
186
187
|
|
|
187
188
|
if (rating === 'good' && compare === 'better') {
|
|
188
|
-
return
|
|
189
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.goodBetterCompare, values);
|
|
189
190
|
}
|
|
190
191
|
if (rating === 'good' && compare === 'worse') {
|
|
191
|
-
return
|
|
192
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.goodWorseCompare, values);
|
|
192
193
|
}
|
|
193
194
|
if (rating === 'good' && compare === 'similar') {
|
|
194
|
-
return
|
|
195
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.goodSimilarCompare, values);
|
|
195
196
|
}
|
|
196
197
|
if (rating === 'good' && !compare) {
|
|
197
|
-
return
|
|
198
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.goodSummarized, values);
|
|
198
199
|
}
|
|
199
200
|
if (rating === 'needs-improvement' && compare === 'better') {
|
|
200
|
-
return
|
|
201
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.needsImprovementBetterCompare, values);
|
|
201
202
|
}
|
|
202
203
|
if (rating === 'needs-improvement' && compare === 'worse') {
|
|
203
|
-
return
|
|
204
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.needsImprovementWorseCompare, values);
|
|
204
205
|
}
|
|
205
206
|
if (rating === 'needs-improvement' && compare === 'similar') {
|
|
206
|
-
return
|
|
207
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.needsImprovementSimilarCompare, values);
|
|
207
208
|
}
|
|
208
209
|
if (rating === 'needs-improvement' && !compare) {
|
|
209
|
-
return
|
|
210
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.needsImprovementSummarized, values);
|
|
210
211
|
}
|
|
211
212
|
if (rating === 'poor' && compare === 'better') {
|
|
212
|
-
return
|
|
213
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.poorBetterCompare, values);
|
|
213
214
|
}
|
|
214
215
|
if (rating === 'poor' && compare === 'worse') {
|
|
215
|
-
return
|
|
216
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.poorWorseCompare, values);
|
|
216
217
|
}
|
|
217
218
|
if (rating === 'poor' && compare === 'similar') {
|
|
218
|
-
return
|
|
219
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.poorSimilarCompare, values);
|
|
219
220
|
}
|
|
220
221
|
if (rating === 'poor' && !compare) {
|
|
221
|
-
return
|
|
222
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.poorSummarized, values);
|
|
222
223
|
}
|
|
223
224
|
|
|
224
225
|
throw new Error('Compare string not found');
|
|
@@ -241,40 +242,40 @@ export function renderDetailedCompareText(options: {
|
|
|
241
242
|
};
|
|
242
243
|
|
|
243
244
|
if (localRating === 'good' && fieldRating === 'good') {
|
|
244
|
-
return
|
|
245
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.goodGoodDetailedCompare, values);
|
|
245
246
|
}
|
|
246
247
|
if (localRating === 'good' && fieldRating === 'needs-improvement') {
|
|
247
|
-
return
|
|
248
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.goodNeedsImprovementDetailedCompare, values);
|
|
248
249
|
}
|
|
249
250
|
if (localRating === 'good' && fieldRating === 'poor') {
|
|
250
|
-
return
|
|
251
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.goodPoorDetailedCompare, values);
|
|
251
252
|
}
|
|
252
253
|
if (localRating === 'good' && !fieldRating) {
|
|
253
|
-
return
|
|
254
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.goodSummarized, values);
|
|
254
255
|
}
|
|
255
256
|
if (localRating === 'needs-improvement' && fieldRating === 'good') {
|
|
256
|
-
return
|
|
257
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.needsImprovementGoodDetailedCompare, values);
|
|
257
258
|
}
|
|
258
259
|
if (localRating === 'needs-improvement' && fieldRating === 'needs-improvement') {
|
|
259
|
-
return
|
|
260
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.needsImprovementNeedsImprovementDetailedCompare, values);
|
|
260
261
|
}
|
|
261
262
|
if (localRating === 'needs-improvement' && fieldRating === 'poor') {
|
|
262
|
-
return
|
|
263
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.needsImprovementPoorDetailedCompare, values);
|
|
263
264
|
}
|
|
264
265
|
if (localRating === 'needs-improvement' && !fieldRating) {
|
|
265
|
-
return
|
|
266
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.needsImprovementSummarized, values);
|
|
266
267
|
}
|
|
267
268
|
if (localRating === 'poor' && fieldRating === 'good') {
|
|
268
|
-
return
|
|
269
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.poorGoodDetailedCompare, values);
|
|
269
270
|
}
|
|
270
271
|
if (localRating === 'poor' && fieldRating === 'needs-improvement') {
|
|
271
|
-
return
|
|
272
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.poorNeedsImprovementDetailedCompare, values);
|
|
272
273
|
}
|
|
273
274
|
if (localRating === 'poor' && fieldRating === 'poor') {
|
|
274
|
-
return
|
|
275
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.poorPoorDetailedCompare, values);
|
|
275
276
|
}
|
|
276
277
|
if (localRating === 'poor' && !fieldRating) {
|
|
277
|
-
return
|
|
278
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.poorSummarized, values);
|
|
278
279
|
}
|
|
279
280
|
|
|
280
281
|
throw new Error('Detailed compare string not found');
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// Copyright 2024 The Chromium Authors
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
|
-
/* eslint-disable @devtools/no-lit-render-outside-of-view */
|
|
5
4
|
|
|
6
5
|
import * as Common from '../../../core/common/common.js';
|
|
7
6
|
import * as i18n from '../../../core/i18n/i18n.js';
|
|
@@ -448,5 +447,5 @@ export const DEFAULT_VIEW: (input: SidebarAnnotationsTabViewInput, output: objec
|
|
|
448
447
|
</setting-checkbox>`
|
|
449
448
|
}
|
|
450
449
|
</span>`,
|
|
451
|
-
target
|
|
450
|
+
target);
|
|
452
451
|
};
|
|
@@ -8,6 +8,7 @@ import './Checklist.js';
|
|
|
8
8
|
import * as i18n from '../../../../core/i18n/i18n.js';
|
|
9
9
|
import type {LCPDiscoveryInsightModel} from '../../../../models/trace/insights/LCPDiscovery.js';
|
|
10
10
|
import * as Trace from '../../../../models/trace/trace.js';
|
|
11
|
+
import * as uiI18n from '../../../../ui/i18n/i18n.js';
|
|
11
12
|
import * as Lit from '../../../../ui/lit/lit.js';
|
|
12
13
|
|
|
13
14
|
import {BaseInsightComponent} from './BaseInsightComponent.js';
|
|
@@ -63,7 +64,7 @@ export class LCPDiscovery extends BaseInsightComponent<LCPDiscoveryInsightModel>
|
|
|
63
64
|
const timeWrapper = document.createElement('span');
|
|
64
65
|
timeWrapper.classList.add('discovery-time-ms');
|
|
65
66
|
timeWrapper.innerText = i18n.TimeUtilities.formatMicroSecondsAsMillisFixed(delay);
|
|
66
|
-
return
|
|
67
|
+
return uiI18n.getFormatLocalizedString(str_, UIStrings.lcpLoadDelay, {PH1: timeWrapper});
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
override renderContent(): Lit.LitTemplate {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Name: Dependencies sourced from the upstream `chromium` repository
|
|
2
2
|
URL: https://source.chromium.org/chromium/chromium/src/+/main:components/variations/proto/devtools/
|
|
3
3
|
Version: N/A
|
|
4
|
-
Revision:
|
|
4
|
+
Revision: 02e01d70b196feed2ae409aa37b1c99afb6c2ef3
|
|
5
5
|
Update Mechanism: Manual (https://crbug.com/428069060)
|
|
6
6
|
License: BSD-3-Clause
|
|
7
7
|
License File: LICENSE
|
|
@@ -31,7 +31,7 @@ Lit.render(
|
|
|
31
31
|
>
|
|
32
32
|
Non-button click trigger
|
|
33
33
|
</span>
|
|
34
|
-
<devtools-tooltip id="rich-tooltip" variant="rich"
|
|
34
|
+
<devtools-tooltip id="rich-tooltip" variant="rich" trigger="click">
|
|
35
35
|
<p>Rich tooltip</p>
|
|
36
36
|
<button>Action</button>
|
|
37
37
|
</devtools-tooltip>
|
|
@@ -167,6 +167,7 @@ const proposedRectForSimpleTooltip =
|
|
|
167
167
|
|
|
168
168
|
export type TooltipVariant = 'simple'|'rich';
|
|
169
169
|
export type PaddingMode = 'small'|'large';
|
|
170
|
+
export type TooltipTrigger = 'hover'|'click'|'both';
|
|
170
171
|
|
|
171
172
|
export interface TooltipProperties {
|
|
172
173
|
id: string;
|
|
@@ -174,6 +175,7 @@ export interface TooltipProperties {
|
|
|
174
175
|
padding?: PaddingMode;
|
|
175
176
|
anchor?: HTMLElement;
|
|
176
177
|
jslogContext?: string;
|
|
178
|
+
trigger?: TooltipTrigger;
|
|
177
179
|
}
|
|
178
180
|
|
|
179
181
|
/**
|
|
@@ -182,7 +184,7 @@ export interface TooltipProperties {
|
|
|
182
184
|
* @property hoverDelay - reflects the `"hover-delay"` attribute.
|
|
183
185
|
* @property variant - reflects the `"variant"` attribute.
|
|
184
186
|
* @property padding - reflects the `"padding"` attribute.
|
|
185
|
-
* @property
|
|
187
|
+
* @property trigger - reflects the `"trigger"` attribute.
|
|
186
188
|
* @property verticalDistanceIncrease - reflects the `"vertical-distance-increase"` attribute.
|
|
187
189
|
* @property preferSpanLeft - reflects the `"prefer-span-left"` attribute.
|
|
188
190
|
* @attribute id - Id of the tooltip. Used for searching an anchor element with aria-describedby.
|
|
@@ -190,17 +192,19 @@ export interface TooltipProperties {
|
|
|
190
192
|
* @attribute variant - Variant of the tooltip, `"simple"` for strings only, inverted background,
|
|
191
193
|
* `"rich"` for interactive content, background according to theme's surface.
|
|
192
194
|
* @attribute padding - Which padding to use, defaults to `"small"`. Use `"large"` for richer content.
|
|
193
|
-
* @attribute
|
|
195
|
+
* @attribute trigger - Specifies which action triggers the tooltip. `"hover"` is the default. `"click"` means the
|
|
196
|
+
* tooltip will be shown on click instead of hover. `"both"` means both hover and click trigger the
|
|
197
|
+
* tooltip.
|
|
194
198
|
* @attribute vertical-distance-increase - The tooltip is moved vertically this many pixels further away from its anchor.
|
|
195
199
|
* @attribute prefer-span-left - If present, the tooltip's preferred position is `"span-left"` (The right
|
|
196
200
|
* side of the tooltip and its anchor are aligned. The tooltip expands to the left from
|
|
197
201
|
* there.). Applies to rich tooltips only.
|
|
198
202
|
* @attribute use-hotkey - If present, the tooltip will be shown on hover but not when receiving focus.
|
|
199
|
-
*
|
|
200
|
-
*
|
|
203
|
+
* Requires a hotkey to open when fosed (Alt-down). When `"trigger"` is present
|
|
204
|
+
* as well, `"trigger"` takes precedence.
|
|
201
205
|
*/
|
|
202
206
|
export class Tooltip extends HTMLElement {
|
|
203
|
-
static readonly observedAttributes = ['id', 'variant', 'jslogcontext'];
|
|
207
|
+
static readonly observedAttributes = ['id', 'variant', 'jslogcontext', 'trigger'];
|
|
204
208
|
static lastOpenedTooltipId: string|null = null;
|
|
205
209
|
|
|
206
210
|
readonly #shadow = this.attachShadow({mode: 'open'});
|
|
@@ -231,16 +235,20 @@ export class Tooltip extends HTMLElement {
|
|
|
231
235
|
}
|
|
232
236
|
}
|
|
233
237
|
|
|
234
|
-
get
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
238
|
+
get trigger(): TooltipTrigger {
|
|
239
|
+
switch (this.getAttribute('trigger')) {
|
|
240
|
+
case 'click':
|
|
241
|
+
return 'click';
|
|
242
|
+
case 'both':
|
|
243
|
+
return 'both';
|
|
244
|
+
case 'hover':
|
|
245
|
+
default:
|
|
246
|
+
return 'hover';
|
|
242
247
|
}
|
|
243
248
|
}
|
|
249
|
+
set trigger(trigger: TooltipTrigger) {
|
|
250
|
+
this.setAttribute('trigger', trigger);
|
|
251
|
+
}
|
|
244
252
|
|
|
245
253
|
get hoverDelay(): number {
|
|
246
254
|
return this.hasAttribute('hover-delay') ? Number(this.getAttribute('hover-delay')) : 300;
|
|
@@ -297,7 +305,7 @@ export class Tooltip extends HTMLElement {
|
|
|
297
305
|
|
|
298
306
|
constructor(properties?: TooltipProperties) {
|
|
299
307
|
super();
|
|
300
|
-
const {id, variant, padding, jslogContext, anchor} = properties ?? {};
|
|
308
|
+
const {id, variant, padding, jslogContext, anchor, trigger} = properties ?? {};
|
|
301
309
|
if (id) {
|
|
302
310
|
this.id = id;
|
|
303
311
|
}
|
|
@@ -317,6 +325,9 @@ export class Tooltip extends HTMLElement {
|
|
|
317
325
|
}
|
|
318
326
|
this.#anchor = anchor;
|
|
319
327
|
}
|
|
328
|
+
if (trigger) {
|
|
329
|
+
this.trigger = trigger;
|
|
330
|
+
}
|
|
320
331
|
}
|
|
321
332
|
|
|
322
333
|
attributeChangedCallback(name: string, oldValue: string, newValue: string): void {
|
|
@@ -463,7 +474,7 @@ export class Tooltip extends HTMLElement {
|
|
|
463
474
|
if (!this.hasAttribute('role')) {
|
|
464
475
|
this.setAttribute('role', 'tooltip');
|
|
465
476
|
}
|
|
466
|
-
this.setAttribute('popover', this.
|
|
477
|
+
this.setAttribute('popover', this.trigger === 'hover' ? 'manual' : 'auto');
|
|
467
478
|
this.#updateJslog();
|
|
468
479
|
}
|
|
469
480
|
|
|
@@ -474,6 +485,9 @@ export class Tooltip extends HTMLElement {
|
|
|
474
485
|
#setClosing = (event: Event): void => {
|
|
475
486
|
if ((event as ToggleEvent).newState === 'closed') {
|
|
476
487
|
this.#closing = true;
|
|
488
|
+
if (this.#timeout) {
|
|
489
|
+
window.clearTimeout(this.#timeout);
|
|
490
|
+
}
|
|
477
491
|
}
|
|
478
492
|
};
|
|
479
493
|
|
|
@@ -521,9 +535,10 @@ export class Tooltip extends HTMLElement {
|
|
|
521
535
|
// as we always want to support ESC to close.
|
|
522
536
|
this.#anchor.addEventListener('keydown', this.#keyDown);
|
|
523
537
|
|
|
524
|
-
if (this.
|
|
538
|
+
if (this.trigger === 'click' || this.trigger === 'both') {
|
|
525
539
|
this.#anchor.addEventListener('click', this.toggle);
|
|
526
|
-
}
|
|
540
|
+
}
|
|
541
|
+
if (this.trigger === 'hover' || this.trigger === 'both') {
|
|
527
542
|
this.#anchor.addEventListener('mouseenter', this.showTooltip);
|
|
528
543
|
if (!this.useHotkey) {
|
|
529
544
|
this.#anchor.addEventListener('focus', this.showTooltip);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Copyright 2025 The Chromium Authors
|
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
/* eslint-disable @devtools/no-imperative-dom-api */
|
|
6
|
+
|
|
7
|
+
import * as I18n from '../../core/i18n/i18n.js';
|
|
8
|
+
import type * as ThirdPartyI18n from '../../third_party/i18n/i18n.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Returns a span element that may contains other DOM element as placeholders
|
|
12
|
+
*/
|
|
13
|
+
export function getFormatLocalizedString(
|
|
14
|
+
registeredStrings: ThirdPartyI18n.LocalizedStringSet.RegisteredFileStrings, stringId: string,
|
|
15
|
+
placeholders: Record<string, Object>): HTMLSpanElement {
|
|
16
|
+
const formatter = registeredStrings.getLocalizedStringSetFor(I18n.DevToolsLocale.DevToolsLocale.instance().locale)
|
|
17
|
+
.getMessageFormatterFor(stringId);
|
|
18
|
+
|
|
19
|
+
const element = document.createElement('span');
|
|
20
|
+
for (const icuElement of formatter.getAst()) {
|
|
21
|
+
if (icuElement.type === /* argumentElement */ 1) {
|
|
22
|
+
const placeholderValue = placeholders[icuElement.value];
|
|
23
|
+
if (placeholderValue) {
|
|
24
|
+
element.append(placeholderValue as Node | string);
|
|
25
|
+
}
|
|
26
|
+
} else if ('value' in icuElement) {
|
|
27
|
+
element.append(String(icuElement.value));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return element;
|
|
31
|
+
}
|
|
@@ -38,7 +38,6 @@ export class SoftDropDown<T> implements ListDelegate<T> {
|
|
|
38
38
|
private list: ListControl<T>;
|
|
39
39
|
private rowHeight: number;
|
|
40
40
|
private width: number;
|
|
41
|
-
private listWasShowing200msAgo: boolean;
|
|
42
41
|
|
|
43
42
|
constructor(model: ListModel<T>, delegate: Delegate<T>, jslogContext?: string) {
|
|
44
43
|
this.delegate = delegate;
|
|
@@ -79,9 +78,8 @@ export class SoftDropDown<T> implements ListDelegate<T> {
|
|
|
79
78
|
'jslog',
|
|
80
79
|
`${VisualLogging.menu().parent('mapped').track({resize: true, keydown: 'ArrowUp|ArrowDown|PageUp|PageDown'})}`);
|
|
81
80
|
|
|
82
|
-
this.listWasShowing200msAgo = false;
|
|
83
81
|
this.element.addEventListener('mousedown', event => {
|
|
84
|
-
if (this.
|
|
82
|
+
if (this.glassPane.isShowing()) {
|
|
85
83
|
this.hide(event);
|
|
86
84
|
} else if (!this.element.disabled) {
|
|
87
85
|
this.show(event);
|
|
@@ -96,9 +94,6 @@ export class SoftDropDown<T> implements ListDelegate<T> {
|
|
|
96
94
|
return;
|
|
97
95
|
}
|
|
98
96
|
|
|
99
|
-
if (!this.listWasShowing200msAgo) {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
97
|
this.selectHighlightedItem();
|
|
103
98
|
if (event.target instanceof Element && event.target?.parentElement) {
|
|
104
99
|
// hide() will consume the mouseup event and click won't be triggered
|
|
@@ -122,9 +117,6 @@ export class SoftDropDown<T> implements ListDelegate<T> {
|
|
|
122
117
|
this.list.selectItem(this.selectedItem);
|
|
123
118
|
}
|
|
124
119
|
event.consume(true);
|
|
125
|
-
window.setTimeout(() => {
|
|
126
|
-
this.listWasShowing200msAgo = true;
|
|
127
|
-
}, 200);
|
|
128
120
|
}
|
|
129
121
|
|
|
130
122
|
private updateGlasspaneSize(): void {
|
|
@@ -134,9 +126,6 @@ export class SoftDropDown<T> implements ListDelegate<T> {
|
|
|
134
126
|
}
|
|
135
127
|
|
|
136
128
|
private hide(event: Event): void {
|
|
137
|
-
window.setTimeout(() => {
|
|
138
|
-
this.listWasShowing200msAgo = false;
|
|
139
|
-
}, 200);
|
|
140
129
|
this.glassPane.hide();
|
|
141
130
|
this.list.selectItem(null);
|
|
142
131
|
ARIAUtils.setExpanded(this.element, false);
|
|
@@ -164,14 +164,12 @@ export interface EventTypes {
|
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
export class ViewManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
167
|
-
readonly views
|
|
168
|
-
private readonly locationNameByViewId
|
|
167
|
+
readonly views = new Map<string, View>();
|
|
168
|
+
private readonly locationNameByViewId = new Map<string, string>();
|
|
169
169
|
private readonly locationOverrideSetting: Common.Settings.Setting<Record<string, string>>;
|
|
170
170
|
|
|
171
171
|
private constructor() {
|
|
172
172
|
super();
|
|
173
|
-
this.views = new Map();
|
|
174
|
-
this.locationNameByViewId = new Map();
|
|
175
173
|
|
|
176
174
|
// Read override setting for location
|
|
177
175
|
this.locationOverrideSetting = Common.Settings.Settings.instance().createSetting('views-location-override', {});
|