chrome-devtools-frontend 1.0.1038685 → 1.0.1040084

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.
@@ -12165,10 +12165,10 @@
12165
12165
  "message": "Show Memory Inspector"
12166
12166
  },
12167
12167
  "ui/components/linear_memory_inspector/LinearMemoryHighlightChipList.ts | deleteHighlight": {
12168
- "message": "Delete memory highlight"
12168
+ "message": "Stop highlighting this memory"
12169
12169
  },
12170
12170
  "ui/components/linear_memory_inspector/LinearMemoryHighlightChipList.ts | jumpToAddress": {
12171
- "message": "Jump to highlighted memory"
12171
+ "message": "Jump to this memory"
12172
12172
  },
12173
12173
  "ui/components/linear_memory_inspector/LinearMemoryInspector.ts | addressHasToBeANumberBetweenSAnd": {
12174
12174
  "message": "Address has to be a number between {PH1} and {PH2}"
@@ -12165,10 +12165,10 @@
12165
12165
  "message": "Ŝh́ôẃ M̂ém̂ór̂ý Îńŝṕêćt̂ór̂"
12166
12166
  },
12167
12167
  "ui/components/linear_memory_inspector/LinearMemoryHighlightChipList.ts | deleteHighlight": {
12168
- "message": "D̂él̂ét̂é m̂ém̂ór̂ý ĥíĝh́l̂íĝh́t̂"
12168
+ "message": "Ŝt́ôṕ ĥíĝh́l̂íĝh́t̂ín̂ǵ t̂h́îś m̂ém̂ór̂ý"
12169
12169
  },
12170
12170
  "ui/components/linear_memory_inspector/LinearMemoryHighlightChipList.ts | jumpToAddress": {
12171
- "message": "Ĵúm̂ṕ t̂ó ĥíĝíĝh́t̂éḿêḿôŕ"
12171
+ "message": "Ĵúm̂ṕ t̂ó t̂h́îś m̂ém̂ór̂ý"
12172
12172
  },
