chrome-devtools-frontend 1.0.976172 → 1.0.977567

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.
Files changed (120) hide show
  1. package/config/gni/devtools_grd_files.gni +6 -1
  2. package/config/gni/devtools_image_files.gni +2 -0
  3. package/front_end/Images/src/minus_icon.svg +3 -0
  4. package/front_end/Images/src/plus_icon.svg +3 -0
  5. package/front_end/core/host/UserMetrics.ts +23 -23
  6. package/front_end/core/i18n/locales/af.json +5 -5
  7. package/front_end/core/i18n/locales/am.json +5 -5
  8. package/front_end/core/i18n/locales/ar.json +5 -5
  9. package/front_end/core/i18n/locales/as.json +5 -5
  10. package/front_end/core/i18n/locales/az.json +5 -5
  11. package/front_end/core/i18n/locales/be.json +5 -5
  12. package/front_end/core/i18n/locales/bg.json +5 -5
  13. package/front_end/core/i18n/locales/bn.json +5 -5
  14. package/front_end/core/i18n/locales/bs.json +5 -5
  15. package/front_end/core/i18n/locales/ca.json +5 -5
  16. package/front_end/core/i18n/locales/cs.json +5 -5
  17. package/front_end/core/i18n/locales/cy.json +5 -5
  18. package/front_end/core/i18n/locales/da.json +5 -5
  19. package/front_end/core/i18n/locales/de.json +5 -5
  20. package/front_end/core/i18n/locales/el.json +5 -5
  21. package/front_end/core/i18n/locales/en-GB.json +5 -5
  22. package/front_end/core/i18n/locales/en-US.json +24 -15
  23. package/front_end/core/i18n/locales/en-XL.json +24 -15
  24. package/front_end/core/i18n/locales/es-419.json +5 -5
  25. package/front_end/core/i18n/locales/es.json +5 -5
  26. package/front_end/core/i18n/locales/et.json +5 -5
  27. package/front_end/core/i18n/locales/eu.json +5 -5
  28. package/front_end/core/i18n/locales/fa.json +5 -5
  29. package/front_end/core/i18n/locales/fi.json +5 -5
  30. package/front_end/core/i18n/locales/fil.json +5 -5
  31. package/front_end/core/i18n/locales/fr-CA.json +5 -5
  32. package/front_end/core/i18n/locales/fr.json +5 -5
  33. package/front_end/core/i18n/locales/gl.json +5 -5
  34. package/front_end/core/i18n/locales/gu.json +5 -5
  35. package/front_end/core/i18n/locales/he.json +5 -5
  36. package/front_end/core/i18n/locales/hi.json +5 -5
  37. package/front_end/core/i18n/locales/hr.json +5 -5
  38. package/front_end/core/i18n/locales/hu.json +5 -5
  39. package/front_end/core/i18n/locales/hy.json +5 -5
  40. package/front_end/core/i18n/locales/id.json +5 -5
  41. package/front_end/core/i18n/locales/is.json +5 -5
  42. package/front_end/core/i18n/locales/it.json +5 -5
  43. package/front_end/core/i18n/locales/ja.json +5 -5
  44. package/front_end/core/i18n/locales/ka.json +5 -5
  45. package/front_end/core/i18n/locales/kk.json +5 -5
  46. package/front_end/core/i18n/locales/km.json +5 -5
  47. package/front_end/core/i18n/locales/kn.json +5 -5
  48. package/front_end/core/i18n/locales/ko.json +5 -5
  49. package/front_end/core/i18n/locales/ky.json +5 -5
  50. package/front_end/core/i18n/locales/lo.json +5 -5
  51. package/front_end/core/i18n/locales/lt.json +5 -5
  52. package/front_end/core/i18n/locales/lv.json +5 -5
  53. package/front_end/core/i18n/locales/mk.json +5 -5
  54. package/front_end/core/i18n/locales/ml.json +5 -5
  55. package/front_end/core/i18n/locales/mn.json +5 -5
  56. package/front_end/core/i18n/locales/mr.json +5 -5
  57. package/front_end/core/i18n/locales/ms.json +5 -5
  58. package/front_end/core/i18n/locales/my.json +5 -5
  59. package/front_end/core/i18n/locales/ne.json +5 -5
  60. package/front_end/core/i18n/locales/nl.json +5 -5
  61. package/front_end/core/i18n/locales/no.json +5 -5
  62. package/front_end/core/i18n/locales/or.json +5 -5
  63. package/front_end/core/i18n/locales/pa.json +5 -5
  64. package/front_end/core/i18n/locales/pl.json +5 -5
  65. package/front_end/core/i18n/locales/pt-PT.json +5 -5
  66. package/front_end/core/i18n/locales/pt.json +5 -5
  67. package/front_end/core/i18n/locales/ro.json +5 -5
  68. package/front_end/core/i18n/locales/ru.json +5 -5
  69. package/front_end/core/i18n/locales/si.json +5 -5
  70. package/front_end/core/i18n/locales/sk.json +5 -5
  71. package/front_end/core/i18n/locales/sl.json +5 -5
  72. package/front_end/core/i18n/locales/sq.json +5 -5
  73. package/front_end/core/i18n/locales/sr-Latn.json +5 -5
  74. package/front_end/core/i18n/locales/sr.json +5 -5
  75. package/front_end/core/i18n/locales/sv.json +5 -5
  76. package/front_end/core/i18n/locales/sw.json +5 -5
  77. package/front_end/core/i18n/locales/ta.json +5 -5
  78. package/front_end/core/i18n/locales/te.json +5 -5
  79. package/front_end/core/i18n/locales/th.json +5 -5
  80. package/front_end/core/i18n/locales/tr.json +5 -5
  81. package/front_end/core/i18n/locales/uk.json +5 -5
  82. package/front_end/core/i18n/locales/ur.json +5 -5
  83. package/front_end/core/i18n/locales/uz.json +5 -5
  84. package/front_end/core/i18n/locales/vi.json +5 -5
  85. package/front_end/core/i18n/locales/zh-HK.json +5 -5
  86. package/front_end/core/i18n/locales/zh-TW.json +5 -5
  87. package/front_end/core/i18n/locales/zh.json +5 -5
  88. package/front_end/core/i18n/locales/zu.json +5 -5
  89. package/front_end/core/sdk/CSSContainerQuery.ts +1 -1
  90. package/front_end/core/sdk/CSSModel.ts +13 -9
  91. package/front_end/generated/InspectorBackendCommands.js +6 -5
  92. package/front_end/generated/protocol.ts +10 -9
  93. package/front_end/models/issues_manager/{SameSiteCookieIssue.ts → CookieIssue.ts} +75 -79
  94. package/front_end/models/issues_manager/Issue.ts +1 -1
  95. package/front_end/models/issues_manager/IssuesManager.ts +3 -9
  96. package/front_end/models/issues_manager/NavigatorUserAgentIssue.ts +1 -1
  97. package/front_end/models/issues_manager/issues_manager.ts +2 -2
  98. package/front_end/models/persistence/NetworkPersistenceManager.ts +1 -1
  99. package/front_end/panels/application/components/BackForwardCacheView.ts +23 -1
  100. package/front_end/panels/elements/ClassesPaneWidget.ts +1 -1
  101. package/front_end/panels/elements/ComputedStyleModel.ts +1 -1
  102. package/front_end/panels/elements/ElementsTreeElement.ts +1 -1
  103. package/front_end/panels/elements/LayersWidget.ts +4 -3
  104. package/front_end/panels/elements/MetricsSidebarPane.ts +2 -2
  105. package/front_end/panels/elements/PlatformFontsWidget.ts +1 -1
  106. package/front_end/panels/elements/StylePropertyTreeElement.ts +1 -1
  107. package/front_end/panels/elements/StylesSidebarPane.ts +10 -8
  108. package/front_end/panels/emulation/MediaQueryInspector.ts +1 -1
  109. package/front_end/panels/issues/IssueView.ts +1 -1
  110. package/front_end/panels/issues/IssuesPane.ts +1 -1
  111. package/front_end/panels/network/NetworkLogView.ts +1 -1
  112. package/front_end/panels/sources/CSSPlugin.ts +77 -22
  113. package/front_end/panels/sources/SourcesView.ts +23 -10
  114. package/front_end/panels/sources/components/HeadersView.css +32 -0
  115. package/front_end/panels/sources/components/HeadersView.ts +89 -0
  116. package/front_end/panels/sources/components/components.ts +9 -0
  117. package/front_end/panels/timeline/TimelineController.ts +17 -5
  118. package/front_end/ui/components/expandable_list/expandableList.css +10 -0
  119. package/front_end/ui/components/text_editor/javascript.ts +46 -1
  120. package/package.json +1 -1
