chrome-devtools-frontend 1.0.1030070 → 1.0.1030457
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/gni/devtools_grd_files.gni +3 -0
- package/config/gni/devtools_image_files.gni +2 -0
- package/docs/workflows.md +1 -1
- package/front_end/Images/src/file-sync_icon.svg +62 -0
- package/front_end/Images/src/file_icon.svg +52 -0
- package/front_end/core/i18n/locales/en-US.json +6 -0
- package/front_end/core/i18n/locales/en-XL.json +6 -0
- package/front_end/models/issues_manager/DeprecationIssue.ts +5 -1
- package/front_end/panels/elements/CSSRuleValidator.ts +356 -21
- package/front_end/panels/elements/CSSRuleValidatorHelper.ts +34 -0
- package/front_end/panels/elements/StylePropertyTreeElement.ts +1 -1
- package/front_end/panels/network/components/RequestHeadersView.css +40 -8
- package/front_end/panels/network/components/RequestHeadersView.ts +95 -12
- package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +1 -0
- package/front_end/ui/components/data_grid/DataGrid.ts +15 -10
- package/front_end/ui/components/data_grid/DataGridController.ts +7 -0
- package/package.json +6 -5
@@ -56,6 +56,8 @@ grd_files_release_sources = [
|
|
56
56
|
"front_end/Images/errorWave.svg",
|
57
57
|
"front_end/Images/error_icon.svg",
|
58
58
|
"front_end/Images/feedback_button_icon.svg",
|
59
|
+
"front_end/Images/file-sync_icon.svg",
|
60
|
+
"front_end/Images/file_icon.svg",
|
59
61
|
"front_end/Images/flex-direction-icon.svg",
|
60
62
|
"front_end/Images/flex-nowrap-icon.svg",
|
61
63
|
"front_end/Images/flex-wrap-icon.svg",
|
@@ -938,6 +940,7 @@ grd_files_debug_sources = [
|
|
938
940
|
"front_end/panels/elements/AccessibilityTreeUtils.js",
|
939
941
|
"front_end/panels/elements/AccessibilityTreeView.js",
|
940
942
|
"front_end/panels/elements/CSSRuleValidator.js",
|
943
|
+
"front_end/panels/elements/CSSRuleValidatorHelper.js",
|
941
944
|
"front_end/panels/elements/ClassesPaneWidget.js",
|
942
945
|
"front_end/panels/elements/ColorSwatchPopoverIcon.js",
|
943
946
|
"front_end/panels/elements/ComputedStyleModel.js",
|
package/docs/workflows.md
CHANGED
@@ -64,7 +64,7 @@ This works with Chromium 79 or later.
|
|
64
64
|
|
65
65
|
Note that `$(realpath out/Default/gen/front_end)` expands to the absolute path to build artifacts for DevTools frontend.
|
66
66
|
|
67
|
-
Open DevTools via F12 on Windows/Linux or Cmd+Option+I on Mac.
|
67
|
+
Open DevTools via F12 or Ctrl+Shift+J on Windows/Linux or Cmd+Option+I on Mac.
|
68
68
|
|
69
69
|
If you get errors along the line of `Uncaught TypeError: Cannot read property 'setInspectedTabId'` you probably specified an incorrect path - the path has to be absolute. On Mac and Linux, the file url will start with __three__ slashes: `file:///Users/...`.
|
70
70
|
|
@@ -0,0 +1,62 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2
|
+
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
3
|
+
|
4
|
+
<svg
|
5
|
+
width="11"
|
6
|
+
height="13"
|
7
|
+
viewBox="0 0 2.9104166 3.4395834"
|
8
|
+
version="1.1"
|
9
|
+
id="svg298"
|
10
|
+
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
11
|
+
sodipodi:docname="file-sync_icon.svg"
|
12
|
+
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
13
|
+
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
14
|
+
xmlns="http://www.w3.org/2000/svg"
|
15
|
+
xmlns:svg="http://www.w3.org/2000/svg">
|
16
|
+
<sodipodi:namedview
|
17
|
+
id="namedview300"
|
18
|
+
pagecolor="#ffffff"
|
19
|
+
bordercolor="#666666"
|
20
|
+
borderopacity="1.0"
|
21
|
+
inkscape:pageshadow="2"
|
22
|
+
inkscape:pageopacity="0.0"
|
23
|
+
inkscape:pagecheckerboard="0"
|
24
|
+
inkscape:document-units="mm"
|
25
|
+
showgrid="false"
|
26
|
+
units="px"
|
27
|
+
inkscape:zoom="6.7736083"
|
28
|
+
inkscape:cx="-60.602855"
|
29
|
+
inkscape:cy="-53.737976"
|
30
|
+
inkscape:window-width="2028"
|
31
|
+
inkscape:window-height="1445"
|
32
|
+
inkscape:window-x="0"
|
33
|
+
inkscape:window-y="0"
|
34
|
+
inkscape:window-maximized="1"
|
35
|
+
inkscape:current-layer="layer1" />
|
36
|
+
<defs
|
37
|
+
id="defs295" />
|
38
|
+
<g
|
39
|
+
inkscape:label="Layer 1"
|
40
|
+
inkscape:groupmode="layer"
|
41
|
+
id="layer1">
|
42
|
+
<g
|
43
|
+
id="g4825"
|
44
|
+
transform="matrix(0.26458333,0,0,0.26458333,-0.26458331,-0.26458331)">
|
45
|
+
<g
|
46
|
+
id="g4829"
|
47
|
+
transform="translate(-76,-24)">
|
48
|
+
<circle
|
49
|
+
style="fill:#009802"
|
50
|
+
id="circle4831"
|
51
|
+
r="2.5"
|
52
|
+
cy="11.5"
|
53
|
+
cx="10.5"
|
54
|
+
transform="matrix(1.2,0,0,1.2,72.4,21.2)" />
|
55
|
+
<path
|
56
|
+
inkscape:connector-curvature="0"
|
57
|
+
id="path4833"
|
58
|
+
d="m 78,25 c -0.54399,0 -1,0.45026 -1,1 v 8 c 0,0.53973 0.44936,1 1,1 h 3.0312 c -0.02335,-0.1633 -0.03125,-0.33024 -0.03125,-0.5 0,-0.16976 0.0079,-0.3367 0.03125,-0.5 H 78 v -8 h 3 v 3 h 3 v 1.5 c 0.1633,-0.02335 0.33024,0 0.5,0 0.16976,0 0.3367,-0.02335 0.5,0 V 28 l -3,-3 z m 4,1 2,2 h -2 z" />
|
59
|
+
</g>
|
60
|
+
</g>
|
61
|
+
</g>
|
62
|
+
</svg>
|
@@ -0,0 +1,52 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2
|
+
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
3
|
+
|
4
|
+
<svg
|
5
|
+
width="12"
|
6
|
+
height="12"
|
7
|
+
viewBox="0 0 3.1749999 3.1750001"
|
8
|
+
version="1.1"
|
9
|
+
id="svg232"
|
10
|
+
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
11
|
+
sodipodi:docname="file_icon.svg"
|
12
|
+
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
13
|
+
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
14
|
+
xmlns="http://www.w3.org/2000/svg"
|
15
|
+
xmlns:svg="http://www.w3.org/2000/svg">
|
16
|
+
<sodipodi:namedview
|
17
|
+
id="namedview234"
|
18
|
+
pagecolor="#ffffff"
|
19
|
+
bordercolor="#666666"
|
20
|
+
borderopacity="1.0"
|
21
|
+
inkscape:pageshadow="2"
|
22
|
+
inkscape:pageopacity="0.0"
|
23
|
+
inkscape:pagecheckerboard="0"
|
24
|
+
inkscape:document-units="mm"
|
25
|
+
showgrid="false"
|
26
|
+
units="px"
|
27
|
+
inkscape:zoom="16.687513"
|
28
|
+
inkscape:cx="-9.49812"
|
29
|
+
inkscape:cy="4.5543036"
|
30
|
+
inkscape:window-width="2028"
|
31
|
+
inkscape:window-height="1445"
|
32
|
+
inkscape:window-x="0"
|
33
|
+
inkscape:window-y="0"
|
34
|
+
inkscape:window-maximized="1"
|
35
|
+
inkscape:current-layer="layer1" />
|
36
|
+
<defs
|
37
|
+
id="defs229" />
|
38
|
+
<g
|
39
|
+
inkscape:label="Layer 1"
|
40
|
+
inkscape:groupmode="layer"
|
41
|
+
id="layer1">
|
42
|
+
<g
|
43
|
+
id="g4835"
|
44
|
+
transform="matrix(0.26458333,0,0,0.26458333,0.26459658,1.9999999e-8)">
|
45
|
+
<path
|
46
|
+
inkscape:connector-curvature="0"
|
47
|
+
id="path4839"
|
48
|
+
d="m 71.625,25.5 h -4.003 c -0.54399,0 -0.99703,0.44566 -0.99703,0.9954 v 8.0092 c 0,0.53973 0.44639,0.9954 0.99703,0.9954 h 6.0059 c 0.54399,0 0.99703,-0.44566 0.99703,-0.9954 V 28.5 l -3,-3 z m 0,1 2,2 h -2 z m -4,0 h 3 v 3 h 3 v 5 h -6 z"
|
49
|
+
transform="translate(-65.625,-24.5)" />
|
50
|
+
</g>
|
51
|
+
</g>
|
52
|
+
</svg>
|
@@ -4847,6 +4847,9 @@
|
|
4847
4847
|
"panels/elements/CSSRuleValidator.ts | ruleViolatedByParentElementRuleReason": {
|
4848
4848
|
"message": "Parent element has {REASON_RULE_CODE} rule, therefore this elements {AFFECTED_RULE_CODE} has no effect"
|
4849
4849
|
},
|
4850
|
+
"panels/elements/CSSRuleValidator.ts | ruleViolatedBySameElementRuleChangeSuggestion": {
|
4851
|
+
"message": "For this property to work, please change the {EXISTING_RULE} rule to {TARGET_RULE}"
|
4852
|
+
},
|
4850
4853
|
"panels/elements/CSSRuleValidator.ts | ruleViolatedBySameElementRuleFix": {
|
4851
4854
|
"message": "For this property to work, please remove or change the value of {REASON_RULE_CODE}"
|
4852
4855
|
},
|
@@ -6860,6 +6863,9 @@
|
|
6860
6863
|
"panels/network/components/RequestHeadersView.ts | general": {
|
6861
6864
|
"message": "General"
|
6862
6865
|
},
|
6866
|
+
"panels/network/components/RequestHeadersView.ts | headerOverrides": {
|
6867
|
+
"message": "Header overrides"
|
6868
|
+
},
|
6863
6869
|
"panels/network/components/RequestHeadersView.ts | learnMore": {
|
6864
6870
|
"message": "Learn more"
|
6865
6871
|
},
|
@@ -4847,6 +4847,9 @@
|
|
4847
4847
|
"panels/elements/CSSRuleValidator.ts | ruleViolatedByParentElementRuleReason": {
|
4848
4848
|
"message": "P̂ár̂én̂t́ êĺêḿêńt̂ h́âś {REASON_RULE_CODE} r̂úl̂é, t̂h́êŕêf́ôŕê t́ĥíŝ él̂ém̂én̂t́ŝ {AFFECTED_RULE_CODE} h́âś n̂ó êf́f̂éĉt́"
|
4849
4849
|
},
|
4850
|
+
"panels/elements/CSSRuleValidator.ts | ruleViolatedBySameElementRuleChangeSuggestion": {
|
4851
|
+
"message": "F̂ór̂ t́ĥíŝ ṕr̂óp̂ér̂t́ŷ t́ô ẃôŕk̂, ṕl̂éâśê ćĥán̂ǵê t́ĥé {EXISTING_RULE} r̂úl̂é t̂ó {TARGET_RULE}"
|
4852
|
+
},
|
4850
4853
|
"panels/elements/CSSRuleValidator.ts | ruleViolatedBySameElementRuleFix": {
|
4851
4854
|
"message": "F̂ór̂ t́ĥíŝ ṕr̂óp̂ér̂t́ŷ t́ô ẃôŕk̂, ṕl̂éâśê ŕêḿôv́ê ór̂ ćĥán̂ǵê t́ĥé v̂ál̂úê óf̂ {REASON_RULE_CODE}"
|
4852
4855
|
},
|
@@ -6860,6 +6863,9 @@
|
|
6860
6863
|
"panels/network/components/RequestHeadersView.ts | general": {
|
6861
6864
|
"message": "Ĝén̂ér̂ál̂"
|
6862
6865
|
},
|
6866
|
+
"panels/network/components/RequestHeadersView.ts | headerOverrides": {
|
6867
|
+
"message": "Ĥéâd́êŕ ôv́êŕr̂íd̂éŝ"
|
6868
|
+
},
|
6863
6869
|
"panels/network/components/RequestHeadersView.ts | learnMore": {
|
6864
6870
|
"message": "L̂éâŕn̂ ḿôŕê"
|
6865
6871
|
},
|
@@ -291,7 +291,11 @@ const UIStrings = {
|
|
291
291
|
*/
|
292
292
|
xhrJSONEncodingDetection: 'UTF-16 is not supported by response json in `XMLHttpRequest`',
|
293
293
|
/**
|
294
|
-
* @description
|
294
|
+
* @description Warning displayed to developers. It is shown when
|
295
|
+
* the `XMLHttpRequest` API is used in a way that it slows down the page load
|
296
|
+
* of the next page. The `main thread` refers to an operating systems thread
|
297
|
+
* used to run most of the processing of HTML documents, so please use a
|
298
|
+
* consistent wording.
|
295
299
|
*/
|
296
300
|
xmlHttpRequestSynchronousInNonWorkerOutsideBeforeUnload:
|
297
301
|
'Synchronous `XMLHttpRequest` on the main thread is deprecated because of its detrimental effects to the end user\u2019s experience. For more help, check https://xhr.spec.whatwg.org/.',
|
@@ -4,6 +4,14 @@
|
|
4
4
|
|
5
5
|
import * as i18n from '../../core/i18n/i18n.js';
|
6
6
|
|
7
|
+
import {
|
8
|
+
buildStyledPropertyText,
|
9
|
+
buildStyledRuleText,
|
10
|
+
isFlexContainer,
|
11
|
+
isGridContainer,
|
12
|
+
isMulticolContainer,
|
13
|
+
} from './CSSRuleValidatorHelper.js';
|
14
|
+
|
7
15
|
const UIStrings = {
|
8
16
|
/**
|
9
17
|
*@description Hint prefix for deprecated properties.
|
@@ -18,25 +26,36 @@ const UIStrings = {
|
|
18
26
|
*@example {flex-wrap: nowrap} REASON_RULE_CODE
|
19
27
|
*@example {align-content} AFFECTED_RULE_CODE
|
20
28
|
*/
|
21
|
-
ruleViolatedBySameElementRuleReason:
|
29
|
+
ruleViolatedBySameElementRuleReason:
|
30
|
+
'This element has {REASON_RULE_CODE} rule, therefore {AFFECTED_RULE_CODE} has no effect.',
|
22
31
|
/**
|
23
32
|
*@description Possible fix for rules that was violated because of same elements rule.
|
24
33
|
*@example {flex-wrap: nowrap} REASON_RULE_CODE
|
25
34
|
*/
|
26
|
-
ruleViolatedBySameElementRuleFix:
|
35
|
+
ruleViolatedBySameElementRuleFix:
|
36
|
+
'For this property to work, please remove or change the value of {REASON_RULE_CODE}',
|
37
|
+
/**
|
38
|
+
*@description Possible fix for rules that was violated because of same elements rule.
|
39
|
+
*@example {display: block} EXISTING_RULE
|
40
|
+
*@example {display: flex} TARGET_RULE
|
41
|
+
*/
|
42
|
+
ruleViolatedBySameElementRuleChangeSuggestion:
|
43
|
+
'For this property to work, please change the {EXISTING_RULE} rule to {TARGET_RULE}',
|
27
44
|
/**
|
28
45
|
*@description Hint for rules that was violated because of parent element rule.
|
29
46
|
*@example {display: block} REASON_RULE_CODE
|
30
47
|
*@example {flex} AFFECTED_RULE_CODE
|
31
48
|
*/
|
32
|
-
ruleViolatedByParentElementRuleReason:
|
49
|
+
ruleViolatedByParentElementRuleReason:
|
50
|
+
'Parent element has {REASON_RULE_CODE} rule, therefore this elements {AFFECTED_RULE_CODE} has no effect',
|
33
51
|
/**
|
34
52
|
*@description Posible fix for rules that was violated because of parent element rule.
|
35
53
|
*@example {display: block} EXISTING_PARENT_ELEMENT_RULE
|
36
54
|
*@example {display: flex} TARGET_PARENT_ELEMENT_RULE
|
37
55
|
*/
|
38
|
-
ruleViolatedByParentElementRuleFix:
|
39
|
-
|
56
|
+
ruleViolatedByParentElementRuleFix:
|
57
|
+
'Please change parent elements {EXISTING_PARENT_ELEMENT_RULE} to {TARGET_PARENT_ELEMENT_RULE} to fix this issue.',
|
58
|
+
};
|
40
59
|
const str_ = i18n.i18n.registerUIStrings('panels/elements/CSSRuleValidator.ts', UIStrings);
|
41
60
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
42
61
|
|
@@ -94,7 +113,9 @@ export abstract class CSSRuleValidator {
|
|
94
113
|
return this.#affectedProperties;
|
95
114
|
}
|
96
115
|
|
97
|
-
abstract getAuthoringHint(
|
116
|
+
abstract getAuthoringHint(
|
117
|
+
propertyName: string, computedStyles: Map<String, String>|null,
|
118
|
+
parentComputedStyles: Map<String, String>|null): AuthoringHint;
|
98
119
|
}
|
99
120
|
|
100
121
|
export class AlignContentValidator extends CSSRuleValidator {
|
@@ -106,16 +127,15 @@ export class AlignContentValidator extends CSSRuleValidator {
|
|
106
127
|
if (computedStyles === null || computedStyles === undefined) {
|
107
128
|
return true;
|
108
129
|
}
|
109
|
-
|
110
|
-
if (display !== 'flex' && display !== 'inline-flex') {
|
130
|
+
if (!isFlexContainer(computedStyles)) {
|
111
131
|
return true;
|
112
132
|
}
|
113
133
|
return computedStyles.get('flex-wrap') !== 'nowrap';
|
114
134
|
}
|
115
135
|
|
116
136
|
getAuthoringHint(): AuthoringHint {
|
117
|
-
const reasonRuleCode = '
|
118
|
-
const affectedRuleCode = '
|
137
|
+
const reasonRuleCode = buildStyledPropertyText('flex-wrap');
|
138
|
+
const affectedRuleCode = buildStyledPropertyText('align-content');
|
119
139
|
|
120
140
|
return new AuthoringHint(
|
121
141
|
'align-content',
|
@@ -138,18 +158,18 @@ export class FlexItemValidator extends CSSRuleValidator {
|
|
138
158
|
}
|
139
159
|
|
140
160
|
isRuleValid(computedStyles: Map<String, String>|null, parentsComputedStyles: Map<String, String>|null): boolean {
|
141
|
-
if (
|
142
|
-
parentsComputedStyles === undefined) {
|
161
|
+
if (parentsComputedStyles === null) {
|
143
162
|
return true;
|
144
163
|
}
|
145
|
-
|
146
|
-
return parentDisplay === 'flex' || parentDisplay === 'inline-flex';
|
164
|
+
return isFlexContainer(parentsComputedStyles);
|
147
165
|
}
|
148
166
|
|
149
|
-
getAuthoringHint(
|
150
|
-
|
151
|
-
|
152
|
-
const
|
167
|
+
getAuthoringHint(
|
168
|
+
property: string, computedStyles: Map<String, String>|null,
|
169
|
+
parentsComputedStyles: Map<String, String>|null): AuthoringHint {
|
170
|
+
const reasonRuleCode = buildStyledRuleText('display', parentsComputedStyles?.get('display'));
|
171
|
+
const affectedRuleCode = buildStyledPropertyText(property);
|
172
|
+
const targetParentRuleCode = buildStyledRuleText('display', 'flex');
|
153
173
|
|
154
174
|
return new AuthoringHint(
|
155
175
|
property,
|
@@ -167,11 +187,326 @@ export class FlexItemValidator extends CSSRuleValidator {
|
|
167
187
|
}
|
168
188
|
}
|
169
189
|
|
170
|
-
|
171
|
-
|
190
|
+
export class FlexContainerValidator extends CSSRuleValidator {
|
191
|
+
constructor() {
|
192
|
+
super(['flex-direction', 'flex-flow', 'flex-wrap', 'justify-content']);
|
193
|
+
}
|
194
|
+
|
195
|
+
isRuleValid(computedStyles: Map<String, String>|null): boolean {
|
196
|
+
if (computedStyles === null) {
|
197
|
+
return true;
|
198
|
+
}
|
199
|
+
return isFlexContainer(computedStyles);
|
200
|
+
}
|
201
|
+
|
202
|
+
getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
|
203
|
+
const reasonRuleCode = buildStyledRuleText('display', computedStyles?.get('display'));
|
204
|
+
const targetRuleCode = buildStyledRuleText('display', 'flex');
|
205
|
+
const affectedRuleCode = buildStyledPropertyText(property);
|
206
|
+
|
207
|
+
return new AuthoringHint(
|
208
|
+
property,
|
209
|
+
AuthoringHintType.RULE_VALIDATION,
|
210
|
+
i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
|
211
|
+
'REASON_RULE_CODE': reasonRuleCode,
|
212
|
+
'AFFECTED_RULE_CODE': affectedRuleCode,
|
213
|
+
}),
|
214
|
+
i18nString(UIStrings.ruleViolatedBySameElementRuleChangeSuggestion, {
|
215
|
+
'EXISTING_RULE': reasonRuleCode,
|
216
|
+
'TARGET_RULE': targetRuleCode,
|
217
|
+
}),
|
218
|
+
true,
|
219
|
+
);
|
220
|
+
}
|
221
|
+
}
|
222
|
+
|
223
|
+
export class GridContainerValidator extends CSSRuleValidator {
|
224
|
+
constructor() {
|
225
|
+
super([
|
226
|
+
'grid',
|
227
|
+
'grid-auto-columns',
|
228
|
+
'grid-auto-flow',
|
229
|
+
'grid-auto-rows',
|
230
|
+
'grid-template',
|
231
|
+
'grid-template-areas',
|
232
|
+
'grid-template-columns',
|
233
|
+
'grid-template-rows',
|
234
|
+
]);
|
235
|
+
}
|
236
|
+
|
237
|
+
isRuleValid(computedStyles: Map<String, String>|null): boolean {
|
238
|
+
if (computedStyles === null) {
|
239
|
+
return true;
|
240
|
+
}
|
241
|
+
return isGridContainer(computedStyles);
|
242
|
+
}
|
243
|
+
|
244
|
+
getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
|
245
|
+
const reasonRuleCode = buildStyledRuleText('display', computedStyles?.get('display'));
|
246
|
+
const targetRuleCode = buildStyledRuleText('display', 'grid');
|
247
|
+
const affectedRuleCode = buildStyledPropertyText(property);
|
248
|
+
|
249
|
+
return new AuthoringHint(
|
250
|
+
property,
|
251
|
+
AuthoringHintType.RULE_VALIDATION,
|
252
|
+
i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
|
253
|
+
'REASON_RULE_CODE': reasonRuleCode,
|
254
|
+
'AFFECTED_RULE_CODE': affectedRuleCode,
|
255
|
+
}),
|
256
|
+
i18nString(UIStrings.ruleViolatedBySameElementRuleChangeSuggestion, {
|
257
|
+
'EXISTING_RULE': reasonRuleCode,
|
258
|
+
'TARGET_RULE': targetRuleCode,
|
259
|
+
}),
|
260
|
+
true,
|
261
|
+
);
|
262
|
+
}
|
263
|
+
}
|
264
|
+
|
265
|
+
export class GridItemValidator extends CSSRuleValidator {
|
266
|
+
constructor() {
|
267
|
+
super([
|
268
|
+
'grid-area',
|
269
|
+
'grid-column',
|
270
|
+
'grid-row',
|
271
|
+
'grid-row-end',
|
272
|
+
'grid-row-start',
|
273
|
+
]);
|
274
|
+
}
|
275
|
+
|
276
|
+
isRuleValid(computedStyles: Map<String, String>|null, parentComputedStyles: Map<String, String>|null): boolean {
|
277
|
+
if (parentComputedStyles === null) {
|
278
|
+
return true;
|
279
|
+
}
|
280
|
+
return isGridContainer(parentComputedStyles);
|
281
|
+
}
|
282
|
+
|
283
|
+
getAuthoringHint(
|
284
|
+
property: string, computedStyles: Map<String, String>|null,
|
285
|
+
parentComputedStyles: Map<String, String>|null): AuthoringHint {
|
286
|
+
const reasonRuleCode = buildStyledRuleText('display', parentComputedStyles?.get('display'));
|
287
|
+
const targetParentRuleCode = buildStyledRuleText('display', 'grid');
|
288
|
+
const affectedRuleCode = buildStyledPropertyText(property);
|
289
|
+
|
290
|
+
return new AuthoringHint(
|
291
|
+
property,
|
292
|
+
AuthoringHintType.RULE_VALIDATION,
|
293
|
+
i18nString(UIStrings.ruleViolatedByParentElementRuleReason, {
|
294
|
+
'REASON_RULE_CODE': reasonRuleCode,
|
295
|
+
'AFFECTED_RULE_CODE': affectedRuleCode,
|
296
|
+
}),
|
297
|
+
i18nString(UIStrings.ruleViolatedByParentElementRuleFix, {
|
298
|
+
'EXISTING_PARENT_ELEMENT_RULE': reasonRuleCode,
|
299
|
+
'TARGET_PARENT_ELEMENT_RULE': targetParentRuleCode,
|
300
|
+
}),
|
301
|
+
true,
|
302
|
+
);
|
303
|
+
}
|
304
|
+
}
|
305
|
+
|
306
|
+
export class FlexGridValidator extends CSSRuleValidator {
|
307
|
+
constructor() {
|
308
|
+
super([
|
309
|
+
'order',
|
310
|
+
'align-content',
|
311
|
+
'align-items',
|
312
|
+
'align-self',
|
313
|
+
]);
|
314
|
+
}
|
315
|
+
|
316
|
+
isRuleValid(computedStyles: Map<String, String>|null): boolean {
|
317
|
+
if (computedStyles === null) {
|
318
|
+
return true;
|
319
|
+
}
|
320
|
+
return isFlexContainer(computedStyles) || isGridContainer(computedStyles);
|
321
|
+
}
|
322
|
+
|
323
|
+
getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
|
324
|
+
const reasonRuleCode = buildStyledRuleText('display', computedStyles?.get('display'));
|
325
|
+
const affectedRuleCode = buildStyledPropertyText(property);
|
326
|
+
|
327
|
+
return new AuthoringHint(
|
328
|
+
property,
|
329
|
+
AuthoringHintType.RULE_VALIDATION,
|
330
|
+
i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
|
331
|
+
'REASON_RULE_CODE': reasonRuleCode,
|
332
|
+
'AFFECTED_RULE_CODE': affectedRuleCode,
|
333
|
+
}),
|
334
|
+
i18nString(UIStrings.ruleViolatedBySameElementRuleFix, {
|
335
|
+
'REASON_RULE_CODE': reasonRuleCode,
|
336
|
+
}),
|
337
|
+
true,
|
338
|
+
);
|
339
|
+
}
|
340
|
+
}
|
341
|
+
|
342
|
+
export class MulticolFlexGridValidator extends CSSRuleValidator {
|
343
|
+
constructor() {
|
344
|
+
super([
|
345
|
+
'gap',
|
346
|
+
'column-gap',
|
347
|
+
'row-gap',
|
348
|
+
'grid-gap',
|
349
|
+
'grid-column-gap',
|
350
|
+
'grid-column-end',
|
351
|
+
'grid-row-gap',
|
352
|
+
]);
|
353
|
+
}
|
354
|
+
|
355
|
+
isRuleValid(computedStyles: Map<String, String>|null): boolean {
|
356
|
+
if (computedStyles === null) {
|
357
|
+
return true;
|
358
|
+
}
|
359
|
+
return isMulticolContainer(computedStyles) || isFlexContainer(computedStyles) || isGridContainer(computedStyles);
|
360
|
+
}
|
361
|
+
|
362
|
+
getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
|
363
|
+
const reasonRuleCode = buildStyledRuleText('display', computedStyles?.get('display'));
|
364
|
+
const affectedRuleCode = buildStyledPropertyText(property);
|
365
|
+
|
366
|
+
return new AuthoringHint(
|
367
|
+
property,
|
368
|
+
AuthoringHintType.RULE_VALIDATION,
|
369
|
+
i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
|
370
|
+
'REASON_RULE_CODE': reasonRuleCode,
|
371
|
+
'AFFECTED_RULE_CODE': affectedRuleCode,
|
372
|
+
}),
|
373
|
+
i18nString(UIStrings.ruleViolatedBySameElementRuleFix, {
|
374
|
+
'REASON_RULE_CODE': reasonRuleCode,
|
375
|
+
}),
|
376
|
+
true,
|
377
|
+
);
|
378
|
+
}
|
379
|
+
}
|
380
|
+
|
381
|
+
export class PaddingValidator extends CSSRuleValidator {
|
382
|
+
constructor() {
|
383
|
+
super([
|
384
|
+
'padding',
|
385
|
+
'padding-top',
|
386
|
+
'padding-right',
|
387
|
+
'padding-bottom',
|
388
|
+
'padding-left',
|
389
|
+
]);
|
390
|
+
}
|
391
|
+
|
392
|
+
isRuleValid(computedStyles: Map<String, String>|null): boolean {
|
393
|
+
const display = computedStyles?.get('display');
|
394
|
+
if (display === null || display === undefined) {
|
395
|
+
return true;
|
396
|
+
}
|
397
|
+
return !['table-row-group', 'table-header-group', 'table-footer-group', 'table-row', 'table-column-group',
|
398
|
+
'table-column']
|
399
|
+
.includes(display as string);
|
400
|
+
}
|
401
|
+
|
402
|
+
getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
|
403
|
+
const reasonRuleCode = buildStyledRuleText('display', computedStyles?.get('display'));
|
404
|
+
const affectedRuleCode = buildStyledPropertyText(property);
|
405
|
+
|
406
|
+
return new AuthoringHint(
|
407
|
+
property,
|
408
|
+
AuthoringHintType.RULE_VALIDATION,
|
409
|
+
i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
|
410
|
+
'REASON_RULE_CODE': reasonRuleCode,
|
411
|
+
'AFFECTED_RULE_CODE': affectedRuleCode,
|
412
|
+
}),
|
413
|
+
i18nString(UIStrings.ruleViolatedBySameElementRuleFix, {
|
414
|
+
'REASON_RULE_CODE': reasonRuleCode,
|
415
|
+
}),
|
416
|
+
true,
|
417
|
+
);
|
418
|
+
}
|
419
|
+
}
|
172
420
|
|
421
|
+
export class PositionValidator extends CSSRuleValidator {
|
422
|
+
constructor() {
|
423
|
+
super([
|
424
|
+
'top',
|
425
|
+
'right',
|
426
|
+
'bottom',
|
427
|
+
'left',
|
428
|
+
]);
|
429
|
+
}
|
430
|
+
|
431
|
+
isRuleValid(computedStyles: Map<String, String>|null): boolean {
|
432
|
+
const position = computedStyles?.get('position');
|
433
|
+
if (position === null || position === undefined) {
|
434
|
+
return true;
|
435
|
+
}
|
436
|
+
return position !== 'static';
|
437
|
+
}
|
438
|
+
|
439
|
+
getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
|
440
|
+
const reasonRuleCode = buildStyledRuleText('position', computedStyles?.get('position'));
|
441
|
+
const affectedRuleCode = buildStyledPropertyText(property);
|
442
|
+
|
443
|
+
return new AuthoringHint(
|
444
|
+
property,
|
445
|
+
AuthoringHintType.RULE_VALIDATION,
|
446
|
+
i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
|
447
|
+
'REASON_RULE_CODE': reasonRuleCode,
|
448
|
+
'AFFECTED_RULE_CODE': affectedRuleCode,
|
449
|
+
}),
|
450
|
+
i18nString(UIStrings.ruleViolatedBySameElementRuleFix, {
|
451
|
+
'REASON_RULE_CODE': reasonRuleCode,
|
452
|
+
}),
|
453
|
+
true,
|
454
|
+
);
|
455
|
+
}
|
456
|
+
}
|
457
|
+
|
458
|
+
export class ZIndexValidator extends CSSRuleValidator {
|
459
|
+
constructor() {
|
460
|
+
super([
|
461
|
+
'z-index',
|
462
|
+
]);
|
463
|
+
}
|
464
|
+
|
465
|
+
isRuleValid(computedStyles: Map<String, String>|null, parentComputedStyles: Map<String, String>|null): boolean {
|
466
|
+
const position = computedStyles?.get('position');
|
467
|
+
if (position === null || position === undefined) {
|
468
|
+
return true;
|
469
|
+
}
|
470
|
+
return ['absolute', 'relative', 'fixed', 'sticky'].includes(position as string) ||
|
471
|
+
isFlexContainer(parentComputedStyles);
|
472
|
+
}
|
473
|
+
|
474
|
+
getAuthoringHint(property: string, computedStyles: Map<String, String>|null): AuthoringHint {
|
475
|
+
const reasonRuleCode = buildStyledRuleText('position', computedStyles?.get('position'));
|
476
|
+
const affectedRuleCode = buildStyledPropertyText(property);
|
477
|
+
|
478
|
+
return new AuthoringHint(
|
479
|
+
property,
|
480
|
+
AuthoringHintType.RULE_VALIDATION,
|
481
|
+
i18nString(UIStrings.ruleViolatedBySameElementRuleReason, {
|
482
|
+
'REASON_RULE_CODE': reasonRuleCode,
|
483
|
+
'AFFECTED_RULE_CODE': affectedRuleCode,
|
484
|
+
}),
|
485
|
+
i18nString(UIStrings.ruleViolatedBySameElementRuleFix, {
|
486
|
+
'REASON_RULE_CODE': reasonRuleCode,
|
487
|
+
}),
|
488
|
+
true,
|
489
|
+
);
|
490
|
+
}
|
491
|
+
}
|
492
|
+
|
493
|
+
const CSS_RULE_VALIDATORS = [
|
494
|
+
AlignContentValidator,
|
495
|
+
FlexItemValidator,
|
496
|
+
FlexContainerValidator,
|
497
|
+
GridContainerValidator,
|
498
|
+
GridItemValidator,
|
499
|
+
FlexGridValidator,
|
500
|
+
MulticolFlexGridValidator,
|
501
|
+
PaddingValidator,
|
502
|
+
PositionValidator,
|
503
|
+
ZIndexValidator,
|
504
|
+
];
|
505
|
+
|
506
|
+
const setupCSSRulesValidators = (): Map<String, CSSRuleValidator[]> => {
|
173
507
|
const validatorsMap = new Map<String, CSSRuleValidator[]>();
|
174
|
-
for (const
|
508
|
+
for (const validatorClass of CSS_RULE_VALIDATORS) {
|
509
|
+
const validator = new validatorClass();
|
175
510
|
const affectedProperties = validator.getAffectedProperties();
|
176
511
|
|
177
512
|
for (const affectedProperty of affectedProperties) {
|
@@ -0,0 +1,34 @@
|
|
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
|
+
export const buildStyledRuleText = (property: String, value: String|undefined): string => {
|
6
|
+
if (value === undefined) {
|
7
|
+
return buildStyledPropertyText(property);
|
8
|
+
}
|
9
|
+
return '<code class="unbreakable-text"><span class="property">' + property + '</span>: ' + value + '</code>';
|
10
|
+
};
|
11
|
+
|
12
|
+
export const buildStyledPropertyText = (property: String): string => {
|
13
|
+
return '<code class="unbreakable-text"><span class="property">' + property + '</span></code>';
|
14
|
+
};
|
15
|
+
|
16
|
+
export const isFlexContainer = (computedStyles: Map<String, String>|null): boolean => {
|
17
|
+
if (computedStyles === null) {
|
18
|
+
return false;
|
19
|
+
}
|
20
|
+
const display = computedStyles.get('display');
|
21
|
+
return display === 'flex' || display === 'inline-flex';
|
22
|
+
};
|
23
|
+
|
24
|
+
export const isGridContainer = (computedStyles: Map<String, String>): boolean => {
|
25
|
+
const display = computedStyles.get('display');
|
26
|
+
return display === 'grid' || display === 'inline-grid';
|
27
|
+
};
|
28
|
+
|
29
|
+
export const isMulticolContainer = (computedStyles: Map<String, String>): boolean => {
|
30
|
+
const columnWidth = computedStyles.get('column-width');
|
31
|
+
const columnCount = computedStyles.get('column-count');
|
32
|
+
|
33
|
+
return columnWidth !== 'auto' || columnCount !== 'auto';
|
34
|
+
};
|
@@ -827,7 +827,7 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
827
827
|
|
828
828
|
for (const validator of cssRuleValidatorsMap.get(propertyName) || []) {
|
829
829
|
if (!validator.isRuleValid(computedStyles, parentComputedStyles)) {
|
830
|
-
return validator.getAuthoringHint(propertyName, this.parentsComputedStyles);
|
830
|
+
return validator.getAuthoringHint(propertyName, this.computedStyles, this.parentsComputedStyles);
|
831
831
|
}
|
832
832
|
}
|
833
833
|
|
@@ -27,17 +27,12 @@ details[open] .header-count {
|
|
27
27
|
display: none;
|
28
28
|
}
|
29
29
|
|
30
|
-
details
|
30
|
+
details .hide-when-closed {
|
31
31
|
display: none;
|
32
32
|
}
|
33
33
|
|
34
|
-
details[open]
|
35
|
-
display:
|
36
|
-
gap: 2px;
|
37
|
-
}
|
38
|
-
|
39
|
-
.raw-checkbox-container {
|
40
|
-
float: right;
|
34
|
+
details[open] .hide-when-closed {
|
35
|
+
display: block;
|
41
36
|
}
|
42
37
|
|
43
38
|
details summary input {
|
@@ -175,3 +170,40 @@ div.raw-headers-row {
|
|
175
170
|
font-size: 90%;
|
176
171
|
color: var(--color-text-secondary);
|
177
172
|
}
|
173
|
+
|
174
|
+
.header-grid-container {
|
175
|
+
display: inline-grid;
|
176
|
+
grid-template-columns: 156px 50px 1fr;
|
177
|
+
grid-gap: 4px;
|
178
|
+
/* Make this fit into the same line as the summary marker */
|
179
|
+
width: calc(100% - 15px);
|
180
|
+
}
|
181
|
+
|
182
|
+
.header-grid-container div:last-child {
|
183
|
+
text-align: right;
|
184
|
+
}
|
185
|
+
|
186
|
+
.header .devtools-link {
|
187
|
+
color: var(--color-text-primary);
|
188
|
+
}
|
189
|
+
|
190
|
+
x-link .inline-icon { /* stylelint-disable-line selector-type-no-unknown */
|
191
|
+
padding-right: 3px;
|
192
|
+
}
|
193
|
+
|
194
|
+
.purple-dot {
|
195
|
+
filter: hue-rotate(160deg);
|
196
|
+
}
|
197
|
+
|
198
|
+
.-theme-with-dark-background .purple-dot,
|
199
|
+
:host-context(.-theme-with-dark-background) .purple-dot {
|
200
|
+
filter: invert(80%) hue-rotate(350deg);
|
201
|
+
}
|
202
|
+
|
203
|
+
summary label {
|
204
|
+
color: var(--color-text-secondary);
|
205
|
+
}
|
206
|
+
|
207
|
+
summary label:hover {
|
208
|
+
color: var(--color-text-primary);
|
209
|
+
}
|
@@ -6,9 +6,12 @@ import * as Common from '../../../core/common/common.js';
|
|
6
6
|
import * as Host from '../../../core/host/host.js';
|
7
7
|
import * as i18n from '../../../core/i18n/i18n.js';
|
8
8
|
import * as Platform from '../../../core/platform/platform.js';
|
9
|
+
import * as Root from '../../../core/root/root.js';
|
9
10
|
import * as SDK from '../../../core/sdk/sdk.js';
|
10
11
|
import * as Protocol from '../../../generated/protocol.js';
|
11
12
|
import * as IssuesManager from '../../../models/issues_manager/issues_manager.js';
|
13
|
+
import * as Persistence from '../../../models/persistence/persistence.js';
|
14
|
+
import * as Workspace from '../../../models/workspace/workspace.js';
|
12
15
|
import * as ClientVariations from '../../../third_party/chromium/client-variations/client-variations.js';
|
13
16
|
import * as Buttons from '../../../ui/components/buttons/buttons.js';
|
14
17
|
import * as ComponentHelpers from '../../../ui/components/helpers/helpers.js';
|
@@ -16,6 +19,7 @@ import * as IconButton from '../../../ui/components/icon_button/icon_button.js';
|
|
16
19
|
import * as Input from '../../../ui/components/input/input.js';
|
17
20
|
import * as UI from '../../../ui/legacy/legacy.js';
|
18
21
|
import * as LitHtml from '../../../ui/lit-html/lit-html.js';
|
22
|
+
import * as Sources from '../../sources/sources.js';
|
19
23
|
|
20
24
|
import requestHeadersViewStyles from './RequestHeadersView.css.js';
|
21
25
|
|
@@ -69,6 +73,11 @@ const UIStrings = {
|
|
69
73
|
*/
|
70
74
|
general: 'General',
|
71
75
|
/**
|
76
|
+
*@description Label for a link from the network panel's headers view to the file in which
|
77
|
+
* header overrides are defined in the sources panel.
|
78
|
+
*/
|
79
|
+
headerOverrides: 'Header overrides',
|
80
|
+
/**
|
72
81
|
*@description Text that is usually a hyperlink to more documentation
|
73
82
|
*/
|
74
83
|
learnMore: 'Learn more',
|
@@ -204,6 +213,7 @@ export class RequestHeadersComponent extends HTMLElement {
|
|
204
213
|
#showRequestHeadersText = false;
|
205
214
|
#showResponseHeadersTextFull = false;
|
206
215
|
#showRequestHeadersTextFull = false;
|
216
|
+
readonly #workspace = Workspace.Workspace.WorkspaceImpl.instance();
|
207
217
|
|
208
218
|
set data(data: RequestHeadersComponentData) {
|
209
219
|
this.#request = data.request;
|
@@ -212,6 +222,23 @@ export class RequestHeadersComponent extends HTMLElement {
|
|
212
222
|
|
213
223
|
connectedCallback(): void {
|
214
224
|
this.#shadow.adoptedStyleSheets = [requestHeadersViewStyles];
|
225
|
+
this.#workspace.addEventListener(
|
226
|
+
Workspace.Workspace.Events.UISourceCodeAdded, this.#uiSourceCodeAddedOrRemoved, this);
|
227
|
+
this.#workspace.addEventListener(
|
228
|
+
Workspace.Workspace.Events.UISourceCodeRemoved, this.#uiSourceCodeAddedOrRemoved, this);
|
229
|
+
}
|
230
|
+
|
231
|
+
disconnectedCallback(): void {
|
232
|
+
this.#workspace.removeEventListener(
|
233
|
+
Workspace.Workspace.Events.UISourceCodeAdded, this.#uiSourceCodeAddedOrRemoved, this);
|
234
|
+
this.#workspace.removeEventListener(
|
235
|
+
Workspace.Workspace.Events.UISourceCodeRemoved, this.#uiSourceCodeAddedOrRemoved, this);
|
236
|
+
}
|
237
|
+
|
238
|
+
#uiSourceCodeAddedOrRemoved(event: Common.EventTarget.EventTargetEvent<Workspace.UISourceCode.UISourceCode>): void {
|
239
|
+
if (this.#getHeaderOverridesFileUrl() === event.data.url()) {
|
240
|
+
this.#render();
|
241
|
+
}
|
215
242
|
}
|
216
243
|
|
217
244
|
#render(): void {
|
@@ -294,6 +321,7 @@ export class RequestHeadersComponent extends HTMLElement {
|
|
294
321
|
title: i18nString(UIStrings.responseHeaders),
|
295
322
|
headerCount: this.#request.sortedResponseHeaders.length,
|
296
323
|
checked: this.#request.responseHeadersText ? this.#showResponseHeadersText : undefined,
|
324
|
+
additionalContent: this.#renderHeaderOverridesLink(),
|
297
325
|
} as CategoryData}
|
298
326
|
aria-label=${i18nString(UIStrings.responseHeaders)}
|
299
327
|
>
|
@@ -306,6 +334,57 @@ export class RequestHeadersComponent extends HTMLElement {
|
|
306
334
|
// clang-format on
|
307
335
|
}
|
308
336
|
|
337
|
+
#renderHeaderOverridesLink(): LitHtml.LitTemplate {
|
338
|
+
const overrideable = Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.HEADER_OVERRIDES);
|
339
|
+
if (!overrideable || !this.#workspace.uiSourceCodeForURL(this.#getHeaderOverridesFileUrl())) {
|
340
|
+
return LitHtml.nothing;
|
341
|
+
}
|
342
|
+
|
343
|
+
const overridesSetting: Common.Settings.Setting<boolean> =
|
344
|
+
Common.Settings.Settings.instance().moduleSetting('persistenceNetworkOverridesEnabled');
|
345
|
+
// Disabled until https://crbug.com/1079231 is fixed.
|
346
|
+
// clang-format off
|
347
|
+
const fileIcon = overridesSetting.get() ? html`
|
348
|
+
<${IconButton.Icon.Icon.litTagName} class="inline-icon purple-dot" .data=${{
|
349
|
+
iconName: 'file-sync_icon',
|
350
|
+
width: '11px',
|
351
|
+
height: '13px',
|
352
|
+
} as IconButton.Icon.IconData}>
|
353
|
+
</${IconButton.Icon.Icon.litTagName}>` : html`
|
354
|
+
<${IconButton.Icon.Icon.litTagName} class="inline-icon" .data=${{
|
355
|
+
iconName: 'file_icon',
|
356
|
+
color: 'var(--color-text-primary)',
|
357
|
+
width: '12px',
|
358
|
+
height: '12px',
|
359
|
+
} as IconButton.Icon.IconData}>
|
360
|
+
</${IconButton.Icon.Icon.litTagName}>`;
|
361
|
+
// clang-format on
|
362
|
+
|
363
|
+
const revealHeadersFile = (event: Event): void => {
|
364
|
+
event.preventDefault();
|
365
|
+
const uiSourceCode = this.#workspace.uiSourceCodeForURL(this.#getHeaderOverridesFileUrl());
|
366
|
+
if (uiSourceCode) {
|
367
|
+
Sources.SourcesPanel.SourcesPanel.instance().showUISourceCode(uiSourceCode);
|
368
|
+
}
|
369
|
+
};
|
370
|
+
|
371
|
+
return html`
|
372
|
+
<x-link @click=${revealHeadersFile} class="link devtools-link">
|
373
|
+
${fileIcon}${i18nString(UIStrings.headerOverrides)}
|
374
|
+
</x-link>
|
375
|
+
`;
|
376
|
+
}
|
377
|
+
|
378
|
+
#getHeaderOverridesFileUrl(): Platform.DevToolsPath.UrlString {
|
379
|
+
if (!this.#request) {
|
380
|
+
return Platform.DevToolsPath.EmptyUrlString;
|
381
|
+
}
|
382
|
+
const fileUrl = Persistence.NetworkPersistenceManager.NetworkPersistenceManager.instance().fileUrlFromNetworkUrl(
|
383
|
+
this.#request.url(), /* ignoreInactive */ true);
|
384
|
+
return fileUrl.substring(0, fileUrl.lastIndexOf('/')) + '/' +
|
385
|
+
Persistence.NetworkPersistenceManager.HEADERS_FILENAME as Platform.DevToolsPath.UrlString;
|
386
|
+
}
|
387
|
+
|
309
388
|
#renderRequestHeaders(): LitHtml.LitTemplate {
|
310
389
|
if (!this.#request) {
|
311
390
|
return LitHtml.nothing;
|
@@ -647,6 +726,7 @@ export interface CategoryData {
|
|
647
726
|
title: Common.UIString.LocalizedString;
|
648
727
|
headerCount?: number;
|
649
728
|
checked?: boolean;
|
729
|
+
additionalContent?: LitHtml.LitTemplate;
|
650
730
|
}
|
651
731
|
|
652
732
|
export class Category extends HTMLElement {
|
@@ -656,6 +736,7 @@ export class Category extends HTMLElement {
|
|
656
736
|
#title: Common.UIString.LocalizedString = Common.UIString.LocalizedEmptyString;
|
657
737
|
#headerCount?: number = undefined;
|
658
738
|
#checked: boolean|undefined = undefined;
|
739
|
+
#additionalContent: LitHtml.LitTemplate|undefined = undefined;
|
659
740
|
|
660
741
|
connectedCallback(): void {
|
661
742
|
this.#shadow.adoptedStyleSheets = [requestHeadersViewStyles, Input.checkboxStyles];
|
@@ -667,6 +748,7 @@ export class Category extends HTMLElement {
|
|
667
748
|
Common.Settings.Settings.instance().createSetting('request-info-' + data.name + '-category-expanded', true);
|
668
749
|
this.#headerCount = data.headerCount;
|
669
750
|
this.#checked = data.checked;
|
751
|
+
this.#additionalContent = data.additionalContent;
|
670
752
|
this.#render();
|
671
753
|
}
|
672
754
|
|
@@ -681,18 +763,19 @@ export class Category extends HTMLElement {
|
|
681
763
|
render(html`
|
682
764
|
<details ?open=${isOpen} @toggle=${this.#onToggle}>
|
683
765
|
<summary class="header" @keydown=${this.#onSummaryKeyDown}>
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
766
|
+
<div class="header-grid-container">
|
767
|
+
<div>
|
768
|
+
${this.#title}${this.#headerCount ?
|
769
|
+
html`<span class="header-count"> (${this.#headerCount})</span>` :
|
770
|
+
LitHtml.nothing
|
771
|
+
}
|
772
|
+
</div>
|
773
|
+
<div class="hide-when-closed">
|
774
|
+
${this.#checked !== undefined ? html`
|
775
|
+
<label><input type="checkbox" .checked=${this.#checked} @change=${this.#onCheckboxToggle} />${i18nString(UIStrings.raw)}</label>
|
776
|
+
` : LitHtml.nothing}
|
777
|
+
</div>
|
778
|
+
<div class="hide-when-closed">${this.#additionalContent}</div>
|
696
779
|
</summary>
|
697
780
|
<slot></slot>
|
698
781
|
</details>
|
@@ -58,6 +58,7 @@ export interface DataGridData {
|
|
58
58
|
activeSort: SortState|null;
|
59
59
|
contextMenus?: DataGridContextMenusConfiguration;
|
60
60
|
label?: string;
|
61
|
+
paddingRowsCount?: number;
|
61
62
|
}
|
62
63
|
|
63
64
|
const enum UserScrollState {
|
@@ -69,7 +70,6 @@ const enum UserScrollState {
|
|
69
70
|
const KEYS_TREATED_AS_CLICKS = new Set([' ', 'Enter']);
|
70
71
|
|
71
72
|
const ROW_HEIGHT_PIXELS = 18;
|
72
|
-
const PADDING_ROWS_COUNT = 10;
|
73
73
|
|
74
74
|
export class DataGrid extends HTMLElement {
|
75
75
|
static readonly litTagName = LitHtml.literal`devtools-data-grid`;
|
@@ -82,6 +82,7 @@ export class DataGrid extends HTMLElement {
|
|
82
82
|
#userScrollState: UserScrollState = UserScrollState.NOT_SCROLLED;
|
83
83
|
#contextMenus?: DataGridContextMenusConfiguration = undefined;
|
84
84
|
#label?: string = undefined;
|
85
|
+
#paddingRowsCount = 10;
|
85
86
|
#currentResize: {
|
86
87
|
rightCellCol: HTMLTableColElement,
|
87
88
|
leftCellCol: HTMLTableColElement,
|
@@ -139,6 +140,7 @@ export class DataGrid extends HTMLElement {
|
|
139
140
|
activeSort: this.#sortState,
|
140
141
|
contextMenus: this.#contextMenus,
|
141
142
|
label: this.#label,
|
143
|
+
paddingRowsCount: this.#paddingRowsCount,
|
142
144
|
};
|
143
145
|
}
|
144
146
|
|
@@ -171,6 +173,10 @@ export class DataGrid extends HTMLElement {
|
|
171
173
|
this.#cellToFocusIfUserTabsIn = calculateFirstFocusableCell({columns: this.#columns, rows: this.#rows});
|
172
174
|
}
|
173
175
|
|
176
|
+
if (data.paddingRowsCount !== undefined) {
|
177
|
+
this.#paddingRowsCount = data.paddingRowsCount;
|
178
|
+
}
|
179
|
+
|
174
180
|
if (this.#hasRenderedAtLeastOnce && this.#userHasCellFocused()) {
|
175
181
|
const [selectedColIndex, selectedRowIndex] = this.#tabbableCell();
|
176
182
|
const columnOutOfBounds = selectedColIndex > this.#columns.length;
|
@@ -220,15 +226,14 @@ export class DataGrid extends HTMLElement {
|
|
220
226
|
return;
|
221
227
|
}
|
222
228
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
229
|
+
const wrapper = this.#shadow.querySelector('.wrapping-container');
|
230
|
+
if (!wrapper) {
|
231
|
+
return;
|
232
|
+
}
|
233
|
+
|
234
|
+
void coordinator.scroll(() => {
|
228
235
|
const scrollHeight = wrapper.scrollHeight;
|
229
|
-
|
230
|
-
wrapper.scrollTo(0, scrollHeight);
|
231
|
-
});
|
236
|
+
wrapper.scrollTo(0, scrollHeight);
|
232
237
|
});
|
233
238
|
}
|
234
239
|
|
@@ -643,7 +648,7 @@ export class DataGrid extends HTMLElement {
|
|
643
648
|
scrollTop = wrapper.scrollTop;
|
644
649
|
clientHeight = wrapper.clientHeight;
|
645
650
|
}
|
646
|
-
const padding = ROW_HEIGHT_PIXELS *
|
651
|
+
const padding = ROW_HEIGHT_PIXELS * this.#paddingRowsCount;
|
647
652
|
let topVisibleRow = Math.floor((scrollTop - padding) / ROW_HEIGHT_PIXELS);
|
648
653
|
let bottomVisibleRow = Math.ceil((scrollTop + clientHeight + padding) / ROW_HEIGHT_PIXELS);
|
649
654
|
|
@@ -31,6 +31,7 @@ export interface DataGridControllerData {
|
|
31
31
|
initialSort?: SortState;
|
32
32
|
contextMenus?: DataGridContextMenusConfiguration;
|
33
33
|
label?: string;
|
34
|
+
paddingRowsCount?: number;
|
34
35
|
}
|
35
36
|
|
36
37
|
export class DataGridController extends HTMLElement {
|
@@ -55,6 +56,8 @@ export class DataGridController extends HTMLElement {
|
|
55
56
|
#sortState: Readonly<SortState>|null = null;
|
56
57
|
#filters: readonly TextUtils.TextUtils.ParsedFilter[] = [];
|
57
58
|
|
59
|
+
#paddingRowsCount?: number;
|
60
|
+
|
58
61
|
connectedCallback(): void {
|
59
62
|
this.#shadow.adoptedStyleSheets = [dataGridControllerStyles];
|
60
63
|
}
|
@@ -66,6 +69,7 @@ export class DataGridController extends HTMLElement {
|
|
66
69
|
filters: this.#filters,
|
67
70
|
contextMenus: this.#contextMenus,
|
68
71
|
label: this.#label,
|
72
|
+
paddingRowsCount: this.#paddingRowsCount,
|
69
73
|
};
|
70
74
|
}
|
71
75
|
|
@@ -88,6 +92,8 @@ export class DataGridController extends HTMLElement {
|
|
88
92
|
this.#sortRows(this.#sortState);
|
89
93
|
}
|
90
94
|
|
95
|
+
this.#paddingRowsCount = data.paddingRowsCount;
|
96
|
+
|
91
97
|
this.#render();
|
92
98
|
}
|
93
99
|
|
@@ -222,6 +228,7 @@ export class DataGridController extends HTMLElement {
|
|
222
228
|
activeSort: this.#sortState,
|
223
229
|
contextMenus: this.#contextMenus,
|
224
230
|
label: this.#label,
|
231
|
+
paddingRowsCount: this.#paddingRowsCount,
|
225
232
|
} as DataGridData}
|
226
233
|
@columnheaderclick=${this.#onColumnHeaderClick}
|
227
234
|
@contextmenucolumnsortclick=${this.#onContextMenuColumnSortClick}
|
package/package.json
CHANGED
@@ -19,12 +19,13 @@
|
|
19
19
|
"url": "git+https://github.com/ChromeDevTools/devtools-frontend.git"
|
20
20
|
},
|
21
21
|
"scripts": {
|
22
|
-
"auto-debug-e2etest": "
|
23
|
-
"auto-debug-interactionstest": "
|
22
|
+
"auto-debug-e2etest": "npm run build && npm run debug-e2etest --",
|
23
|
+
"auto-debug-interactionstest": "npm run build && npm run debug-interactionstest --",
|
24
24
|
"auto-debug-unittest": "DEBUG_TEST=1 npm run auto-unittest --",
|
25
|
-
"auto-e2etest": "
|
26
|
-
"auto-interactionstest": "
|
25
|
+
"auto-e2etest": "npm run build && npm run e2etest --",
|
26
|
+
"auto-interactionstest": "npm run build && npm run interactionstest --",
|
27
27
|
"auto-unittest": "scripts/test/run_auto_unittests.py --no-text-coverage",
|
28
|
+
"prebuild": "gn gen out/Default",
|
28
29
|
"build": "autoninja -C out/Default",
|
29
30
|
"build-release": "autoninja -C out/Release",
|
30
31
|
"check": "npm run check-lint && npm run check-loc",
|
@@ -55,5 +56,5 @@
|
|
55
56
|
"unittest": "scripts/test/run_unittests.py --no-text-coverage",
|
56
57
|
"watch": "vpython third_party/node/node.py --output scripts/watch_build.js"
|
57
58
|
},
|
58
|
-
"version": "1.0.
|
59
|
+
"version": "1.0.1030457"
|
59
60
|
}
|