chrome-devtools-frontend 1.0.976570 → 1.0.977952
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 +4 -1
- package/front_end/core/host/UserMetrics.ts +46 -24
- package/front_end/core/i18n/locales/af.json +5 -5
- package/front_end/core/i18n/locales/am.json +5 -5
- package/front_end/core/i18n/locales/ar.json +5 -5
- package/front_end/core/i18n/locales/as.json +5 -5
- package/front_end/core/i18n/locales/az.json +5 -5
- package/front_end/core/i18n/locales/be.json +5 -5
- package/front_end/core/i18n/locales/bg.json +5 -5
- package/front_end/core/i18n/locales/bn.json +5 -5
- package/front_end/core/i18n/locales/bs.json +5 -5
- package/front_end/core/i18n/locales/ca.json +5 -5
- package/front_end/core/i18n/locales/cs.json +5 -5
- package/front_end/core/i18n/locales/cy.json +5 -5
- package/front_end/core/i18n/locales/da.json +5 -5
- package/front_end/core/i18n/locales/de.json +5 -5
- package/front_end/core/i18n/locales/el.json +5 -5
- package/front_end/core/i18n/locales/en-GB.json +5 -5
- package/front_end/core/i18n/locales/en-US.json +24 -15
- package/front_end/core/i18n/locales/en-XL.json +24 -15
- package/front_end/core/i18n/locales/es-419.json +5 -5
- package/front_end/core/i18n/locales/es.json +5 -5
- package/front_end/core/i18n/locales/et.json +5 -5
- package/front_end/core/i18n/locales/eu.json +5 -5
- package/front_end/core/i18n/locales/fa.json +5 -5
- package/front_end/core/i18n/locales/fi.json +5 -5
- package/front_end/core/i18n/locales/fil.json +5 -5
- package/front_end/core/i18n/locales/fr-CA.json +5 -5
- package/front_end/core/i18n/locales/fr.json +5 -5
- package/front_end/core/i18n/locales/gl.json +5 -5
- package/front_end/core/i18n/locales/gu.json +5 -5
- package/front_end/core/i18n/locales/he.json +5 -5
- package/front_end/core/i18n/locales/hi.json +5 -5
- package/front_end/core/i18n/locales/hr.json +5 -5
- package/front_end/core/i18n/locales/hu.json +5 -5
- package/front_end/core/i18n/locales/hy.json +5 -5
- package/front_end/core/i18n/locales/id.json +5 -5
- package/front_end/core/i18n/locales/is.json +5 -5
- package/front_end/core/i18n/locales/it.json +5 -5
- package/front_end/core/i18n/locales/ja.json +5 -5
- package/front_end/core/i18n/locales/ka.json +5 -5
- package/front_end/core/i18n/locales/kk.json +5 -5
- package/front_end/core/i18n/locales/km.json +5 -5
- package/front_end/core/i18n/locales/kn.json +5 -5
- package/front_end/core/i18n/locales/ko.json +5 -5
- package/front_end/core/i18n/locales/ky.json +5 -5
- package/front_end/core/i18n/locales/lo.json +5 -5
- package/front_end/core/i18n/locales/lt.json +5 -5
- package/front_end/core/i18n/locales/lv.json +5 -5
- package/front_end/core/i18n/locales/mk.json +5 -5
- package/front_end/core/i18n/locales/ml.json +5 -5
- package/front_end/core/i18n/locales/mn.json +5 -5
- package/front_end/core/i18n/locales/mr.json +5 -5
- package/front_end/core/i18n/locales/ms.json +5 -5
- package/front_end/core/i18n/locales/my.json +5 -5
- package/front_end/core/i18n/locales/ne.json +5 -5
- package/front_end/core/i18n/locales/nl.json +5 -5
- package/front_end/core/i18n/locales/no.json +5 -5
- package/front_end/core/i18n/locales/or.json +5 -5
- package/front_end/core/i18n/locales/pa.json +5 -5
- package/front_end/core/i18n/locales/pl.json +5 -5
- package/front_end/core/i18n/locales/pt-PT.json +5 -5
- package/front_end/core/i18n/locales/pt.json +5 -5
- package/front_end/core/i18n/locales/ro.json +5 -5
- package/front_end/core/i18n/locales/ru.json +5 -5
- package/front_end/core/i18n/locales/si.json +5 -5
- package/front_end/core/i18n/locales/sk.json +5 -5
- package/front_end/core/i18n/locales/sl.json +5 -5
- package/front_end/core/i18n/locales/sq.json +5 -5
- package/front_end/core/i18n/locales/sr-Latn.json +5 -5
- package/front_end/core/i18n/locales/sr.json +5 -5
- package/front_end/core/i18n/locales/sv.json +5 -5
- package/front_end/core/i18n/locales/sw.json +5 -5
- package/front_end/core/i18n/locales/ta.json +5 -5
- package/front_end/core/i18n/locales/te.json +5 -5
- package/front_end/core/i18n/locales/th.json +5 -5
- package/front_end/core/i18n/locales/tr.json +5 -5
- package/front_end/core/i18n/locales/uk.json +5 -5
- package/front_end/core/i18n/locales/ur.json +5 -5
- package/front_end/core/i18n/locales/uz.json +5 -5
- package/front_end/core/i18n/locales/vi.json +5 -5
- package/front_end/core/i18n/locales/zh-HK.json +5 -5
- package/front_end/core/i18n/locales/zh-TW.json +5 -5
- package/front_end/core/i18n/locales/zh.json +5 -5
- package/front_end/core/i18n/locales/zu.json +5 -5
- package/front_end/core/sdk/CSSContainerQuery.ts +1 -1
- package/front_end/core/sdk/CSSModel.ts +9 -9
- package/front_end/generated/InspectorBackendCommands.js +6 -5
- package/front_end/generated/protocol.ts +10 -9
- package/front_end/models/issues_manager/{SameSiteCookieIssue.ts → CookieIssue.ts} +75 -79
- package/front_end/models/issues_manager/Issue.ts +1 -1
- package/front_end/models/issues_manager/IssuesManager.ts +3 -9
- package/front_end/models/issues_manager/NavigatorUserAgentIssue.ts +1 -1
- package/front_end/models/issues_manager/issues_manager.ts +2 -2
- package/front_end/models/persistence/NetworkPersistenceManager.ts +4 -4
- package/front_end/panels/application/ApplicationPanelCacheSection.ts +3 -0
- package/front_end/panels/application/ApplicationPanelSidebar.ts +15 -0
- package/front_end/panels/application/InterestGroupTreeElement.ts +2 -0
- package/front_end/panels/application/ReportingApiTreeElement.ts +2 -0
- package/front_end/panels/application/TrustTokensTreeElement.ts +2 -0
- package/front_end/panels/application/components/BackForwardCacheView.ts +23 -1
- package/front_end/panels/elements/ClassesPaneWidget.ts +1 -1
- package/front_end/panels/elements/ComputedStyleModel.ts +1 -1
- package/front_end/panels/elements/ElementsTreeElement.ts +1 -1
- package/front_end/panels/elements/LayersWidget.ts +1 -1
- package/front_end/panels/elements/MetricsSidebarPane.ts +2 -2
- package/front_end/panels/elements/PlatformFontsWidget.ts +1 -1
- package/front_end/panels/elements/StylePropertyTreeElement.ts +1 -1
- package/front_end/panels/elements/StylesSidebarPane.ts +2 -3
- package/front_end/panels/emulation/MediaQueryInspector.ts +1 -1
- package/front_end/panels/issues/IssueView.ts +1 -1
- package/front_end/panels/issues/IssuesPane.ts +1 -1
- package/front_end/panels/network/NetworkLogView.ts +1 -1
- package/front_end/panels/sources/CSSPlugin.ts +1 -1
- package/front_end/panels/sources/SourcesView.ts +23 -10
- package/front_end/panels/sources/components/HeadersView.css +84 -0
- package/front_end/panels/sources/components/HeadersView.ts +300 -0
- package/front_end/panels/sources/components/components.ts +9 -0
- package/front_end/panels/timeline/TimelineController.ts +17 -5
- package/front_end/ui/components/expandable_list/expandableList.css +10 -0
- package/front_end/ui/components/text_editor/javascript.ts +46 -1
- package/package.json +1 -1
@@ -0,0 +1,300 @@
|
|
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 * as i18n from '../../../core/i18n/i18n.js';
|
6
|
+
import * as Persistence from '../../../models/persistence/persistence.js';
|
7
|
+
import * as Workspace from '../../../models/workspace/workspace.js';
|
8
|
+
import * as ComponentHelpers from '../../../ui/components/helpers/helpers.js';
|
9
|
+
import * as UI from '../../../ui/legacy/legacy.js';
|
10
|
+
import * as LitHtml from '../../../ui/lit-html/lit-html.js';
|
11
|
+
|
12
|
+
import HeadersViewStyles from './HeadersView.css.js';
|
13
|
+
|
14
|
+
const UIStrings = {
|
15
|
+
/**
|
16
|
+
*@description Error message for files which cannot not be parsed.
|
17
|
+
*@example {.headers} PH1
|
18
|
+
*/
|
19
|
+
errorWhenParsing: 'Error when parsing \'\'{PH1}\'\'.',
|
20
|
+
/**
|
21
|
+
*@description Explainer for files which cannot be parsed.
|
22
|
+
*@example {.headers} PH1
|
23
|
+
*/
|
24
|
+
parsingErrorExplainer:
|
25
|
+
'This is most likely due to a syntax error in \'\'{PH1}\'\'. Try opening this file in an external editor to fix the error or delete the file and re-create the override.',
|
26
|
+
};
|
27
|
+
const str_ = i18n.i18n.registerUIStrings('panels/sources/components/HeadersView.ts', UIStrings);
|
28
|
+
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
29
|
+
|
30
|
+
export class HeadersView extends UI.View.SimpleView {
|
31
|
+
readonly #headersViewComponent = new HeadersViewComponent();
|
32
|
+
#uiSourceCode: Workspace.UISourceCode.UISourceCode;
|
33
|
+
|
34
|
+
constructor(uiSourceCode: Workspace.UISourceCode.UISourceCode) {
|
35
|
+
super('HeadersView');
|
36
|
+
this.#uiSourceCode = uiSourceCode;
|
37
|
+
this.#uiSourceCode.addEventListener(
|
38
|
+
Workspace.UISourceCode.Events.WorkingCopyChanged, this.#onWorkingCopyChanged, this);
|
39
|
+
this.#uiSourceCode.addEventListener(
|
40
|
+
Workspace.UISourceCode.Events.WorkingCopyCommitted, this.#onWorkingCopyCommitted, this);
|
41
|
+
this.element.appendChild(this.#headersViewComponent);
|
42
|
+
void this.#setInitialData();
|
43
|
+
}
|
44
|
+
|
45
|
+
async #setInitialData(): Promise<void> {
|
46
|
+
const content = await this.#uiSourceCode.requestContent();
|
47
|
+
this.#setComponentData(content.content || '');
|
48
|
+
}
|
49
|
+
|
50
|
+
#setComponentData(content: string): void {
|
51
|
+
let parsingError = false;
|
52
|
+
let headerOverrides: Persistence.NetworkPersistenceManager.HeaderOverride[] = [];
|
53
|
+
content = content || '[]';
|
54
|
+
try {
|
55
|
+
headerOverrides = JSON.parse(content) as Persistence.NetworkPersistenceManager.HeaderOverride[];
|
56
|
+
if (!headerOverrides.every(Persistence.NetworkPersistenceManager.isHeaderOverride)) {
|
57
|
+
throw 'Type mismatch after parsing';
|
58
|
+
}
|
59
|
+
} catch (e) {
|
60
|
+
console.error('Failed to parse', this.#uiSourceCode.url(), 'for locally overriding headers.');
|
61
|
+
parsingError = true;
|
62
|
+
}
|
63
|
+
|
64
|
+
// Header overrides are stored as the key-value pairs of a JSON object on
|
65
|
+
// disk. For the editor we want them as an array instead, so that we can
|
66
|
+
// access/add/remove entries by their index.
|
67
|
+
const arrayOfHeaderOverrideArrays: HeaderOverride[] = headerOverrides.map(headerOverride => {
|
68
|
+
return {
|
69
|
+
applyTo: headerOverride.applyTo,
|
70
|
+
headers: Object.entries(headerOverride.headers).map(([headerName, headerValue]) => {
|
71
|
+
return {
|
72
|
+
name: headerName,
|
73
|
+
value: headerValue,
|
74
|
+
};
|
75
|
+
}),
|
76
|
+
};
|
77
|
+
});
|
78
|
+
|
79
|
+
this.#headersViewComponent.data = {
|
80
|
+
headerOverrides: arrayOfHeaderOverrideArrays,
|
81
|
+
uiSourceCode: this.#uiSourceCode,
|
82
|
+
parsingError,
|
83
|
+
};
|
84
|
+
}
|
85
|
+
|
86
|
+
commitEditing(): void {
|
87
|
+
this.#uiSourceCode.commitWorkingCopy();
|
88
|
+
Persistence.NetworkPersistenceManager.NetworkPersistenceManager.instance().updateInterceptionPatterns();
|
89
|
+
}
|
90
|
+
|
91
|
+
#onWorkingCopyChanged(): void {
|
92
|
+
this.#setComponentData(this.#uiSourceCode.workingCopy());
|
93
|
+
}
|
94
|
+
|
95
|
+
#onWorkingCopyCommitted(): void {
|
96
|
+
this.#setComponentData(this.#uiSourceCode.workingCopy());
|
97
|
+
}
|
98
|
+
|
99
|
+
dispose(): void {
|
100
|
+
this.#uiSourceCode.removeEventListener(
|
101
|
+
Workspace.UISourceCode.Events.WorkingCopyChanged, this.#onWorkingCopyChanged, this);
|
102
|
+
this.#uiSourceCode.removeEventListener(
|
103
|
+
Workspace.UISourceCode.Events.WorkingCopyCommitted, this.#onWorkingCopyCommitted, this);
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
type Header = {
|
108
|
+
name: string,
|
109
|
+
value: string,
|
110
|
+
};
|
111
|
+
|
112
|
+
type HeaderOverride = {
|
113
|
+
applyTo: string,
|
114
|
+
headers: Header[],
|
115
|
+
};
|
116
|
+
|
117
|
+
export interface HeadersViewComponentData {
|
118
|
+
headerOverrides: HeaderOverride[];
|
119
|
+
uiSourceCode: Workspace.UISourceCode.UISourceCode;
|
120
|
+
parsingError: boolean;
|
121
|
+
}
|
122
|
+
|
123
|
+
export class HeadersViewComponent extends HTMLElement {
|
124
|
+
static readonly litTagName = LitHtml.literal`devtools-sources-headers-view`;
|
125
|
+
readonly #shadow = this.attachShadow({mode: 'open'});
|
126
|
+
readonly #boundRender = this.#render.bind(this);
|
127
|
+
#headerOverrides: HeaderOverride[] = [];
|
128
|
+
#uiSourceCode: Workspace.UISourceCode.UISourceCode|null = null;
|
129
|
+
#parsingError = false;
|
130
|
+
|
131
|
+
constructor() {
|
132
|
+
super();
|
133
|
+
this.#shadow.addEventListener('focusin', this.#onFocusIn.bind(this));
|
134
|
+
this.#shadow.addEventListener('focusout', this.#onFocusOut.bind(this));
|
135
|
+
this.#shadow.addEventListener('input', this.#onInput.bind(this));
|
136
|
+
this.#shadow.addEventListener('keydown', this.#onKeyDown.bind(this));
|
137
|
+
}
|
138
|
+
|
139
|
+
connectedCallback(): void {
|
140
|
+
this.#shadow.adoptedStyleSheets = [HeadersViewStyles];
|
141
|
+
}
|
142
|
+
|
143
|
+
set data(data: HeadersViewComponentData) {
|
144
|
+
this.#headerOverrides = data.headerOverrides;
|
145
|
+
this.#uiSourceCode = data.uiSourceCode;
|
146
|
+
this.#parsingError = data.parsingError;
|
147
|
+
void ComponentHelpers.ScheduledRender.scheduleRender(this, this.#boundRender);
|
148
|
+
}
|
149
|
+
|
150
|
+
// 'Enter' key should not create a new line in the contenteditable. Focus
|
151
|
+
// on the next contenteditable instead.
|
152
|
+
#onKeyDown(event: Event): void {
|
153
|
+
const keyboardEvent = event as KeyboardEvent;
|
154
|
+
const target = event.target as HTMLElement;
|
155
|
+
if (target.matches('.editable') && keyboardEvent.key === 'Enter') {
|
156
|
+
event.preventDefault();
|
157
|
+
this.#focusNext(target);
|
158
|
+
}
|
159
|
+
}
|
160
|
+
|
161
|
+
#focusNext(target: HTMLElement): void {
|
162
|
+
const elements = Array.from(this.#shadow.querySelectorAll('.editable')) as HTMLElement[];
|
163
|
+
const idx = elements.indexOf(target);
|
164
|
+
if (idx !== -1 && idx + 1 < elements.length) {
|
165
|
+
elements[idx + 1].focus();
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
#selectAllText(target: HTMLElement): void {
|
170
|
+
const selection = window.getSelection();
|
171
|
+
const range = document.createRange();
|
172
|
+
range.selectNodeContents(target);
|
173
|
+
selection?.removeAllRanges();
|
174
|
+
selection?.addRange(range);
|
175
|
+
}
|
176
|
+
|
177
|
+
#onFocusIn(e: Event): void {
|
178
|
+
const target = e.target as HTMLElement;
|
179
|
+
if (target.matches('.editable')) {
|
180
|
+
this.#selectAllText(target);
|
181
|
+
}
|
182
|
+
}
|
183
|
+
|
184
|
+
#onFocusOut(): void {
|
185
|
+
// clear selection
|
186
|
+
const selection = window.getSelection();
|
187
|
+
selection?.removeAllRanges();
|
188
|
+
}
|
189
|
+
|
190
|
+
#onInput(e: Event): void {
|
191
|
+
const target = e.target as HTMLButtonElement;
|
192
|
+
const rowElement = target.closest('.row') as HTMLElement;
|
193
|
+
const blockIndex = Number(rowElement.dataset.blockIndex);
|
194
|
+
const headerIndex = Number(rowElement.dataset.headerIndex);
|
195
|
+
if (target.matches('.header-name')) {
|
196
|
+
this.#headerOverrides[blockIndex].headers[headerIndex].name = target.innerText;
|
197
|
+
this.#onHeadersChanged();
|
198
|
+
}
|
199
|
+
if (target.matches('.header-value')) {
|
200
|
+
this.#headerOverrides[blockIndex].headers[headerIndex].value = target.innerText;
|
201
|
+
this.#onHeadersChanged();
|
202
|
+
}
|
203
|
+
if (target.matches('.apply-to')) {
|
204
|
+
this.#headerOverrides[blockIndex].applyTo = target.innerText;
|
205
|
+
this.#onHeadersChanged();
|
206
|
+
}
|
207
|
+
}
|
208
|
+
|
209
|
+
#onHeadersChanged(): void {
|
210
|
+
// In the editor header overrides are represented by items in an array, so
|
211
|
+
// that we can access/add/remove entries by their index. On disk, they are
|
212
|
+
// stored as key-value pairs of a JSON object instead.
|
213
|
+
const arrayOfHeaderOverrideObjects: Persistence.NetworkPersistenceManager.HeaderOverride[] =
|
214
|
+
this.#headerOverrides.map(headerOverride => {
|
215
|
+
return {
|
216
|
+
applyTo: headerOverride.applyTo,
|
217
|
+
headers: headerOverride.headers.reduce((a, v) => ({...a, [v.name]: v.value}), {}),
|
218
|
+
};
|
219
|
+
});
|
220
|
+
this.#uiSourceCode?.setWorkingCopy(JSON.stringify(arrayOfHeaderOverrideObjects, null, 2));
|
221
|
+
}
|
222
|
+
|
223
|
+
#render(): void {
|
224
|
+
if (!ComponentHelpers.ScheduledRender.isScheduledRender(this)) {
|
225
|
+
throw new Error('HeadersView render was not scheduled');
|
226
|
+
}
|
227
|
+
|
228
|
+
if (this.#parsingError) {
|
229
|
+
const fileName = this.#uiSourceCode?.name() || '.headers';
|
230
|
+
// clang-format off
|
231
|
+
LitHtml.render(LitHtml.html`
|
232
|
+
<div class="center-wrapper">
|
233
|
+
<div class="centered">
|
234
|
+
<div class="error-header">${i18nString(UIStrings.errorWhenParsing, {PH1: fileName})}</div>
|
235
|
+
<div class="error-body">${i18nString(UIStrings.parsingErrorExplainer, {PH1: fileName})}</div>
|
236
|
+
</div>
|
237
|
+
</div>
|
238
|
+
`, this.#shadow, {host: this});
|
239
|
+
// clang-format on
|
240
|
+
return;
|
241
|
+
}
|
242
|
+
|
243
|
+
// clang-format off
|
244
|
+
LitHtml.render(LitHtml.html`
|
245
|
+
${this.#headerOverrides.map((headerOverride, blockIndex) =>
|
246
|
+
LitHtml.html`
|
247
|
+
${this.#renderApplyToRow(headerOverride.applyTo, blockIndex)}
|
248
|
+
${headerOverride.headers.map((header, headerIndex) =>
|
249
|
+
LitHtml.html`
|
250
|
+
${this.#renderHeaderRow(header, blockIndex, headerIndex)}
|
251
|
+
`,
|
252
|
+
)}
|
253
|
+
`,
|
254
|
+
)}
|
255
|
+
`, this.#shadow, {host: this});
|
256
|
+
// clang-format on
|
257
|
+
}
|
258
|
+
|
259
|
+
#renderApplyToRow(pattern: string, blockIndex: number): LitHtml.TemplateResult {
|
260
|
+
// clang-format off
|
261
|
+
return LitHtml.html`
|
262
|
+
<div class="row" data-block-index=${blockIndex}>
|
263
|
+
<div>${i18n.i18n.lockedString('Apply to')}</div>
|
264
|
+
<div class="separator">:</div>
|
265
|
+
${this.#renderEditable(pattern, 'apply-to')}
|
266
|
+
</div>
|
267
|
+
`;
|
268
|
+
// clang-format on
|
269
|
+
}
|
270
|
+
|
271
|
+
#renderHeaderRow(header: Header, blockIndex: number, headerIndex: number): LitHtml.TemplateResult {
|
272
|
+
// clang-format off
|
273
|
+
return LitHtml.html`
|
274
|
+
<div class="row padded" data-block-index=${blockIndex} data-header-index=${headerIndex}>
|
275
|
+
${this.#renderEditable(header.name, 'header-name red')}
|
276
|
+
<div class="separator">:</div>
|
277
|
+
${this.#renderEditable(header.value, 'header-value')}
|
278
|
+
`;
|
279
|
+
// clang-format on
|
280
|
+
}
|
281
|
+
|
282
|
+
#renderEditable(value: string, className?: string): LitHtml.TemplateResult {
|
283
|
+
// This uses LitHtml's `live`-directive, so that when checking whether to
|
284
|
+
// update during re-render, `value` is compared against the actual live DOM
|
285
|
+
// value of the contenteditable element and not the potentially outdated
|
286
|
+
// value from the previous render.
|
287
|
+
// clang-format off
|
288
|
+
return LitHtml.html`<span contenteditable="true" class="editable ${className}" tabindex="0" .innerText=${LitHtml.Directives.live(value)}></span>`;
|
289
|
+
// clang-format on
|
290
|
+
}
|
291
|
+
}
|
292
|
+
|
293
|
+
ComponentHelpers.CustomElements.defineComponent('devtools-sources-headers-view', HeadersViewComponent);
|
294
|
+
|
295
|
+
declare global {
|
296
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
297
|
+
interface HTMLElementTagNameMap {
|
298
|
+
'devtools-sources-headers-view': HeadersViewComponent;
|
299
|
+
}
|
300
|
+
}
|
@@ -80,18 +80,31 @@ export class TimelineController implements SDK.TargetManager.SDKModelObserver<SD
|
|
80
80
|
function disabledByDefault(category: string): string {
|
81
81
|
return 'disabled-by-default-' + category;
|
82
82
|
}
|
83
|
+
|
84
|
+
// The following categories are also used in other tools, but this panel
|
85
|
+
// offers the possibility of turning them off (see below).
|
86
|
+
// 'disabled-by-default-devtools.screenshot'
|
87
|
+
// └ default: on, option: captureFilmStrip
|
88
|
+
// 'disabled-by-default-devtools.timeline.invalidationTracking'
|
89
|
+
// └ default: off, experiment: timelineInvalidationTracking
|
90
|
+
// 'disabled-by-default-v8.cpu_profiler'
|
91
|
+
// └ default: on, option: enableJSSampling
|
83
92
|
const categoriesArray = [
|
84
93
|
'-*',
|
94
|
+
TimelineModel.TimelineModel.TimelineModelImpl.Category.Console,
|
95
|
+
TimelineModel.TimelineModel.TimelineModelImpl.Category.UserTiming,
|
85
96
|
'devtools.timeline',
|
86
97
|
disabledByDefault('devtools.timeline'),
|
87
98
|
disabledByDefault('devtools.timeline.frame'),
|
88
|
-
'
|
99
|
+
disabledByDefault('devtools.timeline.stack'),
|
89
100
|
disabledByDefault('v8.compile'),
|
90
|
-
|
91
|
-
TimelineModel.TimelineModel.TimelineModelImpl.Category.
|
101
|
+
disabledByDefault('v8.cpu_profiler.hires'),
|
102
|
+
TimelineModel.TimelineModel.TimelineModelImpl.Category.LatencyInfo,
|
92
103
|
TimelineModel.TimelineModel.TimelineModelImpl.Category.Loading,
|
104
|
+
disabledByDefault('lighthouse'),
|
105
|
+
'v8.execute',
|
106
|
+
'v8',
|
93
107
|
];
|
94
|
-
categoriesArray.push(TimelineModel.TimelineModel.TimelineModelImpl.Category.LatencyInfo);
|
95
108
|
|
96
109
|
if (Root.Runtime.experiments.isEnabled('timelineV8RuntimeCallStats') && options.enableJSSampling) {
|
97
110
|
categoriesArray.push(disabledByDefault('v8.runtime_stats_sampling'));
|
@@ -99,7 +112,6 @@ export class TimelineController implements SDK.TargetManager.SDKModelObserver<SD
|
|
99
112
|
if (!Root.Runtime.Runtime.queryParam('timelineTracingJSProfileDisabled') && options.enableJSSampling) {
|
100
113
|
categoriesArray.push(disabledByDefault('v8.cpu_profiler'));
|
101
114
|
}
|
102
|
-
categoriesArray.push(disabledByDefault('devtools.timeline.stack'));
|
103
115
|
if (Root.Runtime.experiments.isEnabled('timelineInvalidationTracking')) {
|
104
116
|
categoriesArray.push(disabledByDefault('devtools.timeline.invalidationTracking'));
|
105
117
|
}
|
@@ -4,6 +4,10 @@
|
|
4
4
|
* found in the LICENSE file.
|
5
5
|
*/
|
6
6
|
|
7
|
+
:host {
|
8
|
+
overflow: hidden;
|
9
|
+
}
|
10
|
+
|
7
11
|
div {
|
8
12
|
line-height: 1.7em;
|
9
13
|
}
|
@@ -53,3 +57,9 @@ button.link {
|
|
53
57
|
font-family: inherit;
|
54
58
|
font-size: inherit;
|
55
59
|
}
|
60
|
+
|
61
|
+
.text-ellipsis {
|
62
|
+
overflow: hidden;
|
63
|
+
text-overflow: ellipsis;
|
64
|
+
white-space: nowrap;
|
65
|
+
}
|
@@ -101,11 +101,11 @@ const dontCompleteIn = new Set([
|
|
101
101
|
'TypeName',
|
102
102
|
]);
|
103
103
|
|
104
|
-
// FIXME Implement Map property completion?
|
105
104
|
export const enum QueryType {
|
106
105
|
Expression = 0,
|
107
106
|
PropertyName = 1,
|
108
107
|
PropertyExpression = 2,
|
108
|
+
PotentiallyRetrievingFromMap = 3,
|
109
109
|
}
|
110
110
|
|
111
111
|
export function getQueryType(tree: CodeMirror.Tree, pos: number, doc: CodeMirror.Text): {
|
@@ -149,6 +149,22 @@ export function getQueryType(tree: CodeMirror.Tree, pos: number, doc: CodeMirror
|
|
149
149
|
return {type: QueryType.PropertyName, relatedNode: node};
|
150
150
|
}
|
151
151
|
}
|
152
|
+
if (node.name === '(') {
|
153
|
+
// map.get(<auto-complete>
|
154
|
+
if (parent.name === 'ArgList' && parent.parent.name === 'CallExpression') {
|
155
|
+
// map.get
|
156
|
+
const callReceiver = parent.parent.firstChild;
|
157
|
+
if (callReceiver.name === 'MemberExpression') {
|
158
|
+
// get
|
159
|
+
const propertyExpression = callReceiver.lastChild;
|
160
|
+
if (doc.sliceString(propertyExpression.from, propertyExpression.to) === 'get') {
|
161
|
+
// map
|
162
|
+
const potentiallyMapObject = callReceiver.firstChild;
|
163
|
+
return {type: QueryType.PotentiallyRetrievingFromMap, relatedNode: potentiallyMapObject};
|
164
|
+
}
|
165
|
+
}
|
166
|
+
}
|
167
|
+
}
|
152
168
|
return {type: QueryType.Expression};
|
153
169
|
}
|
154
170
|
|
@@ -184,6 +200,12 @@ export async function javascriptCompletionSource(cx: CodeMirror.CompletionContex
|
|
184
200
|
}
|
185
201
|
result = await completeProperties(
|
186
202
|
cx.state.sliceDoc(objectExpr.from, objectExpr.to), quote, cx.state.sliceDoc(cx.pos, cx.pos + 1) === ']');
|
203
|
+
} else if (query.type === QueryType.PotentiallyRetrievingFromMap) {
|
204
|
+
const potentialMapObject = query.relatedNode;
|
205
|
+
if (!potentialMapObject) {
|
206
|
+
return null;
|
207
|
+
}
|
208
|
+
result = await maybeCompleteKeysFromMap(cx.state.sliceDoc(potentialMapObject.from, potentialMapObject.to));
|
187
209
|
} else {
|
188
210
|
return null;
|
189
211
|
}
|
@@ -272,6 +294,29 @@ class PropertyCache {
|
|
272
294
|
}
|
273
295
|
}
|
274
296
|
|
297
|
+
async function maybeCompleteKeysFromMap(objectVariable: string): Promise<CompletionSet> {
|
298
|
+
const result = new CompletionSet();
|
299
|
+
const context = getExecutionContext();
|
300
|
+
if (!context) {
|
301
|
+
return result;
|
302
|
+
}
|
303
|
+
const maybeRetrieveKeys =
|
304
|
+
await evaluateExpression(context, `[...Map.prototype.keys.call(${objectVariable})]`, 'completion');
|
305
|
+
if (!maybeRetrieveKeys) {
|
306
|
+
return result;
|
307
|
+
}
|
308
|
+
const properties = SDK.RemoteObject.RemoteArray.objectAsArray(maybeRetrieveKeys);
|
309
|
+
const numProperties = properties.length();
|
310
|
+
for (let i = 0; i < numProperties; i++) {
|
311
|
+
result.add({
|
312
|
+
label: `"${(await properties.at(i)).value}")`,
|
313
|
+
type: 'constant',
|
314
|
+
boost: i * -1,
|
315
|
+
});
|
316
|
+
}
|
317
|
+
return result;
|
318
|
+
}
|
319
|
+
|
275
320
|
async function completeProperties(
|
276
321
|
expression: string,
|
277
322
|
quoted?: string,
|
package/package.json
CHANGED