chrome-devtools-frontend 1.0.1007307 → 1.0.1008562
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 +3 -0
- package/extension-api/ExtensionAPI.d.ts +10 -0
- package/front_end/core/common/ParsedURL.ts +9 -1
- package/front_end/core/i18n/locales/en-US.json +14 -5
- package/front_end/core/i18n/locales/en-XL.json +14 -5
- package/front_end/core/sdk/CSSFontFace.ts +8 -0
- package/front_end/entrypoints/lighthouse_worker/LighthouseWorkerService.ts +1 -4
- package/front_end/generated/InspectorBackendCommands.js +2 -2
- package/front_end/generated/protocol.ts +2 -1
- package/front_end/legacy_test_runner/lighthouse_test_runner/lighthouse_test_runner.js +16 -0
- package/front_end/models/extensions/ExtensionAPI.ts +95 -12
- package/front_end/models/extensions/ExtensionEndpoint.ts +69 -0
- package/front_end/models/extensions/ExtensionServer.ts +21 -0
- package/front_end/models/extensions/LanguageExtensionEndpoint.ts +46 -78
- package/front_end/models/extensions/RecorderExtensionEndpoint.ts +43 -0
- package/front_end/models/extensions/RecorderPluginManager.ts +30 -0
- package/front_end/models/extensions/extensions.ts +2 -0
- package/front_end/models/issues_manager/DeprecationIssue.ts +0 -14
- package/front_end/panels/application/AppManifestView.ts +2 -1
- package/front_end/panels/browser_debugger/DOMBreakpointsSidebarPane.ts +15 -1
- package/front_end/panels/lighthouse/LighthouseController.ts +25 -10
- package/front_end/panels/lighthouse/LighthouseStartView.ts +25 -1
- package/front_end/panels/lighthouse/LighthouseStartViewFR.ts +1 -1
- package/front_end/panels/network/components/RequestHeadersView.css +5 -0
- package/front_end/panels/network/components/RequestHeadersView.ts +56 -6
- package/front_end/ui/components/tree_outline/TreeOutline.ts +4 -0
- package/front_end/ui/components/tree_outline/treeOutline.css +6 -1
- package/package.json +1 -1
@@ -5,9 +5,30 @@
|
|
5
5
|
import type * as SDK from '../../core/sdk/sdk.js';
|
6
6
|
import * as Bindings from '../bindings/bindings.js';
|
7
7
|
import type {Chrome} from '../../../extension-api/ExtensionAPI.js'; // eslint-disable-line rulesdir/es_modules_import
|
8
|
+
import {ExtensionEndpoint} from './ExtensionEndpoint.js';
|
8
9
|
|
9
10
|
import {PrivateAPI} from './ExtensionAPI.js';
|
10
11
|
|
12
|
+
class LanguageExtensionEndpointImpl extends ExtensionEndpoint {
|
13
|
+
private plugin: LanguageExtensionEndpoint;
|
14
|
+
constructor(plugin: LanguageExtensionEndpoint, port: MessagePort) {
|
15
|
+
super(port);
|
16
|
+
this.plugin = plugin;
|
17
|
+
}
|
18
|
+
protected handleEvent({event}: {event: string}): void {
|
19
|
+
switch (event) {
|
20
|
+
case PrivateAPI.LanguageExtensionPluginEvents.UnregisteredLanguageExtensionPlugin: {
|
21
|
+
this.disconnect();
|
22
|
+
const {pluginManager} = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance();
|
23
|
+
if (pluginManager) {
|
24
|
+
pluginManager.removePlugin(this.plugin);
|
25
|
+
}
|
26
|
+
break;
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
11
32
|
export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.DebuggerLanguagePlugin {
|
12
33
|
private readonly supportedScriptTypes: {
|
13
34
|
language: string,
|
@@ -15,13 +36,7 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
15
36
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
16
37
|
symbol_types: Array<string>,
|
17
38
|
};
|
18
|
-
private
|
19
|
-
private nextRequestId: number;
|
20
|
-
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
|
21
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
22
|
-
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
|
23
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
24
|
-
private pendingRequests: Map<any, any>;
|
39
|
+
private endpoint: LanguageExtensionEndpointImpl;
|
25
40
|
constructor(
|
26
41
|
name: string, supportedScriptTypes: {
|
27
42
|
language: string,
|
@@ -32,63 +47,7 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
32
47
|
port: MessagePort) {
|
33
48
|
super(name);
|
34
49
|
this.supportedScriptTypes = supportedScriptTypes;
|
35
|
-
this.
|
36
|
-
this.port.onmessage = this.onResponse.bind(this);
|
37
|
-
this.nextRequestId = 0;
|
38
|
-
this.pendingRequests = new Map();
|
39
|
-
}
|
40
|
-
|
41
|
-
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
|
42
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
43
|
-
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
|
44
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
45
|
-
private sendRequest(method: string, parameters: any): Promise<any> {
|
46
|
-
return new Promise((resolve, reject) => {
|
47
|
-
const requestId = this.nextRequestId++;
|
48
|
-
this.pendingRequests.set(requestId, {resolve, reject});
|
49
|
-
this.port.postMessage({requestId, method, parameters});
|
50
|
-
});
|
51
|
-
}
|
52
|
-
|
53
|
-
private onResponse({data}: MessageEvent<{
|
54
|
-
requestId: number,
|
55
|
-
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
|
56
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
57
|
-
result: any,
|
58
|
-
error: Error|null,
|
59
|
-
}|{
|
60
|
-
event: string,
|
61
|
-
}>): void {
|
62
|
-
if ('event' in data) {
|
63
|
-
const {event} = data;
|
64
|
-
switch (event) {
|
65
|
-
case PrivateAPI.LanguageExtensionPluginEvents.UnregisteredLanguageExtensionPlugin: {
|
66
|
-
for (const {reject} of this.pendingRequests.values()) {
|
67
|
-
reject(new Error('Language extension endpoint disconnected'));
|
68
|
-
}
|
69
|
-
this.pendingRequests.clear();
|
70
|
-
this.port.close();
|
71
|
-
const {pluginManager} = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance();
|
72
|
-
if (pluginManager) {
|
73
|
-
pluginManager.removePlugin(this);
|
74
|
-
}
|
75
|
-
break;
|
76
|
-
}
|
77
|
-
}
|
78
|
-
return;
|
79
|
-
}
|
80
|
-
const {requestId, result, error} = data;
|
81
|
-
if (!this.pendingRequests.has(requestId)) {
|
82
|
-
console.error(`No pending request ${requestId}`);
|
83
|
-
return;
|
84
|
-
}
|
85
|
-
const {resolve, reject} = this.pendingRequests.get(requestId);
|
86
|
-
this.pendingRequests.delete(requestId);
|
87
|
-
if (error) {
|
88
|
-
reject(new Error(error.message));
|
89
|
-
} else {
|
90
|
-
resolve(result);
|
91
|
-
}
|
50
|
+
this.endpoint = new LanguageExtensionEndpointImpl(this, port);
|
92
51
|
}
|
93
52
|
|
94
53
|
handleScript(script: SDK.Script.Script): boolean {
|
@@ -100,7 +59,7 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
100
59
|
/** Notify the plugin about a new script
|
101
60
|
*/
|
102
61
|
addRawModule(rawModuleId: string, symbolsURL: string, rawModule: Chrome.DevTools.RawModule): Promise<string[]> {
|
103
|
-
return this.sendRequest(
|
62
|
+
return this.endpoint.sendRequest(
|
104
63
|
PrivateAPI.LanguageExtensionPluginCommands.AddRawModule, {rawModuleId, symbolsURL, rawModule}) as
|
105
64
|
Promise<string[]>;
|
106
65
|
}
|
@@ -109,33 +68,36 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
109
68
|
* Notifies the plugin that a script is removed.
|
110
69
|
*/
|
111
70
|
removeRawModule(rawModuleId: string): Promise<void> {
|
112
|
-
return this.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.RemoveRawModule, {rawModuleId}) as
|
71
|
+
return this.endpoint.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.RemoveRawModule, {rawModuleId}) as
|
72
|
+
Promise<void>;
|
113
73
|
}
|
114
74
|
|
115
75
|
/** Find locations in raw modules from a location in a source file
|
116
76
|
*/
|
117
77
|
sourceLocationToRawLocation(sourceLocation: Chrome.DevTools.SourceLocation):
|
118
78
|
Promise<Chrome.DevTools.RawLocationRange[]> {
|
119
|
-
return this.sendRequest(
|
79
|
+
return this.endpoint.sendRequest(
|
80
|
+
PrivateAPI.LanguageExtensionPluginCommands.SourceLocationToRawLocation, {sourceLocation}) as
|
120
81
|
Promise<Chrome.DevTools.RawLocationRange[]>;
|
121
82
|
}
|
122
83
|
|
123
84
|
/** Find locations in source files from a location in a raw module
|
124
85
|
*/
|
125
86
|
rawLocationToSourceLocation(rawLocation: Chrome.DevTools.RawLocation): Promise<Chrome.DevTools.SourceLocation[]> {
|
126
|
-
return this.sendRequest(
|
87
|
+
return this.endpoint.sendRequest(
|
88
|
+
PrivateAPI.LanguageExtensionPluginCommands.RawLocationToSourceLocation, {rawLocation}) as
|
127
89
|
Promise<Chrome.DevTools.SourceLocation[]>;
|
128
90
|
}
|
129
91
|
|
130
92
|
getScopeInfo(type: string): Promise<Chrome.DevTools.ScopeInfo> {
|
131
|
-
return this.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.GetScopeInfo, {type}) as
|
93
|
+
return this.endpoint.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.GetScopeInfo, {type}) as
|
132
94
|
Promise<Chrome.DevTools.ScopeInfo>;
|
133
95
|
}
|
134
96
|
|
135
97
|
/** List all variables in lexical scope at a given location in a raw module
|
136
98
|
*/
|
137
99
|
listVariablesInScope(rawLocation: Chrome.DevTools.RawLocation): Promise<Chrome.DevTools.Variable[]> {
|
138
|
-
return this.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.ListVariablesInScope, {rawLocation}) as
|
100
|
+
return this.endpoint.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.ListVariablesInScope, {rawLocation}) as
|
139
101
|
Promise<Chrome.DevTools.Variable[]>;
|
140
102
|
}
|
141
103
|
|
@@ -144,7 +106,8 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
144
106
|
getFunctionInfo(rawLocation: Chrome.DevTools.RawLocation): Promise<{
|
145
107
|
frames: Array<Chrome.DevTools.FunctionInfo>,
|
146
108
|
}> {
|
147
|
-
return this.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.GetFunctionInfo, {rawLocation}) as
|
109
|
+
return this.endpoint.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.GetFunctionInfo, {rawLocation}) as
|
110
|
+
Promise<{
|
148
111
|
frames: Array<Chrome.DevTools.FunctionInfo>,
|
149
112
|
}>;
|
150
113
|
}
|
@@ -153,7 +116,8 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
153
116
|
* that rawLocation is in.
|
154
117
|
*/
|
155
118
|
getInlinedFunctionRanges(rawLocation: Chrome.DevTools.RawLocation): Promise<Chrome.DevTools.RawLocationRange[]> {
|
156
|
-
return this.sendRequest(
|
119
|
+
return this.endpoint.sendRequest(
|
120
|
+
PrivateAPI.LanguageExtensionPluginCommands.GetInlinedFunctionRanges, {rawLocation}) as
|
157
121
|
Promise<Chrome.DevTools.RawLocationRange[]>;
|
158
122
|
}
|
159
123
|
|
@@ -161,7 +125,8 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
161
125
|
* called by the function or inline frame that rawLocation is in.
|
162
126
|
*/
|
163
127
|
getInlinedCalleesRanges(rawLocation: Chrome.DevTools.RawLocation): Promise<Chrome.DevTools.RawLocationRange[]> {
|
164
|
-
return this.sendRequest(
|
128
|
+
return this.endpoint.sendRequest(
|
129
|
+
PrivateAPI.LanguageExtensionPluginCommands.GetInlinedCalleesRanges, {rawLocation}) as
|
165
130
|
Promise<Chrome.DevTools.RawLocationRange[]>;
|
166
131
|
}
|
167
132
|
|
@@ -169,7 +134,8 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
169
134
|
typeInfos: Array<Chrome.DevTools.TypeInfo>,
|
170
135
|
base: Chrome.DevTools.EvalBase,
|
171
136
|
}|null> {
|
172
|
-
return this.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.GetTypeInfo, {expression, context}) as
|
137
|
+
return this.endpoint.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.GetTypeInfo, {expression, context}) as
|
138
|
+
Promise<{
|
173
139
|
typeInfos: Array<Chrome.DevTools.TypeInfo>,
|
174
140
|
base: Chrome.DevTools.EvalBase,
|
175
141
|
}|null>;
|
@@ -183,8 +149,8 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
183
149
|
context: Chrome.DevTools.RawLocation): Promise<{
|
184
150
|
js: string,
|
185
151
|
}> {
|
186
|
-
return this.sendRequest(
|
187
|
-
|
152
|
+
return this.endpoint.sendRequest(
|
153
|
+
PrivateAPI.LanguageExtensionPluginCommands.GetFormatter, {expressionOrField, context}) as Promise<{
|
188
154
|
js: string,
|
189
155
|
}>;
|
190
156
|
}
|
@@ -195,13 +161,15 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
195
161
|
}): Promise<{
|
196
162
|
js: string,
|
197
163
|
}> {
|
198
|
-
return this.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.GetInspectableAddress, {field}) as
|
164
|
+
return this.endpoint.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.GetInspectableAddress, {field}) as
|
165
|
+
Promise<{
|
199
166
|
js: string,
|
200
167
|
}>;
|
201
168
|
}
|
202
169
|
|
203
170
|
async getMappedLines(rawModuleId: string, sourceFileURL: string): Promise<number[]|undefined> {
|
204
|
-
return this.sendRequest(
|
171
|
+
return this.endpoint.sendRequest(
|
172
|
+
PrivateAPI.LanguageExtensionPluginCommands.GetMappedLines, {rawModuleId, sourceFileURL});
|
205
173
|
}
|
206
174
|
|
207
175
|
dispose(): void {
|
@@ -0,0 +1,43 @@
|
|
1
|
+
// Copyright 2022 The Chromium Authors. All rights reserved.
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
3
|
+
// found in the LICENSE file.
|
4
|
+
|
5
|
+
import {PrivateAPI} from './ExtensionAPI.js';
|
6
|
+
import {ExtensionEndpoint} from './ExtensionEndpoint.js';
|
7
|
+
import {RecorderPluginManager} from './RecorderPluginManager.js';
|
8
|
+
|
9
|
+
export class RecorderExtensionEndpoint extends ExtensionEndpoint {
|
10
|
+
private readonly name: string;
|
11
|
+
|
12
|
+
constructor(name: string, port: MessagePort) {
|
13
|
+
super(port);
|
14
|
+
this.name = name;
|
15
|
+
}
|
16
|
+
|
17
|
+
getName(): string {
|
18
|
+
return this.name;
|
19
|
+
}
|
20
|
+
|
21
|
+
protected handleEvent({event}: {event: string}): void {
|
22
|
+
switch (event) {
|
23
|
+
case PrivateAPI.RecorderExtensionPluginEvents.UnregisteredRecorderExtensionPlugin: {
|
24
|
+
this.disconnect();
|
25
|
+
RecorderPluginManager.instance().removePlugin(this);
|
26
|
+
break;
|
27
|
+
}
|
28
|
+
default:
|
29
|
+
throw new Error(`Unrecognized Recorder extension endpoint event: ${event}`);
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
/**
|
34
|
+
* In practice, `recording` is a UserFlow[1], but we avoid defining this type on the
|
35
|
+
* API in order to prevent dependencies between Chrome and puppeteer. Extensions
|
36
|
+
* are responsible for working out potential compatibility issues.
|
37
|
+
*
|
38
|
+
* [1]: https://github.com/puppeteer/replay/blob/main/src/Schema.ts#L245
|
39
|
+
*/
|
40
|
+
stringify(recording: Object): Promise<string> {
|
41
|
+
return this.sendRequest(PrivateAPI.RecorderExtensionPluginCommands.Stringify, {recording});
|
42
|
+
}
|
43
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
// Copyright 2022 The Chromium Authors. All rights reserved.
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
3
|
+
// found in the LICENSE file.
|
4
|
+
|
5
|
+
import type {RecorderExtensionEndpoint} from './RecorderExtensionEndpoint.js';
|
6
|
+
|
7
|
+
let instance: RecorderPluginManager|null = null;
|
8
|
+
|
9
|
+
export class RecorderPluginManager {
|
10
|
+
#plugins: Set<RecorderExtensionEndpoint> = new Set();
|
11
|
+
|
12
|
+
static instance(): RecorderPluginManager {
|
13
|
+
if (!instance) {
|
14
|
+
instance = new RecorderPluginManager();
|
15
|
+
}
|
16
|
+
return instance;
|
17
|
+
}
|
18
|
+
|
19
|
+
addPlugin(plugin: RecorderExtensionEndpoint): void {
|
20
|
+
this.#plugins.add(plugin);
|
21
|
+
}
|
22
|
+
|
23
|
+
removePlugin(plugin: RecorderExtensionEndpoint): void {
|
24
|
+
this.#plugins.delete(plugin);
|
25
|
+
}
|
26
|
+
|
27
|
+
plugins(): RecorderExtensionEndpoint[] {
|
28
|
+
return Array.from(this.#plugins.values());
|
29
|
+
}
|
30
|
+
}
|
@@ -7,6 +7,7 @@ import * as ExtensionPanel from './ExtensionPanel.js';
|
|
7
7
|
import * as ExtensionServer from './ExtensionServer.js';
|
8
8
|
import * as ExtensionTraceProvider from './ExtensionTraceProvider.js';
|
9
9
|
import * as ExtensionView from './ExtensionView.js';
|
10
|
+
import * as RecorderPluginManager from './RecorderPluginManager.js';
|
10
11
|
|
11
12
|
export {
|
12
13
|
ExtensionAPI,
|
@@ -14,4 +15,5 @@ export {
|
|
14
15
|
ExtensionServer,
|
15
16
|
ExtensionTraceProvider,
|
16
17
|
ExtensionView,
|
18
|
+
RecorderPluginManager,
|
17
19
|
};
|
@@ -243,16 +243,6 @@ const UIStrings = {
|
|
243
243
|
* `RTCP MUX` policy.
|
244
244
|
*/
|
245
245
|
rtcpMuxPolicyNegotiate: 'The `rtcpMuxPolicy` option is deprecated and will be removed.',
|
246
|
-
/**
|
247
|
-
* @description A deprecation warning shown in the DevTools Issues tab.
|
248
|
-
* It's shown when a video conferencing website attempts to turn on or
|
249
|
-
* off a feature that has been removed, `RTP data channels`.
|
250
|
-
* `RTP data channels` are used to send and receive arbitrary data,
|
251
|
-
* but have been removed in favor of standardized versions of
|
252
|
-
* `data channels`: `SCTP data channels`.
|
253
|
-
*/
|
254
|
-
rtpDataChannel:
|
255
|
-
'`RTP data channels` are no longer supported. The `RtpDataChannels` constraint is currently ignored, and may cause an error at a later date.',
|
256
246
|
/**
|
257
247
|
* @description TODO(crbug.com/1318878): Description needed for translation
|
258
248
|
*/
|
@@ -500,10 +490,6 @@ export class DeprecationIssue extends Issue {
|
|
500
490
|
feature = 5654810086866944;
|
501
491
|
milestone = 62;
|
502
492
|
break;
|
503
|
-
case Protocol.Audits.DeprecationIssueType.RTPDataChannel:
|
504
|
-
messageFunction = i18nLazyString(UIStrings.rtpDataChannel);
|
505
|
-
milestone = 88;
|
506
|
-
break;
|
507
493
|
case Protocol.Audits.DeprecationIssueType.SharedArrayBufferConstructedWithoutIsolation:
|
508
494
|
messageFunction = i18nLazyString(UIStrings.sharedArrayBufferConstructedWithoutIsolation);
|
509
495
|
milestone = 106;
|
@@ -663,7 +663,8 @@ export class AppManifestView extends UI.Widget.VBox implements SDK.TargetManager
|
|
663
663
|
}
|
664
664
|
|
665
665
|
const userPreferences = parsedManifest['user_preferences'] || {};
|
666
|
-
const
|
666
|
+
const colorScheme = userPreferences['color_scheme'] || {};
|
667
|
+
const colorSchemeDark = colorScheme['dark'] || {};
|
667
668
|
const darkThemeColorString = colorSchemeDark['theme_color'];
|
668
669
|
const hasDarkThemeColor = typeof darkThemeColorString === 'string';
|
669
670
|
this.darkThemeColorField.parentElement?.classList.toggle('hidden', !hasDarkThemeColor);
|
@@ -53,6 +53,13 @@ const UIStrings = {
|
|
53
53
|
*/
|
54
54
|
sS: '{PH1}: {PH2}',
|
55
55
|
/**
|
56
|
+
*@description Text with three placeholders separated by a colon and a comma
|
57
|
+
*@example {Node removed} PH1
|
58
|
+
*@example {div#id1} PH2
|
59
|
+
*@example {checked} PH3
|
60
|
+
*/
|
61
|
+
sSS: '{PH1}: {PH2}, {PH3}',
|
62
|
+
/**
|
56
63
|
*@description Text exposed to screen readers on checked items.
|
57
64
|
*/
|
58
65
|
checked: 'checked',
|
@@ -196,19 +203,26 @@ export class DOMBreakpointsSidebarPane extends UI.Widget.VBox implements
|
|
196
203
|
description.textContent = breakpointTypeLabel ? breakpointTypeLabel() : null;
|
197
204
|
const breakpointTypeText = breakpointTypeLabel ? breakpointTypeLabel() : '';
|
198
205
|
UI.ARIAUtils.setAccessibleName(checkboxElement, breakpointTypeText);
|
206
|
+
const checkedStateText = item.enabled ? i18nString(UIStrings.checked) : i18nString(UIStrings.unchecked);
|
199
207
|
const linkifiedNode = document.createElement('monospace');
|
200
208
|
linkifiedNode.style.display = 'block';
|
201
209
|
labelElement.appendChild(linkifiedNode);
|
202
210
|
void Common.Linkifier.Linkifier.linkify(item.node, {preventKeyboardFocus: true, tooltip: undefined})
|
203
211
|
.then(linkified => {
|
204
212
|
linkifiedNode.appendChild(linkified);
|
213
|
+
// Give the checkbox an aria-label as it is required for all form element
|
205
214
|
UI.ARIAUtils.setAccessibleName(
|
206
215
|
checkboxElement, i18nString(UIStrings.sS, {PH1: breakpointTypeText, PH2: linkified.deepTextContent()}));
|
216
|
+
// The parent list element is the one that actually gets focused.
|
217
|
+
// Assign it an aria-label with complete information for the screen reader to read out properly
|
218
|
+
UI.ARIAUtils.setAccessibleName(
|
219
|
+
element,
|
220
|
+
i18nString(
|
221
|
+
UIStrings.sSS, {PH1: breakpointTypeText, PH2: linkified.deepTextContent(), PH3: checkedStateText}));
|
207
222
|
});
|
208
223
|
|
209
224
|
labelElement.appendChild(description);
|
210
225
|
|
211
|
-
const checkedStateText = item.enabled ? i18nString(UIStrings.checked) : i18nString(UIStrings.unchecked);
|
212
226
|
if (item === this.#highlightedBreakpoint) {
|
213
227
|
element.classList.add('breakpoint-hit');
|
214
228
|
UI.ARIAUtils.setDescription(element, i18nString(UIStrings.sBreakpointHit, {PH1: checkedStateText}));
|
@@ -146,14 +146,22 @@ const UIStrings = {
|
|
146
146
|
*/
|
147
147
|
desktop: 'Desktop',
|
148
148
|
/**
|
149
|
-
|
150
|
-
|
151
|
-
|
149
|
+
* @description Text for an option to select a throttling method.
|
150
|
+
*/
|
151
|
+
throttlingMethod: 'Throttling method',
|
152
152
|
/**
|
153
|
-
|
154
|
-
|
153
|
+
* @description Text for an option in a dropdown to use simulated throttling. This is the default setting.
|
154
|
+
*/
|
155
|
+
simulatedThrottling: 'Simulated throttling (default)',
|
156
|
+
/**
|
157
|
+
* @description Text for an option in a dropdown to use DevTools throttling. This option should only be used by advanced users.
|
158
|
+
*/
|
159
|
+
devtoolsThrottling: 'DevTools throttling (advanced)',
|
160
|
+
/**
|
161
|
+
* @description Tooltip text that appears when hovering over the 'Simulated Throttling' checkbox in the settings pane opened by clicking the setting cog in the start view of the audits panel
|
162
|
+
*/
|
155
163
|
simulateASlowerPageLoadBasedOn:
|
156
|
-
'
|
164
|
+
'Simulated throttling simulates a slower page load based on data from an initial unthrottled load. DevTools throttling actually slows down the page.',
|
157
165
|
/**
|
158
166
|
*@description Text of checkbox to reset storage features prior to running audits in Lighthouse
|
159
167
|
*/
|
@@ -515,17 +523,24 @@ export const RuntimeSettings: RuntimeSetting[] = [
|
|
515
523
|
{
|
516
524
|
// This setting is disabled, but we keep it around to show in the UI.
|
517
525
|
setting: Common.Settings.Settings.instance().createSetting(
|
518
|
-
'lighthouse.throttling',
|
519
|
-
title: i18nLazyString(UIStrings.
|
526
|
+
'lighthouse.throttling', 'simulate', Common.Settings.SettingStorageType.Synced),
|
527
|
+
title: i18nLazyString(UIStrings.throttlingMethod),
|
520
528
|
// We will disable this when we have a Lantern trace viewer within DevTools.
|
521
529
|
learnMore:
|
522
530
|
'https://github.com/GoogleChrome/lighthouse/blob/master/docs/throttling.md#devtools-lighthouse-panel-throttling' as
|
523
531
|
Platform.DevToolsPath.UrlString,
|
524
532
|
description: i18nLazyString(UIStrings.simulateASlowerPageLoadBasedOn),
|
525
533
|
setFlags: (flags: Flags, value: string|boolean): void => {
|
526
|
-
|
534
|
+
if (typeof value === 'string') {
|
535
|
+
flags.throttlingMethod = value;
|
536
|
+
} else {
|
537
|
+
flags.throttlingMethod = value ? 'simulate' : 'devtools';
|
538
|
+
}
|
527
539
|
},
|
528
|
-
options:
|
540
|
+
options: [
|
541
|
+
{label: i18nLazyString(UIStrings.simulatedThrottling), value: 'simulate'},
|
542
|
+
{label: i18nLazyString(UIStrings.devtoolsThrottling), value: 'devtools'},
|
543
|
+
],
|
529
544
|
},
|
530
545
|
{
|
531
546
|
setting: Common.Settings.Settings.instance().createSetting(
|
@@ -103,6 +103,30 @@ export class StartView extends UI.Widget.Widget {
|
|
103
103
|
}
|
104
104
|
}
|
105
105
|
|
106
|
+
protected populateRuntimeSettingAsToolbarDropdown(settingName: string, toolbar: UI.Toolbar.Toolbar): void {
|
107
|
+
const runtimeSetting = RuntimeSettings.find(item => item.setting.name === settingName);
|
108
|
+
if (!runtimeSetting || !runtimeSetting.title) {
|
109
|
+
throw new Error(`${settingName} is not a setting with a title`);
|
110
|
+
}
|
111
|
+
|
112
|
+
const options = runtimeSetting.options?.map(option => ({label: option.label(), value: option.value})) || [];
|
113
|
+
|
114
|
+
runtimeSetting.setting.setTitle(runtimeSetting.title());
|
115
|
+
const control = new UI.Toolbar.ToolbarSettingComboBox(
|
116
|
+
options,
|
117
|
+
runtimeSetting.setting as Common.Settings.Setting<string>,
|
118
|
+
runtimeSetting.title(),
|
119
|
+
);
|
120
|
+
control.setTitle(runtimeSetting.description());
|
121
|
+
toolbar.appendToolbarItem(control);
|
122
|
+
if (runtimeSetting.learnMore) {
|
123
|
+
const link =
|
124
|
+
UI.XLink.XLink.create(runtimeSetting.learnMore, i18nString(UIStrings.learnMore), 'lighthouse-learn-more');
|
125
|
+
link.style.padding = '5px';
|
126
|
+
control.element.appendChild(link);
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
106
130
|
protected populateFormControls(fragment: UI.Fragment.Fragment, mode?: string): void {
|
107
131
|
// Populate the device type
|
108
132
|
const deviceTypeFormElements = fragment.$('device-type-form-elements');
|
@@ -134,7 +158,7 @@ export class StartView extends UI.Widget.Widget {
|
|
134
158
|
protected render(): void {
|
135
159
|
this.populateRuntimeSettingAsToolbarCheckbox('lighthouse.legacy_navigation', this.settingsToolbarInternal);
|
136
160
|
this.populateRuntimeSettingAsToolbarCheckbox('lighthouse.clear_storage', this.settingsToolbarInternal);
|
137
|
-
this.
|
161
|
+
this.populateRuntimeSettingAsToolbarDropdown('lighthouse.throttling', this.settingsToolbarInternal);
|
138
162
|
|
139
163
|
this.startButton = UI.UIUtils.createTextButton(
|
140
164
|
i18nString(UIStrings.generateReport),
|
@@ -49,7 +49,7 @@ export class StartViewFR extends StartView {
|
|
49
49
|
protected render(): void {
|
50
50
|
this.populateRuntimeSettingAsToolbarCheckbox('lighthouse.legacy_navigation', this.settingsToolbarInternal);
|
51
51
|
this.populateRuntimeSettingAsToolbarCheckbox('lighthouse.clear_storage', this.settingsToolbarInternal);
|
52
|
-
this.
|
52
|
+
this.populateRuntimeSettingAsToolbarDropdown('lighthouse.throttling', this.settingsToolbarInternal);
|
53
53
|
|
54
54
|
const {mode} = this.controller.getFlags();
|
55
55
|
this.populateStartButton(mode);
|
@@ -52,6 +52,10 @@ details summary input {
|
|
52
52
|
user-select: text;
|
53
53
|
}
|
54
54
|
|
55
|
+
div.raw-headers-row {
|
56
|
+
display: block;
|
57
|
+
}
|
58
|
+
|
55
59
|
.row:first-of-type {
|
56
60
|
margin-top: 2px;
|
57
61
|
}
|
@@ -103,4 +107,5 @@ details summary input {
|
|
103
107
|
font-family: var(--source-code-font-family);
|
104
108
|
font-size: var(--source-code-font-size);
|
105
109
|
white-space: pre-wrap;
|
110
|
+
word-break: break-all;
|
106
111
|
}
|
@@ -6,12 +6,14 @@ import * as Common from '../../../core/common/common.js';
|
|
6
6
|
import * as i18n from '../../../core/i18n/i18n.js';
|
7
7
|
import {assertNotNullOrUndefined} from '../../../core/platform/platform.js';
|
8
8
|
import * as SDK from '../../../core/sdk/sdk.js';
|
9
|
+
import * as Buttons from '../../../ui/components/buttons/buttons.js';
|
9
10
|
import * as ComponentHelpers from '../../../ui/components/helpers/helpers.js';
|
10
11
|
import * as UI from '../../../ui/legacy/legacy.js';
|
11
12
|
import * as LitHtml from '../../../ui/lit-html/lit-html.js';
|
12
13
|
|
13
14
|
import requestHeadersViewStyles from './RequestHeadersView.css.js';
|
14
15
|
|
16
|
+
const RAW_HEADER_CUTOFF = 3000;
|
15
17
|
const {render, html} = LitHtml;
|
16
18
|
|
17
19
|
const UIStrings = {
|
@@ -64,6 +66,10 @@ const UIStrings = {
|
|
64
66
|
*/
|
65
67
|
responseHeaders: 'Response Headers',
|
66
68
|
/**
|
69
|
+
*@description Text to show more content
|
70
|
+
*/
|
71
|
+
showMore: 'Show more',
|
72
|
+
/**
|
67
73
|
*@description HTTP response code
|
68
74
|
*/
|
69
75
|
statusCode: 'Status Code',
|
@@ -117,6 +123,8 @@ export class RequestHeadersComponent extends HTMLElement {
|
|
117
123
|
#request?: Readonly<SDK.NetworkRequest.NetworkRequest>;
|
118
124
|
#showResponseHeadersText = false;
|
119
125
|
#showRequestHeadersText = false;
|
126
|
+
#showResponseHeadersTextFull = false;
|
127
|
+
#showRequestHeadersTextFull = false;
|
120
128
|
|
121
129
|
set data(data: RequestHeadersComponentData) {
|
122
130
|
this.#request = data.request;
|
@@ -161,9 +169,8 @@ export class RequestHeadersComponent extends HTMLElement {
|
|
161
169
|
} as CategoryData}
|
162
170
|
aria-label=${i18nString(UIStrings.responseHeaders)}
|
163
171
|
>
|
164
|
-
${this.#showResponseHeadersText ?
|
165
|
-
|
166
|
-
` : html`
|
172
|
+
${this.#showResponseHeadersText ?
|
173
|
+
this.#renderRawHeaders(this.#request.responseHeadersText, true) : html`
|
167
174
|
${this.#request.sortedResponseHeaders.map(header => html`
|
168
175
|
<div class="row">
|
169
176
|
<div class="header-name">${header.name}:</div>
|
@@ -198,9 +205,8 @@ export class RequestHeadersComponent extends HTMLElement {
|
|
198
205
|
} as CategoryData}
|
199
206
|
aria-label=${i18nString(UIStrings.requestHeaders)}
|
200
207
|
>
|
201
|
-
${(this.#showRequestHeadersText && requestHeadersText) ?
|
202
|
-
|
203
|
-
` : html`
|
208
|
+
${(this.#showRequestHeadersText && requestHeadersText) ?
|
209
|
+
this.#renderRawHeaders(requestHeadersText, false) : html`
|
204
210
|
${this.#request.requestHeaders().map(header => html`
|
205
211
|
<div class="row">
|
206
212
|
<div class="header-name">${header.name}:</div>
|
@@ -212,6 +218,50 @@ export class RequestHeadersComponent extends HTMLElement {
|
|
212
218
|
`;
|
213
219
|
}
|
214
220
|
|
221
|
+
#renderRawHeaders(rawHeadersText: string, forResponseHeaders: boolean): LitHtml.TemplateResult {
|
222
|
+
const trimmed = rawHeadersText.trim();
|
223
|
+
const showFull = forResponseHeaders ? this.#showResponseHeadersTextFull : this.#showRequestHeadersTextFull;
|
224
|
+
const isShortened = !showFull && trimmed.length > RAW_HEADER_CUTOFF;
|
225
|
+
|
226
|
+
const showMore = ():void => {
|
227
|
+
if (forResponseHeaders) {
|
228
|
+
this.#showResponseHeadersTextFull = true;
|
229
|
+
} else {
|
230
|
+
this.#showRequestHeadersTextFull = true;
|
231
|
+
}
|
232
|
+
this.#render();
|
233
|
+
};
|
234
|
+
|
235
|
+
const onContextMenuOpen = (event: Event): void => {
|
236
|
+
const showFull = forResponseHeaders ? this.#showResponseHeadersTextFull : this.#showRequestHeadersTextFull;
|
237
|
+
if (!showFull) {
|
238
|
+
const contextMenu = new UI.ContextMenu.ContextMenu(event);
|
239
|
+
const section = contextMenu.newSection();
|
240
|
+
section.appendItem(i18nString(UIStrings.showMore), showMore);
|
241
|
+
void contextMenu.show();
|
242
|
+
}
|
243
|
+
};
|
244
|
+
|
245
|
+
const addContextMenuListener = (el: Element):void => {
|
246
|
+
if (isShortened) {
|
247
|
+
el.addEventListener('contextmenu', onContextMenuOpen);
|
248
|
+
}
|
249
|
+
};
|
250
|
+
|
251
|
+
return html`
|
252
|
+
<div class="row raw-headers-row" on-render=${ComponentHelpers.Directives.nodeRenderedCallback(addContextMenuListener)}>
|
253
|
+
<div class="raw-headers">${isShortened ? trimmed.substring(0, RAW_HEADER_CUTOFF) : trimmed}</div>
|
254
|
+
${isShortened ? html`
|
255
|
+
<${Buttons.Button.Button.litTagName}
|
256
|
+
.size=${Buttons.Button.Size.SMALL}
|
257
|
+
.variant=${Buttons.Button.Variant.SECONDARY}
|
258
|
+
@click=${showMore}
|
259
|
+
>${i18nString(UIStrings.showMore)}</${Buttons.Button.Button.litTagName}>
|
260
|
+
` : LitHtml.nothing}
|
261
|
+
</div>
|
262
|
+
`;
|
263
|
+
}
|
264
|
+
|
215
265
|
#renderGeneralSection(): LitHtml.TemplateResult {
|
216
266
|
assertNotNullOrUndefined(this.#request);
|
217
267
|
|
@@ -31,6 +31,7 @@ export interface TreeOutlineData<TreeNodeDataType> {
|
|
31
31
|
*/
|
32
32
|
tree: readonly TreeNode<TreeNodeDataType>[];
|
33
33
|
filter?: (node: TreeNodeDataType) => FilterOption;
|
34
|
+
compact?: boolean;
|
34
35
|
}
|
35
36
|
|
36
37
|
export function defaultRenderer(node: TreeNode<string>): LitHtml.TemplateResult {
|
@@ -111,6 +112,7 @@ export class TreeOutline<TreeNodeDataType> extends HTMLElement {
|
|
111
112
|
return LitHtml.html`${String(node.treeNodeData)}`;
|
112
113
|
};
|
113
114
|
#nodeFilter?: ((node: TreeNodeDataType) => FilterOption);
|
115
|
+
#compact = false;
|
114
116
|
|
115
117
|
/**
|
116
118
|
* scheduledRender = render() has been called and scheduled a render.
|
@@ -155,6 +157,7 @@ export class TreeOutline<TreeNodeDataType> extends HTMLElement {
|
|
155
157
|
this.#defaultRenderer = data.defaultRenderer;
|
156
158
|
this.#treeData = data.tree;
|
157
159
|
this.#nodeFilter = data.filter;
|
160
|
+
this.#compact = data.compact || false;
|
158
161
|
|
159
162
|
if (!this.#hasRenderedAtLeastOnce) {
|
160
163
|
this.#selectedTreeNode = this.#treeData[0];
|
@@ -454,6 +457,7 @@ export class TreeOutline<TreeNodeDataType> extends HTMLElement {
|
|
454
457
|
parent: isExpandableNode(node),
|
455
458
|
selected: this.#isSelectedNode(node),
|
456
459
|
'is-top-level': depth === 0,
|
460
|
+
compact: this.#compact,
|
457
461
|
});
|
458
462
|
const ariaExpandedAttribute =
|
459
463
|
LitHtml.Directives.ifDefined(isExpandableNode(node) ? String(nodeIsExpanded) : undefined);
|