chrome-devtools-frontend 1.0.1558690 → 1.0.1559913
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/front_end/Images/src/container.svg +4 -0
- package/front_end/core/common/Gzip.ts +15 -0
- package/front_end/core/sdk/CSSMetadata.ts +6 -6
- package/front_end/core/sdk/CSSModel.ts +2 -2
- package/front_end/core/sdk/DOMModel.ts +7 -3
- package/front_end/generated/InspectorBackendCommands.ts +2 -1
- package/front_end/generated/SupportedCSSProperties.js +64 -32
- package/front_end/generated/protocol-mapping.d.ts +9 -0
- package/front_end/generated/protocol-proxy-api.d.ts +7 -0
- package/front_end/generated/protocol.ts +14 -1
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +1 -1
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +11 -7
- package/front_end/models/trace/LanternComputationData.ts +4 -3
- package/front_end/models/trace/Processor.ts +6 -5
- package/front_end/models/trace/Styles.ts +10 -1
- package/front_end/models/trace/handlers/LargestImagePaintHandler.ts +2 -2
- package/front_end/models/trace/handlers/MetaHandler.ts +14 -0
- package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +54 -34
- package/front_end/models/trace/helpers/Timing.ts +8 -1
- package/front_end/models/trace/insights/Common.ts +1 -1
- package/front_end/models/trace/insights/LCPBreakdown.ts +4 -4
- package/front_end/models/trace/insights/LCPDiscovery.ts +3 -3
- package/front_end/models/trace/insights/RenderBlocking.ts +1 -1
- package/front_end/models/trace/insights/types.ts +1 -1
- package/front_end/models/trace/types/TraceEvents.ts +62 -10
- package/front_end/panels/common/AiCodeGenerationTeaser.ts +48 -12
- package/front_end/panels/common/aiCodeGenerationTeaser.css +14 -0
- package/front_end/panels/common/common.ts +1 -1
- package/front_end/panels/console/consoleView.css +1 -1
- package/front_end/panels/elements/CSSRuleValidator.ts +38 -0
- package/front_end/panels/elements/ElementsTreeElement.ts +79 -58
- package/front_end/panels/elements/ElementsTreeOutline.ts +0 -17
- package/front_end/panels/elements/StylesSidebarPane.ts +15 -4
- package/front_end/panels/timeline/StatusDialog.ts +4 -3
- package/front_end/panels/timeline/TimelineFlameChartNetworkDataProvider.ts +3 -16
- package/front_end/panels/timeline/TimelineFlameChartView.ts +64 -21
- package/front_end/panels/timeline/TimelinePanel.ts +71 -24
- package/front_end/panels/timeline/TimelineUIUtils.ts +28 -2
- package/front_end/panels/timeline/TimingsTrackAppender.ts +3 -1
- package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +1 -1
- package/front_end/panels/timeline/components/insights/RenderBlocking.ts +6 -4
- package/front_end/panels/timeline/overlays/OverlaysImpl.ts +4 -0
- package/front_end/panels/timeline/timelinePanel.css +8 -1
- package/front_end/panels/timeline/utils/EntryNodes.ts +2 -1
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +70 -28
- package/front_end/ui/legacy/SearchableView.ts +11 -5
- package/front_end/ui/legacy/SplitWidget.ts +1 -1
- package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +43 -9
- package/front_end/ui/visual_logging/KnownContextValues.ts +13 -0
- package/package.json +1 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 The Chromium Authors
|
|
3
|
+
* Use of this source code is governed by a BSD-style license that can be
|
|
4
|
+
* found in the LICENSE file.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
@scope to (devtools-widget > *) {
|
|
8
|
+
.ai-code-generation-teaser {
|
|
9
|
+
.new-badge {
|
|
10
|
+
font-style: normal;
|
|
11
|
+
display: inline-block;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -95,7 +95,7 @@ export class TypeToAllowDialog {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
export {AiCodeCompletionTeaser} from './AiCodeCompletionTeaser.js';
|
|
98
|
-
export
|
|
98
|
+
export * as AiCodeGenerationTeaser from './AiCodeGenerationTeaser.js';
|
|
99
99
|
export {AnnotationManager} from './AnnotationManager.js';
|
|
100
100
|
export {FreDialog} from './FreDialog.js';
|
|
101
101
|
export {GdpSignUpDialog} from './GdpSignUpDialog.js';
|
|
@@ -221,7 +221,7 @@
|
|
|
221
221
|
--console-color-white: #fff;
|
|
222
222
|
|
|
223
223
|
&:focus {
|
|
224
|
-
background-
|
|
224
|
+
background-image: linear-gradient(to bottom, var(--sys-color-state-focus-highlight), var(--sys-color-state-focus-highlight));
|
|
225
225
|
}
|
|
226
226
|
}
|
|
227
227
|
|
|
@@ -85,6 +85,20 @@ const UIStrings = {
|
|
|
85
85
|
*/
|
|
86
86
|
flexGridContainerPropertyRuleFix:
|
|
87
87
|
'Try setting the {PROPERTY_NAME} on the container element or use {ALTERNATIVE_PROPERTY_NAME} instead.',
|
|
88
|
+
/**
|
|
89
|
+
* @description The messages shown in the Style pane when the user hovers over a position-anchor declaration that has no affect on a non-anchor-positioned element.
|
|
90
|
+
* @example {relative} POSITION
|
|
91
|
+
*/
|
|
92
|
+
invalidAnchorPositioning:
|
|
93
|
+
'An anchor was defined but the element was not anchor-positioned but positioned "{POSITION}".',
|
|
94
|
+
/**
|
|
95
|
+
* @description The messages shown in the Style pane when the user hovers over a position-anchor declaration that has no affect on a non-anchor-positioned element.
|
|
96
|
+
*/
|
|
97
|
+
invalidAnchorPositioningFix: 'Set position to either "fixed" or "absolute".',
|
|
98
|
+
/**
|
|
99
|
+
* @description The messages shown in the Style pane when the user hovers over a position-anchor declaration that has no affect on hidden element.
|
|
100
|
+
*/
|
|
101
|
+
unusedAnchorPositioning: 'An anchor was defined but the element is hidden.',
|
|
88
102
|
} as const;
|
|
89
103
|
const str_ = i18n.i18n.registerUIStrings('panels/elements/CSSRuleValidator.ts', UIStrings);
|
|
90
104
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
@@ -547,6 +561,29 @@ export class ZIndexValidator extends CSSRuleValidator {
|
|
|
547
561
|
}
|
|
548
562
|
}
|
|
549
563
|
|
|
564
|
+
export class PositionAnchorValidator extends CSSRuleValidator {
|
|
565
|
+
constructor() {
|
|
566
|
+
super(['position-anchor']);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
override getHint(propertyName: string, computedStyles?: Map<string, string>): Hint|undefined {
|
|
570
|
+
const position = computedStyles?.get('position') ?? 'static';
|
|
571
|
+
const display = computedStyles?.get('display');
|
|
572
|
+
|
|
573
|
+
if (position !== 'absolute' && position !== 'fixed') {
|
|
574
|
+
return new Hint(
|
|
575
|
+
i18nString(UIStrings.invalidAnchorPositioning, {POSITION: position}),
|
|
576
|
+
i18nString(UIStrings.invalidAnchorPositioningFix));
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
if (display === 'none') {
|
|
580
|
+
return new Hint(i18nString(UIStrings.unusedAnchorPositioning, {POSITION: position}), null);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
return undefined;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
550
587
|
/**
|
|
551
588
|
* Validates if CSS width/height are having an effect on an element.
|
|
552
589
|
* See "Applies to" in https://www.w3.org/TR/css-sizing-3/#propdef-width.
|
|
@@ -659,6 +696,7 @@ const CSS_RULE_VALIDATORS = [
|
|
|
659
696
|
MulticolFlexGridValidator,
|
|
660
697
|
PaddingValidator,
|
|
661
698
|
PositionValidator,
|
|
699
|
+
PositionAnchorValidator,
|
|
662
700
|
SizingValidator,
|
|
663
701
|
ZIndexValidator,
|
|
664
702
|
];
|
|
@@ -383,6 +383,7 @@ export interface ViewInput {
|
|
|
383
383
|
|
|
384
384
|
showAdAdorner: boolean;
|
|
385
385
|
showContainerAdorner: boolean;
|
|
386
|
+
containerType?: string;
|
|
386
387
|
showFlexAdorner: boolean;
|
|
387
388
|
showGridAdorner: boolean;
|
|
388
389
|
showGridLanesAdorner: boolean;
|
|
@@ -392,6 +393,7 @@ export interface ViewInput {
|
|
|
392
393
|
isSubgrid: boolean;
|
|
393
394
|
|
|
394
395
|
showViewSourceAdorner: boolean;
|
|
396
|
+
showScrollAdorner: boolean;
|
|
395
397
|
adorners?: Set<Adorners.Adorner.Adorner>;
|
|
396
398
|
nodeInfo?: DocumentFragment;
|
|
397
399
|
topLayerIndex: number;
|
|
@@ -454,9 +456,11 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
|
|
|
454
456
|
ElementsComponents.AdornerManager.RegisteredAdorners.POPOVER);
|
|
455
457
|
const topLayerAdornerConfig = ElementsComponents.AdornerManager.getRegisteredAdorner(
|
|
456
458
|
ElementsComponents.AdornerManager.RegisteredAdorners.TOP_LAYER);
|
|
459
|
+
const scrollAdornerConfig = ElementsComponents.AdornerManager.getRegisteredAdorner(
|
|
460
|
+
ElementsComponents.AdornerManager.RegisteredAdorners.SCROLL);
|
|
457
461
|
const hasAdorners = input.adorners?.size || input.showAdAdorner || input.showContainerAdorner ||
|
|
458
462
|
input.showFlexAdorner || input.showGridAdorner || input.showGridLanesAdorner || input.showMediaAdorner ||
|
|
459
|
-
input.showPopoverAdorner || input.showTopLayerAdorner || input.showViewSourceAdorner;
|
|
463
|
+
input.showPopoverAdorner || input.showTopLayerAdorner || input.showViewSourceAdorner || input.showScrollAdorner;
|
|
460
464
|
// clang-format off
|
|
461
465
|
render(html`
|
|
462
466
|
<div ${ref(el => { output.contentElement = el as HTMLElement; })}>
|
|
@@ -496,7 +500,10 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
|
|
|
496
500
|
}
|
|
497
501
|
}}
|
|
498
502
|
${adornerRef(input)}>
|
|
499
|
-
<span
|
|
503
|
+
<span class="adorner-with-icon">
|
|
504
|
+
<devtools-icon name="container"></devtools-icon>
|
|
505
|
+
<span>${input.containerType}</span>
|
|
506
|
+
</span>
|
|
500
507
|
</devtools-adorner>`: nothing}
|
|
501
508
|
${input.showFlexAdorner ? html`<devtools-adorner
|
|
502
509
|
class=clickable
|
|
@@ -618,6 +625,13 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
|
|
|
618
625
|
${repeat(Array.from((input.adorners ?? new Set()).values()).sort(adornerComparator), adorner => {
|
|
619
626
|
return adorner;
|
|
620
627
|
})}
|
|
628
|
+
${input.showScrollAdorner ? html`<devtools-adorner
|
|
629
|
+
class="scroll"
|
|
630
|
+
.data=${{name: scrollAdornerConfig.name, jslogContext: scrollAdornerConfig.name}}
|
|
631
|
+
aria-label=${i18nString(UIStrings.elementHasScrollableOverflow)}
|
|
632
|
+
${adornerRef(input)}>
|
|
633
|
+
<span>${scrollAdornerConfig.name}</span>
|
|
634
|
+
</devtools-adorner>` : nothing}
|
|
621
635
|
</div>`: nothing}
|
|
622
636
|
</div>
|
|
623
637
|
`, target);
|
|
@@ -689,8 +703,6 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
689
703
|
};
|
|
690
704
|
void this.updateStyleAdorners();
|
|
691
705
|
|
|
692
|
-
void this.updateScrollAdorner();
|
|
693
|
-
|
|
694
706
|
void this.#updateAdorners();
|
|
695
707
|
}
|
|
696
708
|
this.expandAllButtonElement = null;
|
|
@@ -711,34 +723,6 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
711
723
|
if (this.nodeInternal.detached && !this.isClosingTag()) {
|
|
712
724
|
this.listItemNode.setAttribute('title', 'Detached Tree Node');
|
|
713
725
|
}
|
|
714
|
-
|
|
715
|
-
node.domModel().overlayModel().addEventListener(
|
|
716
|
-
SDK.OverlayModel.Events.PERSISTENT_CONTAINER_QUERY_OVERLAY_STATE_CHANGED, event => {
|
|
717
|
-
const {nodeId: eventNodeId, enabled} = event.data;
|
|
718
|
-
if (eventNodeId !== node.id) {
|
|
719
|
-
return;
|
|
720
|
-
}
|
|
721
|
-
this.#containerAdornerActive = enabled;
|
|
722
|
-
this.performUpdate();
|
|
723
|
-
});
|
|
724
|
-
node.domModel().overlayModel().addEventListener(
|
|
725
|
-
SDK.OverlayModel.Events.PERSISTENT_FLEX_CONTAINER_OVERLAY_STATE_CHANGED, event => {
|
|
726
|
-
const {nodeId: eventNodeId, enabled} = event.data;
|
|
727
|
-
if (eventNodeId !== node.id) {
|
|
728
|
-
return;
|
|
729
|
-
}
|
|
730
|
-
this.#flexAdornerActive = enabled;
|
|
731
|
-
this.performUpdate();
|
|
732
|
-
});
|
|
733
|
-
node.domModel().overlayModel().addEventListener(
|
|
734
|
-
SDK.OverlayModel.Events.PERSISTENT_GRID_OVERLAY_STATE_CHANGED, event => {
|
|
735
|
-
const {nodeId: eventNodeId, enabled} = event.data;
|
|
736
|
-
if (eventNodeId !== node.id) {
|
|
737
|
-
return;
|
|
738
|
-
}
|
|
739
|
-
this.#gridAdornerActive = enabled;
|
|
740
|
-
this.performUpdate();
|
|
741
|
-
});
|
|
742
726
|
}
|
|
743
727
|
|
|
744
728
|
static animateOnDOMUpdate(treeElement: ElementsTreeElement): void {
|
|
@@ -804,7 +788,8 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
804
788
|
containerAdornerActive: this.#containerAdornerActive,
|
|
805
789
|
adorners: !this.isClosingTag() ? this.#adorners : undefined,
|
|
806
790
|
showAdAdorner: this.nodeInternal.isAdFrameNode(),
|
|
807
|
-
showContainerAdorner: Boolean(this.#layout?.
|
|
791
|
+
showContainerAdorner: Boolean(this.#layout?.containerType) && !this.isClosingTag(),
|
|
792
|
+
containerType: this.#layout?.containerType,
|
|
808
793
|
showFlexAdorner: Boolean(this.#layout?.isFlex) && !this.isClosingTag(),
|
|
809
794
|
flexAdornerActive: this.#flexAdornerActive,
|
|
810
795
|
showGridAdorner: Boolean(this.#layout?.isGrid) && !this.isClosingTag(),
|
|
@@ -817,6 +802,9 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
817
802
|
popoverAdornerActive: this.#popoverAdornerActive,
|
|
818
803
|
isSubgrid: Boolean(this.#layout?.isSubgrid),
|
|
819
804
|
showViewSourceAdorner: this.nodeInternal.isRootNode() && isOpeningTag(this.tagTypeContext),
|
|
805
|
+
showScrollAdorner: ((this.node().nodeName() === 'HTML' && this.node().ownerDocument?.isScrollable()) ||
|
|
806
|
+
(this.node().nodeName() !== '#document' && this.node().isScrollable())) &&
|
|
807
|
+
!this.isClosingTag(),
|
|
820
808
|
nodeInfo: this.#nodeInfo,
|
|
821
809
|
topLayerIndex: this.node().topLayerIndex(),
|
|
822
810
|
onViewSourceAdornerClick: this.revealHTMLInSources.bind(this),
|
|
@@ -1124,6 +1112,18 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1124
1112
|
if (this.treeOutline && !this.isClosingTag()) {
|
|
1125
1113
|
this.treeOutline.treeElementByNode.set(this.nodeInternal, this);
|
|
1126
1114
|
this.nodeInternal.addEventListener(SDK.DOMModel.DOMNodeEvents.TOP_LAYER_INDEX_CHANGED, this.performUpdate, this);
|
|
1115
|
+
this.nodeInternal.addEventListener(
|
|
1116
|
+
SDK.DOMModel.DOMNodeEvents.SCROLLABLE_FLAG_UPDATED, this.#onScrollableFlagUpdated, this);
|
|
1117
|
+
const overlayModel = this.nodeInternal.domModel().overlayModel();
|
|
1118
|
+
overlayModel.addEventListener(
|
|
1119
|
+
SDK.OverlayModel.Events.PERSISTENT_CONTAINER_QUERY_OVERLAY_STATE_CHANGED,
|
|
1120
|
+
this.#onPersistentContainerQueryOverlayStateChanged, this);
|
|
1121
|
+
overlayModel.addEventListener(
|
|
1122
|
+
SDK.OverlayModel.Events.PERSISTENT_FLEX_CONTAINER_OVERLAY_STATE_CHANGED,
|
|
1123
|
+
this.#onPersistentFlexContainerOverlayStateChanged, this);
|
|
1124
|
+
overlayModel.addEventListener(
|
|
1125
|
+
SDK.OverlayModel.Events.PERSISTENT_GRID_OVERLAY_STATE_CHANGED, this.#onPersistentGridOverlayStateChanged,
|
|
1126
|
+
this);
|
|
1127
1127
|
}
|
|
1128
1128
|
}
|
|
1129
1129
|
|
|
@@ -1135,6 +1135,51 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1135
1135
|
this.treeOutline.treeElementByNode.delete(this.nodeInternal);
|
|
1136
1136
|
}
|
|
1137
1137
|
this.nodeInternal.removeEventListener(SDK.DOMModel.DOMNodeEvents.TOP_LAYER_INDEX_CHANGED, this.performUpdate, this);
|
|
1138
|
+
this.nodeInternal.removeEventListener(
|
|
1139
|
+
SDK.DOMModel.DOMNodeEvents.SCROLLABLE_FLAG_UPDATED, this.#onScrollableFlagUpdated, this);
|
|
1140
|
+
const overlayModel = this.nodeInternal.domModel().overlayModel();
|
|
1141
|
+
overlayModel.removeEventListener(
|
|
1142
|
+
SDK.OverlayModel.Events.PERSISTENT_CONTAINER_QUERY_OVERLAY_STATE_CHANGED,
|
|
1143
|
+
this.#onPersistentContainerQueryOverlayStateChanged, this);
|
|
1144
|
+
overlayModel.removeEventListener(
|
|
1145
|
+
SDK.OverlayModel.Events.PERSISTENT_FLEX_CONTAINER_OVERLAY_STATE_CHANGED,
|
|
1146
|
+
this.#onPersistentFlexContainerOverlayStateChanged, this);
|
|
1147
|
+
overlayModel.removeEventListener(
|
|
1148
|
+
SDK.OverlayModel.Events.PERSISTENT_GRID_OVERLAY_STATE_CHANGED, this.#onPersistentGridOverlayStateChanged, this);
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
#onScrollableFlagUpdated(): void {
|
|
1152
|
+
void this.#updateAdorners();
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
#onPersistentContainerQueryOverlayStateChanged(
|
|
1156
|
+
event: Common.EventTarget.EventTargetEvent<SDK.OverlayModel.ChangedNodeId>): void {
|
|
1157
|
+
const {nodeId: eventNodeId, enabled} = event.data;
|
|
1158
|
+
if (eventNodeId !== this.nodeInternal.id) {
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
|
+
this.#containerAdornerActive = enabled;
|
|
1162
|
+
this.performUpdate();
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
#onPersistentFlexContainerOverlayStateChanged(
|
|
1166
|
+
event: Common.EventTarget.EventTargetEvent<SDK.OverlayModel.ChangedNodeId>): void {
|
|
1167
|
+
const {nodeId: eventNodeId, enabled} = event.data;
|
|
1168
|
+
if (eventNodeId !== this.nodeInternal.id) {
|
|
1169
|
+
return;
|
|
1170
|
+
}
|
|
1171
|
+
this.#flexAdornerActive = enabled;
|
|
1172
|
+
this.performUpdate();
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
#onPersistentGridOverlayStateChanged(event: Common.EventTarget.EventTargetEvent<SDK.OverlayModel.ChangedNodeId>):
|
|
1176
|
+
void {
|
|
1177
|
+
const {nodeId: eventNodeId, enabled} = event.data;
|
|
1178
|
+
if (eventNodeId !== this.nodeInternal.id) {
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
1181
|
+
this.#gridAdornerActive = enabled;
|
|
1182
|
+
this.performUpdate();
|
|
1138
1183
|
}
|
|
1139
1184
|
|
|
1140
1185
|
override onattach(): void {
|
|
@@ -1492,7 +1537,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1492
1537
|
],
|
|
1493
1538
|
},
|
|
1494
1539
|
{
|
|
1495
|
-
condition: (props: SDK.CSSModel.LayoutProperties|null): boolean => Boolean(props?.
|
|
1540
|
+
condition: (props: SDK.CSSModel.LayoutProperties|null): boolean => Boolean(props?.containerType),
|
|
1496
1541
|
items: [
|
|
1497
1542
|
{
|
|
1498
1543
|
label: i18nString(UIStrings.explainContainerQueries),
|
|
@@ -3058,30 +3103,6 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
3058
3103
|
this.#adorners.add(adorner);
|
|
3059
3104
|
}
|
|
3060
3105
|
|
|
3061
|
-
updateScrollAdorner(): void {
|
|
3062
|
-
if (!isOpeningTag(this.tagTypeContext)) {
|
|
3063
|
-
return;
|
|
3064
|
-
}
|
|
3065
|
-
const scrollAdorner =
|
|
3066
|
-
this.#adorners.values().find(x => x.name === ElementsComponents.AdornerManager.RegisteredAdorners.SCROLL);
|
|
3067
|
-
// Check if the node is scrollable, or if it's the <html> element and the document is scrollable
|
|
3068
|
-
// because the top-level document (#document) doesn't have a corresponding tree element.
|
|
3069
|
-
const needsAScrollAdorner = (this.node().nodeName() === 'HTML' && this.node().ownerDocument?.isScrollable()) ||
|
|
3070
|
-
(this.node().nodeName() !== '#document' && this.node().isScrollable());
|
|
3071
|
-
if (needsAScrollAdorner && !scrollAdorner) {
|
|
3072
|
-
this.pushScrollAdorner();
|
|
3073
|
-
} else if (!needsAScrollAdorner && scrollAdorner) {
|
|
3074
|
-
this.removeAdorner(scrollAdorner);
|
|
3075
|
-
}
|
|
3076
|
-
}
|
|
3077
|
-
|
|
3078
|
-
pushScrollAdorner(): void {
|
|
3079
|
-
const config = ElementsComponents.AdornerManager.getRegisteredAdorner(
|
|
3080
|
-
ElementsComponents.AdornerManager.RegisteredAdorners.SCROLL);
|
|
3081
|
-
const adorner = this.adorn(config);
|
|
3082
|
-
UI.Tooltip.Tooltip.install(adorner, i18nString(UIStrings.elementHasScrollableOverflow));
|
|
3083
|
-
adorner.classList.add('scroll');
|
|
3084
|
-
}
|
|
3085
3106
|
}
|
|
3086
3107
|
|
|
3087
3108
|
export const InitialChildrenLimit = 500;
|
|
@@ -1526,7 +1526,6 @@ export class ElementsTreeOutline extends
|
|
|
1526
1526
|
domModel.addEventListener(SDK.DOMModel.Events.DocumentUpdated, this.documentUpdated, this);
|
|
1527
1527
|
domModel.addEventListener(SDK.DOMModel.Events.ChildNodeCountUpdated, this.childNodeCountUpdated, this);
|
|
1528
1528
|
domModel.addEventListener(SDK.DOMModel.Events.DistributedNodesChanged, this.distributedNodesChanged, this);
|
|
1529
|
-
domModel.addEventListener(SDK.DOMModel.Events.ScrollableFlagUpdated, this.scrollableFlagUpdated, this);
|
|
1530
1529
|
domModel.addEventListener(
|
|
1531
1530
|
SDK.DOMModel.Events.AffectedByStartingStylesFlagUpdated, this.affectedByStartingStylesFlagUpdated, this);
|
|
1532
1531
|
domModel.addEventListener(SDK.DOMModel.Events.AdoptedStyleSheetsModified, this.adoptedStyleSheetsModified, this);
|
|
@@ -1542,7 +1541,6 @@ export class ElementsTreeOutline extends
|
|
|
1542
1541
|
domModel.removeEventListener(SDK.DOMModel.Events.DocumentUpdated, this.documentUpdated, this);
|
|
1543
1542
|
domModel.removeEventListener(SDK.DOMModel.Events.ChildNodeCountUpdated, this.childNodeCountUpdated, this);
|
|
1544
1543
|
domModel.removeEventListener(SDK.DOMModel.Events.DistributedNodesChanged, this.distributedNodesChanged, this);
|
|
1545
|
-
domModel.removeEventListener(SDK.DOMModel.Events.ScrollableFlagUpdated, this.scrollableFlagUpdated, this);
|
|
1546
1544
|
domModel.removeEventListener(
|
|
1547
1545
|
SDK.DOMModel.Events.AffectedByStartingStylesFlagUpdated, this.affectedByStartingStylesFlagUpdated, this);
|
|
1548
1546
|
domModel.removeEventListener(SDK.DOMModel.Events.AdoptedStyleSheetsModified, this.adoptedStyleSheetsModified, this);
|
|
@@ -2020,21 +2018,6 @@ export class ElementsTreeOutline extends
|
|
|
2020
2018
|
}
|
|
2021
2019
|
}
|
|
2022
2020
|
|
|
2023
|
-
private scrollableFlagUpdated(event: Common.EventTarget.EventTargetEvent<{node: SDK.DOMModel.DOMNode}>): void {
|
|
2024
|
-
let {node} = event.data;
|
|
2025
|
-
if (node.nodeName() === '#document') {
|
|
2026
|
-
// We show the scroll badge of the document on the <html> element.
|
|
2027
|
-
if (!node.ownerDocument?.documentElement) {
|
|
2028
|
-
return;
|
|
2029
|
-
}
|
|
2030
|
-
node = node.ownerDocument.documentElement;
|
|
2031
|
-
}
|
|
2032
|
-
const treeElement = this.treeElementByNode.get(node);
|
|
2033
|
-
if (treeElement && isOpeningTag(treeElement.tagTypeContext)) {
|
|
2034
|
-
void treeElement.updateScrollAdorner();
|
|
2035
|
-
}
|
|
2036
|
-
}
|
|
2037
|
-
|
|
2038
2021
|
private affectedByStartingStylesFlagUpdated(event: Common.EventTarget.EventTargetEvent<{node: SDK.DOMModel.DOMNode}>):
|
|
2039
2022
|
void {
|
|
2040
2023
|
const {node} = event.data;
|
|
@@ -482,6 +482,10 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
482
482
|
|
|
483
483
|
private onFilterChanged(event: Common.EventTarget.EventTargetEvent<string>): void {
|
|
484
484
|
const regex = event.data ? new RegExp(Platform.StringUtilities.escapeForRegExp(event.data), 'i') : null;
|
|
485
|
+
this.setFilter(regex);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
setFilter(regex: RegExp|null): void {
|
|
485
489
|
this.lastFilterChange = Date.now();
|
|
486
490
|
this.#filterRegex = regex;
|
|
487
491
|
this.updateFilter();
|
|
@@ -1036,6 +1040,7 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
1036
1040
|
let sectionIdx = 0;
|
|
1037
1041
|
let lastParentNode: SDK.DOMModel.DOMNode|null = null;
|
|
1038
1042
|
|
|
1043
|
+
let lastLayerParent: SectionBlock|undefined;
|
|
1039
1044
|
let lastLayers: SDK.CSSLayer.CSSLayer[]|null = null;
|
|
1040
1045
|
let sawLayers = false;
|
|
1041
1046
|
|
|
@@ -1046,6 +1051,7 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
1046
1051
|
if ((layers.length || lastLayers) && lastLayers !== layers) {
|
|
1047
1052
|
const block = SectionBlock.createLayerBlock(parentRule);
|
|
1048
1053
|
blocks.push(block);
|
|
1054
|
+
lastLayerParent?.childBlocks.push(block);
|
|
1049
1055
|
sawLayers = true;
|
|
1050
1056
|
lastLayers = layers;
|
|
1051
1057
|
}
|
|
@@ -1055,12 +1061,12 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
1055
1061
|
// We disable the layer widget initially. If we see a layer in
|
|
1056
1062
|
// the matched styles we reenable the button.
|
|
1057
1063
|
LayersWidget.ButtonProvider.instance().item().setVisible(false);
|
|
1058
|
-
|
|
1059
1064
|
for (const style of matchedStyles.nodeStyles()) {
|
|
1060
1065
|
const parentNode = matchedStyles.isInherited(style) ? matchedStyles.nodeForStyle(style) : null;
|
|
1061
1066
|
if (parentNode && parentNode !== lastParentNode) {
|
|
1062
1067
|
lastParentNode = parentNode;
|
|
1063
1068
|
const block = await SectionBlock.createInheritedNodeBlock(lastParentNode);
|
|
1069
|
+
lastLayerParent = block;
|
|
1064
1070
|
blocks.push(block);
|
|
1065
1071
|
}
|
|
1066
1072
|
|
|
@@ -1078,6 +1084,7 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
1078
1084
|
});
|
|
1079
1085
|
}
|
|
1080
1086
|
}
|
|
1087
|
+
lastLayerParent = undefined;
|
|
1081
1088
|
|
|
1082
1089
|
const customHighlightPseudoRulesets: Array<{
|
|
1083
1090
|
highlightName: string | null,
|
|
@@ -1130,9 +1137,11 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
1130
1137
|
if (parentNode) {
|
|
1131
1138
|
const block =
|
|
1132
1139
|
await SectionBlock.createInheritedPseudoTypeBlock(pseudo.pseudoType, pseudo.highlightName, parentNode);
|
|
1140
|
+
lastLayerParent = block;
|
|
1133
1141
|
blocks.push(block);
|
|
1134
1142
|
} else {
|
|
1135
1143
|
const block = SectionBlock.createPseudoTypeBlock(pseudo.pseudoType, pseudo.highlightName);
|
|
1144
|
+
lastLayerParent = block;
|
|
1136
1145
|
blocks.push(block);
|
|
1137
1146
|
}
|
|
1138
1147
|
}
|
|
@@ -1503,6 +1512,7 @@ const MAX_LINK_LENGTH = 23;
|
|
|
1503
1512
|
export class SectionBlock {
|
|
1504
1513
|
readonly #titleElement: Element|null;
|
|
1505
1514
|
sections: StylePropertiesSection[];
|
|
1515
|
+
childBlocks: SectionBlock[] = [];
|
|
1506
1516
|
#expanded = false;
|
|
1507
1517
|
#icon: Icon|undefined;
|
|
1508
1518
|
constructor(titleElement: Element|null, expandable?: boolean, expandedByDefault?: boolean) {
|
|
@@ -1634,14 +1644,15 @@ export class SectionBlock {
|
|
|
1634
1644
|
}
|
|
1635
1645
|
|
|
1636
1646
|
updateFilter(): number {
|
|
1637
|
-
let hasAnyVisibleSection = false;
|
|
1638
1647
|
let numVisibleSections = 0;
|
|
1648
|
+
for (const childBlock of this.childBlocks) {
|
|
1649
|
+
numVisibleSections += childBlock.updateFilter();
|
|
1650
|
+
}
|
|
1639
1651
|
for (const section of this.sections) {
|
|
1640
1652
|
numVisibleSections += section.updateFilter() ? 1 : 0;
|
|
1641
|
-
hasAnyVisibleSection = section.updateFilter() || hasAnyVisibleSection;
|
|
1642
1653
|
}
|
|
1643
1654
|
if (this.#titleElement) {
|
|
1644
|
-
this.#titleElement.classList.toggle('hidden',
|
|
1655
|
+
this.#titleElement.classList.toggle('hidden', numVisibleSections === 0);
|
|
1645
1656
|
}
|
|
1646
1657
|
return numVisibleSections;
|
|
1647
1658
|
}
|
|
@@ -145,14 +145,15 @@ export class StatusDialog extends UI.Widget.VBox {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
remove(): void {
|
|
148
|
-
(this.element.parentNode as HTMLElement)?.classList.remove('tinted');
|
|
148
|
+
(this.element.parentNode as HTMLElement)?.classList.remove('opaque', 'tinted');
|
|
149
149
|
this.stopTimer();
|
|
150
150
|
this.element.remove();
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
showPane(parent: Element): void {
|
|
153
|
+
showPane(parent: Element, mode: 'tinted'|'opaque' = 'opaque'): void {
|
|
154
154
|
this.show(parent);
|
|
155
|
-
parent.classList.
|
|
155
|
+
parent.classList.toggle('tinted', mode === 'tinted');
|
|
156
|
+
parent.classList.toggle('opaque', mode === 'opaque');
|
|
156
157
|
}
|
|
157
158
|
|
|
158
159
|
enableAndFocusButton(): void {
|
|
@@ -423,28 +423,15 @@ export class TimelineFlameChartNetworkDataProvider implements PerfUI.FlameChart.
|
|
|
423
423
|
|
|
424
424
|
/**
|
|
425
425
|
* When users zoom in the flamechart, we only want to show them the network
|
|
426
|
-
* requests between startTime and endTime.
|
|
427
|
-
* trackAppender to update the timeline data, and then force to create a new
|
|
428
|
-
* PerfUI.FlameChart.FlameChartTimelineData instance to force the flamechart
|
|
429
|
-
* to re-render.
|
|
426
|
+
* requests between startTime and endTime.
|
|
430
427
|
*/
|
|
431
428
|
#updateTimelineData(startTime: Trace.Types.Timing.Milli, endTime: Trace.Types.Timing.Milli): void {
|
|
432
429
|
if (!this.#networkTrackAppender || !this.#timelineData) {
|
|
433
430
|
return;
|
|
434
431
|
}
|
|
432
|
+
// This also has the side-effect of updating this.#timelineData with new
|
|
433
|
+
// information.
|
|
435
434
|
this.#maxLevel = this.#networkTrackAppender.relayoutEntriesWithinBounds(this.#events, startTime, endTime);
|
|
436
|
-
|
|
437
|
-
// TODO(crbug.com/1459225): Remove this recreating code.
|
|
438
|
-
// Force to create a new PerfUI.FlameChart.FlameChartTimelineData instance
|
|
439
|
-
// to force the flamechart to re-render. This also causes crbug.com/1459225.
|
|
440
|
-
this.#timelineData = PerfUI.FlameChart.FlameChartTimelineData.create({
|
|
441
|
-
entryLevels: this.#timelineData?.entryLevels,
|
|
442
|
-
entryTotalTimes: this.#timelineData?.entryTotalTimes,
|
|
443
|
-
entryStartTimes: this.#timelineData?.entryStartTimes,
|
|
444
|
-
groups: this.#timelineData?.groups,
|
|
445
|
-
initiatorsData: this.#timelineData.initiatorsData,
|
|
446
|
-
entryDecorations: this.#timelineData.entryDecorations,
|
|
447
|
-
});
|
|
448
435
|
}
|
|
449
436
|
|
|
450
437
|
/**
|
|
@@ -66,10 +66,12 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
|
66
66
|
*/
|
|
67
67
|
export const SORT_ORDER_PAGE_LOAD_MARKERS: Readonly<Record<string, number>> = {
|
|
68
68
|
[Trace.Types.Events.Name.NAVIGATION_START]: 0,
|
|
69
|
-
[Trace.Types.Events.Name.
|
|
70
|
-
[Trace.Types.Events.Name.
|
|
71
|
-
[Trace.Types.Events.Name.
|
|
72
|
-
[Trace.Types.Events.Name.
|
|
69
|
+
[Trace.Types.Events.Name.SOFT_NAVIGATION_START]: 1,
|
|
70
|
+
[Trace.Types.Events.Name.MARK_LOAD]: 2,
|
|
71
|
+
[Trace.Types.Events.Name.MARK_FCP]: 3,
|
|
72
|
+
[Trace.Types.Events.Name.MARK_DOM_CONTENT]: 4,
|
|
73
|
+
[Trace.Types.Events.Name.MARK_LCP_CANDIDATE]: 5,
|
|
74
|
+
[Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION]: 6,
|
|
73
75
|
};
|
|
74
76
|
|
|
75
77
|
// Threshold to match up overlay markers that are off by a tiny amount so they aren't rendered
|
|
@@ -648,6 +650,7 @@ export class TimelineFlameChartView extends Common.ObjectWrapper.eventMixin<Even
|
|
|
648
650
|
fieldMetricResult = fieldMetricResults.fcp;
|
|
649
651
|
} else if (event.name === Trace.Types.Events.Name.MARK_LCP_CANDIDATE) {
|
|
650
652
|
fieldMetricResult = fieldMetricResults.lcp;
|
|
653
|
+
// Ignoring soft-nav LCP on purpose.
|
|
651
654
|
}
|
|
652
655
|
|
|
653
656
|
if (!fieldMetricResult) {
|
|
@@ -669,7 +672,9 @@ export class TimelineFlameChartView extends Common.ObjectWrapper.eventMixin<Even
|
|
|
669
672
|
// Set markers for Navigations, LCP, FCP, DCL, L.
|
|
670
673
|
const markers = markerEvents.filter(
|
|
671
674
|
event => event.name === Trace.Types.Events.Name.NAVIGATION_START ||
|
|
675
|
+
event.name === Trace.Types.Events.Name.SOFT_NAVIGATION_START ||
|
|
672
676
|
event.name === Trace.Types.Events.Name.MARK_LCP_CANDIDATE ||
|
|
677
|
+
event.name === Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION ||
|
|
673
678
|
event.name === Trace.Types.Events.Name.MARK_FCP ||
|
|
674
679
|
event.name === Trace.Types.Events.Name.MARK_DOM_CONTENT ||
|
|
675
680
|
event.name === Trace.Types.Events.Name.MARK_LOAD);
|
|
@@ -681,6 +686,7 @@ export class TimelineFlameChartView extends Common.ObjectWrapper.eventMixin<Even
|
|
|
681
686
|
marker,
|
|
682
687
|
parsedTrace.data.Meta.traceBounds,
|
|
683
688
|
parsedTrace.data.Meta.navigationsByNavigationId,
|
|
689
|
+
parsedTrace.data.Meta.softNavigationsById,
|
|
684
690
|
parsedTrace.data.Meta.navigationsByFrameId,
|
|
685
691
|
);
|
|
686
692
|
// If any of the markers overlap in timing, lets put them on the same marker.
|
|
@@ -732,24 +738,11 @@ export class TimelineFlameChartView extends Common.ObjectWrapper.eventMixin<Even
|
|
|
732
738
|
entries.push(...Overlays.Overlays.entriesForOverlay(overlay));
|
|
733
739
|
}
|
|
734
740
|
|
|
735
|
-
// The insight's `relatedEvents` property likely already includes the events associated with
|
|
736
|
-
// an overlay, but just in case not, include both arrays. Duplicates are fine.
|
|
737
|
-
let relatedEventsList = this.#activeInsight?.model.relatedEvents;
|
|
738
|
-
if (!relatedEventsList) {
|
|
739
|
-
relatedEventsList = [];
|
|
740
|
-
} else if (relatedEventsList instanceof Map) {
|
|
741
|
-
relatedEventsList = Array.from(relatedEventsList.keys());
|
|
742
|
-
}
|
|
743
|
-
this.#dimInsightRelatedEvents([...entries, ...relatedEventsList]);
|
|
744
|
-
|
|
745
741
|
if (options.updateTraceWindow) {
|
|
746
|
-
// We should only expand the entry track when we are updating the trace window
|
|
747
|
-
// (eg. when insight cards are initially opened).
|
|
742
|
+
// We should only expand the entry track when we are updating the trace window (eg. when insight cards are initially opened).
|
|
748
743
|
// Otherwise the track will open when not intending to.
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
this.#expandEntryTrack(entry);
|
|
752
|
-
}
|
|
744
|
+
this.#bulkExpandGroupsForEntries(entries);
|
|
745
|
+
|
|
753
746
|
const overlaysBounds = Overlays.Overlays.traceWindowContainingOverlays(this.#currentInsightOverlays);
|
|
754
747
|
if (overlaysBounds) {
|
|
755
748
|
// Trace window covering all overlays expanded by 50% so that the overlays cover 2/3 (100/150) of the visible window. (Or use provided override)
|
|
@@ -767,11 +760,26 @@ export class TimelineFlameChartView extends Common.ObjectWrapper.eventMixin<Even
|
|
|
767
760
|
}
|
|
768
761
|
}
|
|
769
762
|
|
|
763
|
+
// The insight's `relatedEvents` property likely already includes the events associated with
|
|
764
|
+
// an overlay, but just in case not, include both arrays. Duplicates are fine.
|
|
765
|
+
let relatedEventsList = this.#activeInsight?.model.relatedEvents;
|
|
766
|
+
if (!relatedEventsList) {
|
|
767
|
+
relatedEventsList = [];
|
|
768
|
+
} else if (relatedEventsList instanceof Map) {
|
|
769
|
+
relatedEventsList = Array.from(relatedEventsList.keys());
|
|
770
|
+
}
|
|
771
|
+
this.#dimInsightRelatedEvents([...entries, ...relatedEventsList]);
|
|
772
|
+
|
|
770
773
|
// Reveal entry if we have one.
|
|
774
|
+
// This is wrapped in a rAF to make sure the FlameChart draw from the
|
|
775
|
+
// expansion of any groups is complete - we need all the update() handlers
|
|
776
|
+
// to have run so the FlameChart has been drawn correctly at the right height.
|
|
771
777
|
if (entries.length !== 0) {
|
|
772
778
|
const earliestEntry =
|
|
773
779
|
entries.reduce((earliest, current) => (earliest.ts < current.ts ? earliest : current), entries[0]);
|
|
774
|
-
|
|
780
|
+
requestAnimationFrame(() => {
|
|
781
|
+
this.revealEventVertically(earliestEntry);
|
|
782
|
+
});
|
|
775
783
|
}
|
|
776
784
|
}
|
|
777
785
|
|
|
@@ -823,6 +831,41 @@ export class TimelineFlameChartView extends Common.ObjectWrapper.eventMixin<Even
|
|
|
823
831
|
}
|
|
824
832
|
}
|
|
825
833
|
|
|
834
|
+
/**
|
|
835
|
+
* Bulk expands the tracks (e.g. groups) that the given entries belong to.
|
|
836
|
+
* Will update them all at once and then do a redraw.
|
|
837
|
+
*/
|
|
838
|
+
#bulkExpandGroupsForEntries(entries: Trace.Types.Events.Event[]): void {
|
|
839
|
+
const networkGroupIndexes = new Set<number>();
|
|
840
|
+
const mainGroupIndexes = new Set<number>();
|
|
841
|
+
|
|
842
|
+
for (const entry of entries) {
|
|
843
|
+
const chartName = Overlays.Overlays.chartForEntry(entry);
|
|
844
|
+
const provider = chartName === 'main' ? this.mainDataProvider : this.networkDataProvider;
|
|
845
|
+
const entryIndex = provider.indexForEvent?.(entry) ?? null;
|
|
846
|
+
if (entryIndex === null) {
|
|
847
|
+
continue;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
const group = provider.groupForEvent?.(entryIndex) ?? null;
|
|
851
|
+
if (!group) {
|
|
852
|
+
continue;
|
|
853
|
+
}
|
|
854
|
+
if (group.expanded) {
|
|
855
|
+
continue;
|
|
856
|
+
}
|
|
857
|
+
const groupIndex = provider.timelineData().groups.indexOf(group);
|
|
858
|
+
if (chartName === 'main') {
|
|
859
|
+
mainGroupIndexes.add(groupIndex);
|
|
860
|
+
} else {
|
|
861
|
+
networkGroupIndexes.add(groupIndex);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
this.mainFlameChart.bulkExpandGroups([...mainGroupIndexes]);
|
|
866
|
+
this.networkFlameChart.bulkExpandGroups([...networkGroupIndexes]);
|
|
867
|
+
}
|
|
868
|
+
|
|
826
869
|
/**
|
|
827
870
|
* Expands the track / group that the given entry is in.
|
|
828
871
|
*/
|