@@ -84,8 +84,9 @@ export class LayersWidget extends UI.Widget.Widget {
84
84
  const makeTreeNode = (parentId: string) =>
85
85
  (layer: Protocol.CSS.CSSLayerData): TreeOutline.TreeOutlineUtils.TreeNode<string> => {
86
86
  const subLayers = layer.subLayers;
87
- const treeNodeData = layer.order + ': ' + layer.name;
88
- const id = parentId ? parentId + '.' + layer.name : layer.name;
87
+ const name = SDK.CSSModel.CSSModel.readableLayerName(layer.name);
88
+ const treeNodeData = layer.order + ': ' + name;
89
+ const id = parentId ? parentId + '.' + name : name;
89
90
  if (!subLayers) {
90
91
  return {treeNodeData, id};
91
92
  }
@@ -96,7 +97,7 @@ export class LayersWidget extends UI.Widget.Widget {
96
97
  Promise.resolve(subLayers.sort((layer1, layer2) => layer1.order - layer2.order).map(makeTreeNode(id))),
97
98
  };
98
99
  };
99
- const rootLayer = await this.cssModel.rootLayerPromise(node.id);
100
+ const rootLayer = await this.cssModel.getRootLayer(node.id);
100
101
  this.layerTreeComponent.data = {
101
102
  defaultRenderer: TreeOutline.TreeOutline.defaultRenderer,
102
103
  tree: [makeTreeNode('')(rootLayer)],
@@ -88,8 +88,8 @@ export class MetricsSidebarPane extends ElementsSidebarPane {
88
88
  }
89
89
 
90
90
  const promises = [
91
- cssModel.computedStylePromise(node.id).then(callback.bind(this)),
92
- cssModel.inlineStylesPromise(node.id).then(inlineStyleResult => {
91
+ cssModel.getComputedStyle(node.id).then(callback.bind(this)),
92
+ cssModel.getInlineStyles(node.id).then(inlineStyleResult => {
93
93
  if (inlineStyleResult && this.node() === node) {
94
94
  this.inlineStyle = inlineStyleResult.inlineStyle;
95
95
  }
@@ -88,7 +88,7 @@ export class PlatformFontsWidget extends UI.ThrottledWidget.ThrottledWidget {
88
88
  return Promise.resolve();
89
89
  }
90
90
 
91
- return cssModel.platformFontsPromise(node.id).then(this.refreshUI.bind(this, node));
91
+ return cssModel.getPlatformFonts(node.id).then(this.refreshUI.bind(this, node));
92
92
  }
93
93
 
94
94
  private refreshUI(node: SDK.DOMModel.DOMNode, platformFonts: Protocol.CSS.PlatformFontUsage[]|null): void {
@@ -278,7 +278,7 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
278
278
  const cssModel = this.parentPaneInternal.cssModel();
279
279
  const node = this.node();
280
280
  if (cssModel && node && typeof node.id !== 'undefined') {
281
- const contrastInfo = new ColorPicker.ContrastInfo.ContrastInfo(await cssModel.backgroundColorsPromise(node.id));
281
+ const contrastInfo = new ColorPicker.ContrastInfo.ContrastInfo(await cssModel.getBackgroundColors(node.id));
282
282
  swatchIcon.setContrastInfo(contrastInfo);
283
283
  }
284
284
  }
@@ -875,7 +875,7 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
875
875
  if (parentRule instanceof SDK.CSSRule.CSSStyleRule) {
876
876
  const layers = parentRule.layers;
877
877
  if ((layers.length || lastLayers) && lastLayers !== layers) {
878
- const block = SectionBlock.createLayerBlock(layers);
878
+ const block = SectionBlock.createLayerBlock(parentRule);
879
879
  blocks.push(block);
880
880
  sawLayers = true;
881
881
  lastLayers = layers;
@@ -1430,18 +1430,21 @@ export class SectionBlock {
1430
1430
  return new SectionBlock(separatorElement);
1431
1431
  }
1432
1432
 
1433
- static createLayerBlock(layers: SDK.CSSLayer.CSSLayer[]): SectionBlock {
1433
+ static createLayerBlock(rule: SDK.CSSRule.CSSStyleRule): SectionBlock {
1434
1434
  const separatorElement = document.createElement('div');
1435
1435
  separatorElement.className = 'sidebar-separator layer-separator';
1436
1436
  UI.UIUtils.createTextChild(separatorElement.createChild('div'), i18nString(UIStrings.layer));
1437
- if (!layers.length) {
1438
- UI.UIUtils.createTextChild(separatorElement.createChild('div'), '\xa0user\xa0agent\xa0stylesheet');
1437
+ const layers = rule.layers;
1438
+ if (!layers.length && rule.origin === Protocol.CSS.StyleSheetOrigin.UserAgent) {
1439
+ const name = rule.origin === Protocol.CSS.StyleSheetOrigin.UserAgent ? '\xa0user\xa0agent\xa0stylesheet' :
1440
+ '\xa0implicit\xa0outer\xa0layer';
1441
+ UI.UIUtils.createTextChild(separatorElement.createChild('div'), name);
1439
1442
  return new SectionBlock(separatorElement);
1440
1443
  }
1441
1444
  const layerLink = separatorElement.createChild('button') as HTMLButtonElement;
1442
1445
  layerLink.className = 'link';
1443
1446
  layerLink.title = i18nString(UIStrings.clickToRevealLayer);
1444
- const name = layers.map(layer => layer.text || '<anonymous>').join('.');
1447
+ const name = layers.map(layer => SDK.CSSModel.CSSModel.readableLayerName(layer.text)).join('.');
1445
1448
  layerLink.textContent = name;
1446
1449
  layerLink.onclick = (): Promise<void> => LayersWidget.LayersWidget.instance().revealLayer(name);
1447
1450
  return new SectionBlock(separatorElement);
@@ -3192,13 +3195,12 @@ export class CSSPropertyPrompt extends UI.TextPrompt.TextPrompt {
3192
3195
  if (!node || this.selectedNodeComputedStyles) {
3193
3196
  return;
3194
3197
  }
3195
- this.selectedNodeComputedStyles = await node.domModel().cssModel().computedStylePromise(node.id);
3198
+ this.selectedNodeComputedStyles = await node.domModel().cssModel().getComputedStyle(node.id);
3196
3199
  const parentNode = node.parentNode;
3197
3200
  if (parentNode) {
3198
- this.parentNodeComputedStyles = await parentNode.domModel().cssModel().computedStylePromise(parentNode.id);
3201
+ this.parentNodeComputedStyles = await parentNode.domModel().cssModel().getComputedStyle(parentNode.id);
3199
3202
  }
3200
3203
  };
3201
-
3202
3204
  for (const result of results) {
3203
3205
  await ensureComputedStyles();
3204
3206
  // Using parent node's computed styles does not work in all cases. For example:
@@ -165,7 +165,7 @@ export class MediaQueryInspector extends UI.Widget.Widget implements
165
165
  return Promise.resolve();
166
166
  }
167
167
 
168
- return this.cssModel.mediaQueriesPromise().then(this.rebuildMediaQueries.bind(this));
168
+ return this.cssModel.getMediaQueries().then(this.rebuildMediaQueries.bind(this));
169
169
  }
170
170
 
171
171
  private squashAdjacentEqual(models: MediaQueryUIModel[]): MediaQueryUIModel[] {
@@ -131,7 +131,7 @@ class AffectedRequestsView extends AffectedResourcesView {
131
131
  const issueTypeToNetworkHeaderMap =
132
132
  new Map<IssuesManager.Issue.IssueCategory, NetworkForward.UIRequestLocation.UIRequestTabs>([
133
133
  [
134
- IssuesManager.Issue.IssueCategory.SameSiteCookie,
134
+ IssuesManager.Issue.IssueCategory.Cookie,
135
135
  NetworkForward.UIRequestLocation.UIRequestTabs.Cookies,
136
136
  ],
137
137
  [
@@ -127,7 +127,7 @@ class IssueCategoryView extends UI.TreeOutline.TreeElement {
127
127
  return i18nString(UIStrings.crossOriginEmbedderPolicy);
128
128
  case IssuesManager.Issue.IssueCategory.MixedContent:
129
129
  return i18nString(UIStrings.mixedContent);
130
- case IssuesManager.Issue.IssueCategory.SameSiteCookie:
130
+ case IssuesManager.Issue.IssueCategory.Cookie:
131
131
  return i18nString(UIStrings.samesiteCookie);
132
132
  case IssuesManager.Issue.IssueCategory.HeavyAd:
133
133
  return i18nString(UIStrings.heavyAds);
@@ -1716,7 +1716,7 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
1716
1716
  return false;
1717
1717
  }
1718
1718
  if (this.onlyIssuesFilterUI.checked() &&
1719
- !IssuesManager.RelatedIssue.hasIssueOfCategory(request, IssuesManager.Issue.IssueCategory.SameSiteCookie)) {
1719
+ !IssuesManager.RelatedIssue.hasIssueOfCategory(request, IssuesManager.Issue.IssueCategory.Cookie)) {
1720
1720
  return false;
1721
1721
  }
1722
1722
  if (this.onlyBlockedRequestsUI.checked() && !request.wasBlocked() && !request.corsErrorStatus()) {
@@ -4,13 +4,17 @@
4
4
 
5
5
  import * as Common from '../../core/common/common.js';
6
6
  import * as i18n from '../../core/i18n/i18n.js';
7
+ import * as Platform from '../../core/platform/platform.js';
7
8
  import * as SDK from '../../core/sdk/sdk.js';
9
+ import type * as Protocol from '../../generated/protocol.js';
8
10
  import type * as Workspace from '../../models/workspace/workspace.js';
9
11
  import * as ColorPicker from '../../ui/legacy/components/color_picker/color_picker.js';
10
12
  import * as InlineEditor from '../../ui/legacy/components/inline_editor/inline_editor.js';
11
13
  import * as CodeMirror from '../../third_party/codemirror.next/codemirror.next.js';
14
+ import type * as SourceFrame from '../../ui/legacy/components/source_frame/source_frame.js';
12
15
  import * as UI from '../../ui/legacy/legacy.js';
13
16
 
17
+ import {assertNotNullOrUndefined} from '../../core/platform/platform.js';
14
18
  import {Plugin} from './Plugin.js';
15
19
 
16
20
  // Plugin to add CSS completion, shortcuts, and color/curve swatches
@@ -29,17 +33,6 @@ const UIStrings = {
29
33
  const str_ = i18n.i18n.registerUIStrings('panels/sources/CSSPlugin.ts', UIStrings);
30
34
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
31
35
 
32
- export function completion(): CodeMirror.Extension {
33
- const {cssCompletionSource} = CodeMirror.css;
34
- return CodeMirror.autocompletion({
35
- override:
36
- [async(cx: CodeMirror.CompletionContext):
37
- Promise<CodeMirror.CompletionResult|null> => {
38
- return (await specificCssCompletion(cx)) || cssCompletionSource(cx);
39
- }],
40
- });
41
- }
42
-
43
36
  const dontCompleteIn = new Set(['ColorLiteral', 'NumberLiteral', 'StringLiteral', 'Comment', 'Important']);
44
37
 
45
38
  function findPropertyAt(node: CodeMirror.SyntaxNode, pos: number): CodeMirror.SyntaxNode|null {
@@ -57,18 +50,43 @@ function findPropertyAt(node: CodeMirror.SyntaxNode, pos: number): CodeMirror.Sy
57
50
  return null;
58
51
  }
59
52
 
60
- function specificCssCompletion(cx: CodeMirror.CompletionContext): CodeMirror.CompletionResult|null {
53
+ function getCurrentStyleSheet(
54
+ url: Platform.DevToolsPath.UrlString, cssModel: SDK.CSSModel.CSSModel): Protocol.CSS.StyleSheetId {
55
+ const currentStyleSheet = cssModel.getStyleSheetIdsForURL(url);
56
+ if (currentStyleSheet.length === 0) {
57
+ Platform.DCHECK(() => currentStyleSheet.length !== 0, 'Can\'t find style sheet ID for current URL');
58
+ }
59
+
60
+ return currentStyleSheet[0];
61
+ }
62
+
63
+ async function specificCssCompletion(
64
+ cx: CodeMirror.CompletionContext, uiSourceCode: Workspace.UISourceCode.UISourceCode,
65
+ cssModel: SDK.CSSModel.CSSModel|undefined): Promise<CodeMirror.CompletionResult|null> {
61
66
  const node = CodeMirror.syntaxTree(cx.state).resolveInner(cx.pos, -1);
67
+ if (node.name === 'ClassName') {
68
+ // Should never happen, but let's code defensively here
69
+ assertNotNullOrUndefined(cssModel);
70
+
71
+ const currentStyleSheet = getCurrentStyleSheet(uiSourceCode.url(), cssModel);
72
+ const existingClassNames = await cssModel.getClassNames(currentStyleSheet);
73
+
74
+ return {
75
+ from: node.from,
76
+ options: existingClassNames.map(value => ({type: 'constant', label: value})),
77
+ };
78
+ }
62
79
  const property = findPropertyAt(node, cx.pos);
63
- if (!property) {
64
- return null;
80
+ if (property) {
81
+ const propertyValues =
82
+ SDK.CSSMetadata.cssMetadata().getPropertyValues(cx.state.sliceDoc(property.from, property.to));
83
+ return {
84
+ from: node.name === 'ValueName' ? node.from : cx.pos,
85
+ options: propertyValues.map(value => ({type: 'constant', label: value})),
86
+ span: /^[\w\P{ASCII}\-]+$/u,
87
+ };
65
88
  }
66
- const propertyValues = SDK.CSSMetadata.cssMetadata().getPropertyValues(cx.state.sliceDoc(property.from, property.to));
67
- return {
68
- from: node.name === 'ValueName' ? node.from : cx.pos,
69
- options: propertyValues.map(value => ({type: 'constant', label: value})),
70
- span: /^[\w\P{ASCII}\-]+$/u,
71
- };
89
+ return null;
72
90
  }
73
91
 
74
92
  function findColorsAndCurves(
@@ -380,12 +398,49 @@ export function cssBindings(): CodeMirror.Extension {
380
398
  });
381
399
  }
382
400
 
383
- export class CSSPlugin extends Plugin {
401
+ export class CSSPlugin extends Plugin implements SDK.TargetManager.SDKModelObserver<SDK.CSSModel.CSSModel> {
402
+ #cssModel?: SDK.CSSModel.CSSModel;
403
+
404
+ constructor(uiSourceCode: Workspace.UISourceCode.UISourceCode, _transformer?: SourceFrame.SourceFrame.Transformer) {
405
+ super(uiSourceCode, _transformer);
406
+ SDK.TargetManager.TargetManager.instance().observeModels(SDK.CSSModel.CSSModel, this);
407
+ }
408
+
384
409
  static accepts(uiSourceCode: Workspace.UISourceCode.UISourceCode): boolean {
385
410
  return uiSourceCode.contentType().isStyleSheet();
386
411
  }
387
412
 
413
+ modelAdded(cssModel: SDK.CSSModel.CSSModel): void {
414
+ if (this.#cssModel) {
415
+ return;
416
+ }
417
+ this.#cssModel = cssModel;
418
+ }
419
+ modelRemoved(cssModel: SDK.CSSModel.CSSModel): void {
420
+ if (this.#cssModel === cssModel) {
421
+ this.#cssModel = undefined;
422
+ }
423
+ }
424
+
388
425
  editorExtension(): CodeMirror.Extension {
389
- return [cssBindings(), completion(), cssSwatches()];
426
+ return [cssBindings(), this.#cssCompletion(), cssSwatches()];
427
+ }
428
+
429
+ #cssCompletion(): CodeMirror.Extension {
430
+ const {cssCompletionSource} = CodeMirror.css;
431
+
432
+ // CodeMirror binds the function below to the state object.
433
+ // Therefore, we can't access `this` and retrieve the following properties.
434
+ // Instead, retrieve them up front to bind them to the correct closure.
435
+ const uiSourceCode = this.uiSourceCode;
436
+ const cssModel = this.#cssModel;
437
+
438
+ return CodeMirror.autocompletion({
439
+ override:
440
+ [async(cx: CodeMirror.CompletionContext):
441
+ Promise<CodeMirror.CompletionResult|null> => {
442
+ return (await specificCssCompletion(cx, uiSourceCode, cssModel)) || cssCompletionSource(cx);
443
+ }],
444
+ });
390
445
  }
391
446
  }
@@ -12,6 +12,7 @@ import * as QuickOpen from '../../ui/legacy/components/quick_open/quick_open.js'
12
12
  import * as SourceFrame from '../../ui/legacy/components/source_frame/source_frame.js';
13
13
  import * as UI from '../../ui/legacy/legacy.js';
14
14
 
15
+ import * as Components from './components/components.js';
15
16
  import {EditingLocationHistoryManager} from './EditingLocationHistoryManager.js';
16
17
  import sourcesViewStyles from './sourcesView.css.js';
17
18
 
@@ -377,6 +378,10 @@ export class SourcesView extends Common.ObjectWrapper.eventMixin<EventTypes, typ
377
378
  sourceView = new SourceFrame.ImageView.ImageView(uiSourceCode.mimeType(), uiSourceCode);
378
379
  } else if (contentType === Common.ResourceType.resourceTypes.Font) {
379
380
  sourceView = new SourceFrame.FontView.FontView(uiSourceCode.mimeType(), uiSourceCode);
381
+ } else if (
382
+ uiSourceCode.name() === HEADER_OVERRIDES_FILENAME &&
383
+ Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.HEADER_OVERRIDES)) {
384
+ sourceView = new Components.HeadersView.HeadersView(uiSourceCode);
380
385
  } else {
381
386
  sourceFrame = new UISourceCodeFrame(uiSourceCode);
382
387
  }
@@ -399,10 +404,18 @@ export class SourcesView extends Common.ObjectWrapper.eventMixin<EventTypes, typ
399
404
  if (widget instanceof SourceFrame.FontView.FontView) {
400
405
  return SourceViewType.FontView;
401
406
  }
407
+ if (widget instanceof Components.HeadersView.HeadersView) {
408
+ return SourceViewType.HeadersView;
409
+ }
402
410
  return SourceViewType.SourceView;
403
411
  }
404
412
 
405
- #sourceViewTypeForContentType(contentType: Common.ResourceType.ResourceType): SourceViewType {
413
+ #sourceViewTypeForUISourceCode(uiSourceCode: Workspace.UISourceCode.UISourceCode): SourceViewType {
414
+ if (uiSourceCode.name() === HEADER_OVERRIDES_FILENAME &&
415
+ Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.HEADER_OVERRIDES)) {
416
+ return SourceViewType.HeadersView;
417
+ }
418
+ const contentType = uiSourceCode.contentType();
406
419
  switch (contentType) {
407
420
  case Common.ResourceType.resourceTypes.Image:
408
421
  return SourceViewType.ImageView;
@@ -417,8 +430,7 @@ export class SourcesView extends Common.ObjectWrapper.eventMixin<EventTypes, typ
417
430
  const uiSourceCode = event.data;
418
431
  const widget = this.sourceViewByUISourceCode.get(uiSourceCode);
419
432
  if (widget) {
420
- const contentType = uiSourceCode.contentType();
421
- if (this.#sourceViewTypeForWidget(widget) !== this.#sourceViewTypeForContentType(contentType)) {
433
+ if (this.#sourceViewTypeForWidget(widget) !== this.#sourceViewTypeForUISourceCode(uiSourceCode)) {
422
434
  // Remove the exisiting editor tab and create a new one of the correct type.
423
435
  this.removeUISourceCodes([uiSourceCode]);
424
436
  this.showSourceLocation(uiSourceCode);
@@ -602,20 +614,18 @@ export class SourcesView extends Common.ObjectWrapper.eventMixin<EventTypes, typ
602
614
  }
603
615
 
604
616
  save(): void {
605
- this.saveSourceFrame(this.currentSourceFrame());
617
+ this.saveSourceView(this.visibleView());
606
618
  }
607
619
 
608
620
  saveAll(): void {
609
621
  const sourceFrames = this.editorContainer.fileViews();
610
- sourceFrames.forEach(this.saveSourceFrame.bind(this));
622
+ sourceFrames.forEach(this.saveSourceView.bind(this));
611
623
  }
612
624
 
613
- private saveSourceFrame(sourceFrame: UI.Widget.Widget|null): void {
614
- if (!(sourceFrame instanceof UISourceCodeFrame)) {
615
- return;
625
+ private saveSourceView(sourceView: UI.Widget.Widget|null): void {
626
+ if (sourceView instanceof UISourceCodeFrame || sourceView instanceof Components.HeadersView.HeadersView) {
627
+ sourceView.commitEditing();
616
628
  }
617
- const uiSourceCodeFrame = (sourceFrame as UISourceCodeFrame);
618
- uiSourceCodeFrame.commitEditing();
619
629
  }
620
630
 
621
631
  toggleBreakpointsActiveState(active: boolean): void {
@@ -764,9 +774,12 @@ export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
764
774
  }
765
775
  }
766
776
 
777
+ const HEADER_OVERRIDES_FILENAME = '.headers';
778
+
767
779
  // eslint-disable-next-line rulesdir/const_enum
768
780
  enum SourceViewType {
769
781
  ImageView = 'ImageView',
770
782
  FontView = 'FontView',
783
+ HeadersView = 'HeadersView',
771
784
  SourceView = 'SourceView',
772
785
  }
@@ -0,0 +1,32 @@
1
+ /*
2
+ * Copyright 2022 The Chromium Authors. All rights reserved.
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
+ :host {
8
+ flex-grow: 1;
9
+ }
10
+
11
+ .center-wrapper {
12
+ height: 100%;
13
+ display: flex;
14
+ justify-content: center;
15
+ align-items: center;
16
+ }
17
+
18
+ .centered {
19
+ margin: 1em;
20
+ max-width: 300px;
21
+ text-align: center;
22
+ }
23
+
24
+ .error-header {
25
+ font-weight: bold;
26
+ margin-bottom: 1em;
27
+ }
28
+
29
+ .error-body {
30
+ line-height: 1.5em;
31
+ color: var(--color-text-secondary);
32
+ }
@@ -0,0 +1,89 @@
1
+ // Copyright 2022 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import * as i18n from '../../../core/i18n/i18n.js';
6
+ import * as Persistence from '../../../models/persistence/persistence.js';
7
+ import type * as Workspace from '../../../models/workspace/workspace.js';
8
+ import * as ComponentHelpers from '../../../ui/components/helpers/helpers.js';
9
+ import * as UI from '../../../ui/legacy/legacy.js';
10
+ import * as LitHtml from '../../../ui/lit-html/lit-html.js';
11
+
12
+ import HeadersViewStyles from './HeadersView.css.js';
13
+
14
+ const UIStrings = {
15
+ /**
16
+ *@description Error message for files which cannot not be parsed.
17
+ *@example {.headers} PH1
18
+ */
19
+ errorWhenParsing: 'Error when parsing \'\'{PH1}\'\'.',
20
+ /**
21
+ *@description Explainer for files which cannot be parsed.
22
+ *@example {.headers} PH1
23
+ */
24
+ parsingErrorExplainer:
25
+ 'This is most likely due to a syntax error in \'\'{PH1}\'\'. Try opening this file in an external editor to fix the error or delete the file and re-create the override.',
26
+ };
27
+ const str_ = i18n.i18n.registerUIStrings('panels/sources/components/HeadersView.ts', UIStrings);
28
+ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
29
+
30
+ export class HeadersView extends UI.View.SimpleView {
31
+ readonly #headersViewComponent = new HeadersViewComponent();
32
+ #uiSourceCode: Workspace.UISourceCode.UISourceCode;
33
+
34
+ constructor(uiSourceCode: Workspace.UISourceCode.UISourceCode) {
35
+ super('HeadersView');
36
+ this.#uiSourceCode = uiSourceCode;
37
+ this.element.appendChild(this.#headersViewComponent);
38
+ this.#headersViewComponent.data = {
39
+ uiSourceCode: this.#uiSourceCode,
40
+ };
41
+ }
42
+
43
+ commitEditing(): void {
44
+ this.#uiSourceCode.commitWorkingCopy();
45
+ Persistence.NetworkPersistenceManager.NetworkPersistenceManager.instance().updateInterceptionPatterns();
46
+ }
47
+ }
48
+
49
+ export interface HeadersViewComponentData {
50
+ uiSourceCode: Workspace.UISourceCode.UISourceCode;
51
+ }
52
+
53
+ export class HeadersViewComponent extends HTMLElement {
54
+ static readonly litTagName = LitHtml.literal`devtools-sources-headers-view`;
55
+ readonly #shadow = this.attachShadow({mode: 'open'});
56
+ #uiSourceCode: Workspace.UISourceCode.UISourceCode|null = null;
57
+
58
+ connectedCallback(): void {
59
+ this.#shadow.adoptedStyleSheets = [HeadersViewStyles];
60
+ }
61
+
62
+ set data(data: HeadersViewComponentData) {
63
+ this.#uiSourceCode = data.uiSourceCode;
64
+ this.#render();
65
+ }
66
+
67
+ #render(): void {
68
+ const fileName = this.#uiSourceCode?.name() || '.headers';
69
+ // clang-format off
70
+ LitHtml.render(LitHtml.html`
71
+ <div class="center-wrapper">
72
+ <div class="centered">
73
+ <div class="error-header">${i18nString(UIStrings.errorWhenParsing, {PH1: fileName})}</div>
74
+ <div class="error-body">${i18nString(UIStrings.parsingErrorExplainer, {PH1: fileName})}</div>
75
+ </div>
76
+ </div>
77
+ `, this.#shadow, {host: this});
78
+ // clang-format on
79
+ }
80
+ }
81
+
82
+ ComponentHelpers.CustomElements.defineComponent('devtools-sources-headers-view', HeadersViewComponent);
83
+
84
+ declare global {
85
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
86
+ interface HTMLElementTagNameMap {
87
+ 'devtools-sources-headers-view': HeadersViewComponent;
88
+ }
89
+ }
@@ -0,0 +1,9 @@
1
+ // Copyright 2022 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import * as HeadersView from './HeadersView.js';
6
+
7
+ export {
8
+ HeadersView,
9
+ };
@@ -80,18 +80,31 @@ export class TimelineController implements SDK.TargetManager.SDKModelObserver<SD
80
80
  function disabledByDefault(category: string): string {
81
81
  return 'disabled-by-default-' + category;
82
82
  }
83
+
84
+ // The following categories are also used in other tools, but this panel
85
+ // offers the possibility of turning them off (see below).
86
+ // 'disabled-by-default-devtools.screenshot'
87
+ // └ default: on, option: captureFilmStrip
88
+ // 'disabled-by-default-devtools.timeline.invalidationTracking'
89
+ // └ default: off, experiment: timelineInvalidationTracking
90
+ // 'disabled-by-default-v8.cpu_profiler'
91
+ // └ default: on, option: enableJSSampling
83
92
  const categoriesArray = [
84
93
  '-*',
94
+ TimelineModel.TimelineModel.TimelineModelImpl.Category.Console,
95
+ TimelineModel.TimelineModel.TimelineModelImpl.Category.UserTiming,
85
96
  'devtools.timeline',
86
97
  disabledByDefault('devtools.timeline'),
87
98
  disabledByDefault('devtools.timeline.frame'),
88
- 'v8.execute',
99
+ disabledByDefault('devtools.timeline.stack'),
89
100
  disabledByDefault('v8.compile'),
90
- TimelineModel.TimelineModel.TimelineModelImpl.Category.Console,
91
- TimelineModel.TimelineModel.TimelineModelImpl.Category.UserTiming,
101
+ disabledByDefault('v8.cpu_profiler.hires'),
102
+ TimelineModel.TimelineModel.TimelineModelImpl.Category.LatencyInfo,
92
103
  TimelineModel.TimelineModel.TimelineModelImpl.Category.Loading,
104
+ disabledByDefault('lighthouse'),
105
+ 'v8.execute',
106
+ 'v8',
93
107
  ];
94
- categoriesArray.push(TimelineModel.TimelineModel.TimelineModelImpl.Category.LatencyInfo);
95
108
 
96
109
  if (Root.Runtime.experiments.isEnabled('timelineV8RuntimeCallStats') && options.enableJSSampling) {
97
110
  categoriesArray.push(disabledByDefault('v8.runtime_stats_sampling'));
@@ -99,7 +112,6 @@ export class TimelineController implements SDK.TargetManager.SDKModelObserver<SD
99
112
  if (!Root.Runtime.Runtime.queryParam('timelineTracingJSProfileDisabled') && options.enableJSSampling) {
100
113
  categoriesArray.push(disabledByDefault('v8.cpu_profiler'));
101
114
  }
102
- categoriesArray.push(disabledByDefault('devtools.timeline.stack'));
103
115
  if (Root.Runtime.experiments.isEnabled('timelineInvalidationTracking')) {
104
116
  categoriesArray.push(disabledByDefault('devtools.timeline.invalidationTracking'));
105
117
  }
@@ -4,6 +4,10 @@
4
4
  * found in the LICENSE file.
5
5
  */
6
6
 
7
+ :host {
8
+ overflow: hidden;
9
+ }
10
+
7
11
  div {
8
12
  line-height: 1.7em;
9
13
  }
@@ -53,3 +57,9 @@ button.link {
53
57
  font-family: inherit;
54
58
  font-size: inherit;
55
59
  }
60
+
61
+ .text-ellipsis {
62
+ overflow: hidden;
63
+ text-overflow: ellipsis;
64
+ white-space: nowrap;
65
+ }
@@ -101,11 +101,11 @@ const dontCompleteIn = new Set([
101
101
  'TypeName',
102
102
  ]);
103
103
 
104
- // FIXME Implement Map property completion?
105
104
  export const enum QueryType {
106
105
  Expression = 0,
107
106
  PropertyName = 1,
108
107
  PropertyExpression = 2,
108
+ PotentiallyRetrievingFromMap = 3,
109
109
  }
110
110
 
111
111
  export function getQueryType(tree: CodeMirror.Tree, pos: number, doc: CodeMirror.Text): {
@@ -149,6 +149,22 @@ export function getQueryType(tree: CodeMirror.Tree, pos: number, doc: CodeMirror
149
149
  return {type: QueryType.PropertyName, relatedNode: node};
150
150
  }
151
151
  }
152
+ if (node.name === '(') {
153
+ // map.get(<auto-complete>
154
+ if (parent.name === 'ArgList' && parent.parent.name === 'CallExpression') {
155
+ // map.get
156
+ const callReceiver = parent.parent.firstChild;
157
+ if (callReceiver.name === 'MemberExpression') {
158
+ // get
159
+ const propertyExpression = callReceiver.lastChild;
160
+ if (doc.sliceString(propertyExpression.from, propertyExpression.to) === 'get') {
161
+ // map
162
+ const potentiallyMapObject = callReceiver.firstChild;
163
+ return {type: QueryType.PotentiallyRetrievingFromMap, relatedNode: potentiallyMapObject};
164
+ }
165
+ }
166
+ }
167
+ }
152
168
  return {type: QueryType.Expression};
153
169
  }
154
170
 
@@ -184,6 +200,12 @@ export async function javascriptCompletionSource(cx: CodeMirror.CompletionContex
184
200
  }
185
201
  result = await completeProperties(
186
202
  cx.state.sliceDoc(objectExpr.from, objectExpr.to), quote, cx.state.sliceDoc(cx.pos, cx.pos + 1) === ']');
203
+ } else if (query.type === QueryType.PotentiallyRetrievingFromMap) {
204
+ const potentialMapObject = query.relatedNode;
205
+ if (!potentialMapObject) {
206
+ return null;
207
+ }
208
+ result = await maybeCompleteKeysFromMap(cx.state.sliceDoc(potentialMapObject.from, potentialMapObject.to));
187
209
  } else {
188
210
  return null;
189
211
  }
@@ -272,6 +294,29 @@ class PropertyCache {
272
294
  }
273
295
  }
274
296
 
297
+ async function maybeCompleteKeysFromMap(objectVariable: string): Promise<CompletionSet> {
298
+ const result = new CompletionSet();
299
+ const context = getExecutionContext();
300
+ if (!context) {
301
+ return result;
302
+ }
303
+ const maybeRetrieveKeys =
304
+ await evaluateExpression(context, `[...Map.prototype.keys.call(${objectVariable})]`, 'completion');
305
+ if (!maybeRetrieveKeys) {
306
+ return result;
307
+ }
308
+ const properties = SDK.RemoteObject.RemoteArray.objectAsArray(maybeRetrieveKeys);
309
+ const numProperties = properties.length();
310
+ for (let i = 0; i < numProperties; i++) {
311
+ result.add({
312
+ label: `"${(await properties.at(i)).value}")`,
313
+ type: 'constant',
314
+ boost: i * -1,
315
+ });
316
+ }
317
+ return result;
318
+ }
319
+
275
320
  async function completeProperties(
276
321
  expression: string,
277
322
  quoted?: string,
package/package.json CHANGED
@@ -54,5 +54,5 @@
54
54
  "unittest": "scripts/test/run_unittests.py --no-text-coverage",
55
55
  "watch": "third_party/node/node.py --output scripts/watch_build.js"
56
56
  },
57
- "version": "1.0.976172"
57
+ "version": "1.0.977567"
58
58
  }