chrome-devtools-frontend 1.0.1038113 → 1.0.1039659
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/front_end/core/common/ParsedURL.ts +1 -1
- package/front_end/core/i18n/locales/en-US.json +2 -2
- package/front_end/core/i18n/locales/en-XL.json +2 -2
- package/front_end/core/sdk/ResourceTreeModel.ts +12 -8
- package/front_end/panels/application/IndexedDBModel.ts +68 -41
- package/front_end/panels/application/IndexedDBViews.ts +3 -1
- package/front_end/panels/elements/StylesSidebarPane.ts +5 -1
- package/front_end/panels/settings/KeybindsSettingsTab.ts +1 -0
- package/front_end/panels/settings/keybindsSettingsTab.css +4 -0
- package/front_end/panels/sources/NavigatorView.ts +5 -0
- package/front_end/services/puppeteer/PuppeteerConnection.ts +1 -1
- package/front_end/ui/components/linear_memory_inspector/LinearMemoryHighlightChipList.ts +16 -6
- package/front_end/ui/components/linear_memory_inspector/LinearMemoryInspector.ts +28 -4
- package/front_end/ui/components/linear_memory_inspector/LinearMemoryViewer.ts +15 -0
- package/front_end/ui/components/linear_memory_inspector/linearMemoryHighlightChipList.css +27 -12
- package/front_end/ui/components/linear_memory_inspector/linearMemoryViewer.css +19 -4
- package/package.json +1 -1
@@ -177,7 +177,7 @@ export class ParsedURL {
|
|
177
177
|
*/
|
178
178
|
static encodedFromParentPathAndName(parentPath: Platform.DevToolsPath.EncodedPathString, name: string):
|
179
179
|
Platform.DevToolsPath.EncodedPathString {
|
180
|
-
return ParsedURL.concatenate(parentPath, '/',
|
180
|
+
return ParsedURL.concatenate(parentPath, '/', ParsedURL.preEncodeSpecialCharactersInPath(name));
|
181
181
|
}
|
182
182
|
|
183
183
|
/**
|
@@ -12165,10 +12165,10 @@
|
|
12165
12165
|
"message": "Show Memory Inspector"
|
12166
12166
|
},
|
12167
12167
|
"ui/components/linear_memory_inspector/LinearMemoryHighlightChipList.ts | deleteHighlight": {
|
12168
|
-
"message": "
|
12168
|
+
"message": "Stop highlighting this memory"
|
12169
12169
|
},
|
12170
12170
|
"ui/components/linear_memory_inspector/LinearMemoryHighlightChipList.ts | jumpToAddress": {
|
12171
|
-
"message": "Jump to
|
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": "
|
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̂ó
|
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}"
|
@@ -134,6 +134,9 @@ export class ResourceTreeModel extends SDKModel<EventTypes> {
|
|
134
134
|
}
|
135
135
|
|
136
136
|
async storageKeyForFrame(frameId: Protocol.Page.FrameId): Promise<string|null> {
|
137
|
+
if (!this.framesInternal.has(frameId)) {
|
138
|
+
return null;
|
139
|
+
}
|
137
140
|
const response = await this.storageAgent.invoke_getStorageKeyForFrame({frameId: frameId});
|
138
141
|
if (response.getError() === 'Frame tree node for given frame not found') {
|
139
142
|
return null;
|
@@ -540,11 +543,11 @@ export class ResourceTreeModel extends SDKModel<EventTypes> {
|
|
540
543
|
const storageKeys = new Set<string>();
|
541
544
|
let mainStorageKey: string|null = null;
|
542
545
|
|
543
|
-
for (const {isMainFrame, storageKey} of await Promise.all(
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
546
|
+
for (const {isMainFrame, storageKey} of await Promise.all([...this.framesInternal.values()].map(
|
547
|
+
f => f.getStorageKey(/* forceFetch */ false).then(k => ({
|
548
|
+
isMainFrame: f.isMainFrame(),
|
549
|
+
storageKey: k,
|
550
|
+
}))))) {
|
548
551
|
if (isMainFrame) {
|
549
552
|
mainStorageKey = storageKey;
|
550
553
|
}
|
@@ -570,7 +573,7 @@ export class ResourceTreeModel extends SDKModel<EventTypes> {
|
|
570
573
|
}
|
571
574
|
|
572
575
|
async getMainStorageKey(): Promise<string|null> {
|
573
|
-
return this.mainFrame ? this.mainFrame.
|
576
|
+
return this.mainFrame ? this.mainFrame.getStorageKey(/* forceFetch */ false) : null;
|
574
577
|
}
|
575
578
|
|
576
579
|
getMainSecurityOrigin(): string|null {
|
@@ -767,6 +770,7 @@ export class ResourceTreeFrame {
|
|
767
770
|
this.#urlInternal = framePayload.url as Platform.DevToolsPath.UrlString;
|
768
771
|
this.#domainAndRegistryInternal = framePayload.domainAndRegistry;
|
769
772
|
this.#securityOriginInternal = framePayload.securityOrigin;
|
773
|
+
void this.getStorageKey(/* forceFetch */ true);
|
770
774
|
this.#unreachableUrlInternal =
|
771
775
|
framePayload.unreachableUrl as Platform.DevToolsPath.UrlString || Platform.DevToolsPath.EmptyUrlString;
|
772
776
|
this.#adFrameStatusInternal = framePayload?.adFrameStatus;
|
@@ -827,8 +831,8 @@ export class ResourceTreeFrame {
|
|
827
831
|
return this.#securityOriginInternal;
|
828
832
|
}
|
829
833
|
|
830
|
-
|
831
|
-
if (!this.#storageKeyInternal) {
|
834
|
+
getStorageKey(forceFetch: boolean): Promise<string|null> {
|
835
|
+
if (!this.#storageKeyInternal || forceFetch) {
|
832
836
|
this.#storageKeyInternal = this.#model.storageKeyForFrame(this.#idInternal);
|
833
837
|
}
|
834
838
|
return this.#storageKeyInternal;
|
@@ -176,9 +176,11 @@ export class IndexedDBModel extends SDK.SDKModel.SDKModel<EventTypes> implements
|
|
176
176
|
if (!this.enabled) {
|
177
177
|
return;
|
178
178
|
}
|
179
|
-
|
180
|
-
|
181
|
-
|
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
|
-
|
197
|
-
|
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
|
-
|
203
|
-
|
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
|
-
|
292
|
-
|
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
|
-
|
339
|
-
|
340
|
-
|
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
|
361
|
-
const primaryKey = runtimeModel
|
362
|
-
const value = runtimeModel
|
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
|
-
|
373
|
-
|
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
|
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
|
-
|
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
|
}
|
@@ -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
|
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);
|
@@ -1266,6 +1266,10 @@ export class NavigatorSourceTreeElement extends UI.TreeOutline.TreeElement {
|
|
1266
1266
|
}
|
1267
1267
|
}
|
1268
1268
|
|
1269
|
+
updateAccessibleName(): void {
|
1270
|
+
UI.ARIAUtils.setAccessibleName(this.listItemElement, `${this.uiSourceCodeInternal.name()}, ${this.nodeType}`);
|
1271
|
+
}
|
1272
|
+
|
1269
1273
|
get uiSourceCode(): Workspace.UISourceCode.UISourceCode {
|
1270
1274
|
return this.uiSourceCodeInternal;
|
1271
1275
|
}
|
@@ -1523,6 +1527,7 @@ export class NavigatorUISourceCodeTreeNode extends NavigatorTreeNode {
|
|
1523
1527
|
tooltip = i18nString(UIStrings.sFromSourceMap, {PH1: this.uiSourceCodeInternal.displayName()});
|
1524
1528
|
}
|
1525
1529
|
this.treeElement.tooltip = tooltip;
|
1530
|
+
this.treeElement.updateAccessibleName();
|
1526
1531
|
|
1527
1532
|
this.parent?.childrenInternal.delete(this.id);
|
1528
1533
|
this.id = 'UISourceCode:' + this.uiSourceCodeInternal.canononicalScriptId();
|
@@ -100,7 +100,7 @@ export async function getPuppeteerConnection(
|
|
100
100
|
);
|
101
101
|
|
102
102
|
const [, browser] = await Promise.all([
|
103
|
-
connection.
|
103
|
+
connection._createSession({targetId: mainTargetId}, /* emulateAutoAttach=*/ true),
|
104
104
|
browserPromise,
|
105
105
|
]);
|
106
106
|
|
@@ -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
|
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
|
18
|
+
jumpToAddress: 'Jump to this memory',
|
18
19
|
/**
|
19
|
-
*@description Tooltip text that appears when hovering over
|
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: '
|
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
|
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
|
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
|
+
}
|
package/package.json
CHANGED