chrome-devtools-frontend 1.0.1701636 → 1.0.1702515
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/eslint.config.mjs +3 -1
- package/front_end/core/host/UserMetricsEnums.ts +2 -1
- package/front_end/core/root/ExperimentNames.ts +1 -0
- package/front_end/core/sdk/CSSPropertyParserMatchers.ts +2 -7
- package/front_end/devtools_compatibility.js +2 -1
- package/front_end/entrypoints/main/MainImpl.ts +8 -0
- package/front_end/generated/InspectorBackendCommands.ts +3 -3
- package/front_end/generated/protocol.ts +0 -3
- package/front_end/models/ai_assistance/AiAgent2.ts +13 -1
- package/front_end/models/ai_assistance/AiConversation.ts +1 -1
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +13 -19
- package/front_end/models/change_tracker/ChangeTracker.ts +5 -64
- package/front_end/models/comment_manager/CommentManager.ts +3 -5
- package/front_end/models/comment_manager/CommentThread.ts +30 -13
- package/front_end/models/issues_manager/CookieDeprecationMetadataIssue.ts +6 -7
- package/front_end/models/issues_manager/DeprecationIssue.ts +1 -1
- package/front_end/models/issues_manager/MarkdownIssueDescription.ts +14 -5
- package/front_end/models/issues_manager/SRIMessageSignatureIssue.ts +2 -4
- package/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantRead.md +0 -1
- package/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantReadOptOut.md +5 -0
- package/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantSet.md +0 -1
- package/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantSetOptOut.md +5 -0
- package/front_end/models/issues_manager/descriptions/deprecation.md +1 -1
- package/front_end/models/issues_manager/descriptions/sriValidationFailedIntegrityMismatch.md +2 -0
- package/front_end/models/persistence/NetworkPersistenceManager.ts +14 -2
- package/front_end/panels/common/CommentThreadWidget.ts +29 -10
- package/front_end/panels/common/CommentsOverlayWidget.ts +50 -14
- package/front_end/panels/common/commentThreadWidget.css +11 -0
- package/front_end/panels/elements/StylePropertiesSection.ts +10 -0
- package/front_end/panels/elements/StylePropertyTreeElement.ts +1 -1
- package/front_end/panels/elements/StylesSidebarPane.ts +101 -49
- package/front_end/panels/elements/components/CSSQuery.ts +1 -1
- package/front_end/panels/elements/components/cssQuery.css +4 -0
- package/front_end/panels/elements/elements.ts +0 -1
- package/front_end/panels/elements/stylesSidebarPane.css +6 -0
- package/front_end/panels/sources/ResourceOriginPlugin.ts +8 -3
- package/front_end/panels/sources/ScopeChainSidebarPane.ts +3 -4
- package/front_end/panels/sources/TabbedEditorContainer.ts +339 -126
- package/front_end/panels/sources/UISourceCodeFrame.ts +9 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/chromium/client-variations/ClientVariations.js +25 -96
- package/front_end/third_party/codemirror.next/chunk/angular.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/codemirror.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/cpp.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/cpp.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/java.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/java.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/legacy.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/less.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/less.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/markdown.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/markdown.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/php.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/php.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/python.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/python.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/sass.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/sass.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/svelte.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/svelte.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/vue.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/wast.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/wast.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/xml.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/xml.js.map +1 -1
- package/front_end/third_party/codemirror.next/codemirror.next.js +1 -1
- package/front_end/third_party/codemirror.next/package.json +4 -1
- package/front_end/third_party/codemirror.next/rebuild.sh +1 -1
- package/front_end/ui/comments/CommentOverlayManager.ts +11 -10
- package/front_end/ui/components/markdown_view/MarkdownPlaceholderLitRenderer.ts +117 -0
- package/front_end/ui/components/markdown_view/markdown_view.ts +2 -0
- package/front_end/ui/legacy/Treeoutline.ts +28 -19
- package/front_end/ui/legacy/UIUtils.ts +1 -1
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +228 -343
- package/front_end/ui/legacy/components/object_ui/objectPropertiesSection.css +2 -27
- package/mcp/mcp.ts +1 -0
- package/package.json +1 -1
|
@@ -270,6 +270,8 @@ export class NetworkPersistenceManager extends Common.ObjectWrapper.ObjectWrappe
|
|
|
270
270
|
encodeURI(pathPart).replace(/[\/\*]/g, match => '%' + match[0].charCodeAt(0).toString(16).toUpperCase());
|
|
271
271
|
if (encodedName === '..') {
|
|
272
272
|
encodedName = '%2E%2E';
|
|
273
|
+
} else if (encodedName === '.') {
|
|
274
|
+
encodedName = '%2E';
|
|
273
275
|
}
|
|
274
276
|
if (Host.Platform.isWin()) {
|
|
275
277
|
// Windows does not allow ':' and '?' in filenames
|
|
@@ -335,7 +337,10 @@ export class NetworkPersistenceManager extends Common.ObjectWrapper.ObjectWrappe
|
|
|
335
337
|
if (!encodedFilePath) {
|
|
336
338
|
return null;
|
|
337
339
|
}
|
|
338
|
-
const encodedPath = Common.ParsedURL.ParsedURL.
|
|
340
|
+
const encodedPath = Common.ParsedURL.ParsedURL.substr(encodedFilePath, 0, encodedFilePath.lastIndexOf('/'));
|
|
341
|
+
if (!encodedPath) {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
339
344
|
uiSourceCode = await this.#project.createFile(encodedPath, HEADERS_FILENAME, '');
|
|
340
345
|
Host.userMetrics.actionTaken(Host.UserMetrics.Action.HeaderOverrideFileCreated);
|
|
341
346
|
}
|
|
@@ -525,6 +530,10 @@ export class NetworkPersistenceManager extends Common.ObjectWrapper.ObjectWrappe
|
|
|
525
530
|
const encodedFileName = Common.ParsedURL.ParsedURL.substring(encodedPath, lastIndexOfSlash + 1);
|
|
526
531
|
const rawFileName = Common.ParsedURL.ParsedURL.encodedPathToRawPathString(encodedFileName);
|
|
527
532
|
encodedPath = Common.ParsedURL.ParsedURL.substr(encodedPath, 0, lastIndexOfSlash);
|
|
533
|
+
if (!encodedPath || rawFileName === HEADERS_FILENAME) {
|
|
534
|
+
this.#savingForOverrides.delete(uiSourceCode);
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
528
537
|
if (this.#project) {
|
|
529
538
|
await this.#project.createFile(encodedPath, rawFileName, content ?? '', isEncoded);
|
|
530
539
|
}
|
|
@@ -564,7 +573,7 @@ export class NetworkPersistenceManager extends Common.ObjectWrapper.ObjectWrappe
|
|
|
564
573
|
const relativePathParts = FileSystemWorkspaceBinding.relativePath(uiSourceCode);
|
|
565
574
|
// Decode twice to handle paths generated on Windows OS.
|
|
566
575
|
const host = this.decodeLocalPathToUrlPath(this.decodeLocalPathToUrlPath(relativePathParts[0] || '')).toLowerCase();
|
|
567
|
-
return ['chrome:', 'data:', 'blob:', 'javascript:', 'about:', 'mailto:', 'vbscript:'].includes(host) ||
|
|
576
|
+
return ['chrome:', 'data:', 'blob:', 'javascript:', 'about:', 'mailto:', 'vbscript:', '.', '..'].includes(host) ||
|
|
568
577
|
forbiddenUrls.includes(host);
|
|
569
578
|
}
|
|
570
579
|
|
|
@@ -578,6 +587,9 @@ export class NetworkPersistenceManager extends Common.ObjectWrapper.ObjectWrappe
|
|
|
578
587
|
if (!url) {
|
|
579
588
|
return false;
|
|
580
589
|
}
|
|
590
|
+
if ((url.scheme === 'http' || url.scheme === 'https') && (!url.host || url.host === '.' || url.host === '..')) {
|
|
591
|
+
return true;
|
|
592
|
+
}
|
|
581
593
|
return !['http', 'https', 'file'].includes(url.scheme) || forbiddenUrls.includes(url.host);
|
|
582
594
|
}
|
|
583
595
|
|
|
@@ -7,6 +7,7 @@ import '../../ui/components/tooltips/tooltips.js';
|
|
|
7
7
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
8
8
|
import type * as SDK from '../../core/sdk/sdk.js';
|
|
9
9
|
import type * as CommentManager from '../../models/comment_manager/comment_manager.js';
|
|
10
|
+
import * as Buttons from '../../ui/components/buttons/buttons.js';
|
|
10
11
|
import * as Input from '../../ui/components/input/input.js';
|
|
11
12
|
import * as MarkdownView from '../../ui/components/markdown_view/markdown_view.js';
|
|
12
13
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
@@ -41,6 +42,10 @@ const UIStrings = {
|
|
|
41
42
|
* @description aria-label for the comment text area.
|
|
42
43
|
*/
|
|
43
44
|
commentInputAriaLabel: 'Comment input',
|
|
45
|
+
/**
|
|
46
|
+
* @description Tooltip and aria-label for the close button in the comment thread header.
|
|
47
|
+
*/
|
|
48
|
+
close: 'Close',
|
|
44
49
|
} as const;
|
|
45
50
|
|
|
46
51
|
const UIStringsNotTranslate = {
|
|
@@ -70,6 +75,7 @@ export interface ViewInput {
|
|
|
70
75
|
textAreaRef: Lit.Directives.Ref<HTMLTextAreaElement>;
|
|
71
76
|
onAddComment: (text: string) => void;
|
|
72
77
|
onCommentTextChange: (event: Event) => void;
|
|
78
|
+
onClose?: () => void;
|
|
73
79
|
}
|
|
74
80
|
|
|
75
81
|
export type ViewOutput = undefined;
|
|
@@ -87,16 +93,27 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTML
|
|
|
87
93
|
widget(DOMNodeLink, {node: input.title.node}) :
|
|
88
94
|
html`<span class="selected-item-text">${input.title.text}</span>`}
|
|
89
95
|
</span>
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
<
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
<div class="header-actions">
|
|
97
|
+
${hasComment ? html`
|
|
98
|
+
<div class="sent-status">
|
|
99
|
+
<devtools-icon
|
|
100
|
+
class="check-icon"
|
|
101
|
+
name="checkmark"
|
|
102
|
+
aria-label=${i18nString(UIStrings.sentCheckmark)}>
|
|
103
|
+
</devtools-icon>
|
|
104
|
+
<span>${i18nString(UIStrings.sent)}</span>
|
|
105
|
+
</div>
|
|
106
|
+
` : Lit.nothing}
|
|
107
|
+
<devtools-button
|
|
108
|
+
class="close-button"
|
|
109
|
+
aria-label=${i18nString(UIStrings.close)}
|
|
110
|
+
.iconName=${'cross'}
|
|
111
|
+
.variant=${Buttons.Button.Variant.ICON}
|
|
112
|
+
.size=${Buttons.Button.Size.SMALL}
|
|
113
|
+
.title=${i18nString(UIStrings.close)}
|
|
114
|
+
@click=${input.onClose}
|
|
115
|
+
></devtools-button>
|
|
116
|
+
</div>
|
|
100
117
|
</div>
|
|
101
118
|
|
|
102
119
|
${hasComment ? html`
|
|
@@ -171,6 +188,7 @@ export class CommentThreadWidget extends UI.Widget.Widget {
|
|
|
171
188
|
#textAreaRef = createRef<HTMLTextAreaElement>();
|
|
172
189
|
#view: View;
|
|
173
190
|
onAddComment?: (text: string) => void;
|
|
191
|
+
onClose?: () => void;
|
|
174
192
|
|
|
175
193
|
constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
|
|
176
194
|
super(element);
|
|
@@ -213,6 +231,7 @@ export class CommentThreadWidget extends UI.Widget.Widget {
|
|
|
213
231
|
textAreaRef: this.#textAreaRef,
|
|
214
232
|
onAddComment: this.#handleAddComment,
|
|
215
233
|
onCommentTextChange: this.#handleCommentTextChange,
|
|
234
|
+
onClose: this.onClose,
|
|
216
235
|
};
|
|
217
236
|
this.#view(viewInput, undefined, this.contentElement);
|
|
218
237
|
}
|
|
@@ -31,6 +31,7 @@ export interface ViewInput {
|
|
|
31
31
|
activePin: Comments.CommentOverlayManager.PinPositionData|null;
|
|
32
32
|
title: Title;
|
|
33
33
|
onAddComment: (text: string) => void;
|
|
34
|
+
onCloseCommentThread: () => void;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
export type View = (
|
|
@@ -103,6 +104,7 @@ const DEFAULT_VIEW: View = (input: ViewInput, _output: undefined, target: HTMLEl
|
|
|
103
104
|
title: input.title,
|
|
104
105
|
comments: [...item.thread.comments],
|
|
105
106
|
onAddComment: input.onAddComment,
|
|
107
|
+
onClose: input.onCloseCommentThread,
|
|
106
108
|
})}
|
|
107
109
|
</div>
|
|
108
110
|
`,
|
|
@@ -124,6 +126,18 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
|
|
|
124
126
|
#cachedTitle: Title = {text: ''};
|
|
125
127
|
#cachedTitleAnchor: CommentManager.CommentManager.CommentAnchorSignature|null = null;
|
|
126
128
|
|
|
129
|
+
#setActiveThreadId(threadId: string|null): void {
|
|
130
|
+
if (this.#activeThreadId !== threadId) {
|
|
131
|
+
this.#clearCloseTimeout();
|
|
132
|
+
this.#activeThreadId = threadId;
|
|
133
|
+
if (threadId && this.isShowing()) {
|
|
134
|
+
document.documentElement.addEventListener('keydown', this.#onKeyDown);
|
|
135
|
+
} else {
|
|
136
|
+
document.documentElement.removeEventListener('keydown', this.#onKeyDown);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
127
141
|
constructor(
|
|
128
142
|
element: HTMLElement|undefined,
|
|
129
143
|
[commentManager]: UI.Widget.WidgetDependencies<typeof CommentsOverlayWidget>,
|
|
@@ -170,12 +184,16 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
|
|
|
170
184
|
this.#onAgentAttachedChanged,
|
|
171
185
|
this,
|
|
172
186
|
);
|
|
187
|
+
if (this.#activeThreadId) {
|
|
188
|
+
document.documentElement.addEventListener('keydown', this.#onKeyDown);
|
|
189
|
+
}
|
|
173
190
|
|
|
174
191
|
this.requestUpdate();
|
|
175
192
|
}
|
|
176
193
|
|
|
177
194
|
override willHide(): void {
|
|
178
195
|
this.#clearCloseTimeout();
|
|
196
|
+
document.documentElement.removeEventListener('keydown', this.#onKeyDown);
|
|
179
197
|
this.#commentOverlayManager.stop();
|
|
180
198
|
this.#commentOverlayManager.removeEventListener(
|
|
181
199
|
Comments.CommentOverlayManager.Events.POSITIONS_UPDATED,
|
|
@@ -219,7 +237,7 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
|
|
|
219
237
|
CommentManager.CommentManager.EventTypes[CommentManager.CommentManager.Events.AGENT_ATTACHED_CHANGED]>,
|
|
220
238
|
): void {
|
|
221
239
|
if (!event.data) {
|
|
222
|
-
this.#
|
|
240
|
+
this.#setActiveThreadId(null);
|
|
223
241
|
}
|
|
224
242
|
this.requestUpdate();
|
|
225
243
|
}
|
|
@@ -230,7 +248,7 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
|
|
|
230
248
|
): void {
|
|
231
249
|
const isModeActive = event.data;
|
|
232
250
|
if (!isModeActive) {
|
|
233
|
-
this.#
|
|
251
|
+
this.#setActiveThreadId(null);
|
|
234
252
|
}
|
|
235
253
|
const action = UI.ActionRegistry.ActionRegistry.instance().getAction(
|
|
236
254
|
'comments.toggle-comment-mode',
|
|
@@ -242,9 +260,9 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
|
|
|
242
260
|
#onStateChanged(): void {
|
|
243
261
|
const draftThread = this.#commentManager.getCommentThreads().find(t => t.status === 'DRAFT');
|
|
244
262
|
if (draftThread) {
|
|
245
|
-
this.#
|
|
263
|
+
this.#setActiveThreadId(draftThread.id);
|
|
246
264
|
} else if (this.#activeThreadId && !this.#commentManager.getCommentThread(this.#activeThreadId)) {
|
|
247
|
-
this.#
|
|
265
|
+
this.#setActiveThreadId(null);
|
|
248
266
|
}
|
|
249
267
|
this.requestUpdate();
|
|
250
268
|
}
|
|
@@ -272,7 +290,6 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
|
|
|
272
290
|
return {node};
|
|
273
291
|
}
|
|
274
292
|
}
|
|
275
|
-
return {text: ''};
|
|
276
293
|
}
|
|
277
294
|
|
|
278
295
|
if (anchor.networkRequestId) {
|
|
@@ -287,19 +304,35 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
|
|
|
287
304
|
}
|
|
288
305
|
|
|
289
306
|
#handlePinClick = (threadId: string): void => {
|
|
290
|
-
const thread = this.#commentManager.getCommentThread(threadId);
|
|
291
307
|
if (this.#activeThreadId === threadId) {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
308
|
+
this.#handleCloseCommentThread();
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
this.#commentOverlayManager.clearDraftThreads();
|
|
313
|
+
this.#setActiveThreadId(threadId);
|
|
314
|
+
this.requestUpdate();
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
#handleCloseCommentThread = (): void => {
|
|
318
|
+
if (!this.#activeThreadId) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const thread = this.#commentManager.getCommentThread(this.#activeThreadId);
|
|
322
|
+
if (thread?.status === 'DRAFT') {
|
|
297
323
|
this.#commentOverlayManager.clearDraftThreads();
|
|
298
|
-
this.#activeThreadId = threadId;
|
|
299
324
|
}
|
|
325
|
+
this.#setActiveThreadId(null);
|
|
300
326
|
this.requestUpdate();
|
|
301
327
|
};
|
|
302
328
|
|
|
329
|
+
#onKeyDown = (event: KeyboardEvent): void => {
|
|
330
|
+
if (this.#activeThreadId && event.key === 'Escape' && !event.isComposing) {
|
|
331
|
+
event.consume(true);
|
|
332
|
+
this.#handleCloseCommentThread();
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
|
|
303
336
|
override async performUpdate(signal?: AbortSignal): Promise<void> {
|
|
304
337
|
if (!this.#commentManager.isAgentAttached()) {
|
|
305
338
|
this.#view(
|
|
@@ -313,6 +346,7 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
|
|
|
313
346
|
activePin: null,
|
|
314
347
|
title: {text: ''},
|
|
315
348
|
onAddComment: () => {},
|
|
349
|
+
onCloseCommentThread: this.#handleCloseCommentThread,
|
|
316
350
|
},
|
|
317
351
|
undefined,
|
|
318
352
|
this.contentElement,
|
|
@@ -342,16 +376,18 @@ export class CommentsOverlayWidget extends UI.Widget.Widget {
|
|
|
342
376
|
if (!activeThread) {
|
|
343
377
|
return;
|
|
344
378
|
}
|
|
345
|
-
activeThread.
|
|
379
|
+
activeThread.sendToAgent(text);
|
|
346
380
|
const threadId = activeThread.id;
|
|
381
|
+
this.#clearCloseTimeout();
|
|
347
382
|
this.#closeTimeoutId = window.setTimeout(() => {
|
|
348
383
|
this.#closeTimeoutId = null;
|
|
349
384
|
if (this.#activeThreadId === threadId) {
|
|
350
|
-
this.#
|
|
385
|
+
this.#setActiveThreadId(null);
|
|
351
386
|
this.requestUpdate();
|
|
352
387
|
}
|
|
353
388
|
}, AUTO_CLOSE_DELAY_MS);
|
|
354
389
|
},
|
|
390
|
+
onCloseCommentThread: this.#handleCloseCommentThread,
|
|
355
391
|
};
|
|
356
392
|
this.#view(viewInput, undefined, this.contentElement);
|
|
357
393
|
}
|
|
@@ -30,6 +30,17 @@
|
|
|
30
30
|
gap: var(--sys-size-4);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
.header-actions {
|
|
34
|
+
display: flex;
|
|
35
|
+
align-items: center;
|
|
36
|
+
gap: var(--sys-size-3);
|
|
37
|
+
flex-shrink: 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.close-button {
|
|
41
|
+
flex-shrink: 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
33
44
|
.sent-status {
|
|
34
45
|
display: flex;
|
|
35
46
|
align-items: center;
|
|
@@ -304,6 +304,7 @@ export class StylePropertiesSection {
|
|
|
304
304
|
closeBrace.createChild('span').textContent = '}';
|
|
305
305
|
} else {
|
|
306
306
|
this.titleElement.classList.add('hidden');
|
|
307
|
+
this.updateAncestorRuleList();
|
|
307
308
|
}
|
|
308
309
|
|
|
309
310
|
if (rule) {
|
|
@@ -425,6 +426,7 @@ export class StylePropertiesSection {
|
|
|
425
426
|
this.computedStyleExtraFields = computedStyleExtraFields;
|
|
426
427
|
this.#lastInheritedNode = matchedStyles.isInherited(style) ? matchedStyles.nodeForStyle(style) : null;
|
|
427
428
|
this.update(true);
|
|
429
|
+
this.updateCollapsedState();
|
|
428
430
|
}
|
|
429
431
|
|
|
430
432
|
inheritedNode(): SDK.DOMModel.DOMNode|null {
|
|
@@ -1250,6 +1252,14 @@ export class StylePropertiesSection {
|
|
|
1250
1252
|
this.#ancestorClosingBracesElement.removeChildren();
|
|
1251
1253
|
this.maybeCreateAncestorRules(this.styleInternal);
|
|
1252
1254
|
this.#styleRuleElement.style.paddingLeft = `${this.nestingLevel}ch`;
|
|
1255
|
+
if (this.headerText().length === 0 && (this.styleInternal.parentRule instanceof SDK.CSSRule.CSSStyleRule)) {
|
|
1256
|
+
const lastAncestor = this.#ancestorRuleListElement.lastElementChild;
|
|
1257
|
+
if (lastAncestor && this.#collapseIcon && this.#statusElement) {
|
|
1258
|
+
this.#collapseIcon.slot = 'indent';
|
|
1259
|
+
lastAncestor.append(this.#collapseIcon, this.#statusElement);
|
|
1260
|
+
}
|
|
1261
|
+
this.#ancestorClosingBracesElement.firstElementChild?.classList.add('sidebar-pane-closing-brace');
|
|
1262
|
+
}
|
|
1253
1263
|
}
|
|
1254
1264
|
|
|
1255
1265
|
isPropertyInherited(propertyName: string): boolean {
|
|
@@ -2044,7 +2044,7 @@ export class AnchorFunctionRenderer extends AnchorFunctionRendererBase {
|
|
|
2044
2044
|
|
|
2045
2045
|
override render(match: SDK.CSSPropertyParserMatchers.AnchorFunctionMatch, context: RenderingContext): Node[] {
|
|
2046
2046
|
const content = document.createElement('span');
|
|
2047
|
-
if (match.node.name
|
|
2047
|
+
if (match.node.name === 'VariableName') {
|
|
2048
2048
|
// Link an anchor double-dashed ident to its matching anchor element.
|
|
2049
2049
|
void AnchorFunctionRenderer.decorateAnchorForAnchorLink(this.#stylesContainer, content, {identifier: match.text});
|
|
2050
2050
|
} else {
|
|
@@ -1126,27 +1126,39 @@ export class StylesSidebarPane extends StylesSidebarPaneBase implements StylesCo
|
|
|
1126
1126
|
}
|
|
1127
1127
|
}
|
|
1128
1128
|
|
|
1129
|
-
private getStyleId(
|
|
1129
|
+
private getStyleId(section: StylePropertiesSection): string {
|
|
1130
|
+
const style = section.styleInternal;
|
|
1131
|
+
const node = section.matchedStyles.isInherited(style) ? section.matchedStyles.nodeForStyle(style) :
|
|
1132
|
+
section.matchedStyles.node();
|
|
1133
|
+
const nodeId = node?.id ?? '';
|
|
1130
1134
|
if (style.range) {
|
|
1131
|
-
return `${style.styleSheetId || ''}:${style.range.toString()}`;
|
|
1135
|
+
return `${nodeId}:${style.styleSheetId || ''}:${style.range.toString()}`;
|
|
1132
1136
|
}
|
|
1133
1137
|
if (style.type === SDK.CSSStyleDeclaration.Type.Inline || style.type === SDK.CSSStyleDeclaration.Type.Attributes) {
|
|
1134
|
-
return style.type
|
|
1138
|
+
return `${nodeId}:${style.type}`;
|
|
1135
1139
|
}
|
|
1136
1140
|
if (style.type === SDK.CSSStyleDeclaration.Type.Animation) {
|
|
1137
|
-
return `${style.type}:${style.animationName() || ''}:${style.cssText}`;
|
|
1141
|
+
return `${nodeId}:${style.type}:${style.animationName() || ''}:${style.cssText}`;
|
|
1138
1142
|
}
|
|
1139
1143
|
const parentRule = style.parentRule;
|
|
1140
1144
|
if (parentRule instanceof SDK.CSSRule.CSSStyleRule) {
|
|
1141
|
-
|
|
1145
|
+
const ruleTypes = parentRule.ruleTypes.join(',');
|
|
1146
|
+
const nesting = parentRule.nestingSelectors?.join(',') ?? '';
|
|
1147
|
+
const media = parentRule.media.map(m => m.text).join(',');
|
|
1148
|
+
const containers = parentRule.containerQueries.map(c => c.text).join(',');
|
|
1149
|
+
const supports = parentRule.supports.map(s => s.text).join(',');
|
|
1150
|
+
const scopes = parentRule.scopes.map(s => s.text).join(',');
|
|
1151
|
+
const layers = parentRule.layers.map(l => l.text).join(',');
|
|
1152
|
+
return `${nodeId}:${style.type}:${parentRule.selectorText()}:${ruleTypes}:${nesting}:${media}:${containers}:${
|
|
1153
|
+
supports}:${scopes}:${layers}`;
|
|
1142
1154
|
}
|
|
1143
1155
|
if (parentRule instanceof SDK.CSSRule.CSSKeyframeRule) {
|
|
1144
|
-
return `${style.type}:${parentRule.parentRuleName()}:${parentRule.key().text}`;
|
|
1156
|
+
return `${nodeId}:${style.type}:${parentRule.parentRuleName()}:${parentRule.key().text}`;
|
|
1145
1157
|
}
|
|
1146
1158
|
if (parentRule instanceof SDK.CSSRule.CSSPropertyRule) {
|
|
1147
|
-
return `${style.type}:${parentRule.propertyName().text}`;
|
|
1159
|
+
return `${nodeId}:${style.type}:${parentRule.propertyName().text}`;
|
|
1148
1160
|
}
|
|
1149
|
-
return `${style.type}:${style.cssText}`;
|
|
1161
|
+
return `${nodeId}:${style.type}:${style.cssText}`;
|
|
1150
1162
|
}
|
|
1151
1163
|
|
|
1152
1164
|
rebuildSectionsForMatchedStyleRulesForTest(matchedStyles: SDK.CSSMatchedStyles.CSSMatchedStyles,
|
|
@@ -1170,7 +1182,7 @@ export class StylesSidebarPane extends StylesSidebarPaneBase implements StylesCo
|
|
|
1170
1182
|
|
|
1171
1183
|
this.idleCallbackManager = new IdleCallbackManager();
|
|
1172
1184
|
|
|
1173
|
-
const blocks = [new SectionBlock(null)];
|
|
1185
|
+
const blocks = [new SectionBlock(null, undefined, undefined, 'main')];
|
|
1174
1186
|
let sectionIdx = 0;
|
|
1175
1187
|
let lastParentNode: SDK.DOMModel.DOMNode|null = null;
|
|
1176
1188
|
|
|
@@ -1183,7 +1195,7 @@ export class StylesSidebarPane extends StylesSidebarPaneBase implements StylesCo
|
|
|
1183
1195
|
if (parentRule instanceof SDK.CSSRule.CSSStyleRule) {
|
|
1184
1196
|
const layers = parentRule.layers;
|
|
1185
1197
|
if ((layers.length || lastLayers) && lastLayers !== layers) {
|
|
1186
|
-
const block = SectionBlock.createLayerBlock(parentRule);
|
|
1198
|
+
const block = SectionBlock.createLayerBlock(parentRule, lastLayerParent?.id);
|
|
1187
1199
|
blocks.push(block);
|
|
1188
1200
|
lastLayerParent?.childBlocks.push(block);
|
|
1189
1201
|
sawLayers = true;
|
|
@@ -1409,37 +1421,36 @@ export class StylesSidebarPane extends StylesSidebarPaneBase implements StylesCo
|
|
|
1409
1421
|
return blocks;
|
|
1410
1422
|
}
|
|
1411
1423
|
|
|
1412
|
-
return this.mergeInactiveStyles(blocks
|
|
1424
|
+
return this.mergeInactiveStyles(blocks, matchedStyles, computedStyles, parentsComputedStyles,
|
|
1425
|
+
computedStyleExtraFields);
|
|
1413
1426
|
}
|
|
1414
1427
|
|
|
1415
|
-
private
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
private mergeInactiveStyles(blocks: SectionBlock[]): SectionBlock[] {
|
|
1425
|
-
const blockIds = this.computeBlockIds(blocks);
|
|
1426
|
-
for (const [id, block] of this.#allKnownBlocks) {
|
|
1427
|
-
if (!blockIds.has(block)) {
|
|
1428
|
-
blockIds.set(block, id);
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
const getBlockId = (block: SectionBlock): string => blockIds.get(block) || 'UNKNOWN_BLOCK';
|
|
1428
|
+
private mergeInactiveStyles(
|
|
1429
|
+
blocks: SectionBlock[],
|
|
1430
|
+
matchedStyles: SDK.CSSMatchedStyles.CSSMatchedStyles,
|
|
1431
|
+
computedStyles: Map<string, string>|null,
|
|
1432
|
+
parentsComputedStyles: Map<string, string>|null,
|
|
1433
|
+
computedStyleExtraFields: Protocol.CSS.ComputedStyleExtraFields|null,
|
|
1434
|
+
): SectionBlock[] {
|
|
1435
|
+
const getBlockId = (block: SectionBlock): string => block.id;
|
|
1432
1436
|
|
|
1433
1437
|
for (const block of blocks) {
|
|
1434
1438
|
const bid = getBlockId(block);
|
|
1435
1439
|
const knownBlock = this.#allKnownBlocks.get(bid);
|
|
1436
1440
|
if (knownBlock) {
|
|
1437
|
-
|
|
1441
|
+
knownBlock.sections = mergeOrderedItems(
|
|
1438
1442
|
knownBlock.sections,
|
|
1439
1443
|
block.sections,
|
|
1440
|
-
section => this.getStyleId(section
|
|
1441
|
-
section =>
|
|
1444
|
+
section => this.getStyleId(section),
|
|
1445
|
+
(section, active, newSection) => {
|
|
1446
|
+
if (active && newSection) {
|
|
1447
|
+
section.rebuildWithPayload(matchedStyles, newSection.style(), computedStyles, parentsComputedStyles,
|
|
1448
|
+
computedStyleExtraFields);
|
|
1449
|
+
}
|
|
1450
|
+
section.setInactive(!active);
|
|
1451
|
+
},
|
|
1442
1452
|
);
|
|
1453
|
+
block.sections = knownBlock.sections;
|
|
1443
1454
|
}
|
|
1444
1455
|
}
|
|
1445
1456
|
|
|
@@ -1448,7 +1459,11 @@ export class StylesSidebarPane extends StylesSidebarPaneBase implements StylesCo
|
|
|
1448
1459
|
oldBlocks,
|
|
1449
1460
|
blocks,
|
|
1450
1461
|
getBlockId,
|
|
1451
|
-
block
|
|
1462
|
+
(block, active) => {
|
|
1463
|
+
if (!active) {
|
|
1464
|
+
block.sections.forEach(section => section.setInactive(true));
|
|
1465
|
+
}
|
|
1466
|
+
},
|
|
1452
1467
|
);
|
|
1453
1468
|
|
|
1454
1469
|
this.#allKnownBlocks.clear();
|
|
@@ -1456,6 +1471,19 @@ export class StylesSidebarPane extends StylesSidebarPaneBase implements StylesCo
|
|
|
1456
1471
|
this.#allKnownBlocks.set(getBlockId(block), block);
|
|
1457
1472
|
}
|
|
1458
1473
|
|
|
1474
|
+
// Restore child relationships using the new tree structure,
|
|
1475
|
+
// but pointing to the final instances.
|
|
1476
|
+
for (const newBlock of blocks) {
|
|
1477
|
+
const finalBlock = this.#allKnownBlocks.get(getBlockId(newBlock));
|
|
1478
|
+
if (finalBlock) {
|
|
1479
|
+
const newChildBlocks =
|
|
1480
|
+
newBlock.childBlocks.map(child => this.#allKnownBlocks.get(getBlockId(child))).filter(b => b !== undefined);
|
|
1481
|
+
finalBlock.childBlocks = finalBlock === newBlock ?
|
|
1482
|
+
newChildBlocks :
|
|
1483
|
+
mergeOrderedItems(finalBlock.childBlocks, newChildBlocks, getBlockId, () => {});
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1459
1487
|
return finalBlocks;
|
|
1460
1488
|
}
|
|
1461
1489
|
|
|
@@ -1871,7 +1899,7 @@ export class SectionBlock {
|
|
|
1871
1899
|
childBlocks: SectionBlock[] = [];
|
|
1872
1900
|
#expanded = false;
|
|
1873
1901
|
#icon: Icon|undefined;
|
|
1874
|
-
constructor(titleElement: Element|null, expandable?: boolean, expandedByDefault?: boolean) {
|
|
1902
|
+
constructor(titleElement: Element|null, expandable?: boolean, expandedByDefault?: boolean, readonly id = 'main') {
|
|
1875
1903
|
this.#titleElement = titleElement;
|
|
1876
1904
|
this.sections = [];
|
|
1877
1905
|
this.#expanded = expandedByDefault ?? false;
|
|
@@ -1905,7 +1933,7 @@ export class SectionBlock {
|
|
|
1905
1933
|
const pseudoArgumentString = pseudoArgument ? `(${pseudoArgument})` : '';
|
|
1906
1934
|
const pseudoTypeString = `${pseudoType}${pseudoArgumentString}`;
|
|
1907
1935
|
separatorElement.textContent = i18nString(UIStrings.pseudoSElement, {PH1: pseudoTypeString});
|
|
1908
|
-
return new SectionBlock(separatorElement);
|
|
1936
|
+
return new SectionBlock(separatorElement, false, false, `pseudo:${pseudoType}:${pseudoArgument ?? ''}`);
|
|
1909
1937
|
}
|
|
1910
1938
|
|
|
1911
1939
|
static async createInheritedPseudoTypeBlock(pseudoType: Protocol.DOM.PseudoType, pseudoArgument: string|null,
|
|
@@ -1918,12 +1946,13 @@ export class SectionBlock {
|
|
|
1918
1946
|
UI.UIUtils.createTextChild(separatorElement, i18nString(UIStrings.inheritedFromSPseudoOf, {PH1: pseudoTypeString}));
|
|
1919
1947
|
const link = PanelsCommon.DOMLinkifier.Linkifier.instance().linkify(node, {preventKeyboardFocus: true});
|
|
1920
1948
|
render(link, separatorElement);
|
|
1921
|
-
return new SectionBlock(separatorElement
|
|
1949
|
+
return new SectionBlock(separatorElement, false, false,
|
|
1950
|
+
`inherited-pseudo:${pseudoType}:${pseudoArgument ?? ''}:${node.id}`);
|
|
1922
1951
|
}
|
|
1923
1952
|
|
|
1924
1953
|
static createRegisteredPropertiesBlock(expandedByDefault: boolean): SectionBlock {
|
|
1925
1954
|
const separatorElement = document.createElement('div');
|
|
1926
|
-
const block = new SectionBlock(separatorElement, true, expandedByDefault);
|
|
1955
|
+
const block = new SectionBlock(separatorElement, true, expandedByDefault, 'registered-properties');
|
|
1927
1956
|
separatorElement.className = 'sidebar-separator';
|
|
1928
1957
|
separatorElement.appendChild(document.createTextNode(REGISTERED_PROPERTY_SECTION_NAME));
|
|
1929
1958
|
return block;
|
|
@@ -1931,7 +1960,7 @@ export class SectionBlock {
|
|
|
1931
1960
|
|
|
1932
1961
|
static createFunctionBlock(expandedByDefault: boolean): SectionBlock {
|
|
1933
1962
|
const separatorElement = document.createElement('div');
|
|
1934
|
-
const block = new SectionBlock(separatorElement, true, expandedByDefault);
|
|
1963
|
+
const block = new SectionBlock(separatorElement, true, expandedByDefault, 'functions');
|
|
1935
1964
|
separatorElement.className = 'sidebar-separator';
|
|
1936
1965
|
separatorElement.appendChild(document.createTextNode(FUNCTION_SECTION_NAME));
|
|
1937
1966
|
return block;
|
|
@@ -1942,12 +1971,12 @@ export class SectionBlock {
|
|
|
1942
1971
|
separatorElement.className = 'sidebar-separator';
|
|
1943
1972
|
separatorElement.setAttribute('jslog', `${VisualLogging.sectionHeader('keyframes')}`);
|
|
1944
1973
|
separatorElement.textContent = `@keyframes ${keyframesName}`;
|
|
1945
|
-
return new SectionBlock(separatorElement);
|
|
1974
|
+
return new SectionBlock(separatorElement, false, false, `keyframes:${keyframesName}`);
|
|
1946
1975
|
}
|
|
1947
1976
|
|
|
1948
1977
|
static createAtRuleBlock(expandedByDefault: boolean): SectionBlock {
|
|
1949
1978
|
const separatorElement = document.createElement('div');
|
|
1950
|
-
const block = new SectionBlock(separatorElement, true, expandedByDefault);
|
|
1979
|
+
const block = new SectionBlock(separatorElement, true, expandedByDefault, 'at-rules');
|
|
1951
1980
|
separatorElement.className = 'sidebar-separator';
|
|
1952
1981
|
separatorElement.appendChild(document.createTextNode(i18nString(UIStrings.atRuleSection)));
|
|
1953
1982
|
return block;
|
|
@@ -1958,7 +1987,7 @@ export class SectionBlock {
|
|
|
1958
1987
|
separatorElement.className = 'sidebar-separator';
|
|
1959
1988
|
separatorElement.setAttribute('jslog', `${VisualLogging.sectionHeader('position-try')}`);
|
|
1960
1989
|
separatorElement.textContent = `@position-try ${positionTryName}`;
|
|
1961
|
-
return new SectionBlock(separatorElement);
|
|
1990
|
+
return new SectionBlock(separatorElement, false, false, `position-try:${positionTryName}`);
|
|
1962
1991
|
}
|
|
1963
1992
|
|
|
1964
1993
|
static async createInheritedNodeBlock(node: SDK.DOMModel.DOMNode): Promise<SectionBlock> {
|
|
@@ -1970,10 +1999,10 @@ export class SectionBlock {
|
|
|
1970
1999
|
preventKeyboardFocus: true,
|
|
1971
2000
|
});
|
|
1972
2001
|
render(link, separatorElement);
|
|
1973
|
-
return new SectionBlock(separatorElement);
|
|
2002
|
+
return new SectionBlock(separatorElement, false, false, `inherited-node:${node.id}`);
|
|
1974
2003
|
}
|
|
1975
2004
|
|
|
1976
|
-
static createLayerBlock(rule: SDK.CSSRule.CSSStyleRule): SectionBlock {
|
|
2005
|
+
static createLayerBlock(rule: SDK.CSSRule.CSSStyleRule, parentBlockId = 'main'): SectionBlock {
|
|
1977
2006
|
const separatorElement = document.createElement('div');
|
|
1978
2007
|
separatorElement.className = 'sidebar-separator layer-separator';
|
|
1979
2008
|
separatorElement.setAttribute('jslog', `${VisualLogging.sectionHeader('layer')}`);
|
|
@@ -1983,7 +2012,7 @@ export class SectionBlock {
|
|
|
1983
2012
|
const name = rule.origin === Protocol.CSS.StyleSheetOrigin.UserAgent ? '\xa0user\xa0agent\xa0stylesheet' :
|
|
1984
2013
|
'\xa0implicit\xa0outer\xa0layer';
|
|
1985
2014
|
UI.UIUtils.createTextChild(separatorElement.createChild('div'), name);
|
|
1986
|
-
return new SectionBlock(separatorElement);
|
|
2015
|
+
return new SectionBlock(separatorElement, false, false, `layer:${parentBlockId}:${name}`);
|
|
1987
2016
|
}
|
|
1988
2017
|
const layerLink = separatorElement.createChild('button');
|
|
1989
2018
|
layerLink.className = 'link';
|
|
@@ -1991,7 +2020,7 @@ export class SectionBlock {
|
|
|
1991
2020
|
const name = layers.map(layer => SDK.CSSModel.CSSModel.readableLayerName(layer.text)).join('.');
|
|
1992
2021
|
layerLink.textContent = name;
|
|
1993
2022
|
layerLink.onclick = () => LayersWidget.LayersWidget.instance().revealLayer(name);
|
|
1994
|
-
return new SectionBlock(separatorElement);
|
|
2023
|
+
return new SectionBlock(separatorElement, false, false, `layer:${parentBlockId}:${name}`);
|
|
1995
2024
|
}
|
|
1996
2025
|
|
|
1997
2026
|
updateFilter(): number {
|
|
@@ -2701,30 +2730,53 @@ export function mergeOrderedItems<T>(
|
|
|
2701
2730
|
oldItems: T[],
|
|
2702
2731
|
newItems: T[],
|
|
2703
2732
|
getId: (item: T) => string,
|
|
2704
|
-
|
|
2733
|
+
toggleActive: (item: T, active: boolean, newItem?: T) => void,
|
|
2705
2734
|
): T[] {
|
|
2706
2735
|
const newIds = new Set(newItems.map(getId));
|
|
2736
|
+
const oldItemById = new Map(oldItems.map(item => [getId(item), item]));
|
|
2737
|
+
const handledIds = new Set<string>();
|
|
2707
2738
|
const merged: T[] = [];
|
|
2708
2739
|
let newIdx = 0;
|
|
2709
2740
|
|
|
2710
2741
|
for (const oldItem of oldItems) {
|
|
2711
2742
|
const oldId = getId(oldItem);
|
|
2743
|
+
if (handledIds.has(oldId)) {
|
|
2744
|
+
continue;
|
|
2745
|
+
}
|
|
2712
2746
|
if (newIds.has(oldId)) {
|
|
2713
2747
|
while (newIdx < newItems.length) {
|
|
2714
2748
|
const newItem = newItems[newIdx++];
|
|
2715
|
-
|
|
2716
|
-
|
|
2749
|
+
const newId = getId(newItem);
|
|
2750
|
+
const existingItem = oldItemById.get(newId);
|
|
2751
|
+
if (existingItem) {
|
|
2752
|
+
toggleActive(existingItem, true, newItem);
|
|
2753
|
+
merged.push(existingItem);
|
|
2754
|
+
handledIds.add(newId);
|
|
2755
|
+
} else {
|
|
2756
|
+
merged.push(newItem);
|
|
2757
|
+
}
|
|
2758
|
+
if (newId === oldId) {
|
|
2717
2759
|
break;
|
|
2718
2760
|
}
|
|
2719
2761
|
}
|
|
2720
2762
|
} else {
|
|
2721
|
-
|
|
2763
|
+
toggleActive(oldItem, false);
|
|
2722
2764
|
merged.push(oldItem);
|
|
2765
|
+
handledIds.add(oldId);
|
|
2723
2766
|
}
|
|
2724
2767
|
}
|
|
2725
2768
|
|
|
2726
2769
|
while (newIdx < newItems.length) {
|
|
2727
|
-
|
|
2770
|
+
const newItem = newItems[newIdx++];
|
|
2771
|
+
const newId = getId(newItem);
|
|
2772
|
+
const existingItem = oldItemById.get(newId);
|
|
2773
|
+
if (existingItem && !handledIds.has(newId)) {
|
|
2774
|
+
toggleActive(existingItem, true, newItem);
|
|
2775
|
+
merged.push(existingItem);
|
|
2776
|
+
handledIds.add(newId);
|
|
2777
|
+
} else if (!handledIds.has(newId)) {
|
|
2778
|
+
merged.push(newItem);
|
|
2779
|
+
}
|
|
2728
2780
|
}
|
|
2729
2781
|
|
|
2730
2782
|
return merged;
|