chrome-devtools-frontend 1.0.1016605 → 1.0.1017091
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/gni/devtools_grd_files.gni +2 -0
- package/front_end/core/i18n/locales/en-US.json +3 -0
- package/front_end/core/i18n/locales/en-XL.json +3 -0
- package/front_end/core/sdk/DOMModel.ts +11 -0
- package/front_end/core/sdk/ResourceTreeModel.ts +59 -0
- package/front_end/core/sdk/Script.ts +1 -1
- package/front_end/core/sdk/SecurityOriginManager.ts +1 -1
- package/front_end/core/sdk/StorageKeyManager.ts +71 -0
- package/front_end/core/sdk/sdk.ts +2 -0
- package/front_end/entrypoints/formatter_worker/ScopeParser.ts +4 -2
- package/front_end/panels/application/ApplicationPanelSidebar.ts +5 -1
- package/front_end/panels/application/DOMStorageModel.ts +138 -10
- package/front_end/panels/application/StorageView.ts +64 -5
- package/front_end/panels/elements/ElementsTreeElement.ts +25 -18
- package/front_end/panels/elements/ElementsTreeOutline.ts +44 -8
- package/front_end/panels/elements/TopLayerContainer.ts +97 -0
- package/front_end/panels/elements/components/AdornerManager.ts +7 -0
- package/front_end/panels/elements/elements.ts +4 -0
- package/front_end/panels/sources/ScopeChainSidebarPane.ts +1 -1
- package/front_end/ui/components/linear_memory_inspector/LinearMemoryInspectorController.ts +5 -6
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +5 -3
- package/package.json +1 -1
@@ -654,6 +654,7 @@ grd_files_debug_sources = [
|
|
654
654
|
"front_end/core/sdk/ServiceWorkerManager.js",
|
655
655
|
"front_end/core/sdk/SourceMap.js",
|
656
656
|
"front_end/core/sdk/SourceMapManager.js",
|
657
|
+
"front_end/core/sdk/StorageKeyManager.js",
|
657
658
|
"front_end/core/sdk/Target.js",
|
658
659
|
"front_end/core/sdk/TargetManager.js",
|
659
660
|
"front_end/core/sdk/TracingManager.js",
|
@@ -961,6 +962,7 @@ grd_files_debug_sources = [
|
|
961
962
|
"front_end/panels/elements/StylePropertyTreeElement.js",
|
962
963
|
"front_end/panels/elements/StylePropertyUtils.js",
|
963
964
|
"front_end/panels/elements/StylesSidebarPane.js",
|
965
|
+
"front_end/panels/elements/TopLayerContainer.js",
|
964
966
|
"front_end/panels/elements/classesPaneWidget.css.js",
|
965
967
|
"front_end/panels/elements/components/AccessibilityTreeNode.js",
|
966
968
|
"front_end/panels/elements/components/AdornerManager.js",
|
@@ -5159,6 +5159,9 @@
|
|
5159
5159
|
"panels/elements/StylesSidebarPane.ts | unknownPropertyName": {
|
5160
5160
|
"message": "Unknown property name"
|
5161
5161
|
},
|
5162
|
+
"panels/elements/TopLayerContainer.ts | topLayer": {
|
5163
|
+
"message": "top-layer"
|
5164
|
+
},
|
5162
5165
|
"panels/emulation/DeviceModeToolbar.ts | addDevicePixelRatio": {
|
5163
5166
|
"message": "Add device pixel ratio"
|
5164
5167
|
},
|
@@ -5159,6 +5159,9 @@
|
|
5159
5159
|
"panels/elements/StylesSidebarPane.ts | unknownPropertyName": {
|
5160
5160
|
"message": "Ûńk̂ńôẃn̂ ṕr̂óp̂ér̂t́ŷ ńâḿê"
|
5161
5161
|
},
|
5162
|
+
"panels/elements/TopLayerContainer.ts | topLayer": {
|
5163
|
+
"message": "t̂óp̂-ĺâýêŕ"
|
5164
|
+
},
|
5162
5165
|
"panels/emulation/DeviceModeToolbar.ts | addDevicePixelRatio": {
|
5163
5166
|
"message": "Âd́d̂ d́êv́îćê ṕîx́êĺ r̂át̂íô"
|
5164
5167
|
},
|
@@ -1410,6 +1410,10 @@ export class DOMModel extends SDKModel<EventTypes> {
|
|
1410
1410
|
this.scheduleMutationEvent(node);
|
1411
1411
|
}
|
1412
1412
|
|
1413
|
+
topLayerElementsUpdated(): void {
|
1414
|
+
this.dispatchEventToListeners(Events.TopLayerElementsChanged);
|
1415
|
+
}
|
1416
|
+
|
1413
1417
|
pseudoElementRemoved(parentId: Protocol.DOM.NodeId, pseudoElementId: Protocol.DOM.NodeId): void {
|
1414
1418
|
const parent = this.idToDOMNode.get(parentId);
|
1415
1419
|
if (!parent) {
|
@@ -1511,6 +1515,10 @@ export class DOMModel extends SDKModel<EventTypes> {
|
|
1511
1515
|
return this.agent.invoke_querySelectorAll({nodeId, selector}).then(({nodeIds}) => nodeIds);
|
1512
1516
|
}
|
1513
1517
|
|
1518
|
+
getTopLayerElements(): Promise<Protocol.DOM.NodeId[]|null> {
|
1519
|
+
return this.agent.invoke_getTopLayerElements().then(({nodeIds}) => nodeIds);
|
1520
|
+
}
|
1521
|
+
|
1514
1522
|
markUndoableState(minorChange?: boolean): void {
|
1515
1523
|
void DOMModelUndoStack.instance().markUndoableState(this, minorChange || false);
|
1516
1524
|
}
|
@@ -1574,6 +1582,7 @@ export enum Events {
|
|
1574
1582
|
ChildNodeCountUpdated = 'ChildNodeCountUpdated',
|
1575
1583
|
DistributedNodesChanged = 'DistributedNodesChanged',
|
1576
1584
|
MarkersChanged = 'MarkersChanged',
|
1585
|
+
TopLayerElementsChanged = 'TopLayerElementsChanged',
|
1577
1586
|
}
|
1578
1587
|
|
1579
1588
|
export type EventTypes = {
|
@@ -1587,6 +1596,7 @@ export type EventTypes = {
|
|
1587
1596
|
[Events.ChildNodeCountUpdated]: DOMNode,
|
1588
1597
|
[Events.DistributedNodesChanged]: DOMNode,
|
1589
1598
|
[Events.MarkersChanged]: DOMNode,
|
1599
|
+
[Events.TopLayerElementsChanged]: void,
|
1590
1600
|
};
|
1591
1601
|
|
1592
1602
|
class DOMDispatcher implements ProtocolProxyApi.DOMDispatcher {
|
@@ -1652,6 +1662,7 @@ class DOMDispatcher implements ProtocolProxyApi.DOMDispatcher {
|
|
1652
1662
|
}
|
1653
1663
|
|
1654
1664
|
topLayerElementsUpdated(): void {
|
1665
|
+
this.#domModel.topLayerElementsUpdated();
|
1655
1666
|
}
|
1656
1667
|
}
|
1657
1668
|
|
@@ -50,10 +50,13 @@ import {Capability} from './Target.js';
|
|
50
50
|
import {SDKModel} from './SDKModel.js';
|
51
51
|
import {TargetManager} from './TargetManager.js';
|
52
52
|
import {SecurityOriginManager} from './SecurityOriginManager.js';
|
53
|
+
import {StorageKeyManager} from './StorageKeyManager.js';
|
53
54
|
|
54
55
|
export class ResourceTreeModel extends SDKModel<EventTypes> {
|
55
56
|
readonly agent: ProtocolProxyApi.PageApi;
|
57
|
+
readonly storageAgent: ProtocolProxyApi.StorageApi;
|
56
58
|
readonly #securityOriginManager: SecurityOriginManager;
|
59
|
+
readonly #storageKeyManager: StorageKeyManager;
|
57
60
|
readonly framesInternal: Map<string, ResourceTreeFrame>;
|
58
61
|
#cachedResourcesProcessed: boolean;
|
59
62
|
#pendingReloadOptions: {
|
@@ -75,8 +78,10 @@ export class ResourceTreeModel extends SDKModel<EventTypes> {
|
|
75
78
|
networkManager.addEventListener(NetworkManagerEvents.RequestUpdateDropped, this.onRequestUpdateDropped, this);
|
76
79
|
}
|
77
80
|
this.agent = target.pageAgent();
|
81
|
+
this.storageAgent = target.storageAgent();
|
78
82
|
void this.agent.invoke_enable();
|
79
83
|
this.#securityOriginManager = (target.model(SecurityOriginManager) as SecurityOriginManager);
|
84
|
+
this.#storageKeyManager = (target.model(StorageKeyManager) as StorageKeyManager);
|
80
85
|
this.#pendingBackForwardCacheNotUsedEvents = new Set<Protocol.Page.BackForwardCacheNotUsedEvent>();
|
81
86
|
this.#pendingPrerenderAttemptCompletedEvents = new Set<Protocol.Page.PrerenderAttemptCompletedEvent>();
|
82
87
|
target.registerPageDispatcher(new PageDispatcher(this));
|
@@ -129,6 +134,14 @@ export class ResourceTreeModel extends SDKModel<EventTypes> {
|
|
129
134
|
}
|
130
135
|
}
|
131
136
|
|
137
|
+
async storageKeyForFrame(frameId: Protocol.Page.FrameId): Promise<string|null> {
|
138
|
+
const response = await this.storageAgent.invoke_getStorageKeyForFrame({frameId: frameId});
|
139
|
+
if (response.getError() === 'Frame tree node for given frame not found') {
|
140
|
+
return null;
|
141
|
+
}
|
142
|
+
return response.storageKey;
|
143
|
+
}
|
144
|
+
|
132
145
|
domModel(): DOMModel {
|
133
146
|
return this.target().model(DOMModel) as DOMModel;
|
134
147
|
}
|
@@ -164,6 +177,7 @@ export class ResourceTreeModel extends SDKModel<EventTypes> {
|
|
164
177
|
}
|
165
178
|
this.dispatchEventToListeners(Events.FrameAdded, frame);
|
166
179
|
this.updateSecurityOrigins();
|
180
|
+
void this.updateStorageKeys();
|
167
181
|
}
|
168
182
|
|
169
183
|
frameAttached(
|
@@ -233,6 +247,7 @@ export class ResourceTreeModel extends SDKModel<EventTypes> {
|
|
233
247
|
this.target().setInspectedURL(frame.url);
|
234
248
|
}
|
235
249
|
this.updateSecurityOrigins();
|
250
|
+
void this.updateStorageKeys();
|
236
251
|
}
|
237
252
|
|
238
253
|
documentOpened(framePayload: Protocol.Page.Frame): void {
|
@@ -265,6 +280,7 @@ export class ResourceTreeModel extends SDKModel<EventTypes> {
|
|
265
280
|
frame.remove(isSwap);
|
266
281
|
}
|
267
282
|
this.updateSecurityOrigins();
|
283
|
+
void this.updateStorageKeys();
|
268
284
|
}
|
269
285
|
|
270
286
|
private onRequestFinished(event: Common.EventTarget.EventTargetEvent<NetworkRequest>): void {
|
@@ -520,6 +536,26 @@ export class ResourceTreeModel extends SDKModel<EventTypes> {
|
|
520
536
|
};
|
521
537
|
}
|
522
538
|
|
539
|
+
private async getStorageKeyData(): Promise<StorageKeyData> {
|
540
|
+
const storageKeys = new Set<string>();
|
541
|
+
let mainStorageKey: string|null = null;
|
542
|
+
|
543
|
+
for (const {isMainFrame, storageKey} of await Promise.all(
|
544
|
+
[...this.framesInternal.values()].map(async f => f.storageKey.then(k => ({
|
545
|
+
isMainFrame: f.isMainFrame(),
|
546
|
+
storageKey: k,
|
547
|
+
}))))) {
|
548
|
+
if (isMainFrame) {
|
549
|
+
mainStorageKey = storageKey;
|
550
|
+
}
|
551
|
+
if (storageKey) {
|
552
|
+
storageKeys.add(storageKey);
|
553
|
+
}
|
554
|
+
}
|
555
|
+
|
556
|
+
return {storageKeys: storageKeys, mainStorageKey: mainStorageKey};
|
557
|
+
}
|
558
|
+
|
523
559
|
private updateSecurityOrigins(): void {
|
524
560
|
const data = this.getSecurityOriginData();
|
525
561
|
this.#securityOriginManager.setMainSecurityOrigin(
|
@@ -527,6 +563,16 @@ export class ResourceTreeModel extends SDKModel<EventTypes> {
|
|
527
563
|
this.#securityOriginManager.updateSecurityOrigins(data.securityOrigins);
|
528
564
|
}
|
529
565
|
|
566
|
+
private async updateStorageKeys(): Promise<void> {
|
567
|
+
const data = await this.getStorageKeyData();
|
568
|
+
this.#storageKeyManager.setMainStorageKey(data.mainStorageKey || '');
|
569
|
+
this.#storageKeyManager.updateStorageKeys(data.storageKeys);
|
570
|
+
}
|
571
|
+
|
572
|
+
async getMainStorageKey(): Promise<string|null> {
|
573
|
+
return this.mainFrame ? this.mainFrame.storageKey : null;
|
574
|
+
}
|
575
|
+
|
530
576
|
getMainSecurityOrigin(): string|null {
|
531
577
|
const data = this.getSecurityOriginData();
|
532
578
|
return data.mainSecurityOrigin || data.unreachableMainSecurityOrigin;
|
@@ -626,6 +672,7 @@ export class ResourceTreeFrame {
|
|
626
672
|
#urlInternal: Platform.DevToolsPath.UrlString;
|
627
673
|
#domainAndRegistryInternal: string;
|
628
674
|
#securityOriginInternal: string|null;
|
675
|
+
#storageKeyInternal?: Promise<string|null>;
|
629
676
|
#unreachableUrlInternal: Platform.DevToolsPath.UrlString;
|
630
677
|
#adFrameStatusInternal?: Protocol.Page.AdFrameStatus;
|
631
678
|
#secureContextType: Protocol.Page.SecureContextType|null;
|
@@ -758,6 +805,13 @@ export class ResourceTreeFrame {
|
|
758
805
|
return this.#securityOriginInternal;
|
759
806
|
}
|
760
807
|
|
808
|
+
get storageKey(): Promise<string|null> {
|
809
|
+
if (!this.#storageKeyInternal) {
|
810
|
+
this.#storageKeyInternal = this.#model.storageKeyForFrame(this.#idInternal);
|
811
|
+
}
|
812
|
+
return this.#storageKeyInternal;
|
813
|
+
}
|
814
|
+
|
761
815
|
unreachableUrl(): Platform.DevToolsPath.UrlString {
|
762
816
|
return this.#unreachableUrlInternal;
|
763
817
|
}
|
@@ -1122,3 +1176,8 @@ export interface SecurityOriginData {
|
|
1122
1176
|
mainSecurityOrigin: string|null;
|
1123
1177
|
unreachableMainSecurityOrigin: string|null;
|
1124
1178
|
}
|
1179
|
+
|
1180
|
+
export interface StorageKeyData {
|
1181
|
+
storageKeys: Set<string>;
|
1182
|
+
mainStorageKey: string|null;
|
1183
|
+
}
|
@@ -268,7 +268,7 @@ export class Script implements TextUtils.ContentProvider.ContentProvider, FrameA
|
|
268
268
|
return {status: Protocol.Debugger.SetScriptSourceResponseStatus.Ok};
|
269
269
|
}
|
270
270
|
const response = await this.debuggerModel.target().debuggerAgent().invoke_setScriptSource(
|
271
|
-
{scriptId: this.scriptId, scriptSource: newSource});
|
271
|
+
{scriptId: this.scriptId, scriptSource: newSource, allowTopFrameEditing: true});
|
272
272
|
if (response.getError()) {
|
273
273
|
// Something went seriously wrong, like the V8 inspector no longer knowing about this script without
|
274
274
|
// shutting down the Debugger agent etc.
|
@@ -81,5 +81,5 @@ export type EventTypes = {
|
|
81
81
|
[Events.MainSecurityOriginChanged]: MainSecurityOriginChangedEvent,
|
82
82
|
};
|
83
83
|
|
84
|
-
// TODO(jarhar): this is the
|
84
|
+
// TODO(jarhar): this is the one of the two usages of Capability.None. Do something about it!
|
85
85
|
SDKModel.register(SecurityOriginManager, {capabilities: Capability.None, autostart: false});
|
@@ -0,0 +1,71 @@
|
|
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 type {Target} from './Target.js';
|
6
|
+
import {Capability} from './Target.js';
|
7
|
+
import {SDKModel} from './SDKModel.js';
|
8
|
+
|
9
|
+
export class StorageKeyManager extends SDKModel<EventTypes> {
|
10
|
+
#mainStorageKeyInternal: string;
|
11
|
+
#storageKeysInternal: Set<string>;
|
12
|
+
constructor(target: Target) {
|
13
|
+
super(target);
|
14
|
+
|
15
|
+
this.#mainStorageKeyInternal = '';
|
16
|
+
this.#storageKeysInternal = new Set();
|
17
|
+
}
|
18
|
+
|
19
|
+
updateStorageKeys(storageKeys: Set<string>): void {
|
20
|
+
const oldStorageKeys = this.#storageKeysInternal;
|
21
|
+
this.#storageKeysInternal = storageKeys;
|
22
|
+
|
23
|
+
for (const storageKey of oldStorageKeys) {
|
24
|
+
if (!this.#storageKeysInternal.has(storageKey)) {
|
25
|
+
this.dispatchEventToListeners(Events.StorageKeyRemoved, storageKey);
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
for (const storageKey of this.#storageKeysInternal) {
|
30
|
+
if (!oldStorageKeys.has(storageKey)) {
|
31
|
+
this.dispatchEventToListeners(Events.StorageKeyAdded, storageKey);
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
storageKeys(): string[] {
|
37
|
+
return [...this.#storageKeysInternal];
|
38
|
+
}
|
39
|
+
|
40
|
+
mainStorageKey(): string {
|
41
|
+
return this.#mainStorageKeyInternal;
|
42
|
+
}
|
43
|
+
|
44
|
+
setMainStorageKey(storageKey: string): void {
|
45
|
+
this.#mainStorageKeyInternal = storageKey;
|
46
|
+
this.dispatchEventToListeners(Events.MainStorageKeyChanged, {
|
47
|
+
mainStorageKey: this.#mainStorageKeyInternal,
|
48
|
+
});
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
// TODO(crbug.com/1167717): Make this a const enum again
|
53
|
+
// eslint-disable-next-line rulesdir/const_enum
|
54
|
+
export enum Events {
|
55
|
+
StorageKeyAdded = 'StorageKeyAdded',
|
56
|
+
StorageKeyRemoved = 'StorageKeyRemoved',
|
57
|
+
MainStorageKeyChanged = 'MainStorageKeyChanged',
|
58
|
+
}
|
59
|
+
|
60
|
+
export interface MainStorageKeyChangedEvent {
|
61
|
+
mainStorageKey: string;
|
62
|
+
}
|
63
|
+
|
64
|
+
export type EventTypes = {
|
65
|
+
[Events.StorageKeyAdded]: string,
|
66
|
+
[Events.StorageKeyRemoved]: string,
|
67
|
+
[Events.MainStorageKeyChanged]: MainStorageKeyChangedEvent,
|
68
|
+
};
|
69
|
+
|
70
|
+
// TODO(jarhar): this is the one of the two usages of Capability.None. Do something about it!
|
71
|
+
SDKModel.register(StorageKeyManager, {capabilities: Capability.None, autostart: false});
|
@@ -72,6 +72,7 @@ import * as ServiceWorkerCacheModel from './ServiceWorkerCacheModel.js';
|
|
72
72
|
import * as ServiceWorkerManager from './ServiceWorkerManager.js';
|
73
73
|
import * as SourceMap from './SourceMap.js';
|
74
74
|
import * as SourceMapManager from './SourceMapManager.js';
|
75
|
+
import * as StorageKeyManager from './StorageKeyManager.js';
|
75
76
|
import * as Target from './Target.js';
|
76
77
|
import * as TargetManager from './TargetManager.js';
|
77
78
|
import * as TracingManager from './TracingManager.js';
|
@@ -141,6 +142,7 @@ export {
|
|
141
142
|
ServiceWorkerManager,
|
142
143
|
SourceMap,
|
143
144
|
SourceMapManager,
|
145
|
+
StorageKeyManager,
|
144
146
|
Target,
|
145
147
|
TargetManager,
|
146
148
|
TracingManager,
|
@@ -312,8 +312,9 @@ export class ScopeVariableAnalysis {
|
|
312
312
|
break;
|
313
313
|
case 'Property':
|
314
314
|
if (node.shorthand) {
|
315
|
-
console.assert(node.value === node.key);
|
316
315
|
console.assert(node.value.type === 'Identifier');
|
316
|
+
console.assert(node.key.type === 'Identifier');
|
317
|
+
console.assert((node.value as Acorn.ESTree.Identifier).name === (node.key as Acorn.ESTree.Identifier).name);
|
317
318
|
this.#addVariable((node.value as Acorn.ESTree.Identifier).name, node.value.start, DefinitionKind.None, true);
|
318
319
|
} else {
|
319
320
|
if (node.computed) {
|
@@ -469,8 +470,9 @@ export class ScopeVariableAnalysis {
|
|
469
470
|
case 'Property':
|
470
471
|
// This is AssignmentProperty inside an object pattern.
|
471
472
|
if (node.shorthand) {
|
472
|
-
console.assert(node.value === node.key);
|
473
473
|
console.assert(node.value.type === 'Identifier');
|
474
|
+
console.assert(node.key.type === 'Identifier');
|
475
|
+
console.assert((node.value as Acorn.ESTree.Identifier).name === (node.key as Acorn.ESTree.Identifier).name);
|
474
476
|
this.#addVariable((node.value as Acorn.ESTree.Identifier).name, node.value.start, definitionKind, true);
|
475
477
|
} else {
|
476
478
|
if (node.computed) {
|
@@ -603,6 +603,7 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
|
|
603
603
|
|
604
604
|
private addDOMStorage(domStorage: DOMStorage): void {
|
605
605
|
console.assert(!this.domStorageTreeElements.get(domStorage));
|
606
|
+
console.assert(Boolean(domStorage.storageKey) || Boolean(domStorage.securityOrigin));
|
606
607
|
|
607
608
|
const domStorageTreeElement = new DOMStorageTreeElement(this.panel, domStorage);
|
608
609
|
this.domStorageTreeElements.set(domStorage, domStorageTreeElement);
|
@@ -1422,7 +1423,10 @@ export class DOMStorageTreeElement extends ApplicationPanelTreeElement {
|
|
1422
1423
|
private readonly domStorage: DOMStorage;
|
1423
1424
|
constructor(storagePanel: ResourcesPanel, domStorage: DOMStorage) {
|
1424
1425
|
super(
|
1425
|
-
storagePanel,
|
1426
|
+
storagePanel,
|
1427
|
+
domStorage.securityOrigin ? domStorage.securityOrigin :
|
1428
|
+
(domStorage.storageKey ? domStorage.storageKey : i18nString(UIStrings.localFiles)),
|
1429
|
+
false);
|
1426
1430
|
this.domStorage = domStorage;
|
1427
1431
|
const icon = UI.Icon.Icon.create('mediumicon-table', 'resource-tree-item');
|
1428
1432
|
this.setLeadingIcons([icon]);
|
@@ -38,13 +38,15 @@ import type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';
|
|
38
38
|
|
39
39
|
export class DOMStorage extends Common.ObjectWrapper.ObjectWrapper<DOMStorage.EventTypes> {
|
40
40
|
private readonly model: DOMStorageModel;
|
41
|
-
private readonly securityOriginInternal: string;
|
41
|
+
private readonly securityOriginInternal: string|null;
|
42
|
+
private readonly storageKeyInternal: string|null;
|
42
43
|
private readonly isLocalStorageInternal: boolean;
|
43
44
|
|
44
|
-
constructor(model: DOMStorageModel, securityOrigin: string, isLocalStorage: boolean) {
|
45
|
+
constructor(model: DOMStorageModel, securityOrigin: string, storageKey: string, isLocalStorage: boolean) {
|
45
46
|
super();
|
46
47
|
this.model = model;
|
47
48
|
this.securityOriginInternal = securityOrigin;
|
49
|
+
this.storageKeyInternal = storageKey;
|
48
50
|
this.isLocalStorageInternal = isLocalStorage;
|
49
51
|
}
|
50
52
|
|
@@ -52,14 +54,46 @@ export class DOMStorage extends Common.ObjectWrapper.ObjectWrapper<DOMStorage.Ev
|
|
52
54
|
return {securityOrigin: securityOrigin, isLocalStorage: isLocalStorage};
|
53
55
|
}
|
54
56
|
|
57
|
+
static storageIdWithSecurityOrigin(securityOrigin: string, isLocalStorage: boolean): Protocol.DOMStorage.StorageId {
|
58
|
+
return {securityOrigin: securityOrigin, isLocalStorage: isLocalStorage};
|
59
|
+
}
|
60
|
+
|
61
|
+
static storageIdWithStorageKey(storageKey: string, isLocalStorage: boolean): Protocol.DOMStorage.StorageId {
|
62
|
+
return {storageKey: storageKey, isLocalStorage: isLocalStorage};
|
63
|
+
}
|
64
|
+
|
65
|
+
get idWithSecurityOrigin(): Protocol.DOMStorage.StorageId {
|
66
|
+
let securityOrigin = '';
|
67
|
+
if (this.securityOriginInternal) {
|
68
|
+
securityOrigin = this.securityOriginInternal;
|
69
|
+
}
|
70
|
+
return DOMStorage.storageIdWithSecurityOrigin(securityOrigin, this.isLocalStorageInternal);
|
71
|
+
}
|
72
|
+
|
73
|
+
get idWithStorageKey(): Protocol.DOMStorage.StorageId {
|
74
|
+
let storageKey = '';
|
75
|
+
if (this.storageKeyInternal) {
|
76
|
+
storageKey = this.storageKeyInternal;
|
77
|
+
}
|
78
|
+
return DOMStorage.storageIdWithStorageKey(storageKey, this.isLocalStorageInternal);
|
79
|
+
}
|
80
|
+
|
55
81
|
get id(): Protocol.DOMStorage.StorageId {
|
56
|
-
|
82
|
+
// TODO(crbug.com/1313434) Prioritize storageKey once everything is ready
|
83
|
+
if (this.securityOriginInternal) {
|
84
|
+
return this.idWithSecurityOrigin;
|
85
|
+
}
|
86
|
+
return this.idWithStorageKey;
|
57
87
|
}
|
58
88
|
|
59
|
-
get securityOrigin(): string {
|
89
|
+
get securityOrigin(): string|null {
|
60
90
|
return this.securityOriginInternal;
|
61
91
|
}
|
62
92
|
|
93
|
+
get storageKey(): string|null {
|
94
|
+
return this.storageKeyInternal;
|
95
|
+
}
|
96
|
+
|
63
97
|
get isLocalStorage(): boolean {
|
64
98
|
return this.isLocalStorageInternal;
|
65
99
|
}
|
@@ -116,6 +150,7 @@ export namespace DOMStorage {
|
|
116
150
|
|
117
151
|
export class DOMStorageModel extends SDK.SDKModel.SDKModel<EventTypes> {
|
118
152
|
private readonly securityOriginManager: SDK.SecurityOriginManager.SecurityOriginManager|null;
|
153
|
+
private readonly storageKeyManagerInternal: SDK.StorageKeyManager.StorageKeyManager|null;
|
119
154
|
private storagesInternal: {
|
120
155
|
[x: string]: DOMStorage,
|
121
156
|
};
|
@@ -126,10 +161,15 @@ export class DOMStorageModel extends SDK.SDKModel.SDKModel<EventTypes> {
|
|
126
161
|
super(target);
|
127
162
|
|
128
163
|
this.securityOriginManager = target.model(SDK.SecurityOriginManager.SecurityOriginManager);
|
164
|
+
this.storageKeyManagerInternal = target.model(SDK.StorageKeyManager.StorageKeyManager);
|
129
165
|
this.storagesInternal = {};
|
130
166
|
this.agent = target.domstorageAgent();
|
131
167
|
}
|
132
168
|
|
169
|
+
get storageKeyManagerForTest(): SDK.StorageKeyManager.StorageKeyManager|null {
|
170
|
+
return this.storageKeyManagerInternal;
|
171
|
+
}
|
172
|
+
|
133
173
|
enable(): void {
|
134
174
|
if (this.enabled) {
|
135
175
|
return;
|
@@ -146,6 +186,16 @@ export class DOMStorageModel extends SDK.SDKModel.SDKModel<EventTypes> {
|
|
146
186
|
this.addOrigin(securityOrigin);
|
147
187
|
}
|
148
188
|
}
|
189
|
+
if (this.storageKeyManagerInternal) {
|
190
|
+
this.storageKeyManagerInternal.addEventListener(
|
191
|
+
SDK.StorageKeyManager.Events.StorageKeyAdded, this.storageKeyAdded, this);
|
192
|
+
this.storageKeyManagerInternal.addEventListener(
|
193
|
+
SDK.StorageKeyManager.Events.StorageKeyRemoved, this.storageKeyRemoved, this);
|
194
|
+
|
195
|
+
for (const storageKey of this.storageKeyManagerInternal.storageKeys()) {
|
196
|
+
this.addStorageKey(storageKey);
|
197
|
+
}
|
198
|
+
}
|
149
199
|
void this.agent.invoke_enable();
|
150
200
|
|
151
201
|
this.enabled = true;
|
@@ -156,7 +206,7 @@ export class DOMStorageModel extends SDK.SDKModel.SDKModel<EventTypes> {
|
|
156
206
|
return;
|
157
207
|
}
|
158
208
|
for (const isLocal of [true, false]) {
|
159
|
-
const key = this.
|
209
|
+
const key = this.keyForSecurityOrigin(origin, isLocal);
|
160
210
|
const storage = this.storagesInternal[key];
|
161
211
|
if (!storage) {
|
162
212
|
return;
|
@@ -167,10 +217,30 @@ export class DOMStorageModel extends SDK.SDKModel.SDKModel<EventTypes> {
|
|
167
217
|
this.addOrigin(origin);
|
168
218
|
}
|
169
219
|
|
220
|
+
clearForStorageKey(storageKey: string): void {
|
221
|
+
if (!this.enabled) {
|
222
|
+
return;
|
223
|
+
}
|
224
|
+
for (const isLocal of [true, false]) {
|
225
|
+
const key = this.keyForStorageKey(storageKey, isLocal);
|
226
|
+
const storage = this.storagesInternal[key];
|
227
|
+
if (!storage) {
|
228
|
+
return;
|
229
|
+
}
|
230
|
+
storage.clear();
|
231
|
+
}
|
232
|
+
this.removeStorageKey(storageKey);
|
233
|
+
this.addStorageKey(storageKey);
|
234
|
+
}
|
235
|
+
|
170
236
|
private securityOriginAdded(event: Common.EventTarget.EventTargetEvent<string>): void {
|
171
237
|
this.addOrigin(event.data);
|
172
238
|
}
|
173
239
|
|
240
|
+
private storageKeyAdded(event: Common.EventTarget.EventTargetEvent<string>): void {
|
241
|
+
this.addStorageKey(event.data);
|
242
|
+
}
|
243
|
+
|
174
244
|
private addOrigin(securityOrigin: string): void {
|
175
245
|
const parsed = new Common.ParsedURL.ParsedURL(securityOrigin);
|
176
246
|
// These are "opaque" origins which are not supposed to support DOM storage.
|
@@ -179,21 +249,67 @@ export class DOMStorageModel extends SDK.SDKModel.SDKModel<EventTypes> {
|
|
179
249
|
}
|
180
250
|
|
181
251
|
for (const isLocal of [true, false]) {
|
182
|
-
const key = this.
|
252
|
+
const key = this.keyForSecurityOrigin(securityOrigin, isLocal);
|
183
253
|
console.assert(!this.storagesInternal[key]);
|
184
|
-
|
254
|
+
if (this.duplicateExists(key)) {
|
255
|
+
continue;
|
256
|
+
}
|
257
|
+
const storage = new DOMStorage(this, securityOrigin, '', isLocal);
|
258
|
+
this.storagesInternal[key] = storage;
|
259
|
+
this.dispatchEventToListeners(Events.DOMStorageAdded, storage);
|
260
|
+
}
|
261
|
+
}
|
262
|
+
|
263
|
+
private addStorageKey(storageKey: string): void {
|
264
|
+
for (const isLocal of [true, false]) {
|
265
|
+
const key = this.keyForStorageKey(storageKey, isLocal);
|
266
|
+
console.assert(!this.storagesInternal[key]);
|
267
|
+
if (this.duplicateExists(key)) {
|
268
|
+
continue;
|
269
|
+
}
|
270
|
+
const storage = new DOMStorage(this, '', storageKey, isLocal);
|
185
271
|
this.storagesInternal[key] = storage;
|
186
272
|
this.dispatchEventToListeners(Events.DOMStorageAdded, storage);
|
187
273
|
}
|
188
274
|
}
|
189
275
|
|
276
|
+
private duplicateExists(key: string): boolean {
|
277
|
+
const parsedKey = JSON.parse(key);
|
278
|
+
for (const storageInternal in this.storagesInternal) {
|
279
|
+
const parsedStorageInternalKey = JSON.parse(storageInternal);
|
280
|
+
if (parsedKey.isLocalStorage === parsedStorageInternalKey.isLocalStorage) {
|
281
|
+
if (parsedKey.storageKey?.slice(0, -1) === parsedStorageInternalKey.securityOrigin ||
|
282
|
+
parsedKey.securityOrigin === parsedStorageInternalKey.storageKey?.slice(0, -1)) {
|
283
|
+
return true;
|
284
|
+
}
|
285
|
+
}
|
286
|
+
}
|
287
|
+
return false;
|
288
|
+
}
|
289
|
+
|
190
290
|
private securityOriginRemoved(event: Common.EventTarget.EventTargetEvent<string>): void {
|
191
291
|
this.removeOrigin(event.data);
|
192
292
|
}
|
193
293
|
|
294
|
+
private storageKeyRemoved(event: Common.EventTarget.EventTargetEvent<string>): void {
|
295
|
+
this.removeStorageKey(event.data);
|
296
|
+
}
|
297
|
+
|
194
298
|
private removeOrigin(securityOrigin: string): void {
|
195
299
|
for (const isLocal of [true, false]) {
|
196
|
-
const key = this.
|
300
|
+
const key = this.keyForSecurityOrigin(securityOrigin, isLocal);
|
301
|
+
const storage = this.storagesInternal[key];
|
302
|
+
if (!storage) {
|
303
|
+
continue;
|
304
|
+
}
|
305
|
+
delete this.storagesInternal[key];
|
306
|
+
this.dispatchEventToListeners(Events.DOMStorageRemoved, storage);
|
307
|
+
}
|
308
|
+
}
|
309
|
+
|
310
|
+
private removeStorageKey(storageKey: string): void {
|
311
|
+
for (const isLocal of [true, false]) {
|
312
|
+
const key = this.keyForStorageKey(storageKey, isLocal);
|
197
313
|
const storage = this.storagesInternal[key];
|
198
314
|
if (!storage) {
|
199
315
|
continue;
|
@@ -203,8 +319,20 @@ export class DOMStorageModel extends SDK.SDKModel.SDKModel<EventTypes> {
|
|
203
319
|
}
|
204
320
|
}
|
205
321
|
|
206
|
-
private storageKey(securityOrigin: string, isLocalStorage: boolean): string {
|
207
|
-
|
322
|
+
private storageKey(securityOrigin: string, storageKey: string, isLocalStorage: boolean): string {
|
323
|
+
// TODO(crbug.com/1313434) Prioritize storageKey once everything is ready
|
324
|
+
if (securityOrigin) {
|
325
|
+
return JSON.stringify(DOMStorage.storageIdWithSecurityOrigin(securityOrigin, isLocalStorage));
|
326
|
+
}
|
327
|
+
return JSON.stringify(DOMStorage.storageIdWithStorageKey(storageKey, isLocalStorage));
|
328
|
+
}
|
329
|
+
|
330
|
+
private keyForSecurityOrigin(securityOrigin: string, isLocalStorage: boolean): string {
|
331
|
+
return this.storageKey(securityOrigin, '', isLocalStorage);
|
332
|
+
}
|
333
|
+
|
334
|
+
private keyForStorageKey(storageKey: string, isLocalStorage: boolean): string {
|
335
|
+
return this.storageKey('', storageKey, isLocalStorage);
|
208
336
|
}
|
209
337
|
|
210
338
|
domStorageItemsCleared(storageId: Protocol.DOMStorage.StorageId): void {
|
@@ -147,6 +147,7 @@ export class StorageView extends UI.ThrottledWidget.ThrottledWidget {
|
|
147
147
|
private reportView: UI.ReportView.ReportView;
|
148
148
|
private target: SDK.Target.Target|null;
|
149
149
|
private securityOrigin: string|null;
|
150
|
+
private storageKey: string|null;
|
150
151
|
private settings: Map<Protocol.Storage.StorageType, Common.Settings.Setting<boolean>>;
|
151
152
|
private includeThirdPartyCookiesSetting: Common.Settings.Setting<boolean>;
|
152
153
|
private quotaRow: HTMLElement;
|
@@ -180,6 +181,7 @@ export class StorageView extends UI.ThrottledWidget.ThrottledWidget {
|
|
180
181
|
this.reportView.show(this.contentElement);
|
181
182
|
this.target = null;
|
182
183
|
this.securityOrigin = null;
|
184
|
+
this.storageKey = null;
|
183
185
|
|
184
186
|
this.settings = new Map();
|
185
187
|
for (const type of AllStorageTypes) {
|
@@ -277,6 +279,11 @@ export class StorageView extends UI.ThrottledWidget.ThrottledWidget {
|
|
277
279
|
securityOriginManager.mainSecurityOrigin(), securityOriginManager.unreachableMainSecurityOrigin());
|
278
280
|
securityOriginManager.addEventListener(
|
279
281
|
SDK.SecurityOriginManager.Events.MainSecurityOriginChanged, this.originChanged, this);
|
282
|
+
const storageKeyManager =
|
283
|
+
target.model(SDK.StorageKeyManager.StorageKeyManager) as SDK.StorageKeyManager.StorageKeyManager;
|
284
|
+
this.updateStorageKey(storageKeyManager.mainStorageKey());
|
285
|
+
storageKeyManager.addEventListener(
|
286
|
+
SDK.StorageKeyManager.Events.MainStorageKeyChanged, this.storageKeyChanged, this);
|
280
287
|
}
|
281
288
|
|
282
289
|
targetRemoved(target: SDK.Target.Target): void {
|
@@ -287,6 +294,10 @@ export class StorageView extends UI.ThrottledWidget.ThrottledWidget {
|
|
287
294
|
SDK.SecurityOriginManager.SecurityOriginManager;
|
288
295
|
securityOriginManager.removeEventListener(
|
289
296
|
SDK.SecurityOriginManager.Events.MainSecurityOriginChanged, this.originChanged, this);
|
297
|
+
const storageKeyManager =
|
298
|
+
target.model(SDK.StorageKeyManager.StorageKeyManager) as SDK.StorageKeyManager.StorageKeyManager;
|
299
|
+
storageKeyManager.removeEventListener(
|
300
|
+
SDK.StorageKeyManager.Events.MainStorageKeyChanged, this.storageKeyChanged, this);
|
290
301
|
}
|
291
302
|
|
292
303
|
private originChanged(
|
@@ -295,6 +306,12 @@ export class StorageView extends UI.ThrottledWidget.ThrottledWidget {
|
|
295
306
|
this.updateOrigin(mainSecurityOrigin, unreachableMainSecurityOrigin);
|
296
307
|
}
|
297
308
|
|
309
|
+
private storageKeyChanged(
|
310
|
+
event: Common.EventTarget.EventTargetEvent<SDK.StorageKeyManager.MainStorageKeyChangedEvent>): void {
|
311
|
+
const {mainStorageKey} = event.data;
|
312
|
+
this.updateStorageKey(mainStorageKey);
|
313
|
+
}
|
314
|
+
|
298
315
|
private updateOrigin(mainOrigin: string, unreachableMainOrigin: string|null): void {
|
299
316
|
const oldOrigin = this.securityOrigin;
|
300
317
|
if (unreachableMainOrigin) {
|
@@ -313,6 +330,20 @@ export class StorageView extends UI.ThrottledWidget.ThrottledWidget {
|
|
313
330
|
void this.doUpdate();
|
314
331
|
}
|
315
332
|
|
333
|
+
private updateStorageKey(mainStorageKey: string): void {
|
334
|
+
const oldStorageKey = this.storageKey;
|
335
|
+
|
336
|
+
this.storageKey = mainStorageKey;
|
337
|
+
this.reportView.setSubtitle(mainStorageKey);
|
338
|
+
|
339
|
+
if (oldStorageKey !== this.storageKey) {
|
340
|
+
this.quotaOverrideControlRow.classList.add('hidden');
|
341
|
+
this.quotaOverrideCheckbox.checkboxElement.checked = false;
|
342
|
+
this.quotaOverrideErrorMessage.textContent = '';
|
343
|
+
}
|
344
|
+
void this.doUpdate();
|
345
|
+
}
|
346
|
+
|
316
347
|
private async applyQuotaOverrideFromInputField(): Promise<void> {
|
317
348
|
if (!this.target || !this.securityOrigin) {
|
318
349
|
this.quotaOverrideErrorMessage.textContent = i18nString(UIStrings.internalError);
|
@@ -375,7 +406,12 @@ export class StorageView extends UI.ThrottledWidget.ThrottledWidget {
|
|
375
406
|
|
376
407
|
if (this.target) {
|
377
408
|
const includeThirdPartyCookies = this.includeThirdPartyCookiesSetting.get();
|
378
|
-
|
409
|
+
// TODO(crbug.com/1313434) Prioritize storageKey once everything is ready
|
410
|
+
if (this.securityOrigin) {
|
411
|
+
StorageView.clear(this.target, this.securityOrigin, selectedStorageTypes, includeThirdPartyCookies);
|
412
|
+
} else if (this.storageKey) {
|
413
|
+
StorageView.clearByStorageKey(this.target, this.storageKey, selectedStorageTypes);
|
414
|
+
}
|
379
415
|
}
|
380
416
|
|
381
417
|
this.clearButton.disabled = true;
|
@@ -436,6 +472,20 @@ export class StorageView extends UI.ThrottledWidget.ThrottledWidget {
|
|
436
472
|
}
|
437
473
|
}
|
438
474
|
|
475
|
+
static clearByStorageKey(target: SDK.Target.Target, storageKey: string, selectedStorageTypes: string[]): void {
|
476
|
+
// TODO(crbug.com/1313434) Invoke protocol `clear` once it ready for storageKey
|
477
|
+
|
478
|
+
const set = new Set(selectedStorageTypes);
|
479
|
+
const hasAll = set.has(Protocol.Storage.StorageType.All);
|
480
|
+
|
481
|
+
if (set.has(Protocol.Storage.StorageType.Local_storage) || hasAll) {
|
482
|
+
const storageModel = target.model(DOMStorageModel);
|
483
|
+
if (storageModel) {
|
484
|
+
storageModel.clearForStorageKey(storageKey);
|
485
|
+
}
|
486
|
+
}
|
487
|
+
}
|
488
|
+
|
439
489
|
async doUpdate(): Promise<void> {
|
440
490
|
if (!this.securityOrigin || !this.target) {
|
441
491
|
this.quotaRow.textContent = '';
|
@@ -556,6 +606,14 @@ export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
|
|
556
606
|
return false;
|
557
607
|
}
|
558
608
|
|
609
|
+
private async clear(target: SDK.Target.Target, resourceTreeModel: SDK.ResourceTreeModel.ResourceTreeModel):
|
610
|
+
Promise<void> {
|
611
|
+
const storageKey = await resourceTreeModel.getMainStorageKey();
|
612
|
+
if (storageKey) {
|
613
|
+
StorageView.clearByStorageKey(target, storageKey, AllStorageTypes);
|
614
|
+
}
|
615
|
+
}
|
616
|
+
|
559
617
|
private handleClear(includeThirdPartyCookies: boolean): boolean {
|
560
618
|
const target = SDK.TargetManager.TargetManager.instance().mainTarget();
|
561
619
|
if (!target) {
|
@@ -566,11 +624,12 @@ export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
|
|
566
624
|
return false;
|
567
625
|
}
|
568
626
|
const securityOrigin = resourceTreeModel.getMainSecurityOrigin();
|
569
|
-
|
570
|
-
|
627
|
+
// TODO(crbug.com/1313434) Prioritize storageKey functionality once everything is ready
|
628
|
+
if (securityOrigin) {
|
629
|
+
StorageView.clear(target, securityOrigin, AllStorageTypes, includeThirdPartyCookies);
|
630
|
+
return true;
|
571
631
|
}
|
572
|
-
|
573
|
-
StorageView.clear(target, securityOrigin, AllStorageTypes, includeThirdPartyCookies);
|
632
|
+
void this.clear(target, resourceTreeModel);
|
574
633
|
return true;
|
575
634
|
}
|
576
635
|
}
|
@@ -294,7 +294,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
294
294
|
if (node.isAdFrameNode()) {
|
295
295
|
const config = ElementsComponents.AdornerManager.getRegisteredAdorner(
|
296
296
|
ElementsComponents.AdornerManager.RegisteredAdorners.AD);
|
297
|
-
const adorner = this.adorn(config
|
297
|
+
const adorner = this.adorn(config);
|
298
298
|
UI.Tooltip.Tooltip.install(adorner, i18nString(UIStrings.thisFrameWasIdentifiedAsAnAd));
|
299
299
|
}
|
300
300
|
}
|
@@ -1962,17 +1962,22 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
1962
1962
|
}
|
1963
1963
|
|
1964
1964
|
// TODO: add unit tests for adorner-related methods after component and TypeScript works are done
|
1965
|
-
adorn({name}: {name: string},
|
1966
|
-
|
1967
|
-
adornerContent
|
1965
|
+
adorn({name}: {name: string}, content?: HTMLElement): Adorners.Adorner.Adorner {
|
1966
|
+
let adornerContent = content;
|
1967
|
+
if (!adornerContent) {
|
1968
|
+
adornerContent = document.createElement('span');
|
1969
|
+
adornerContent.textContent = name;
|
1970
|
+
}
|
1968
1971
|
const adorner = new Adorners.Adorner.Adorner();
|
1969
1972
|
adorner.data = {
|
1970
1973
|
name,
|
1971
1974
|
content: adornerContent,
|
1972
1975
|
};
|
1973
|
-
|
1974
|
-
|
1975
|
-
|
1976
|
+
if (isOpeningTag(this.tagTypeContext)) {
|
1977
|
+
this.tagTypeContext.adorners.push(adorner);
|
1978
|
+
ElementsPanel.instance().registerAdorner(adorner);
|
1979
|
+
this.updateAdorners(this.tagTypeContext);
|
1980
|
+
}
|
1976
1981
|
return adorner;
|
1977
1982
|
}
|
1978
1983
|
|
@@ -2010,14 +2015,16 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
2010
2015
|
}
|
2011
2016
|
}
|
2012
2017
|
|
2013
|
-
removeAllAdorners(
|
2014
|
-
|
2015
|
-
|
2016
|
-
|
2017
|
-
|
2018
|
+
removeAllAdorners(): void {
|
2019
|
+
if (isOpeningTag(this.tagTypeContext)) {
|
2020
|
+
for (const adorner of this.tagTypeContext.adorners) {
|
2021
|
+
ElementsPanel.instance().deregisterAdorner(adorner);
|
2022
|
+
adorner.remove();
|
2023
|
+
}
|
2018
2024
|
|
2019
|
-
|
2020
|
-
|
2025
|
+
this.tagTypeContext.adorners = [];
|
2026
|
+
this.updateAdorners(this.tagTypeContext);
|
2027
|
+
}
|
2021
2028
|
}
|
2022
2029
|
|
2023
2030
|
private updateAdorners(context: OpeningTagContext): void {
|
@@ -2098,7 +2105,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
2098
2105
|
|
2099
2106
|
const config = ElementsComponents.AdornerManager.getRegisteredAdorner(
|
2100
2107
|
ElementsComponents.AdornerManager.RegisteredAdorners.GRID);
|
2101
|
-
const adorner = this.adorn(config
|
2108
|
+
const adorner = this.adorn(config);
|
2102
2109
|
adorner.classList.add('grid');
|
2103
2110
|
|
2104
2111
|
const onClick = (((): void => {
|
@@ -2135,7 +2142,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
2135
2142
|
}
|
2136
2143
|
const config = ElementsComponents.AdornerManager.getRegisteredAdorner(
|
2137
2144
|
ElementsComponents.AdornerManager.RegisteredAdorners.SCROLL_SNAP);
|
2138
|
-
const adorner = this.adorn(config
|
2145
|
+
const adorner = this.adorn(config);
|
2139
2146
|
adorner.classList.add('scroll-snap');
|
2140
2147
|
|
2141
2148
|
const onClick = (((): void => {
|
@@ -2174,7 +2181,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
2174
2181
|
}
|
2175
2182
|
const config = ElementsComponents.AdornerManager.getRegisteredAdorner(
|
2176
2183
|
ElementsComponents.AdornerManager.RegisteredAdorners.FLEX);
|
2177
|
-
const adorner = this.adorn(config
|
2184
|
+
const adorner = this.adorn(config);
|
2178
2185
|
adorner.classList.add('flex');
|
2179
2186
|
|
2180
2187
|
const onClick = (((): void => {
|
@@ -2213,7 +2220,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
2213
2220
|
}
|
2214
2221
|
const config = ElementsComponents.AdornerManager.getRegisteredAdorner(
|
2215
2222
|
ElementsComponents.AdornerManager.RegisteredAdorners.CONTAINER);
|
2216
|
-
const adorner = this.adorn(config
|
2223
|
+
const adorner = this.adorn(config);
|
2217
2224
|
adorner.classList.add('container');
|
2218
2225
|
|
2219
2226
|
const onClick = (((): void => {
|
@@ -43,6 +43,7 @@ import {ElementsPanel} from './ElementsPanel.js';
|
|
43
43
|
import {ElementsTreeElement, InitialChildrenLimit} from './ElementsTreeElement.js';
|
44
44
|
import elementsTreeOutlineStyles from './elementsTreeOutline.css.js';
|
45
45
|
import {ImagePreviewPopover} from './ImagePreviewPopover.js';
|
46
|
+
import {TopLayerContainer} from './TopLayerContainer.js';
|
46
47
|
|
47
48
|
import type {MarkerDecoratorRegistration} from './MarkerDecorator.js';
|
48
49
|
|
@@ -100,6 +101,7 @@ export class ElementsTreeOutline extends
|
|
100
101
|
private treeElementBeingDragged?: ElementsTreeElement;
|
101
102
|
private dragOverTreeElement?: ElementsTreeElement;
|
102
103
|
private updateModifiedNodesTimeout?: number;
|
104
|
+
private topLayerContainer?: TopLayerContainer;
|
103
105
|
|
104
106
|
constructor(omitRootDOMNode?: boolean, selectEnabled?: boolean, hideGutter?: boolean) {
|
105
107
|
super();
|
@@ -1001,6 +1003,7 @@ export class ElementsTreeOutline extends
|
|
1001
1003
|
domModel.addEventListener(SDK.DOMModel.Events.DocumentUpdated, this.documentUpdated, this);
|
1002
1004
|
domModel.addEventListener(SDK.DOMModel.Events.ChildNodeCountUpdated, this.childNodeCountUpdated, this);
|
1003
1005
|
domModel.addEventListener(SDK.DOMModel.Events.DistributedNodesChanged, this.distributedNodesChanged, this);
|
1006
|
+
domModel.addEventListener(SDK.DOMModel.Events.TopLayerElementsChanged, this.topLayerElementsChanged, this);
|
1004
1007
|
}
|
1005
1008
|
|
1006
1009
|
unwireFromDOMModel(domModel: SDK.DOMModel.DOMModel): void {
|
@@ -1013,6 +1016,7 @@ export class ElementsTreeOutline extends
|
|
1013
1016
|
domModel.removeEventListener(SDK.DOMModel.Events.DocumentUpdated, this.documentUpdated, this);
|
1014
1017
|
domModel.removeEventListener(SDK.DOMModel.Events.ChildNodeCountUpdated, this.childNodeCountUpdated, this);
|
1015
1018
|
domModel.removeEventListener(SDK.DOMModel.Events.DistributedNodesChanged, this.distributedNodesChanged, this);
|
1019
|
+
domModel.removeEventListener(SDK.DOMModel.Events.TopLayerElementsChanged, this.topLayerElementsChanged, this);
|
1016
1020
|
elementsTreeOutlineByDOMModel.delete(domModel);
|
1017
1021
|
}
|
1018
1022
|
|
@@ -1164,13 +1168,41 @@ export class ElementsTreeOutline extends
|
|
1164
1168
|
return Promise.resolve();
|
1165
1169
|
}
|
1166
1170
|
|
1167
|
-
return new Promise(resolve => {
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1171
|
+
return new Promise<void>(resolve => {
|
1172
|
+
treeElement.node().getChildNodes(() => {
|
1173
|
+
populatedTreeElements.add(treeElement);
|
1174
|
+
this.updateModifiedParentNode(treeElement.node());
|
1175
|
+
resolve();
|
1176
|
+
});
|
1177
|
+
})
|
1178
|
+
.then(() => {
|
1179
|
+
if (treeElement.node().nodeName() === 'BODY') {
|
1180
|
+
void this.createTopLayerContainer(treeElement);
|
1181
|
+
}
|
1182
|
+
});
|
1183
|
+
}
|
1184
|
+
|
1185
|
+
async createTopLayerContainer(bodyElement: ElementsTreeElement): Promise<void> {
|
1186
|
+
if (!this.topLayerContainer) {
|
1187
|
+
this.topLayerContainer = new TopLayerContainer(bodyElement);
|
1188
|
+
}
|
1189
|
+
this.topLayerContainer.updateBody(bodyElement);
|
1190
|
+
await this.updateTopLayerContainer();
|
1191
|
+
}
|
1192
|
+
|
1193
|
+
async updateTopLayerContainer(): Promise<void> {
|
1194
|
+
if (this.topLayerContainer) {
|
1195
|
+
const bodyElement = this.topLayerContainer.bodyElement;
|
1196
|
+
if (!bodyElement.children().includes(this.topLayerContainer) && !this.topLayerContainer.parent &&
|
1197
|
+
!this.topLayerContainer.treeOutline) {
|
1198
|
+
bodyElement.insertChild(this.topLayerContainer, bodyElement.childCount() - 1);
|
1199
|
+
}
|
1200
|
+
this.topLayerContainer.removeChildren();
|
1201
|
+
const topLayerElementsExists = await this.topLayerContainer.addTopLayerElementsAsChildren();
|
1202
|
+
if (!topLayerElementsExists) {
|
1203
|
+
bodyElement.removeChild(this.topLayerContainer);
|
1204
|
+
}
|
1205
|
+
}
|
1174
1206
|
}
|
1175
1207
|
|
1176
1208
|
private createElementTreeElement(node: SDK.DOMModel.DOMNode, isClosingTag?: boolean): ElementsTreeElement {
|
@@ -1318,7 +1350,7 @@ export class ElementsTreeOutline extends
|
|
1318
1350
|
}
|
1319
1351
|
|
1320
1352
|
insertChildElement(
|
1321
|
-
treeElement: ElementsTreeElement, child: SDK.DOMModel.DOMNode, index: number,
|
1353
|
+
treeElement: ElementsTreeElement|TopLayerContainer, child: SDK.DOMModel.DOMNode, index: number,
|
1322
1354
|
isClosingTag?: boolean): ElementsTreeElement {
|
1323
1355
|
const newElement = this.createElementTreeElement(child, isClosingTag);
|
1324
1356
|
treeElement.insertChild(newElement, index);
|
@@ -1427,6 +1459,10 @@ export class ElementsTreeOutline extends
|
|
1427
1459
|
}
|
1428
1460
|
}
|
1429
1461
|
|
1462
|
+
private async topLayerElementsChanged(): Promise<void> {
|
1463
|
+
await this.updateTopLayerContainer();
|
1464
|
+
}
|
1465
|
+
|
1430
1466
|
private static treeOutlineSymbol = Symbol('treeOutline');
|
1431
1467
|
}
|
1432
1468
|
|
@@ -0,0 +1,97 @@
|
|
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
|
+
import * as i18n from '../../core/i18n/i18n.js';
|
5
|
+
import * as SDK from '../../core/sdk/sdk.js';
|
6
|
+
import * as UI from '../../ui/legacy/legacy.js';
|
7
|
+
|
8
|
+
import * as ElementsComponents from './components/components.js';
|
9
|
+
import * as ElementsTreeOutline from './ElementsTreeOutline.js';
|
10
|
+
|
11
|
+
import type {ElementsTreeElement} from './ElementsTreeElement.js';
|
12
|
+
|
13
|
+
const UIStrings = {
|
14
|
+
/**
|
15
|
+
* @description Top layer is rendered closest to the user within a viewport, therefore its elements always appear on top of all other content
|
16
|
+
*/
|
17
|
+
topLayer: 'top-layer',
|
18
|
+
};
|
19
|
+
|
20
|
+
const str_ = i18n.i18n.registerUIStrings('panels/elements/TopLayerContainer.ts', UIStrings);
|
21
|
+
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
22
|
+
|
23
|
+
export class TopLayerContainer extends UI.TreeOutline.TreeElement {
|
24
|
+
treeOutline: ElementsTreeOutline.ElementsTreeOutline|null;
|
25
|
+
domModel: SDK.DOMModel.DOMModel;
|
26
|
+
currentTopLayerElements: Set<ElementsTreeElement>;
|
27
|
+
bodyElement: ElementsTreeElement;
|
28
|
+
|
29
|
+
constructor(bodyElement: ElementsTreeElement) {
|
30
|
+
super('#top-layer');
|
31
|
+
this.bodyElement = bodyElement;
|
32
|
+
this.domModel = bodyElement.node().domModel();
|
33
|
+
this.treeOutline = null;
|
34
|
+
this.currentTopLayerElements = new Set();
|
35
|
+
}
|
36
|
+
|
37
|
+
updateBody(bodyElement: ElementsTreeElement): void {
|
38
|
+
this.bodyElement = bodyElement;
|
39
|
+
}
|
40
|
+
|
41
|
+
async addTopLayerElementsAsChildren(): Promise<boolean> {
|
42
|
+
this.removeCurrentTopLayerElementsAdorners();
|
43
|
+
this.currentTopLayerElements = new Set();
|
44
|
+
const newTopLayerElementsIDs = await this.domModel.getTopLayerElements();
|
45
|
+
if (newTopLayerElementsIDs === null) {
|
46
|
+
return false;
|
47
|
+
}
|
48
|
+
let topLayerElementIndex = 0;
|
49
|
+
if (newTopLayerElementsIDs) {
|
50
|
+
for (const elementID of newTopLayerElementsIDs) {
|
51
|
+
const topLayerDOMNode = this.domModel.idToDOMNode.get(elementID);
|
52
|
+
// Will need to add support for backdrop in the future.
|
53
|
+
if (topLayerDOMNode && topLayerDOMNode.nodeName() !== '::backdrop') {
|
54
|
+
topLayerElementIndex++;
|
55
|
+
const topLayerElementShortcut = new SDK.DOMModel.DOMNodeShortcut(
|
56
|
+
this.domModel.target(), topLayerDOMNode.backendNodeId(), 0, topLayerDOMNode.nodeName());
|
57
|
+
const topLayerTreeElement = this.treeOutline?.treeElementByNode.get(topLayerDOMNode);
|
58
|
+
const topLayerElementRepresentation = new ElementsTreeOutline.ShortcutTreeElement(topLayerElementShortcut);
|
59
|
+
if (topLayerTreeElement && !this.currentTopLayerElements.has(topLayerTreeElement)) {
|
60
|
+
this.appendChild(topLayerElementRepresentation);
|
61
|
+
this.addTopLayerAdorner(topLayerTreeElement, topLayerElementRepresentation, topLayerElementIndex);
|
62
|
+
this.currentTopLayerElements.add(topLayerTreeElement);
|
63
|
+
}
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
return topLayerElementIndex > 0;
|
68
|
+
}
|
69
|
+
|
70
|
+
private removeCurrentTopLayerElementsAdorners(): void {
|
71
|
+
for (const topLayerElement of this.currentTopLayerElements) {
|
72
|
+
topLayerElement.removeAllAdorners();
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
private addTopLayerAdorner(
|
77
|
+
element: ElementsTreeElement, topLayerElementRepresentation: ElementsTreeOutline.ShortcutTreeElement,
|
78
|
+
topLayerElementIndex: number): void {
|
79
|
+
const config = ElementsComponents.AdornerManager.getRegisteredAdorner(
|
80
|
+
ElementsComponents.AdornerManager.RegisteredAdorners.TOP_LAYER);
|
81
|
+
const adornerContent = document.createElement('span');
|
82
|
+
adornerContent.textContent = ` top-layer (${topLayerElementIndex}) `;
|
83
|
+
const adorner = element?.adorn(config, adornerContent);
|
84
|
+
if (adorner) {
|
85
|
+
const onClick = (((): void => {
|
86
|
+
topLayerElementRepresentation.revealAndSelect();
|
87
|
+
}) as EventListener);
|
88
|
+
adorner.addInteraction(onClick, {
|
89
|
+
isToggle: false,
|
90
|
+
shouldPropagateOnKeydown: false,
|
91
|
+
ariaLabelDefault: i18nString(UIStrings.topLayer),
|
92
|
+
ariaLabelActive: i18nString(UIStrings.topLayer),
|
93
|
+
});
|
94
|
+
adorner.addEventListener('mousedown', e => e.consume(), false);
|
95
|
+
}
|
96
|
+
}
|
97
|
+
}
|
@@ -30,6 +30,7 @@ export enum RegisteredAdorners {
|
|
30
30
|
SCROLL_SNAP = 'scroll-snap',
|
31
31
|
CONTAINER = 'container',
|
32
32
|
SLOT = 'slot',
|
33
|
+
TOP_LAYER = 'top-layer',
|
33
34
|
}
|
34
35
|
|
35
36
|
// This enum-like const object serves as the authoritative registry for all the
|
@@ -72,6 +73,12 @@ export function getRegisteredAdorner(which: RegisteredAdorners): RegisteredAdorn
|
|
72
73
|
category: AdornerCategories.LAYOUT,
|
73
74
|
enabledByDefault: true,
|
74
75
|
};
|
76
|
+
case RegisteredAdorners.TOP_LAYER:
|
77
|
+
return {
|
78
|
+
name: 'top-layer',
|
79
|
+
category: AdornerCategories.LAYOUT,
|
80
|
+
enabledByDefault: true,
|
81
|
+
};
|
75
82
|
}
|
76
83
|
}
|
77
84
|
|
@@ -9,6 +9,7 @@ import './DOMLinkifier.js';
|
|
9
9
|
import './DOMPath.js';
|
10
10
|
import './ElementsSidebarPane.js';
|
11
11
|
import './ElementsTreeElement.js';
|
12
|
+
import './TopLayerContainer.js';
|
12
13
|
import './ElementsTreeOutline.js';
|
13
14
|
import './EventListenersWidget.js';
|
14
15
|
import './MarkerDecorator.js';
|
@@ -25,6 +26,7 @@ import './ElementsPanel.js';
|
|
25
26
|
import './ClassesPaneWidget.js';
|
26
27
|
import './ElementStatePaneWidget.js';
|
27
28
|
import './ElementsTreeElementHighlighter.js';
|
29
|
+
import './TopLayerContainer.js';
|
28
30
|
|
29
31
|
import * as ClassesPaneWidget from './ClassesPaneWidget.js';
|
30
32
|
import * as ColorSwatchPopoverIcon from './ColorSwatchPopoverIcon.js';
|
@@ -53,6 +55,7 @@ import * as StylePropertyHighlighter from './StylePropertyHighlighter.js';
|
|
53
55
|
import * as StylePropertyTreeElement from './StylePropertyTreeElement.js';
|
54
56
|
import * as StylePropertyUtils from './StylePropertyUtils.js';
|
55
57
|
import * as StylesSidebarPane from './StylesSidebarPane.js';
|
58
|
+
import * as TopLayerContainer from './TopLayerContainer.js';
|
56
59
|
|
57
60
|
export {
|
58
61
|
ClassesPaneWidget,
|
@@ -82,4 +85,5 @@ export {
|
|
82
85
|
StylePropertyTreeElement,
|
83
86
|
StylePropertyUtils,
|
84
87
|
StylesSidebarPane,
|
88
|
+
TopLayerContainer,
|
85
89
|
};
|
@@ -319,6 +319,6 @@ export class OpenLinearMemoryInspector extends UI.Widget.VBox implements UI.Cont
|
|
319
319
|
private async openMemoryInspector(obj: SDK.RemoteObject.RemoteObject): Promise<void> {
|
320
320
|
const controller = LinearMemoryInspector.LinearMemoryInspectorController.LinearMemoryInspectorController.instance();
|
321
321
|
Host.userMetrics.linearMemoryInspectorRevealedFrom(Host.UserMetrics.LinearMemoryInspectorRevealedFrom.ContextMenu);
|
322
|
-
void controller.openInspectorView(obj
|
322
|
+
void controller.openInspectorView(obj);
|
323
323
|
}
|
324
324
|
}
|
@@ -77,17 +77,16 @@ async function getBufferFromObject(obj: SDK.RemoteObject.RemoteObject): Promise<
|
|
77
77
|
return new SDK.RemoteObject.RemoteArrayBuffer(obj);
|
78
78
|
}
|
79
79
|
|
80
|
+
export function isDWARFMemoryObject(obj: SDK.RemoteObject.RemoteObject): boolean {
|
81
|
+
return obj instanceof Bindings.DebuggerLanguagePlugins.ValueNode && obj.inspectableAddress !== undefined;
|
82
|
+
}
|
83
|
+
|
80
84
|
export function isMemoryObjectProperty(obj: SDK.RemoteObject.RemoteObject): boolean {
|
81
85
|
const isWasmOrBuffer = obj.type === 'object' && obj.subtype && ACCEPTED_MEMORY_TYPES.includes(obj.subtype);
|
82
|
-
if (isWasmOrBuffer) {
|
86
|
+
if (isWasmOrBuffer || isDWARFMemoryObject(obj)) {
|
83
87
|
return true;
|
84
88
|
}
|
85
89
|
|
86
|
-
const isWasmDWARF = obj instanceof Bindings.DebuggerLanguagePlugins.ValueNode;
|
87
|
-
if (isWasmDWARF) {
|
88
|
-
return obj.inspectableAddress !== undefined;
|
89
|
-
}
|
90
|
-
|
91
90
|
return false;
|
92
91
|
}
|
93
92
|
|
@@ -388,11 +388,13 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
388
388
|
}
|
389
389
|
|
390
390
|
static appendMemoryIcon(element: Element, obj: SDK.RemoteObject.RemoteObject): void {
|
391
|
-
// We show the memory icon only on ArrayBuffer
|
391
|
+
// We show the memory icon only on ArrayBuffer, WebAssembly.Memory and DWARF memory instances.
|
392
392
|
// TypedArrays DataViews are also supported, but showing the icon next to their
|
393
393
|
// previews is quite a significant visual overhead, and users can easily get to
|
394
394
|
// their buffers and open the memory inspector from there.
|
395
|
-
|
395
|
+
const arrayBufferOrWasmMemory =
|
396
|
+
(obj.type === 'object' && (obj.subtype === 'arraybuffer' || obj.subtype === 'webassemblymemory'));
|
397
|
+
if (!arrayBufferOrWasmMemory && !LinearMemoryInspector.LinearMemoryInspectorController.isDWARFMemoryObject(obj)) {
|
396
398
|
return;
|
397
399
|
}
|
398
400
|
const memoryIcon = new IconButton.Icon.Icon();
|
@@ -408,7 +410,7 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
408
410
|
const controller =
|
409
411
|
LinearMemoryInspector.LinearMemoryInspectorController.LinearMemoryInspectorController.instance();
|
410
412
|
Host.userMetrics.linearMemoryInspectorRevealedFrom(Host.UserMetrics.LinearMemoryInspectorRevealedFrom.MemoryIcon);
|
411
|
-
void controller.openInspectorView(obj
|
413
|
+
void controller.openInspectorView(obj);
|
412
414
|
};
|
413
415
|
|
414
416
|
UI.Tooltip.Tooltip.install(memoryIcon, 'Reveal in Memory Inspector panel');
|
package/package.json
CHANGED