chrome-devtools-frontend 1.0.1001476 → 1.0.1003469
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/config/gni/devtools_grd_files.gni +5 -6
- package/front_end/core/common/ParsedURL.ts +3 -3
- package/front_end/core/host/InspectorFrontendHost.ts +30 -1
- package/front_end/core/host/InspectorFrontendHostAPI.ts +1 -0
- package/front_end/core/host/UserMetrics.ts +17 -1
- package/front_end/core/i18n/locales/en-US.json +24 -63
- package/front_end/core/i18n/locales/en-XL.json +24 -63
- package/front_end/core/protocol_client/InspectorBackend.ts +4 -0
- package/front_end/core/root/Runtime.ts +7 -3
- package/front_end/core/sdk/ServiceWorkerManager.ts +6 -5
- package/front_end/core/sdk/TracingModel.ts +5 -4
- package/front_end/devtools_compatibility.js +1 -0
- package/front_end/entrypoints/formatter_worker/FormatterActions.ts +14 -0
- package/front_end/entrypoints/formatter_worker/ScopeParser.ts +491 -0
- package/front_end/entrypoints/formatter_worker/Substitute.ts +4 -440
- package/front_end/entrypoints/formatter_worker/formatter_worker.ts +2 -0
- package/front_end/entrypoints/main/MainImpl.ts +1 -0
- package/front_end/generated/InspectorBackendCommands.js +42 -12
- package/front_end/generated/SupportedCSSProperties.js +3 -5
- package/front_end/generated/protocol-mapping.d.ts +5 -1
- package/front_end/generated/protocol-proxy-api.d.ts +4 -1
- package/front_end/generated/protocol.ts +68 -14
- package/front_end/models/bindings/CompilerScriptMapping.ts +1 -1
- package/front_end/models/issues_manager/AttributionReportingIssue.ts +6 -34
- package/front_end/models/issues_manager/DeprecationIssue.ts +84 -172
- package/front_end/models/issues_manager/Issue.ts +8 -4
- package/front_end/models/issues_manager/descriptions/arInvalidHeader.md +3 -0
- package/front_end/models/persistence/NetworkPersistenceManager.ts +20 -0
- package/front_end/models/timeline_model/TimelineModel.ts +2 -49
- package/front_end/panels/application/AppManifestView.ts +3 -3
- package/front_end/panels/application/ApplicationPanelCacheSection.ts +3 -1
- package/front_end/panels/application/ApplicationPanelSidebar.ts +11 -6
- package/front_end/panels/application/ApplicationPanelTreeElement.ts +2 -2
- package/front_end/panels/application/BackgroundServiceView.ts +5 -4
- package/front_end/panels/application/ResourcesPanel.ts +1 -1
- package/front_end/panels/console/ConsoleViewMessage.ts +6 -3
- package/front_end/panels/css_overview/components/CSSOverviewStartView.ts +3 -2
- package/front_end/panels/elements/StylePropertyTreeElement.ts +19 -13
- package/front_end/panels/elements/StylesSidebarPane.ts +74 -5
- package/front_end/panels/elements/stylesSidebarPane.css +3 -0
- package/front_end/panels/issues/AffectedResourcesView.ts +4 -3
- package/front_end/panels/issues/AffectedSourcesView.ts +2 -1
- package/front_end/panels/issues/AttributionReportingIssueDetailsView.ts +9 -38
- package/front_end/panels/issues/IssueView.ts +1 -1
- package/front_end/panels/lighthouse/LighthouseController.ts +6 -3
- package/front_end/panels/lighthouse/LighthouseReporterTypes.ts +2 -1
- package/front_end/panels/lighthouse/lighthousePanel.css +4 -0
- package/front_end/panels/network/NetworkLogView.ts +32 -0
- package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +2 -2
- package/front_end/panels/profiler/HeapSnapshotView.ts +2 -1
- package/front_end/panels/profiler/ProfileDataGrid.ts +1 -1
- package/front_end/panels/security/SecurityPanel.ts +6 -5
- package/front_end/panels/settings/SettingsScreen.ts +2 -3
- package/front_end/panels/sources/SourcesNavigator.ts +1 -1
- package/front_end/panels/sources/SourcesPanel.ts +1 -1
- package/front_end/panels/timeline/PerformanceModel.ts +2 -6
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +5 -26
- package/front_end/panels/timeline/TimelineUIUtils.ts +14 -12
- package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +1036 -1088
- package/front_end/third_party/lighthouse/locales/en-US.json +244 -4
- package/front_end/third_party/lighthouse/locales/en-XL.json +244 -4
- package/front_end/third_party/lighthouse/report/bundle.d.ts +4 -22
- package/front_end/third_party/lighthouse/report/bundle.js +23 -366
- package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +1 -1
- package/front_end/ui/components/docs/linkifier/simple-url.ts +2 -1
- package/front_end/ui/components/docs/panel_feedback/basic.ts +3 -2
- package/front_end/ui/components/docs/panel_feedback/button.ts +2 -1
- package/front_end/ui/components/linkifier/LinkifierImpl.ts +4 -3
- package/front_end/ui/components/linkifier/LinkifierUtils.ts +2 -3
- package/front_end/ui/components/panel_feedback/FeedbackButton.ts +4 -6
- package/front_end/ui/components/panel_feedback/PanelFeedback.ts +5 -4
- package/front_end/ui/components/request_link_icon/RequestLinkIcon.ts +3 -3
- package/front_end/ui/components/text_editor/javascript.ts +6 -15
- package/front_end/ui/legacy/EmptyWidget.ts +2 -1
- package/front_end/ui/legacy/InspectorView.ts +29 -0
- package/front_end/ui/legacy/UIUtils.ts +4 -4
- package/front_end/ui/legacy/XLink.ts +12 -13
- package/front_end/ui/legacy/components/color_picker/ContrastDetails.ts +2 -4
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +1 -1
- package/front_end/ui/legacy/components/perf_ui/LineLevelProfile.ts +0 -2
- package/front_end/ui/legacy/components/utils/ImagePreview.ts +3 -7
- package/front_end/ui/legacy/components/utils/Linkifier.ts +23 -23
- package/front_end/ui/legacy/toolbar.css +1 -1
- package/package.json +1 -1
- package/scripts/whitespaces.txt +1 -0
- package/front_end/models/issues_manager/descriptions/arInvalidAttributionSourceEventId.md +0 -3
- package/front_end/models/issues_manager/descriptions/arInvalidAttributionSourceExpiry.md +0 -4
- package/front_end/models/issues_manager/descriptions/arInvalidAttributionSourcePriority.md +0 -4
@@ -98,7 +98,6 @@ export class TimelineModelImpl {
|
|
98
98
|
private lastRecalculateStylesEvent!: SDK.TracingModel.Event|null;
|
99
99
|
private currentScriptEvent!: SDK.TracingModel.Event|null;
|
100
100
|
private eventStack!: SDK.TracingModel.Event[];
|
101
|
-
private knownInputEvents!: Set<string>;
|
102
101
|
private browserFrameTracking!: boolean;
|
103
102
|
private persistentIds!: boolean;
|
104
103
|
private legacyCurrentPage!: any;
|
@@ -226,7 +225,8 @@ export class TimelineModelImpl {
|
|
226
225
|
}
|
227
226
|
|
228
227
|
isMainFrameNavigationStartEvent(event: SDK.TracingModel.Event): boolean {
|
229
|
-
return this.isNavigationStartEvent(event) &&
|
228
|
+
return this.isNavigationStartEvent(event) &&
|
229
|
+
(event.args['data']['isOutermostMainFrame'] ?? event.args['data']['isLoadingMainFrame']) &&
|
230
230
|
event.args['data']['documentLoaderURL'];
|
231
231
|
}
|
232
232
|
|
@@ -573,7 +573,6 @@ export class TimelineModelImpl {
|
|
573
573
|
this.lastRecalculateStylesEvent = null;
|
574
574
|
this.currentScriptEvent = null;
|
575
575
|
this.eventStack = [];
|
576
|
-
this.knownInputEvents = new Set();
|
577
576
|
this.browserFrameTracking = false;
|
578
577
|
this.persistentIds = false;
|
579
578
|
this.legacyCurrentPage = null;
|
@@ -833,44 +832,6 @@ export class TimelineModelImpl {
|
|
833
832
|
group(TrackType.Animation).push(asyncEvent);
|
834
833
|
continue;
|
835
834
|
}
|
836
|
-
|
837
|
-
if (asyncEvent.hasCategory(TimelineModelImpl.Category.LatencyInfo) ||
|
838
|
-
asyncEvent.name === RecordType.ImplSideFling) {
|
839
|
-
const lastStep = asyncEvent.steps[asyncEvent.steps.length - 1];
|
840
|
-
if (!lastStep) {
|
841
|
-
throw new Error('AsyncEvent.steps access is out of bounds.');
|
842
|
-
}
|
843
|
-
if (lastStep.phase !== SDK.TracingModel.Phase.NestableAsyncEnd) {
|
844
|
-
continue;
|
845
|
-
}
|
846
|
-
const chromeLatencyInfo = asyncEvent.args['chrome_latency_info'];
|
847
|
-
|
848
|
-
const data = chromeLatencyInfo?.['component_info'];
|
849
|
-
asyncEvent.causedFrame =
|
850
|
-
Boolean(data?.some((c: any) => c['component_type'] === 'COMPONENT_INPUT_EVENT_LATENCY_RENDERER_SWAP'));
|
851
|
-
if (asyncEvent.hasCategory(TimelineModelImpl.Category.LatencyInfo)) {
|
852
|
-
if (lastStep.id && !this.knownInputEvents.has(chromeLatencyInfo.trace_id)) {
|
853
|
-
continue;
|
854
|
-
}
|
855
|
-
if (asyncEvent.name === RecordType.InputLatencyMouseMove && !asyncEvent.causedFrame) {
|
856
|
-
continue;
|
857
|
-
}
|
858
|
-
// Coalesced events are not really been processed, no need to track them.
|
859
|
-
if (!data || data['is_coalesced']) {
|
860
|
-
continue;
|
861
|
-
}
|
862
|
-
|
863
|
-
const rendererMain =
|
864
|
-
data?.find((c: any) => c['component_type'] === 'COMPONENT_INPUT_EVENT_LATENCY_RENDERER_MAIN');
|
865
|
-
if (rendererMain) {
|
866
|
-
const time = rendererMain['time_us'] / 1000;
|
867
|
-
TimelineData.forEvent(asyncEvent.steps[0]).timeWaitingForMainThread =
|
868
|
-
time - asyncEvent.steps[0].startTime;
|
869
|
-
}
|
870
|
-
}
|
871
|
-
group(TrackType.Input).push(asyncEvent);
|
872
|
-
continue;
|
873
|
-
}
|
874
835
|
}
|
875
836
|
}
|
876
837
|
|
@@ -1210,13 +1171,6 @@ export class TimelineModelImpl {
|
|
1210
1171
|
}
|
1211
1172
|
|
1212
1173
|
private processBrowserEvent(event: SDK.TracingModel.Event): void {
|
1213
|
-
if (event.name === RecordType.LatencyInfoFlow) {
|
1214
|
-
if (event.args.chrome_latency_info?.trace_id) {
|
1215
|
-
this.knownInputEvents.add(event.args.chrome_latency_info.trace_id);
|
1216
|
-
}
|
1217
|
-
return;
|
1218
|
-
}
|
1219
|
-
|
1220
1174
|
if (event.name === RecordType.ResourceWillSendRequest) {
|
1221
1175
|
const requestId = event.args?.data?.requestId;
|
1222
1176
|
if (typeof requestId === 'string') {
|
@@ -1715,7 +1669,6 @@ export class Track {
|
|
1715
1669
|
export enum TrackType {
|
1716
1670
|
MainThread = 'MainThread',
|
1717
1671
|
Worker = 'Worker',
|
1718
|
-
Input = 'Input',
|
1719
1672
|
Animation = 'Animation',
|
1720
1673
|
Timings = 'Timings',
|
1721
1674
|
Console = 'Console',
|
@@ -433,7 +433,7 @@ export class AppManifestView extends UI.Widget.VBox implements SDK.TargetManager
|
|
433
433
|
.addChangeListener(this.updateManifest.bind(this, true));
|
434
434
|
|
435
435
|
this.emptyView = new UI.EmptyWidget.EmptyWidget(i18nString(UIStrings.noManifestDetected));
|
436
|
-
this.emptyView.appendLink('https://web.dev/add-manifest/');
|
436
|
+
this.emptyView.appendLink('https://web.dev/add-manifest/' as Platform.DevToolsPath.UrlString);
|
437
437
|
|
438
438
|
this.emptyView.show(this.contentElement);
|
439
439
|
this.emptyView.hideWidget();
|
@@ -693,7 +693,7 @@ export class AppManifestView extends UI.Widget.VBox implements SDK.TargetManager
|
|
693
693
|
this.newNoteUrlField.parentElement?.classList.toggle('hidden', !hasNewNoteUrl);
|
694
694
|
this.newNoteUrlField.removeChildren();
|
695
695
|
if (hasNewNoteUrl) {
|
696
|
-
const completeURL = (Common.ParsedURL.ParsedURL.completeURL(url, newNoteUrl) as
|
696
|
+
const completeURL = (Common.ParsedURL.ParsedURL.completeURL(url, newNoteUrl) as Platform.DevToolsPath.UrlString);
|
697
697
|
const link = Components.Linkifier.Linkifier.linkifyURL(
|
698
698
|
completeURL, ({text: newNoteUrl} as Components.Linkifier.LinkifyURLOptions));
|
699
699
|
link.tabIndex = 0;
|
@@ -763,7 +763,7 @@ export class AppManifestView extends UI.Widget.VBox implements SDK.TargetManager
|
|
763
763
|
shortcutSection.appendFlexedField('Description', shortcut.description);
|
764
764
|
}
|
765
765
|
const urlField = shortcutSection.appendFlexedField('URL');
|
766
|
-
const shortcutUrl =
|
766
|
+
const shortcutUrl = Common.ParsedURL.ParsedURL.completeURL(url, shortcut.url) as Platform.DevToolsPath.UrlString;
|
767
767
|
const link = Components.Linkifier.Linkifier.linkifyURL(
|
768
768
|
shortcutUrl, ({text: shortcut.url} as Components.Linkifier.LinkifyURLOptions));
|
769
769
|
link.tabIndex = 0;
|
@@ -41,7 +41,9 @@ export class ServiceWorkerCacheTreeElement extends ExpandableApplicationPanelTre
|
|
41
41
|
constructor(resourcesPanel: ResourcesPanel) {
|
42
42
|
super(resourcesPanel, i18nString(UIStrings.cacheStorage), 'CacheStorage');
|
43
43
|
const icon = UI.Icon.Icon.create('mediumicon-database', 'resource-tree-item');
|
44
|
-
this.setLink(
|
44
|
+
this.setLink(
|
45
|
+
'https://developer.chrome.com/docs/devtools/storage/cache/?utm_source=devtools' as
|
46
|
+
Platform.DevToolsPath.UrlString);
|
45
47
|
this.setLeadingIcons([icon]);
|
46
48
|
this.swCacheModel = null;
|
47
49
|
this.swCacheTreeElements = new Set();
|
@@ -243,7 +243,8 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
|
|
243
243
|
this.localStorageListTreeElement =
|
244
244
|
new ExpandableApplicationPanelTreeElement(panel, i18nString(UIStrings.localStorage), 'LocalStorage');
|
245
245
|
this.localStorageListTreeElement.setLink(
|
246
|
-
'https://developer.chrome.com/docs/devtools/storage/localstorage/?utm_source=devtools'
|
246
|
+
'https://developer.chrome.com/docs/devtools/storage/localstorage/?utm_source=devtools' as
|
247
|
+
Platform.DevToolsPath.UrlString);
|
247
248
|
const localStorageIcon = UI.Icon.Icon.create('mediumicon-table', 'resource-tree-item');
|
248
249
|
this.localStorageListTreeElement.setLeadingIcons([localStorageIcon]);
|
249
250
|
|
@@ -251,19 +252,22 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
|
|
251
252
|
this.sessionStorageListTreeElement =
|
252
253
|
new ExpandableApplicationPanelTreeElement(panel, i18nString(UIStrings.sessionStorage), 'SessionStorage');
|
253
254
|
this.sessionStorageListTreeElement.setLink(
|
254
|
-
'https://developer.chrome.com/docs/devtools/storage/sessionstorage/?utm_source=devtools'
|
255
|
+
'https://developer.chrome.com/docs/devtools/storage/sessionstorage/?utm_source=devtools' as
|
256
|
+
Platform.DevToolsPath.UrlString);
|
255
257
|
const sessionStorageIcon = UI.Icon.Icon.create('mediumicon-table', 'resource-tree-item');
|
256
258
|
this.sessionStorageListTreeElement.setLeadingIcons([sessionStorageIcon]);
|
257
259
|
|
258
260
|
storageTreeElement.appendChild(this.sessionStorageListTreeElement);
|
259
261
|
this.indexedDBListTreeElement = new IndexedDBTreeElement(panel);
|
260
262
|
this.indexedDBListTreeElement.setLink(
|
261
|
-
'https://developer.chrome.com/docs/devtools/storage/indexeddb/?utm_source=devtools'
|
263
|
+
'https://developer.chrome.com/docs/devtools/storage/indexeddb/?utm_source=devtools' as
|
264
|
+
Platform.DevToolsPath.UrlString);
|
262
265
|
storageTreeElement.appendChild(this.indexedDBListTreeElement);
|
263
266
|
this.databasesListTreeElement =
|
264
267
|
new ExpandableApplicationPanelTreeElement(panel, i18nString(UIStrings.webSql), 'Databases');
|
265
268
|
this.databasesListTreeElement.setLink(
|
266
|
-
'https://developer.chrome.com/docs/devtools/storage/websql/?utm_source=devtools'
|
269
|
+
'https://developer.chrome.com/docs/devtools/storage/websql/?utm_source=devtools' as
|
270
|
+
Platform.DevToolsPath.UrlString);
|
267
271
|
const databaseIcon = UI.Icon.Icon.create('mediumicon-database', 'resource-tree-item');
|
268
272
|
this.databasesListTreeElement.setLeadingIcons([databaseIcon]);
|
269
273
|
|
@@ -271,7 +275,8 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
|
|
271
275
|
this.cookieListTreeElement =
|
272
276
|
new ExpandableApplicationPanelTreeElement(panel, i18nString(UIStrings.cookies), 'Cookies');
|
273
277
|
this.cookieListTreeElement.setLink(
|
274
|
-
'https://developer.chrome.com/docs/devtools/storage/cookies/?utm_source=devtools'
|
278
|
+
'https://developer.chrome.com/docs/devtools/storage/cookies/?utm_source=devtools' as
|
279
|
+
Platform.DevToolsPath.UrlString);
|
275
280
|
const cookieIcon = UI.Icon.Icon.create('mediumicon-cookie', 'resource-tree-item');
|
276
281
|
this.cookieListTreeElement.setLeadingIcons([cookieIcon]);
|
277
282
|
storageTreeElement.appendChild(this.cookieListTreeElement);
|
@@ -1505,7 +1510,7 @@ export class StorageCategoryView extends UI.Widget.VBox {
|
|
1505
1510
|
this.emptyWidget.text = text;
|
1506
1511
|
}
|
1507
1512
|
|
1508
|
-
setLink(link:
|
1513
|
+
setLink(link: Platform.DevToolsPath.UrlString|null): void {
|
1509
1514
|
if (link && !this.linkElement) {
|
1510
1515
|
this.linkElement = this.emptyWidget.appendLink(link);
|
1511
1516
|
}
|
@@ -47,7 +47,7 @@ export class ApplicationPanelTreeElement extends UI.TreeOutline.TreeElement {
|
|
47
47
|
export class ExpandableApplicationPanelTreeElement extends ApplicationPanelTreeElement {
|
48
48
|
protected readonly expandedSetting: Common.Settings.Setting<boolean>;
|
49
49
|
protected readonly categoryName: string;
|
50
|
-
protected categoryLink:
|
50
|
+
protected categoryLink: Platform.DevToolsPath.UrlString|null;
|
51
51
|
|
52
52
|
constructor(resourcesPanel: ResourcesPanel, categoryName: string, settingsKey: string, settingsDefault = false) {
|
53
53
|
super(resourcesPanel, categoryName, false);
|
@@ -61,7 +61,7 @@ export class ExpandableApplicationPanelTreeElement extends ApplicationPanelTreeE
|
|
61
61
|
return 'category://' + this.categoryName as Platform.DevToolsPath.UrlString;
|
62
62
|
}
|
63
63
|
|
64
|
-
setLink(link:
|
64
|
+
setLink(link: Platform.DevToolsPath.UrlString): void {
|
65
65
|
this.categoryLink = link;
|
66
66
|
}
|
67
67
|
|
@@ -2,17 +2,18 @@
|
|
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-next-line rulesdir/es_modules_import
|
6
|
-
import emptyWidgetStyles from '../../ui/legacy/emptyWidget.css.js';
|
7
|
-
import backgroundServiceViewStyles from './backgroundServiceView.css.js';
|
8
5
|
import type * as Common from '../../core/common/common.js';
|
9
6
|
import * as i18n from '../../core/i18n/i18n.js';
|
10
7
|
import * as Platform from '../../core/platform/platform.js';
|
11
8
|
import * as SDK from '../../core/sdk/sdk.js';
|
9
|
+
import * as Protocol from '../../generated/protocol.js';
|
12
10
|
import * as Bindings from '../../models/bindings/bindings.js';
|
13
11
|
import * as DataGrid from '../../ui/legacy/components/data_grid/data_grid.js';
|
12
|
+
// eslint-disable-next-line rulesdir/es_modules_import
|
13
|
+
import emptyWidgetStyles from '../../ui/legacy/emptyWidget.css.js';
|
14
14
|
import * as UI from '../../ui/legacy/legacy.js';
|
15
|
-
|
15
|
+
|
16
|
+
import backgroundServiceViewStyles from './backgroundServiceView.css.js';
|
16
17
|
|
17
18
|
import type {BackgroundServiceModel} from './BackgroundServiceModel.js';
|
18
19
|
import {Events} from './BackgroundServiceModel.js';
|
@@ -140,7 +140,7 @@ export class ResourcesPanel extends UI.Panel.PanelWithSidebar {
|
|
140
140
|
return view;
|
141
141
|
}
|
142
142
|
|
143
|
-
showCategoryView(categoryName: string, categoryLink:
|
143
|
+
showCategoryView(categoryName: string, categoryLink: Platform.DevToolsPath.UrlString|null): void {
|
144
144
|
if (!this.categoryView) {
|
145
145
|
this.categoryView = new StorageCategoryView();
|
146
146
|
}
|
@@ -1439,7 +1439,8 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
|
|
1439
1439
|
}
|
1440
1440
|
|
1441
1441
|
// SyntaxErrors might not populate the URL field. Try to resolve it via scriptId.
|
1442
|
-
const url =
|
1442
|
+
const url =
|
1443
|
+
exceptionDetails.url as Platform.DevToolsPath.UrlString || debuggerModel.scriptForId(scriptId)?.sourceURL;
|
1443
1444
|
if (!url) {
|
1444
1445
|
return;
|
1445
1446
|
}
|
@@ -1531,7 +1532,9 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
|
|
1531
1532
|
}
|
1532
1533
|
|
1533
1534
|
private linkifyWithCustomLinkifier(
|
1534
|
-
string: string,
|
1535
|
+
string: string,
|
1536
|
+
linkifier: (arg0: string, arg1: Platform.DevToolsPath.UrlString, arg2?: number, arg3?: number) => Node):
|
1537
|
+
DocumentFragment {
|
1535
1538
|
if (string.length > getMaxTokenizableStringLength()) {
|
1536
1539
|
const propertyValue = new ObjectUI.ObjectPropertiesSection.ExpandableTextPropertyValue(
|
1537
1540
|
document.createElement('span'), string, getLongStringVisibleLength());
|
@@ -1563,7 +1566,7 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
|
|
1563
1566
|
if (splitResult) {
|
1564
1567
|
linkNode = linkifier(token.text, sourceURL, splitResult.lineNumber, splitResult.columnNumber);
|
1565
1568
|
} else {
|
1566
|
-
linkNode = linkifier(token.text,
|
1569
|
+
linkNode = linkifier(token.text, Platform.DevToolsPath.EmptyUrlString);
|
1567
1570
|
}
|
1568
1571
|
container.appendChild(linkNode);
|
1569
1572
|
break;
|
@@ -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 type * as Platform from '../../../core/platform/platform.js';
|
6
7
|
import * as Buttons from '../../../ui/components/buttons/buttons.js';
|
7
8
|
import * as ComponentHelpers from '../../../ui/components/helpers/helpers.js';
|
8
9
|
import * as PanelFeedback from '../../../ui/components/panel_feedback/panel_feedback.js';
|
@@ -43,8 +44,8 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
43
44
|
|
44
45
|
const {render, html} = LitHtml;
|
45
46
|
|
46
|
-
const FEEDBACK_LINK = 'https://g.co/devtools/css-overview-feedback';
|
47
|
-
const DOC_LINK = 'https://developer.chrome.com/docs/devtools/css-overview';
|
47
|
+
const FEEDBACK_LINK = 'https://g.co/devtools/css-overview-feedback' as Platform.DevToolsPath.UrlString;
|
48
|
+
const DOC_LINK = 'https://developer.chrome.com/docs/devtools/css-overview' as Platform.DevToolsPath.UrlString;
|
48
49
|
export class OverviewStartRequestedEvent extends Event {
|
49
50
|
static readonly eventName = 'overviewstartrequested';
|
50
51
|
|
@@ -848,45 +848,46 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
848
848
|
return;
|
849
849
|
}
|
850
850
|
|
851
|
+
const contextMenu = this.createCopyContextMenu(event);
|
852
|
+
void contextMenu.show();
|
853
|
+
}
|
854
|
+
|
855
|
+
createCopyContextMenu(event: Event): UI.ContextMenu.ContextMenu {
|
851
856
|
const contextMenu = new UI.ContextMenu.ContextMenu(event);
|
852
|
-
contextMenu.
|
857
|
+
contextMenu.headerSection().appendItem(i18nString(UIStrings.copyDeclaration), () => {
|
853
858
|
const propertyText = `${this.property.name}: ${this.property.value};`;
|
854
859
|
Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(propertyText);
|
855
860
|
Host.userMetrics.styleTextCopied(Host.UserMetrics.StyleTextCopied.DeclarationViaContextMenu);
|
856
861
|
});
|
857
862
|
|
858
|
-
contextMenu.
|
863
|
+
contextMenu.headerSection().appendItem(i18nString(UIStrings.copyProperty), () => {
|
859
864
|
Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(this.property.name);
|
860
865
|
Host.userMetrics.styleTextCopied(Host.UserMetrics.StyleTextCopied.PropertyViaContextMenu);
|
861
866
|
});
|
862
867
|
|
863
|
-
contextMenu.
|
868
|
+
contextMenu.headerSection().appendItem(i18nString(UIStrings.copyValue), () => {
|
864
869
|
Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(this.property.value);
|
865
870
|
Host.userMetrics.styleTextCopied(Host.UserMetrics.StyleTextCopied.ValueViaContextMenu);
|
866
871
|
});
|
867
872
|
|
868
|
-
contextMenu.
|
873
|
+
contextMenu.headerSection().appendItem(i18nString(UIStrings.copyRule), () => {
|
869
874
|
const section = (this.section() as StylePropertiesSection);
|
870
875
|
const ruleText = StylesSidebarPane.formatLeadingProperties(section).ruleText;
|
871
876
|
Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(ruleText);
|
872
877
|
Host.userMetrics.styleTextCopied(Host.UserMetrics.StyleTextCopied.RuleViaContextMenu);
|
873
878
|
});
|
874
879
|
|
875
|
-
contextMenu.
|
880
|
+
contextMenu.headerSection().appendItem(
|
881
|
+
i18nString(UIStrings.copyCssDeclarationAsJs), this.copyCssDeclarationAsJs.bind(this));
|
882
|
+
|
883
|
+
contextMenu.clipboardSection().appendItem(i18nString(UIStrings.copyAllDeclarations), () => {
|
876
884
|
const section = (this.section() as StylePropertiesSection);
|
877
885
|
const allDeclarationText = StylesSidebarPane.formatLeadingProperties(section).allDeclarationText;
|
878
886
|
Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(allDeclarationText);
|
879
887
|
Host.userMetrics.styleTextCopied(Host.UserMetrics.StyleTextCopied.AllDeclarationsViaContextMenu);
|
880
888
|
});
|
881
889
|
|
882
|
-
contextMenu.defaultSection().appendItem(i18nString(UIStrings.viewComputedValue), () => {
|
883
|
-
void this.viewComputedValue();
|
884
|
-
});
|
885
|
-
|
886
890
|
contextMenu.clipboardSection().appendItem(
|
887
|
-
i18nString(UIStrings.copyCssDeclarationAsJs), this.copyCssDeclarationAsJs.bind(this));
|
888
|
-
|
889
|
-
contextMenu.defaultSection().appendItem(
|
890
891
|
i18nString(UIStrings.copyAllCssDeclarationsAsJs), this.copyAllCssDeclarationAsJs.bind(this));
|
891
892
|
|
892
893
|
// TODO(changhaohan): conditionally add this item only when there are changes to copy
|
@@ -896,7 +897,11 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
896
897
|
Host.userMetrics.styleTextCopied(Host.UserMetrics.StyleTextCopied.AllChangesViaStylesPane);
|
897
898
|
});
|
898
899
|
|
899
|
-
|
900
|
+
contextMenu.footerSection().appendItem(i18nString(UIStrings.viewComputedValue), () => {
|
901
|
+
void this.viewComputedValue();
|
902
|
+
});
|
903
|
+
|
904
|
+
return contextMenu;
|
900
905
|
}
|
901
906
|
|
902
907
|
private async viewComputedValue(): Promise<void> {
|
@@ -1513,6 +1518,7 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
1513
1518
|
}
|
1514
1519
|
if (updatedProperty) {
|
1515
1520
|
this.listItemElement.classList.toggle('changed', this.isPropertyChanged(updatedProperty));
|
1521
|
+
this.parentPane().updateChangeStatus();
|
1516
1522
|
}
|
1517
1523
|
|
1518
1524
|
this.matchedStylesInternal.resetActiveProperties();
|
@@ -147,6 +147,14 @@ const UIStrings = {
|
|
147
147
|
*/
|
148
148
|
automaticDarkMode: 'Automatic dark mode',
|
149
149
|
/**
|
150
|
+
*@description Tooltip text that appears when hovering over the css changes button in the Styles Sidebar Pane of the Elements panel
|
151
|
+
*/
|
152
|
+
copyAllCSSChanges: 'Copy all the CSS changes',
|
153
|
+
/**
|
154
|
+
*@description Tooltip text that appears after clicking on the copy CSS changes button
|
155
|
+
*/
|
156
|
+
copiedToClipboard: 'Copied to clipboard',
|
157
|
+
/**
|
150
158
|
*@description Text displayed on layer separators in the styles sidebar pane.
|
151
159
|
*/
|
152
160
|
layer: 'Layer',
|
@@ -207,6 +215,7 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
207
215
|
private readonly imagePreviewPopover: ImagePreviewPopover;
|
208
216
|
activeCSSAngle: InlineEditor.CSSAngle.CSSAngle|null;
|
209
217
|
#urlToChangeTracker: Map<Platform.DevToolsPath.UrlString, ChangeTracker> = new Map();
|
218
|
+
#copyChangesButton?: UI.Toolbar.ToolbarButton;
|
210
219
|
|
211
220
|
static instance(): StylesSidebarPane {
|
212
221
|
if (!stylesSidebarPaneInstance) {
|
@@ -579,6 +588,11 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
579
588
|
if (!this.initialUpdateCompleted) {
|
580
589
|
this.initialUpdateCompleted = true;
|
581
590
|
this.appendToolbarItem(this.createRenderingShortcuts());
|
591
|
+
if (Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.STYLES_PANE_CSS_CHANGES)) {
|
592
|
+
this.#copyChangesButton = this.createCopyAllChangesButton();
|
593
|
+
this.appendToolbarItem(this.#copyChangesButton);
|
594
|
+
this.#copyChangesButton.element.classList.add('hidden');
|
595
|
+
}
|
582
596
|
this.dispatchEventToListeners(Events.InitialUpdateCompleted);
|
583
597
|
}
|
584
598
|
|
@@ -1109,6 +1123,22 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
1109
1123
|
return changedLines.has(formattedLineNumber + 1);
|
1110
1124
|
}
|
1111
1125
|
|
1126
|
+
updateChangeStatus(): void {
|
1127
|
+
if (!this.#copyChangesButton) {
|
1128
|
+
return;
|
1129
|
+
}
|
1130
|
+
|
1131
|
+
let hasChangedStyles = false;
|
1132
|
+
for (const changeTracker of this.#urlToChangeTracker.values()) {
|
1133
|
+
if (changeTracker.changedLines.size > 0) {
|
1134
|
+
hasChangedStyles = true;
|
1135
|
+
break;
|
1136
|
+
}
|
1137
|
+
}
|
1138
|
+
|
1139
|
+
this.#copyChangesButton.element.classList.toggle('hidden', !hasChangedStyles);
|
1140
|
+
}
|
1141
|
+
|
1112
1142
|
private async refreshChangedLines(uiSourceCode: Workspace.UISourceCode.UISourceCode): Promise<void> {
|
1113
1143
|
const changeTracker = this.#urlToChangeTracker.get(uiSourceCode.url());
|
1114
1144
|
if (!changeTracker) {
|
@@ -1290,6 +1320,29 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
1290
1320
|
|
1291
1321
|
return button;
|
1292
1322
|
}
|
1323
|
+
|
1324
|
+
private createCopyAllChangesButton(): UI.Toolbar.ToolbarButton {
|
1325
|
+
const copyAllChangesButton =
|
1326
|
+
new UI.Toolbar.ToolbarButton(i18nString(UIStrings.copyAllCSSChanges), 'largeicon-copy');
|
1327
|
+
// TODO(1296947): implement a dedicated component to share between all copy buttons
|
1328
|
+
copyAllChangesButton.element.setAttribute('data-content', i18nString(UIStrings.copiedToClipboard));
|
1329
|
+
let timeout: number|undefined;
|
1330
|
+
copyAllChangesButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, async () => {
|
1331
|
+
const allChanges = await this.getFormattedChanges();
|
1332
|
+
Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(allChanges);
|
1333
|
+
Host.userMetrics.styleTextCopied(Host.UserMetrics.StyleTextCopied.AllChangesViaStylesPane);
|
1334
|
+
if (timeout) {
|
1335
|
+
clearTimeout(timeout);
|
1336
|
+
timeout = undefined;
|
1337
|
+
}
|
1338
|
+
copyAllChangesButton.element.classList.add('copied-to-clipboard');
|
1339
|
+
timeout = window.setTimeout(() => {
|
1340
|
+
copyAllChangesButton.element.classList.remove('copied-to-clipboard');
|
1341
|
+
timeout = undefined;
|
1342
|
+
}, 2000);
|
1343
|
+
});
|
1344
|
+
return copyAllChangesButton;
|
1345
|
+
}
|
1293
1346
|
}
|
1294
1347
|
|
1295
1348
|
export const enum Events {
|
@@ -1301,6 +1354,10 @@ export interface StylesUpdateCompletedEvent {
|
|
1301
1354
|
hasMatchedStyles: boolean;
|
1302
1355
|
}
|
1303
1356
|
|
1357
|
+
interface CompletionResult extends UI.SuggestBox.Suggestion {
|
1358
|
+
isCSSVariableColor?: boolean;
|
1359
|
+
}
|
1360
|
+
|
1304
1361
|
export type EventTypes = {
|
1305
1362
|
[Events.InitialUpdateCompleted]: void,
|
1306
1363
|
[Events.StylesUpdateCompleted]: StylesUpdateCompletedEvent,
|
@@ -1596,8 +1653,8 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
|
|
1596
1653
|
return Promise.resolve([]);
|
1597
1654
|
}
|
1598
1655
|
|
1599
|
-
const prefixResults:
|
1600
|
-
const anywhereResults:
|
1656
|
+
const prefixResults: Array<CompletionResult> = [];
|
1657
|
+
const anywhereResults: Array<CompletionResult> = [];
|
1601
1658
|
if (!editingVariable) {
|
1602
1659
|
this.cssCompletions.forEach(completion => filterCompletions.call(this, completion, false /* variable */));
|
1603
1660
|
}
|
@@ -1692,10 +1749,10 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
|
|
1692
1749
|
|
1693
1750
|
if (this.isColorAware && !this.isEditingName) {
|
1694
1751
|
results.sort((a, b) => {
|
1695
|
-
if (
|
1752
|
+
if (a.isCSSVariableColor && b.isCSSVariableColor) {
|
1696
1753
|
return 0;
|
1697
1754
|
}
|
1698
|
-
return a.
|
1755
|
+
return a.isCSSVariableColor ? -1 : 1;
|
1699
1756
|
});
|
1700
1757
|
}
|
1701
1758
|
return Promise.resolve(results);
|
@@ -1703,7 +1760,7 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
|
|
1703
1760
|
function filterCompletions(
|
1704
1761
|
this: CSSPropertyPrompt, completion: string, variable: boolean, nameValue?: boolean): void {
|
1705
1762
|
const index = completion.toLowerCase().indexOf(lowerQuery);
|
1706
|
-
const result:
|
1763
|
+
const result: CompletionResult = {
|
1707
1764
|
text: completion,
|
1708
1765
|
title: undefined,
|
1709
1766
|
subtitle: undefined,
|
@@ -1714,6 +1771,7 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
|
|
1714
1771
|
selectionRange: undefined,
|
1715
1772
|
hideGhostText: undefined,
|
1716
1773
|
iconElement: undefined,
|
1774
|
+
isCSSVariableColor: false,
|
1717
1775
|
};
|
1718
1776
|
if (variable) {
|
1719
1777
|
const computedValue =
|
@@ -1722,6 +1780,9 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
|
|
1722
1780
|
const color = Common.Color.Color.parse(computedValue);
|
1723
1781
|
if (color) {
|
1724
1782
|
result.subtitleRenderer = swatchRenderer.bind(null, color);
|
1783
|
+
result.isCSSVariableColor = true;
|
1784
|
+
} else {
|
1785
|
+
result.subtitleRenderer = computedValueSubtitleRenderer.bind(null, computedValue);
|
1725
1786
|
}
|
1726
1787
|
}
|
1727
1788
|
}
|
@@ -1742,6 +1803,14 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
|
|
1742
1803
|
swatch.style.pointerEvents = 'none';
|
1743
1804
|
return swatch;
|
1744
1805
|
}
|
1806
|
+
function computedValueSubtitleRenderer(computedValue: string): Element {
|
1807
|
+
const subtitleElement = document.createElement('span');
|
1808
|
+
subtitleElement.className = 'suggestion-subtitle';
|
1809
|
+
subtitleElement.textContent = `${computedValue}`;
|
1810
|
+
subtitleElement.style.maxWidth = '100px';
|
1811
|
+
subtitleElement.title = `${computedValue}`;
|
1812
|
+
return subtitleElement;
|
1813
|
+
}
|
1745
1814
|
}
|
1746
1815
|
}
|
1747
1816
|
|
@@ -232,6 +232,9 @@
|
|
232
232
|
|
233
233
|
.sidebar-pane-section-toolbar.new-rule-toolbar {
|
234
234
|
visibility: hidden;
|
235
|
+
margin-bottom: 5px;
|
236
|
+
|
237
|
+
--toolbar-height: 16px;
|
235
238
|
}
|
236
239
|
|
237
240
|
.styles-pane:not(.is-editing-style) .styles-section.matched-styles:not(.read-only):hover .sidebar-pane-section-toolbar.new-rule-toolbar {
|
@@ -5,6 +5,7 @@
|
|
5
5
|
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
|
+
import type * as Platform from '../../core/platform/platform.js';
|
8
9
|
import * as SDK from '../../core/sdk/sdk.js';
|
9
10
|
import type * as IssuesManager from '../../models/issues_manager/issues_manager.js';
|
10
11
|
import * as Logs from '../../models/logs/logs.js';
|
@@ -44,7 +45,7 @@ export const enum AffectedItem {
|
|
44
45
|
Source = 'Source',
|
45
46
|
}
|
46
47
|
|
47
|
-
export const extractShortPath = (path:
|
48
|
+
export const extractShortPath = (path: Platform.DevToolsPath.UrlString): string => {
|
48
49
|
// 1st regex matches everything after last '/'
|
49
50
|
// if path ends with '/', 2nd regex returns everything between the last two '/'
|
50
51
|
return (/[^/]+$/.exec(path) || /[^/]+\/$/.exec(path) || [''])[0];
|
@@ -255,8 +256,8 @@ export abstract class AffectedResourcesView extends UI.TreeOutline.TreeElement {
|
|
255
256
|
// TODO(crbug.com/1108503): Add some mechanism to be able to add telemetry to this element.
|
256
257
|
const linkifier = new Components.Linkifier.Linkifier(maxLengthForDisplayedURLs);
|
257
258
|
const sourceAnchor = linkifier.linkifyScriptLocation(
|
258
|
-
target || null, sourceLocation.scriptId || null, sourceLocation.url
|
259
|
-
{columnNumber: sourceLocation.columnNumber, inlineFrameIndex: 0});
|
259
|
+
target || null, sourceLocation.scriptId || null, sourceLocation.url as Platform.DevToolsPath.UrlString,
|
260
|
+
sourceLocation.lineNumber, {columnNumber: sourceLocation.columnNumber, inlineFrameIndex: 0});
|
260
261
|
sourceCodeLocation.appendChild(sourceAnchor);
|
261
262
|
}
|
262
263
|
element.appendChild(sourceCodeLocation);
|
@@ -42,7 +42,8 @@ export class AffectedSourcesView extends AffectedResourcesView {
|
|
42
42
|
// Also, this element has a context menu, so we should be able to
|
43
43
|
// track when the user use the context menu too.
|
44
44
|
// TODO(crbug.com/1108503): Add some mechanism to be able to add telemetry to this element.
|
45
|
-
const anchorElement =
|
45
|
+
const anchorElement =
|
46
|
+
Components.Linkifier.Linkifier.linkifyURL(url as Platform.DevToolsPath.UrlString, linkifierURLOptions);
|
46
47
|
cellElement.appendChild(anchorElement);
|
47
48
|
const rowElement = document.createElement('tr');
|
48
49
|
rowElement.classList.add('affected-resource-source');
|