12173
12173
  "ui/components/linear_memory_inspector/LinearMemoryInspector.ts | addressHasToBeANumberBetweenSAnd": {
12174
12174
  "message": "Âd́d̂ŕêśŝ h́âś t̂ó b̂é â ńûḿb̂ér̂ b́êt́ŵéêń {PH1} âńd̂ {PH2}"
@@ -5,7 +5,7 @@
5
5
  import * as Protocol from '../../generated/protocol.js';
6
6
  import * as TextUtils from '../../models/text_utils/text_utils.js';
7
7
 
8
- import {cssMetadata, CustomVariableRegex, VariableRegex} from './CSSMetadata.js';
8
+ import {cssMetadata, VariableRegex} from './CSSMetadata.js';
9
9
 
10
10
  import {type CSSModel} from './CSSModel.js';
11
11
  import {type CSSProperty} from './CSSProperty.js';
@@ -618,7 +618,8 @@ class NodeCascade {
618
618
  this.propertiesState.clear();
619
619
  this.activeProperties.clear();
620
620
 
621
- for (const style of this.styles) {
621
+ for (let i = this.styles.length - 1; i >= 0; i--) {
622
+ const style = this.styles[i];
622
623
  const rule = style.parentRule;
623
624
  // Compute cascade for CSSStyleRules only.
624
625
  if (rule && !(rule instanceof CSSStyleRule)) {
@@ -637,44 +638,43 @@ class NodeCascade {
637
638
  continue;
638
639
  }
639
640
 
640
- if (!property.activeInStyle()) {
641
- this.propertiesState.set(property, PropertyState.Overloaded);
641
+ // When a property does not have a range in an otherwise ranged CSSStyleDeclaration,
642
+ // we consider it as a non-leading property (see computeLeadingProperties()), and most
643
+ // of them are computed longhands. We exclude these from activeProperties calculation,
644
+ // and use parsed longhands instead (see below).
645
+ if (style.range && !property.range) {
642
646
  continue;
643
647
  }
644
648
 
645
- const canonicalName = metadata.canonicalPropertyName(property.name);
646
- const isPropShorthand = Boolean(metadata.getLonghands(canonicalName));
647
-
648
- if (isPropShorthand) {
649
- const longhandsFromShort =
650
- (property.value.match(CustomVariableRegex) || []).map(e => e.replace(CustomVariableRegex, '$2'));
651
- longhandsFromShort.forEach(longhandProperty => {
652
- if (metadata.isCSSPropertyName(longhandProperty)) {
653
- const activeProperty = this.activeProperties.get(longhandProperty);
654
- if (!activeProperty) {
655
- this.activeProperties.set(longhandProperty, property);
656
- } else {
657
- this.propertiesState.set(activeProperty, PropertyState.Overloaded);
658
- this.activeProperties.set(longhandProperty, property);
659
- }
660
- }
661
- });
662
- }
663
-
664
- const activeProperty = this.activeProperties.get(canonicalName);
665
- if (activeProperty && (activeProperty.important || !property.important)) {
649
+ if (!property.activeInStyle()) {
666
650
  this.propertiesState.set(property, PropertyState.Overloaded);
667
651
  continue;
668
652
  }
669
653
 
670
- if (activeProperty) {
671
- this.propertiesState.set(activeProperty, PropertyState.Overloaded);
654
+ const canonicalName = metadata.canonicalPropertyName(property.name);
655
+ this.updatePropertyState(property, canonicalName);
656
+ for (const longhand of property.getLonghandProperties()) {
657
+ if (metadata.isCSSPropertyName(longhand.name)) {
658
+ this.updatePropertyState(longhand, longhand.name);
659
+ }
672
660
  }
673
- this.propertiesState.set(property, PropertyState.Active);
674
- this.activeProperties.set(canonicalName, property);
675
661
  }
676
662
  }
677
663
  }
664
+
665
+ private updatePropertyState(propertyWithHigherSpecificity: CSSProperty, canonicalName: string): void {
666
+ const activeProperty = this.activeProperties.get(canonicalName);
667
+ if (activeProperty?.important && !propertyWithHigherSpecificity.important) {
668
+ this.propertiesState.set(propertyWithHigherSpecificity, PropertyState.Overloaded);
669
+ return;
670
+ }
671
+
672
+ if (activeProperty) {
673
+ this.propertiesState.set(activeProperty, PropertyState.Overloaded);
674
+ }
675
+ this.propertiesState.set(propertyWithHigherSpecificity, PropertyState.Active);
676
+ this.activeProperties.set(canonicalName, propertyWithHigherSpecificity);
677
+ }
678
678
  }
679
679
 
680
680
  class DOMInheritanceCascade {
@@ -841,9 +841,7 @@ class DOMInheritanceCascade {
841
841
  const activeProperties = new Map<string, CSSProperty>();
842
842
  for (const nodeCascade of this.#nodeCascades) {
843
843
  nodeCascade.computeActiveProperties();
844
- for (const entry of nodeCascade.propertiesState.entries()) {
845
- const property = (entry[0] as CSSProperty);
846
- const state = (entry[1] as PropertyState);
844
+ for (const [property, state] of nodeCascade.propertiesState) {
847
845
  if (state === PropertyState.Overloaded) {
848
846
  this.#propertiesState.set(property, PropertyState.Overloaded);
849
847
  continue;
@@ -858,11 +856,9 @@ class DOMInheritanceCascade {
858
856
  }
859
857
  }
860
858
  // If every longhand of the shorthand is not active, then the shorthand is not active too.
861
- for (const entry of activeProperties.entries()) {
862
- const canonicalName = (entry[0] as string);
863
- const shorthandProperty = (entry[1] as CSSProperty);
859
+ for (const [canonicalName, shorthandProperty] of activeProperties) {
864
860
  const shorthandStyle = shorthandProperty.ownerStyle;
865
- const longhands = shorthandStyle.longhandProperties(shorthandProperty.name);
861
+ const longhands = shorthandProperty.getLonghandProperties();
866
862
  if (!longhands.length) {
867
863
  continue;
868
864
  }
@@ -27,10 +27,12 @@ export class CSSProperty {
27
27
  #nameRangeInternal: TextUtils.TextRange.TextRange|null;
28
28
  #valueRangeInternal: TextUtils.TextRange.TextRange|null;
29
29
  #invalidString?: Common.UIString.LocalizedString;
30
+ #longhandProperties: CSSProperty[] = [];
30
31
 
31
32
  constructor(
32
33
  ownerStyle: CSSStyleDeclaration, index: number, name: string, value: string, important: boolean,
33
- disabled: boolean, parsedOk: boolean, implicit: boolean, text?: string|null, range?: Protocol.CSS.SourceRange) {
34
+ disabled: boolean, parsedOk: boolean, implicit: boolean, text?: string|null, range?: Protocol.CSS.SourceRange,
35
+ longhandProperties?: Protocol.CSS.CSSProperty[]) {
34
36
  this.ownerStyle = ownerStyle;
35
37
  this.index = index;
36
38
  this.name = name;
@@ -44,6 +46,24 @@ export class CSSProperty {
44
46
  this.#active = true;
45
47
  this.#nameRangeInternal = null;
46
48
  this.#valueRangeInternal = null;
49
+
50
+ if (longhandProperties && longhandProperties.length > 0) {
51
+ for (const property of longhandProperties) {
52
+ this.#longhandProperties.push(new CSSProperty(
53
+ ownerStyle, this.#longhandProperties.length, property.name, property.value, important, disabled, parsedOk,
54
+ true));
55
+ }
56
+ } else {
57
+ // Blink would not parse shorthands containing 'var()' functions:
58
+ // https://drafts.csswg.org/css-variables/#variables-in-shorthands).
59
+ // Therefore we manually check if the current property is a shorthand,
60
+ // and fills its longhand components with empty values.
61
+ const longhandNames = cssMetadata().getLonghands(name);
62
+ for (const longhandName of longhandNames || []) {
63
+ this.#longhandProperties.push(new CSSProperty(
64
+ ownerStyle, this.#longhandProperties.length, longhandName, '', important, disabled, parsedOk, true));
65
+ }
66
+ }
47
67
  }
48
68
 
49
69
  static parsePayload(ownerStyle: CSSStyleDeclaration, index: number, payload: Protocol.CSS.CSSProperty): CSSProperty {
@@ -55,7 +75,7 @@ export class CSSProperty {
55
75
  const result = new CSSProperty(
56
76
  ownerStyle, index, payload.name, payload.value, payload.important || false, payload.disabled || false,
57
77
  ('parsedOk' in payload) ? Boolean(payload.parsedOk) : true, Boolean(payload.implicit), payload.text,
58
- payload.range);
78
+ payload.range, payload.longhandProperties);
59
79
  return result;
60
80
  }
61
81
 
@@ -302,4 +322,8 @@ export class CSSProperty {
302
322
  getInvalidStringForInvalidProperty(): Common.UIString.LocalizedString|undefined {
303
323
  return this.#invalidString;
304
324
  }
325
+
326
+ getLonghandProperties(): CSSProperty[] {
327
+ return this.#longhandProperties;
328
+ }
305
329
  }
@@ -62,19 +62,15 @@ export class CSSStyleDeclaration {
62
62
 
63
63
  if (payload.cssText && this.range) {
64
64
  const cssText = new TextUtils.Text.Text(payload.cssText);
65
- let start: {
66
- line: number,
67
- column: number,
68
- }|{
69
- line: number,
70
- column: number,
71
- } = {line: this.range.startLine, column: this.range.startColumn};
65
+ let start = {line: this.range.startLine, column: this.range.startColumn};
72
66
  for (const cssProperty of payload.cssProperties) {
73
67
  const range = cssProperty.range;
74
68
  if (range) {
75
69
  parseUnusedText.call(this, cssText, start.line, start.column, range.startLine, range.startColumn);
76
70
  start = {line: range.endLine, column: range.endColumn};
77
71
  }
72
+ // TODO(changhaohan): we should try not including longhand properties anymore, because
73
+ // they are already included in the longhandProperties field in a shorthand property.
78
74
  this.#allPropertiesInternal.push(
79
75
  CSSProperty.parsePayload(this, this.#allPropertiesInternal.length, cssProperty));
80
76
  }
@@ -303,18 +299,6 @@ export class CSSStyleDeclaration {
303
299
  return property ? property.implicit : false;
304
300
  }
305
301
 
306
- longhandProperties(name: string): CSSProperty[] {
307
- const longhands = cssMetadata().getLonghands(name.toLowerCase());
308
- const result = [];
309
- for (let i = 0; longhands && i < longhands.length; ++i) {
310
- const property = this.#activePropertyMap.get(longhands[i]);
311
- if (property) {
312
- result.push(property);
313
- }
314
- }
315
- return result;
316
- }
317
-
318
302
  propertyAt(index: number): CSSProperty|null {
319
303
  return (index < this.allProperties().length) ? this.allProperties()[index] : null;
320
304
  }
@@ -458,7 +458,7 @@ export class AppManifestView extends UI.Widget.VBox implements SDK.TargetManager
458
458
  this.presentationSection = this.reportView.appendSection(i18nString(UIStrings.presentation));
459
459
  this.protocolHandlersSection = this.reportView.appendSection(i18nString(UIStrings.protocolHandlers));
460
460
  this.protocolHandlersView = new ApplicationComponents.ProtocolHandlersView.ProtocolHandlersView();
461
- this.protocolHandlersSection.contentElement.append(this.protocolHandlersView);
461
+ this.protocolHandlersSection.appendFieldWithCustomView(this.protocolHandlersView);
462
462
  this.iconsSection = this.reportView.appendSection(i18nString(UIStrings.icons), 'report-section-icons');
463
463
  this.shortcutSections = [];
464
464
  this.screenshotsSections = [];
@@ -981,7 +981,8 @@ export class AppManifestTreeElement extends ApplicationPanelTreeElement {
981
981
  for (const section of staticSections) {
982
982
  const sectionElement = section.getTitleElement();
983
983
  const childTitle = section.title();
984
- const child = new ManifestChildTreeElement(this.resourcesPanel, sectionElement, childTitle);
984
+ const sectionFieldElement = section.getFieldElement();
985
+ const child = new ManifestChildTreeElement(this.resourcesPanel, sectionElement, childTitle, sectionFieldElement);
985
986
  this.appendChild(child);
986
987
  }
987
988
  }
@@ -998,12 +999,15 @@ export class AppManifestTreeElement extends ApplicationPanelTreeElement {
998
999
 
999
1000
  export class ManifestChildTreeElement extends ApplicationPanelTreeElement {
1000
1001
  #sectionElement: Element;
1001
- constructor(storagePanel: ResourcesPanel, element: Element, childTitle: string) {
1002
+ #sectionFieldElement: HTMLElement;
1003
+ constructor(storagePanel: ResourcesPanel, element: Element, childTitle: string, fieldElement: HTMLElement) {
1002
1004
  super(storagePanel, childTitle, false);
1003
1005
  const icon = UI.Icon.Icon.create('mediumicon-manifest', 'resource-tree-item');
1004
1006
  this.setLeadingIcons([icon]);
1005
1007
  this.#sectionElement = element;
1008
+ this.#sectionFieldElement = fieldElement;
1006
1009
  self.onInvokeElement(this.listItemElement, this.onInvoke.bind(this));
1010
+ this.listItemElement.addEventListener('keydown', this.onInvokeElementKeydown.bind(this));
1007
1011
  UI.ARIAUtils.setAccessibleName(
1008
1012
  this.listItemElement, i18nString(UIStrings.beforeInvokeAlert, {PH1: this.listItemElement.title}));
1009
1013
  }
@@ -1018,6 +1022,26 @@ export class ManifestChildTreeElement extends ApplicationPanelTreeElement {
1018
1022
  UI.ARIAUtils.alert(i18nString(UIStrings.onInvokeAlert, {PH1: this.listItemElement.title}));
1019
1023
  Host.userMetrics.manifestSectionSelected(this.listItemElement.title);
1020
1024
  }
1025
+ // direct focus to the corresponding element
1026
+ onInvokeElementKeydown(event: KeyboardEvent): void {
1027
+ if (event.key !== 'Tab' || event.shiftKey) {
1028
+ return;
1029
+ }
1030
+ const checkBoxElement = this.#sectionFieldElement.querySelector('.mask-checkbox');
1031
+ let focusableElement: HTMLElement|null = this.#sectionFieldElement.querySelector('[tabindex="0"]');
1032
+ if (checkBoxElement && checkBoxElement.shadowRoot) {
1033
+ focusableElement = checkBoxElement.shadowRoot.querySelector('input') || null;
1034
+ } else if (!focusableElement) {
1035
+ // special case for protocol handler section since it is a custom Element and has different structure than the others
1036
+ focusableElement = this.#sectionFieldElement.querySelector('devtools-protocol-handlers-view')
1037
+ ?.shadowRoot?.querySelector('[tabindex="0"]') ||
1038
+ null;
1039
+ }
1040
+ if (focusableElement) {
1041
+ focusableElement?.focus();
1042
+ event.consume(true);
1043
+ }
1044
+ }
1021
1045
  }
1022
1046
 
1023
1047
  export class ClearStorageTreeElement extends ApplicationPanelTreeElement {
@@ -176,9 +176,11 @@ export class IndexedDBModel extends SDK.SDKModel.SDKModel<EventTypes> implements
176
176
  if (!this.enabled) {
177
177
  return;
178
178
  }
179
- await this.indexedDBAgent.invoke_deleteDatabase(
180
- {securityOrigin: databaseId.securityOrigin, databaseName: databaseId.name});
181
- void this.loadDatabaseNames(databaseId.securityOrigin);
179
+ if (databaseId.securityOrigin) {
180
+ await this.indexedDBAgent.invoke_deleteDatabase(
181
+ {securityOrigin: databaseId.securityOrigin, databaseName: databaseId.name});
182
+ void this.loadDatabaseNames(databaseId.securityOrigin);
183
+ }
182
184
  }
183
185
 
184
186
  async refreshDatabaseNames(): Promise<void> {
@@ -193,14 +195,18 @@ export class IndexedDBModel extends SDK.SDKModel.SDKModel<EventTypes> implements
193
195
  }
194
196
 
195
197
  async clearObjectStore(databaseId: DatabaseId, objectStoreName: string): Promise<void> {
196
- await this.indexedDBAgent.invoke_clearObjectStore(
197
- {securityOrigin: databaseId.securityOrigin, databaseName: databaseId.name, objectStoreName});
198
+ if (databaseId.securityOrigin) {
199
+ await this.indexedDBAgent.invoke_clearObjectStore(
200
+ {securityOrigin: databaseId.securityOrigin, databaseName: databaseId.name, objectStoreName});
201
+ }
198
202
  }
199
203
 
200
204
  async deleteEntries(databaseId: DatabaseId, objectStoreName: string, idbKeyRange: IDBKeyRange): Promise<void> {
201
205
  const keyRange = IndexedDBModel.keyRangeFromIDBKeyRange(idbKeyRange);
202
- await this.indexedDBAgent.invoke_deleteObjectStoreEntries(
203
- {securityOrigin: databaseId.securityOrigin, databaseName: databaseId.name, objectStoreName, keyRange});
206
+ if (databaseId.securityOrigin) {
207
+ await this.indexedDBAgent.invoke_deleteObjectStoreEntries(
208
+ {securityOrigin: databaseId.securityOrigin, databaseName: databaseId.name, objectStoreName, keyRange});
209
+ }
204
210
  }
205
211
 
206
212
  private securityOriginAdded(event: Common.EventTarget.EventTargetEvent<string>): void {
@@ -259,19 +265,19 @@ export class IndexedDBModel extends SDK.SDKModel.SDKModel<EventTypes> implements
259
265
  for (const securityOrigin in this.databaseNamesBySecurityOrigin) {
260
266
  const databaseNames = this.databaseNamesBySecurityOrigin[securityOrigin];
261
267
  for (let i = 0; i < databaseNames.length; ++i) {
262
- result.push(new DatabaseId(securityOrigin, databaseNames[i]));
268
+ result.push(new DatabaseId(securityOrigin, undefined, databaseNames[i]));
263
269
  }
264
270
  }
265
271
  return result;
266
272
  }
267
273
 
268
274
  private databaseAdded(securityOrigin: string, databaseName: string): void {
269
- const databaseId = new DatabaseId(securityOrigin, databaseName);
275
+ const databaseId = new DatabaseId(securityOrigin, undefined, databaseName);
270
276
  this.dispatchEventToListeners(Events.DatabaseAdded, {model: this, databaseId: databaseId});
271
277
  }
272
278
 
273
279
  private databaseRemoved(securityOrigin: string, databaseName: string): void {
274
- const databaseId = new DatabaseId(securityOrigin, databaseName);
280
+ const databaseId = new DatabaseId(securityOrigin, undefined, databaseName);
275
281
  this.dispatchEventToListeners(Events.DatabaseRemoved, {model: this, databaseId: databaseId});
276
282
  }
277
283
 
@@ -288,15 +294,20 @@ export class IndexedDBModel extends SDK.SDKModel.SDKModel<EventTypes> implements
288
294
  }
289
295
 
290
296
  private async loadDatabase(databaseId: DatabaseId, entriesUpdated: boolean): Promise<void> {
291
- const {databaseWithObjectStores} = await this.indexedDBAgent.invoke_requestDatabase(
292
- {securityOrigin: databaseId.securityOrigin, databaseName: databaseId.name});
297
+ let databaseWithObjectStores: Protocol.IndexedDB.DatabaseWithObjectStores|null = null;
298
+ if (databaseId.securityOrigin) {
299
+ databaseWithObjectStores = (await this.indexedDBAgent.invoke_requestDatabase({
300
+ securityOrigin: databaseId.securityOrigin,
301
+ databaseName: databaseId.name,
302
+ })).databaseWithObjectStores;
303
+ if (!this.databaseNamesBySecurityOrigin[databaseId.securityOrigin]) {
304
+ return;
305
+ }
306
+ }
293
307
 
294
308
  if (!databaseWithObjectStores) {
295
309
  return;
296
310
  }
297
- if (!this.databaseNamesBySecurityOrigin[databaseId.securityOrigin]) {
298
- return;
299
- }
300
311
 
301
312
  const databaseModel = new Database(databaseId, databaseWithObjectStores.version);
302
313
  this.databasesInternal.set(databaseId, databaseModel);
@@ -334,44 +345,58 @@ export class IndexedDBModel extends SDK.SDKModel.SDKModel<EventTypes> implements
334
345
  idbKeyRange: IDBKeyRange|null, skipCount: number, pageSize: number,
335
346
  callback: (arg0: Array<Entry>, arg1: boolean) => void): Promise<void> {
336
347
  const keyRange = idbKeyRange ? IndexedDBModel.keyRangeFromIDBKeyRange(idbKeyRange) : undefined;
348
+ const runtimeModel = this.target().model(SDK.RuntimeModel.RuntimeModel);
349
+ let response: Protocol.IndexedDB.RequestDataResponse|null = null;
350
+
351
+ if (databaseId.securityOrigin) {
352
+ response = await this.indexedDBAgent.invoke_requestData({
353
+ securityOrigin: databaseId.securityOrigin,
354
+ databaseName,
355
+ objectStoreName,
356
+ indexName,
357
+ skipCount,
358
+ pageSize,
359
+ keyRange,
360
+ });
361
+ if (!runtimeModel || !this.databaseNamesBySecurityOrigin[databaseId.securityOrigin]) {
362
+ return;
363
+ }
364
+ }
337
365
 
338
- const response = await this.indexedDBAgent.invoke_requestData({
339
- securityOrigin: databaseId.securityOrigin,
340
- databaseName,
341
- objectStoreName,
342
- indexName,
343
- skipCount,
344
- pageSize,
345
- keyRange,
346
- });
347
-
366
+ if (!response) {
367
+ return;
368
+ }
348
369
  if (response.getError()) {
349
370
  console.error('IndexedDBAgent error: ' + response.getError());
350
371
  return;
351
372
  }
352
373
 
353
- const runtimeModel = this.target().model(SDK.RuntimeModel.RuntimeModel);
354
- if (!runtimeModel || !this.databaseNamesBySecurityOrigin[databaseId.securityOrigin]) {
355
- return;
356
- }
357
374
  const dataEntries = response.objectStoreDataEntries;
358
375
  const entries = [];
359
376
  for (const dataEntry of dataEntries) {
360
- const key = runtimeModel.createRemoteObject(dataEntry.key);
361
- const primaryKey = runtimeModel.createRemoteObject(dataEntry.primaryKey);
362
- const value = runtimeModel.createRemoteObject(dataEntry.value);
377
+ const key = runtimeModel?.createRemoteObject(dataEntry.key);
378
+ const primaryKey = runtimeModel?.createRemoteObject(dataEntry.primaryKey);
379
+ const value = runtimeModel?.createRemoteObject(dataEntry.value);
380
+ if (!key || !primaryKey || !value) {
381
+ return;
382
+ }
363
383
  entries.push(new Entry(key, primaryKey, value));
364
384
  }
365
385
  callback(entries, response.hasMore);
366
386
  }
367
387
 
368
388
  async getMetadata(databaseId: DatabaseId, objectStore: ObjectStore): Promise<ObjectStoreMetadata|null> {
369
- const databaseOrigin = databaseId.securityOrigin;
370
389
  const databaseName = databaseId.name;
371
390
  const objectStoreName = objectStore.name;
372
- const response =
373
- await this.indexedDBAgent.invoke_getMetadata({securityOrigin: databaseOrigin, databaseName, objectStoreName});
391
+ let response: Protocol.IndexedDB.GetMetadataResponse|null = null;
392
+ if (databaseId.securityOrigin) {
393
+ response = await this.indexedDBAgent.invoke_getMetadata(
394
+ {securityOrigin: databaseId.securityOrigin, databaseName, objectStoreName});
395
+ }
374
396
 
397
+ if (!response) {
398
+ return null;
399
+ }
375
400
  if (response.getError()) {
376
401
  console.error('IndexedDBAgent error: ' + response.getError());
377
402
  return null;
@@ -382,7 +407,7 @@ export class IndexedDBModel extends SDK.SDKModel.SDKModel<EventTypes> implements
382
407
  private async refreshDatabaseList(securityOrigin: string): Promise<void> {
383
408
  const databaseNames = await this.loadDatabaseNames(securityOrigin);
384
409
  for (const databaseName of databaseNames) {
385
- void this.loadDatabase(new DatabaseId(securityOrigin, databaseName), false);
410
+ void this.loadDatabase(new DatabaseId(securityOrigin, undefined, databaseName), false);
386
411
  }
387
412
  }
388
413
 
@@ -400,7 +425,7 @@ export class IndexedDBModel extends SDK.SDKModel.SDKModel<EventTypes> implements
400
425
 
401
426
  indexedDBContentUpdated({origin: securityOrigin, databaseName, objectStoreName}:
402
427
  Protocol.Storage.IndexedDBContentUpdatedEvent): void {
403
- const databaseId = new DatabaseId(securityOrigin, databaseName);
428
+ const databaseId = new DatabaseId(securityOrigin, undefined, databaseName);
404
429
  this.dispatchEventToListeners(
405
430
  Events.IndexedDBContentUpdated, {databaseId: databaseId, objectStoreName: objectStoreName, model: this});
406
431
  }
@@ -450,15 +475,17 @@ export class Entry {
450
475
  }
451
476
 
452
477
  export class DatabaseId {
453
- securityOrigin: string;
478
+ readonly securityOrigin?: string;
479
+ readonly storageKey?: string;
454
480
  name: string;
455
- constructor(securityOrigin: string, name: string) {
456
- this.securityOrigin = securityOrigin;
481
+ constructor(securityOrigin: string|undefined, storageKey: string|undefined, name: string) {
482
+ securityOrigin ? this.securityOrigin = securityOrigin : (storageKey ? this.storageKey = storageKey : undefined);
457
483
  this.name = name;
458
484
  }
459
485
 
460
486
  equals(databaseId: DatabaseId): boolean {
461
- return this.name === databaseId.name && this.securityOrigin === databaseId.securityOrigin;
487
+ return this.name === databaseId.name && this.securityOrigin === databaseId.securityOrigin &&
488
+ this.storageKey === databaseId.storageKey;
462
489
  }
463
490
  }
464
491
 
@@ -198,7 +198,9 @@ export class IDBDatabaseView extends UI.Widget.VBox {
198
198
  }
199
199
 
200
200
  private refreshDatabase(): void {
201
- this.securityOriginElement.textContent = this.database.databaseId.securityOrigin;
201
+ if (this.database.databaseId.securityOrigin) {
202
+ this.securityOriginElement.textContent = this.database.databaseId.securityOrigin;
203
+ }
202
204
  if (this.versionElement) {
203
205
  this.versionElement.textContent = this.database.version.toString();
204
206
  }
@@ -971,7 +971,7 @@ export class StylePropertiesSection {
971
971
  break;
972
972
  }
973
973
  count++;
974
- const isShorthand = Boolean(style.longhandProperties(property.name).length);
974
+ const isShorthand = property.getLonghandProperties().length > 0;
975
975
  const inherited = this.isPropertyInherited(property.name);
976
976
  const overloaded = this.isPropertyOverloaded(property);
977
977
  if (style.parentRule && style.parentRule.isUserAgent() && inherited) {
@@ -558,19 +558,19 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
558
558
  return;
559
559
  }
560
560
 
561
- const longhandProperties = this.style.longhandProperties(this.name);
561
+ const longhandProperties = this.property.getLonghandProperties();
562
562
  const leadingProperties = this.style.leadingProperties();
563
563
 
564
- for (let i = 0; i < longhandProperties.length; ++i) {
565
- const name = longhandProperties[i].name;
564
+ for (const property of longhandProperties) {
565
+ const name = property.name;
566
566
  let inherited = false;
567
567
  let overloaded = false;
568
568
 
569
569
  const section = this.section();
570
570
  if (section) {
571
571
  inherited = section.isPropertyInherited(name);
572
- overloaded = this.matchedStylesInternal.propertyState(longhandProperties[i]) ===
573
- SDK.CSSMatchedStyles.PropertyState.Overloaded;
572
+ overloaded =
573
+ this.matchedStylesInternal.propertyState(property) === SDK.CSSMatchedStyles.PropertyState.Overloaded;
574
574
  }
575
575
 
576
576
  const leadingProperty = leadingProperties.find(property => property.name === name && property.activeInStyle());
@@ -579,8 +579,7 @@ export class StylePropertyTreeElement extends UI.TreeOutline.TreeElement {
579
579
  }
580
580
 
581
581
  const item = new StylePropertyTreeElement(
582
- this.parentPaneInternal, this.matchedStylesInternal, longhandProperties[i], false, inherited, overloaded,
583
- false);
582
+ this.parentPaneInternal, this.matchedStylesInternal, property, false, inherited, overloaded, false);
584
583
  item.setComputedStyles(this.computedStyles);
585
584
  item.setParentsComputedStyles(this.parentsComputedStyles);
586
585
  this.appendChild(item);
@@ -1396,7 +1396,11 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
1396
1396
  button.setToggleWithDot(true);
1397
1397
 
1398
1398
  button.element.addEventListener('click', event => {
1399
- const menu = new UI.ContextMenu.ContextMenu(event);
1399
+ const boundingRect = button.element.getBoundingClientRect();
1400
+ const menu = new UI.ContextMenu.ContextMenu(event, {
1401
+ x: boundingRect.left,
1402
+ y: boundingRect.bottom,
1403
+ });
1400
1404
  const preferredColorScheme = prefersColorSchemeSetting.get();
1401
1405
  const isLightColorScheme = preferredColorScheme === 'light';
1402
1406
  const isDarkColorScheme = preferredColorScheme === 'dark';
@@ -461,6 +461,7 @@ export class ShortcutListItem {
461
461
  private createIconButton(label: string, iconName: string, className: string, listener: () => void):
462
462
  HTMLButtonElement {
463
463
  const button = document.createElement('button') as HTMLButtonElement;
464
+ button.setAttribute('title', label);
464
465
  button.appendChild(UI.Icon.Icon.create(iconName));
465
466
  button.addEventListener('click', listener);
466
467
  UI.ARIAUtils.setAccessibleName(button, label);
@@ -171,6 +171,10 @@ button.text-button {
171
171
  margin: 0 2px;
172
172
  }
173
173
 
174
+ .keybinds-list-text:has(.keybinds-delete-button) {
175
+ grid-column: 3 / -1;
176
+ }
177
+
174
178
  .docs-link.devtools-link {
175
179
  align-self: flex-start;
176
180
  min-height: 2em;
@@ -12,13 +12,16 @@ import linearMemoryHighlightChipListStyles from './linearMemoryHighlightChipList
12
12
 
13
13
  const UIStrings = {
14
14
  /**
15
- *@description Tooltip text that appears when hovering over a 'jump-to-highlight-button' button that is on the left side of a 'highlight-chip' chip.
15
+ *@description Tooltip text that appears when hovering over an inspected variable's button in the Linear Memory Highlight Chip List.
16
+ Clicking the button changes the displayed slice of computer memory in the Linear Memory Inspector to contain the inspected variable's bytes.
16
17
  */
17
- jumpToAddress: 'Jump to highlighted memory',
18
+ jumpToAddress: 'Jump to this memory',
18
19
  /**
19
- *@description Tooltip text that appears when hovering over a 'remove-highlight-button' button that is on the right end of a 'highlight-chip' chip.
20
+ *@description Tooltip text that appears when hovering over an inspected variable's delete button in the Linear Memory Highlight Chip List.
21
+ Clicking the delete button stops highlighting the variable's memory in the Linear Memory Inspector.
22
+ 'Memory' is a slice of bytes in the computer memory.
20
23
  */
21
- deleteHighlight: 'Delete memory highlight',
24
+ deleteHighlight: 'Stop highlighting this memory',
22
25
  };
23
26
  const str_ =
24
27
  i18n.i18n.registerUIStrings('ui/components/linear_memory_inspector/LinearMemoryHighlightChipList.ts', UIStrings);
@@ -27,6 +30,7 @@ const {render, html} = LitHtml;
27
30
 
28
31
  export interface LinearMemoryHighlightChipListData {
29
32
  highlightInfos: Array<HighlightInfo>;
33
+ focusedMemoryHighlight?: HighlightInfo;
30
34
  }
31
35
 
32
36
  export class DeleteMemoryHighlightEvent extends Event {
@@ -54,6 +58,7 @@ export class LinearMemoryHighlightChipList extends HTMLElement {
54
58
 
55
59
  readonly #shadow = this.attachShadow({mode: 'open'});
56
60
  #highlightedAreas: HighlightInfo[] = [];
61
+ #focusedMemoryHighlight?: HighlightInfo;
57
62
 
58
63
  connectedCallback(): void {
59
64
  this.#shadow.adoptedStyleSheets = [linearMemoryHighlightChipListStyles];
@@ -61,6 +66,7 @@ export class LinearMemoryHighlightChipList extends HTMLElement {
61
66
 
62
67
  set data(data: LinearMemoryHighlightChipListData) {
63
68
  this.#highlightedAreas = data.highlightInfos;
69
+ this.#focusedMemoryHighlight = data.focusedMemoryHighlight;
64
70
  this.#render();
65
71
  }
66
72
 
@@ -83,11 +89,15 @@ export class LinearMemoryHighlightChipList extends HTMLElement {
83
89
  #createChip(highlightInfo: HighlightInfo): LitHtml.TemplateResult {
84
90
  const expressionName = highlightInfo.name || '<anonymous>';
85
91
  const expressionType = highlightInfo.type;
86
-
92
+ const isFocused = highlightInfo === this.#focusedMemoryHighlight;
93
+ const classMap = {
94
+ focused: isFocused,
95
+ 'highlight-chip': true,
96
+ };
87
97
  // Disabled until https://crbug.com/1079231 is fixed.
88
98
  // clang-format off
89
99
  return html`
90
- <div class="highlight-chip">
100
+ <div class=${LitHtml.Directives.classMap(classMap)}>
91
101
  <button class="jump-to-highlight-button" title=${
92
102
  i18nString(UIStrings.jumpToAddress)}
93
103
  @click=${():void => this.#onJumpToHighlightClick(highlightInfo.startAddress)}>
@@ -203,6 +203,7 @@ export class LinearMemoryInspector extends HTMLElement {
203
203
  const canGoForwardInHistory = this.#history.canRollover();
204
204
 
205
205
  const highlightedMemoryAreas = this.#highlightInfo ? [this.#highlightInfo] : [];
206
+ const focusedMemoryHighlight = this.#getSmallestEnclosingMemoryHighlight(highlightedMemoryAreas, this.#address);
206
207
  // Disabled until https://crbug.com/1079231 is fixed.
207
208
  // clang-format off
208
209
  render(html`
@@ -214,9 +215,8 @@ export class LinearMemoryInspector extends HTMLElement {
214
215
  @pagenavigation=${this.#navigatePage}
215
216
  @historynavigation=${this.#navigateHistory}></${LinearMemoryNavigator.litTagName}>
216
217
  <${LinearMemoryHighlightChipList.litTagName}
217
- .data=${{highlightInfos: highlightedMemoryAreas} as LinearMemoryHighlightChipListData}
218
- @jumptohighlightedmemory=${this.#onJumpToAddress}
219
- @>
218
+ .data=${{highlightInfos: highlightedMemoryAreas, focusedMemoryHighlight: focusedMemoryHighlight } as LinearMemoryHighlightChipListData}
219
+ @jumptohighlightedmemory=${this.#onJumpToAddress}>
220
220
  </${LinearMemoryHighlightChipList.litTagName}>
221
221
  <${LinearMemoryViewer.litTagName}
222
222
  .data=${{
@@ -224,7 +224,8 @@ export class LinearMemoryInspector extends HTMLElement {
224
224
  end - this.#memoryOffset),
225
225
  address: this.#address, memoryOffset: start,
226
226
  focus: this.#currentNavigatorMode === Mode.Submitted,
227
- highlightInfo: this.#highlightInfo } as LinearMemoryViewerData}
227
+ highlightInfo: this.#highlightInfo,
228
+ focusedMemoryHighlight: focusedMemoryHighlight } as LinearMemoryViewerData}
228
229
  @byteselected=${this.#onByteSelected}
229
230
  @resize=${this.#resize}>
230
231
  </${LinearMemoryViewer.litTagName}>
@@ -375,6 +376,29 @@ export class LinearMemoryInspector extends HTMLElement {
375
376
  this.#address = address;
376
377
  this.dispatchEvent(new AddressChangedEvent(this.#address));
377
378
  }
379
+
380
+ // Returns the highlightInfo with the smallest size property that encloses the provided address.
381
+ // If there are multiple smallest enclosing highlights, we pick the one appearing the earliest in highlightedMemoryAreas.
382
+ // If no such highlightInfo exists, it returns undefined.
383
+ //
384
+ // Selecting the smallest enclosing memory highlight is a heuristic that aims to pick the
385
+ // most specific highlight given a provided address. This way, objects contained in other objects are
386
+ // potentially still accessible.
387
+ #getSmallestEnclosingMemoryHighlight(highlightedMemoryAreas: HighlightInfo[], address: number): HighlightInfo
388
+ |undefined {
389
+ let smallestEnclosingHighlight;
390
+ for (const highlightedMemory of highlightedMemoryAreas) {
391
+ if (highlightedMemory.startAddress <= address &&
392
+ address < highlightedMemory.startAddress + highlightedMemory.size) {
393
+ if (!smallestEnclosingHighlight) {
394
+ smallestEnclosingHighlight = highlightedMemory;
395
+ } else if (highlightedMemory.size < smallestEnclosingHighlight.size) {
396
+ smallestEnclosingHighlight = highlightedMemory;
397
+ }
398
+ }
399
+ }
400
+ return smallestEnclosingHighlight;
401
+ }
378
402
  }
379
403
 
380
404
  ComponentHelpers.CustomElements.defineComponent('devtools-linear-memory-inspector-inspector', LinearMemoryInspector);
@@ -16,6 +16,7 @@ export interface LinearMemoryViewerData {
16
16
  memoryOffset: number;
17
17
  focus: boolean;
18
18
  highlightInfo?: HighlightInfo;
19
+ focusedMemoryHighlight?: HighlightInfo;
19
20
  }
20
21
 
21
22
  export class ByteSelectedEvent extends Event {
@@ -53,6 +54,7 @@ export class LinearMemoryViewer extends HTMLElement {
53
54
  #address = 0;
54
55
  #memoryOffset = 0;
55
56
  #highlightInfo?: HighlightInfo;
57
+ #focusedMemoryHighlight?: HighlightInfo;
56
58
 
57
59
  #numRows = 1;
58
60
  #numBytesInRow = BYTE_GROUP_SIZE;
@@ -73,6 +75,7 @@ export class LinearMemoryViewer extends HTMLElement {
73
75
  this.#memory = data.memory;
74
76
  this.#address = data.address;
75
77
  this.#highlightInfo = data.highlightInfo;
78
+ this.#focusedMemoryHighlight = data.focusedMemoryHighlight;
76
79
  this.#memoryOffset = data.memoryOffset;
77
80
  this.#focusOnByte = data.focus;
78
81
  this.#update();
@@ -239,12 +242,14 @@ export class LinearMemoryViewer extends HTMLElement {
239
242
  const addMargin = i !== startIndex && (i - startIndex) % BYTE_GROUP_SIZE === 0;
240
243
  const selected = i === this.#address - this.#memoryOffset;
241
244
  const shouldBeHighlighted = this.#shouldBeHighlighted(actualIndex);
245
+ const focusedMemoryArea = this.#isFocusedArea(actualIndex);
242
246
  const classMap = {
243
247
  'cell': true,
244
248
  'byte-cell': true,
245
249
  'byte-group-margin': addMargin,
246
250
  selected,
247
251
  'highlight-area': shouldBeHighlighted,
252
+ 'focused-area': focusedMemoryArea,
248
253
  };
249
254
  const isSelectableCell = i < this.#memory.length;
250
255
  const byteValue = isSelectableCell ? html`${toHexString({number: this.#memory[i], pad: 2, prefix: false})}` : '';
@@ -259,11 +264,13 @@ export class LinearMemoryViewer extends HTMLElement {
259
264
  for (let i = startIndex; i < endIndex; ++i) {
260
265
  const actualIndex = i + this.#memoryOffset;
261
266
  const shouldBeHighlighted = this.#shouldBeHighlighted(actualIndex);
267
+ const focusedMemoryArea = this.#isFocusedArea(actualIndex);
262
268
  const classMap = {
263
269
  'cell': true,
264
270
  'text-cell': true,
265
271
  selected: this.#address - this.#memoryOffset === i,
266
272
  'highlight-area': shouldBeHighlighted,
273
+ 'focused-area': focusedMemoryArea,
267
274
  };
268
275
  const isSelectableCell = i < this.#memory.length;
269
276
  const value = isSelectableCell ? html`${this.#toAscii(this.#memory[i])}` : '';
@@ -291,6 +298,14 @@ export class LinearMemoryViewer extends HTMLElement {
291
298
  return this.#highlightInfo.startAddress <= index
292
299
  && index < this.#highlightInfo.startAddress + this.#highlightInfo.size;
293
300
  }
301
+
302
+ #isFocusedArea(index: number): boolean {
303
+ if (!this.#focusedMemoryHighlight) {
304
+ return false;
305
+ }
306
+ return this.#focusedMemoryHighlight.startAddress <= index
307
+ && index < this.#focusedMemoryHighlight.startAddress + this.#focusedMemoryHighlight.size;
308
+ }
294
309
  }
295
310
 
296
311
  ComponentHelpers.CustomElements.defineComponent('devtools-linear-memory-inspector-viewer', LinearMemoryViewer);
@@ -59,18 +59,6 @@
59
59
  border-radius: 50%;
60
60
  }
61
61
 
62
- .highlight-chip:hover > .delete-highlight-container {
63
- display: flex;
64
- /* To avoid issues with stacking semi-transparent colors, we use a hardcoded solid color here. */
65
- background: linear-gradient(90deg, transparent 0%, rgb(241 243 244) 25%); /* stylelint-disable-line plugin/use_theme_colors */
66
- }
67
-
68
- :host-context(.-theme-with-dark-background) .highlight-chip:hover > .delete-highlight-container {
69
- display: flex;
70
- /* To avoid issues with stacking semi-transparent colors, we use a hardcoded solid color here. */
71
- background: linear-gradient(90deg, transparent 0%, rgb(41 42 45) 25%); /* stylelint-disable-line plugin/use_theme_colors */
72
- }
73
-
74
62
  .jump-to-highlight-button {
75
63
  cursor: pointer;
76
64
  padding: 0;
@@ -108,3 +96,30 @@
108
96
  white-space: pre;
109
97
  flex-shrink: 0;
110
98
  }
99
+
100
+ .highlight-chip.focused {
101
+ border-color: var(--color-primary);
102
+ background-color: var(--color-button-secondary-background-hovering);
103
+ }
104
+
105
+ .highlight-chip:hover > .delete-highlight-container {
106
+ display: flex;
107
+ /* To avoid issues with stacking semi-transparent colors, we use a hardcoded solid color here. */
108
+ background: linear-gradient(90deg, transparent 0%, rgb(241 243 244) 25%); /* stylelint-disable-line plugin/use_theme_colors */
109
+ }
110
+
111
+ .highlight-chip.focused:hover > .delete-highlight-container {
112
+ /* To avoid issues with stacking semi-transparent colors, we use a hardcoded solid color here. */
113
+ background: linear-gradient(90deg, transparent 0%, rgb(231 241 253) 25%); /* stylelint-disable-line plugin/use_theme_colors */
114
+ }
115
+
116
+ :host-context(.-theme-with-dark-background) .highlight-chip:hover > .delete-highlight-container {
117
+ display: flex;
118
+ /* To avoid issues with stacking semi-transparent colors, we use a hardcoded solid color here. */
119
+ background: linear-gradient(90deg, transparent 0%, rgb(41 42 45) 25%); /* stylelint-disable-line plugin/use_theme_colors */
120
+ }
121
+
122
+ :host-context(.-theme-with-dark-background) .highlight-chip.focused:hover > .delete-highlight-container {
123
+ /* To avoid issues with stacking semi-transparent colors, we use a hardcoded solid color here. */
124
+ background: linear-gradient(90deg, transparent 0%, rgb(48 55 68) 25%); /* stylelint-disable-line plugin/use_theme_colors */
125
+ }
@@ -36,10 +36,6 @@
36
36
  background-color: var(--legacy-item-selection-bg-color);
37
37
  }
38
38
 
39
- .highlight-area {
40
- background-color: var(--legacy-item-selection-bg-color);
41
- }
42
-
43
39
  .byte-cell {
44
40
  min-width: 21px;
45
41
  color: var(--color-text-primary);
@@ -69,3 +65,22 @@
69
65
  background-color: var(--color-details-hairline);
70
66
  margin: 0 4px;
71
67
  }
68
+
69
+ .highlight-area {
70
+ background-color: var(--color-background-elevation-2);
71
+ }
72
+
73
+ .cell.focused-area {
74
+ background-color: var(--color-primary-variant);
75
+ color: var(--color-button-primary-text);
76
+ }
77
+
78
+ .cell.focused-area.selected {
79
+ background: rgb(1 74 195); /* stylelint-disable-line plugin/use_theme_colors */
80
+ border-color: var(--color-button-outline-focus);
81
+ }
82
+
83
+ :host-context(.-theme-with-dark-background) .cell.focused-area.selected {
84
+ background: rgb(192 216 255); /* stylelint-disable-line plugin/use_theme_colors */
85
+ border-color: var(--color-button-outline-focus);
86
+ }
@@ -130,6 +130,13 @@ export class Section extends VBox {
130
130
  return this.titleElement;
131
131
  }
132
132
 
133
+ getFieldElement(): HTMLElement {
134
+ return this.fieldList;
135
+ }
136
+ appendFieldWithCustomView(customElement: HTMLElement): void {
137
+ this.fieldList.append(customElement);
138
+ }
139
+
133
140
  setTitle(title: string, tooltip?: string): void {
134
141
  if (this.titleElement.textContent !== title) {
135
142
  this.titleElement.textContent = title;
package/package.json CHANGED
@@ -56,5 +56,5 @@
56
56
  "unittest": "scripts/test/run_unittests.py --no-text-coverage",
57
57
  "watch": "vpython third_party/node/node.py --output scripts/watch_build.js"
58
58
  },
59
- "version": "1.0.1038685"
59
+ "version": "1.0.1040084"
60
60
  }