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.
@@ -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",
@@ -66,6 +66,8 @@ devtools_svg_sources = [
66
66
  "errorWave.svg",
67
67
  "error_icon.svg",
68
68
  "feedback_button_icon.svg",
69
+ "file-sync_icon.svg",
70
+ "file_icon.svg",
69
71
  "flex-direction-icon.svg",
70
72
  "flex-nowrap-icon.svg",
71
73
  "flex-wrap-icon.svg",
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 TODO(crbug.com/1318882): Description needed for translation
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: 'This element has {REASON_RULE_CODE} rule, therefore {AFFECTED_RULE_CODE} has no effect.',
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: 'For this property to work, please remove or change the value of {REASON_RULE_CODE}',
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: 'Parent element has {REASON_RULE_CODE} rule, therefore this elements {AFFECTED_RULE_CODE} has no effect',
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: 'Please change parent elements {EXISTING_PARENT_ELEMENT_RULE} to {TARGET_PARENT_ELEMENT_RULE} to fix this issue.',
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(propertyName: string, parentComputedStyles: Map<String, String>|null): AuthoringHint;
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
- const display = computedStyles.get('display');
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 = '<code class="unbreakable-text"><span class="property">flex-wrap</span>: nowrap</code>';
118
- const affectedRuleCode = '<code class="unbreakable-text"><span class="property">align-content</span></code>';
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 (computedStyles === null || computedStyles === undefined || parentsComputedStyles === null ||
142
- parentsComputedStyles === undefined) {
161
+ if (parentsComputedStyles === null) {
143
162
  return true;
144
163
  }
145
- const parentDisplay = parentsComputedStyles.get('display');
146
- return parentDisplay === 'flex' || parentDisplay === 'inline-flex';
164
+ return isFlexContainer(parentsComputedStyles);
147
165
  }
148
166
 
149
- getAuthoringHint(property: string, parentsComputedStyles: Map<String, String>|null): AuthoringHint {
150
- const reasonRuleCode = '<code class="unbreakable-text"><span class="property">display</span>:' + parentsComputedStyles?.get('display') + '</code>';
151
- const affectedRuleCode = '<code class="unbreakable-text"><span class="property">' + property + '</span></code>';
152
- const targetParentRuleCode = '<code class="unbreakable-text"><span class="property">display</span>: flex</code>';
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
- const setupCSSRulesValidators = (): Map<String, CSSRuleValidator[]> => {
171
- const validators = [new AlignContentValidator(), new FlexItemValidator()];
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 validator of validators) {
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 summary label {
30
+ details .hide-when-closed {
31
31
  display: none;
32
32
  }
33
33
 
34
- details[open] summary label {
35
- display: inline-flex;
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
- ${this.#title}${this.#headerCount ?
685
- html`<span class="header-count"> (${this.#headerCount})</span>` :
686
- LitHtml.nothing
687
- }
688
- ${this.#checked !== undefined ? html`
689
- <span class="raw-checkbox-container">
690
- <label>
691
- <input type="checkbox" .checked=${this.#checked} @change=${this.#onCheckboxToggle} />
692
- ${i18nString(UIStrings.raw)}
693
- </label>
694
- </span>
695
- ` : LitHtml.nothing}
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>
@@ -164,6 +164,7 @@ export class ProtocolMonitorImpl extends UI.Widget.VBox {
164
164
  this.infoWidget = new InfoWidget();
165
165
 
166
166
  const dataGridInitialData: DataGrid.DataGridController.DataGridControllerData = {
167
+ paddingRowsCount: 100,
167
168
  columns: [
168
169
  {
169
170
  id: 'type',
@@ -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
- void coordinator.read(() => {
224
- const wrapper = this.#shadow.querySelector('.wrapping-container');
225
- if (!wrapper) {
226
- return;
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
- void coordinator.scroll(() => {
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 * PADDING_ROWS_COUNT;
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": "autoninja -C out/Default && npm run debug-e2etest --",
23
- "auto-debug-interactionstest": "autoninja -C out/Default && npm run 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": "autoninja -C out/Default && npm run e2etest --",
26
- "auto-interactionstest": "autoninja -C out/Default && npm run 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.1030070"
59
+ "version": "1.0.1030457"
59
60
  }