mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-10-13 01:54:52 +08:00
Introduce a new namespace "Root" to be able to disambiguate between Runtime the namespace and Runtime the object. roll CodeMirror The above line is necessary to fix the presubmit, which complains about CodeMirror changes. This is only updating a type reference. Bug: 1006759 Change-Id: I04941d9f18649701060e3035f7eeb2ef3abb51e4 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1829708 Reviewed-by: Yang Guo <yangguo@chromium.org> Commit-Queue: Tim Van der Lippe <tvanderlippe@chromium.org> Cr-Original-Commit-Position: refs/heads/master@{#701257} Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src Cr-Mirrored-Commit: 17cc008cf6ad28c6e8c07c638a1b380ca30e7f79
1964 lines
60 KiB
JavaScript
1964 lines
60 KiB
JavaScript
/*
|
|
* Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved.
|
|
* Copyright (C) 2009 Joseph Pecoraro
|
|
* Copyright (C) 2013 Samsung Electronics. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
|
|
* its contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
/**
|
|
* @implements {SDK.TargetManager.Observer}
|
|
* @unrestricted
|
|
*/
|
|
Resources.ApplicationPanelSidebar = class extends UI.VBox {
|
|
/**
|
|
* @param {!Resources.ResourcesPanel} panel
|
|
*/
|
|
constructor(panel) {
|
|
super();
|
|
|
|
this._panel = panel;
|
|
|
|
this._sidebarTree = new UI.TreeOutlineInShadow();
|
|
this._sidebarTree.element.classList.add('resources-sidebar');
|
|
this._sidebarTree.registerRequiredCSS('resources/resourcesSidebar.css');
|
|
this._sidebarTree.element.classList.add('filter-all');
|
|
// Listener needs to have been set up before the elements are added
|
|
this._sidebarTree.addEventListener(UI.TreeOutline.Events.ElementAttached, this._treeElementAdded, this);
|
|
|
|
this.contentElement.appendChild(this._sidebarTree.element);
|
|
this._applicationTreeElement = this._addSidebarSection(Common.UIString('Application'));
|
|
const manifestTreeElement = new Resources.AppManifestTreeElement(panel);
|
|
this._applicationTreeElement.appendChild(manifestTreeElement);
|
|
this.serviceWorkersTreeElement = new Resources.ServiceWorkersTreeElement(panel);
|
|
this._applicationTreeElement.appendChild(this.serviceWorkersTreeElement);
|
|
const clearStorageTreeElement = new Resources.ClearStorageTreeElement(panel);
|
|
this._applicationTreeElement.appendChild(clearStorageTreeElement);
|
|
|
|
const storageTreeElement = this._addSidebarSection(Common.UIString('Storage'));
|
|
this.localStorageListTreeElement =
|
|
new Resources.StorageCategoryTreeElement(panel, Common.UIString('Local Storage'), 'LocalStorage');
|
|
this.localStorageListTreeElement.setLink(
|
|
'https://developers.google.com/web/tools/chrome-devtools/storage/localstorage?utm_source=devtools');
|
|
const localStorageIcon = UI.Icon.create('mediumicon-table', 'resource-tree-item');
|
|
this.localStorageListTreeElement.setLeadingIcons([localStorageIcon]);
|
|
|
|
storageTreeElement.appendChild(this.localStorageListTreeElement);
|
|
this.sessionStorageListTreeElement =
|
|
new Resources.StorageCategoryTreeElement(panel, Common.UIString('Session Storage'), 'SessionStorage');
|
|
this.sessionStorageListTreeElement.setLink(
|
|
'https://developers.google.com/web/tools/chrome-devtools/storage/sessionstorage?utm_source=devtools');
|
|
const sessionStorageIcon = UI.Icon.create('mediumicon-table', 'resource-tree-item');
|
|
this.sessionStorageListTreeElement.setLeadingIcons([sessionStorageIcon]);
|
|
|
|
storageTreeElement.appendChild(this.sessionStorageListTreeElement);
|
|
this.indexedDBListTreeElement = new Resources.IndexedDBTreeElement(panel);
|
|
this.indexedDBListTreeElement.setLink(
|
|
'https://developers.google.com/web/tools/chrome-devtools/storage/indexeddb?utm_source=devtools');
|
|
storageTreeElement.appendChild(this.indexedDBListTreeElement);
|
|
this.databasesListTreeElement =
|
|
new Resources.StorageCategoryTreeElement(panel, Common.UIString('Web SQL'), 'Databases');
|
|
this.databasesListTreeElement.setLink(
|
|
'https://developers.google.com/web/tools/chrome-devtools/storage/websql?utm_source=devtools');
|
|
const databaseIcon = UI.Icon.create('mediumicon-database', 'resource-tree-item');
|
|
this.databasesListTreeElement.setLeadingIcons([databaseIcon]);
|
|
|
|
storageTreeElement.appendChild(this.databasesListTreeElement);
|
|
this.cookieListTreeElement = new Resources.StorageCategoryTreeElement(panel, Common.UIString('Cookies'), 'Cookies');
|
|
this.cookieListTreeElement.setLink(
|
|
'https://developers.google.com/web/tools/chrome-devtools/storage/cookies?utm_source=devtools');
|
|
const cookieIcon = UI.Icon.create('mediumicon-cookie', 'resource-tree-item');
|
|
this.cookieListTreeElement.setLeadingIcons([cookieIcon]);
|
|
storageTreeElement.appendChild(this.cookieListTreeElement);
|
|
|
|
const cacheTreeElement = this._addSidebarSection(Common.UIString('Cache'));
|
|
this.cacheStorageListTreeElement = new Resources.ServiceWorkerCacheTreeElement(panel);
|
|
cacheTreeElement.appendChild(this.cacheStorageListTreeElement);
|
|
this.applicationCacheListTreeElement =
|
|
new Resources.StorageCategoryTreeElement(panel, Common.UIString('Application Cache'), 'ApplicationCache');
|
|
this.applicationCacheListTreeElement.setLink(
|
|
'https://developers.google.com/web/tools/chrome-devtools/storage/applicationcache?utm_source=devtools');
|
|
const applicationCacheIcon = UI.Icon.create('mediumicon-table', 'resource-tree-item');
|
|
this.applicationCacheListTreeElement.setLeadingIcons([applicationCacheIcon]);
|
|
|
|
cacheTreeElement.appendChild(this.applicationCacheListTreeElement);
|
|
|
|
if (Root.Runtime.experiments.isEnabled('backgroundServices')) {
|
|
const backgroundServiceTreeElement = this._addSidebarSection(ls`Background Services`);
|
|
|
|
this.backgroundFetchTreeElement =
|
|
new Resources.BackgroundServiceTreeElement(panel, Protocol.BackgroundService.ServiceName.BackgroundFetch);
|
|
backgroundServiceTreeElement.appendChild(this.backgroundFetchTreeElement);
|
|
this.backgroundSyncTreeElement =
|
|
new Resources.BackgroundServiceTreeElement(panel, Protocol.BackgroundService.ServiceName.BackgroundSync);
|
|
backgroundServiceTreeElement.appendChild(this.backgroundSyncTreeElement);
|
|
|
|
if (Root.Runtime.experiments.isEnabled('backgroundServicesNotifications')) {
|
|
this.notificationsTreeElement =
|
|
new Resources.BackgroundServiceTreeElement(panel, Protocol.BackgroundService.ServiceName.Notifications);
|
|
backgroundServiceTreeElement.appendChild(this.notificationsTreeElement);
|
|
}
|
|
if (Root.Runtime.experiments.isEnabled('backgroundServicesPaymentHandler')) {
|
|
this.paymentHandlerTreeElement =
|
|
new Resources.BackgroundServiceTreeElement(panel, Protocol.BackgroundService.ServiceName.PaymentHandler);
|
|
backgroundServiceTreeElement.appendChild(this.paymentHandlerTreeElement);
|
|
}
|
|
if (Root.Runtime.experiments.isEnabled('backgroundServicesPeriodicBackgroundSync')) {
|
|
this.periodicBackgroundSyncTreeElement = new Resources.BackgroundServiceTreeElement(
|
|
panel, Protocol.BackgroundService.ServiceName.PeriodicBackgroundSync);
|
|
backgroundServiceTreeElement.appendChild(this.periodicBackgroundSyncTreeElement);
|
|
}
|
|
if (Root.Runtime.experiments.isEnabled('backgroundServicesPushMessaging')) {
|
|
this.pushMessagingTreeElement =
|
|
new Resources.BackgroundServiceTreeElement(panel, Protocol.BackgroundService.ServiceName.PushMessaging);
|
|
backgroundServiceTreeElement.appendChild(this.pushMessagingTreeElement);
|
|
}
|
|
}
|
|
|
|
this._resourcesSection = new Resources.ResourcesSection(panel, this._addSidebarSection(Common.UIString('Frames')));
|
|
|
|
/** @type {!Map.<!Resources.Database, !Object.<string, !Resources.DatabaseTableView>>} */
|
|
this._databaseTableViews = new Map();
|
|
/** @type {!Map.<!Resources.Database, !Resources.DatabaseQueryView>} */
|
|
this._databaseQueryViews = new Map();
|
|
/** @type {!Map.<!Resources.Database, !Resources.DatabaseTreeElement>} */
|
|
this._databaseTreeElements = new Map();
|
|
/** @type {!Map.<!Resources.DOMStorage, !Resources.DOMStorageTreeElement>} */
|
|
this._domStorageTreeElements = new Map();
|
|
/** @type {!Object.<string, boolean>} */
|
|
this._domains = {};
|
|
|
|
this._sidebarTree.contentElement.addEventListener('mousemove', this._onmousemove.bind(this), false);
|
|
this._sidebarTree.contentElement.addEventListener('mouseleave', this._onmouseleave.bind(this), false);
|
|
|
|
SDK.targetManager.observeTargets(this);
|
|
SDK.targetManager.addModelListener(
|
|
SDK.ResourceTreeModel, SDK.ResourceTreeModel.Events.FrameNavigated, this._frameNavigated, this);
|
|
|
|
const selection = this._panel.lastSelectedItemPath();
|
|
if (!selection.length) {
|
|
manifestTreeElement.select();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {string} title
|
|
* @return {!UI.TreeElement}
|
|
*/
|
|
_addSidebarSection(title) {
|
|
const treeElement = new UI.TreeElement(title, true);
|
|
treeElement.listItemElement.classList.add('storage-group-list-item');
|
|
treeElement.setCollapsible(false);
|
|
treeElement.selectable = false;
|
|
this._sidebarTree.appendChild(treeElement);
|
|
return treeElement;
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @param {!SDK.Target} target
|
|
*/
|
|
targetAdded(target) {
|
|
if (this._target) {
|
|
return;
|
|
}
|
|
this._target = target;
|
|
this._databaseModel = target.model(Resources.DatabaseModel);
|
|
if (this._databaseModel) {
|
|
this._databaseModel.addEventListener(Resources.DatabaseModel.Events.DatabaseAdded, this._databaseAdded, this);
|
|
this._databaseModel.addEventListener(Resources.DatabaseModel.Events.DatabasesRemoved, this._resetWebSQL, this);
|
|
}
|
|
|
|
const resourceTreeModel = target.model(SDK.ResourceTreeModel);
|
|
if (!resourceTreeModel) {
|
|
return;
|
|
}
|
|
|
|
if (resourceTreeModel.cachedResourcesLoaded()) {
|
|
this._initialize();
|
|
}
|
|
|
|
resourceTreeModel.addEventListener(SDK.ResourceTreeModel.Events.CachedResourcesLoaded, this._initialize, this);
|
|
resourceTreeModel.addEventListener(
|
|
SDK.ResourceTreeModel.Events.WillLoadCachedResources, this._resetWithFrames, this);
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @param {!SDK.Target} target
|
|
*/
|
|
targetRemoved(target) {
|
|
if (target !== this._target) {
|
|
return;
|
|
}
|
|
delete this._target;
|
|
|
|
const resourceTreeModel = target.model(SDK.ResourceTreeModel);
|
|
if (resourceTreeModel) {
|
|
resourceTreeModel.removeEventListener(SDK.ResourceTreeModel.Events.CachedResourcesLoaded, this._initialize, this);
|
|
resourceTreeModel.removeEventListener(
|
|
SDK.ResourceTreeModel.Events.WillLoadCachedResources, this._resetWithFrames, this);
|
|
}
|
|
if (this._databaseModel) {
|
|
this._databaseModel.removeEventListener(Resources.DatabaseModel.Events.DatabaseAdded, this._databaseAdded, this);
|
|
this._databaseModel.removeEventListener(Resources.DatabaseModel.Events.DatabasesRemoved, this._resetWebSQL, this);
|
|
this._databaseModel = null;
|
|
}
|
|
|
|
this._resetWithFrames();
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
focus() {
|
|
this._sidebarTree.focus();
|
|
}
|
|
|
|
_initialize() {
|
|
for (const frame of SDK.ResourceTreeModel.frames()) {
|
|
this._addCookieDocument(frame);
|
|
}
|
|
if (this._databaseModel) {
|
|
this._databaseModel.enable();
|
|
}
|
|
|
|
const cacheStorageModel = this._target.model(SDK.ServiceWorkerCacheModel);
|
|
if (cacheStorageModel) {
|
|
cacheStorageModel.enable();
|
|
}
|
|
const resourceTreeModel = this._target.model(SDK.ResourceTreeModel);
|
|
if (resourceTreeModel) {
|
|
this._populateApplicationCacheTree(resourceTreeModel);
|
|
}
|
|
SDK.targetManager.observeModels(Resources.DOMStorageModel, /** @type {!SDK.SDKModelObserver} */ ({
|
|
modelAdded: model => this._domStorageModelAdded(model),
|
|
modelRemoved: model => this._domStorageModelRemoved(model)
|
|
}));
|
|
this.indexedDBListTreeElement._initialize();
|
|
SDK.targetManager.observeModels(
|
|
Resources.IndexedDBModel, /** @type {!SDK.SDKModelObserver} */ ({
|
|
modelAdded: model => model.enable(),
|
|
modelRemoved: model => this.indexedDBListTreeElement.removeIndexedDBForModel(model)
|
|
}));
|
|
const serviceWorkerCacheModel = this._target.model(SDK.ServiceWorkerCacheModel);
|
|
this.cacheStorageListTreeElement._initialize(serviceWorkerCacheModel);
|
|
const backgroundServiceModel = this._target.model(Resources.BackgroundServiceModel);
|
|
if (Root.Runtime.experiments.isEnabled('backgroundServices')) {
|
|
this.backgroundFetchTreeElement._initialize(backgroundServiceModel);
|
|
this.backgroundSyncTreeElement._initialize(backgroundServiceModel);
|
|
if (Root.Runtime.experiments.isEnabled('backgroundServicesNotifications')) {
|
|
this.notificationsTreeElement._initialize(backgroundServiceModel);
|
|
}
|
|
if (Root.Runtime.experiments.isEnabled('backgroundServicesPaymentHandler')) {
|
|
this.paymentHandlerTreeElement._initialize(backgroundServiceModel);
|
|
}
|
|
if (Root.Runtime.experiments.isEnabled('backgroundServicesPeriodicBackgroundSync')) {
|
|
this.periodicBackgroundSyncTreeElement._initialize(backgroundServiceModel);
|
|
}
|
|
if (Root.Runtime.experiments.isEnabled('backgroundServicesPushMessaging')) {
|
|
this.pushMessagingTreeElement._initialize(backgroundServiceModel);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {!Resources.DOMStorageModel} model
|
|
*/
|
|
_domStorageModelAdded(model) {
|
|
model.enable();
|
|
model.storages().forEach(this._addDOMStorage.bind(this));
|
|
model.addEventListener(Resources.DOMStorageModel.Events.DOMStorageAdded, this._domStorageAdded, this);
|
|
model.addEventListener(Resources.DOMStorageModel.Events.DOMStorageRemoved, this._domStorageRemoved, this);
|
|
}
|
|
|
|
/**
|
|
* @param {!Resources.DOMStorageModel} model
|
|
*/
|
|
_domStorageModelRemoved(model) {
|
|
model.storages().forEach(this._removeDOMStorage.bind(this));
|
|
model.removeEventListener(Resources.DOMStorageModel.Events.DOMStorageAdded, this._domStorageAdded, this);
|
|
model.removeEventListener(Resources.DOMStorageModel.Events.DOMStorageRemoved, this._domStorageRemoved, this);
|
|
}
|
|
|
|
_resetWithFrames() {
|
|
this._resourcesSection.reset();
|
|
this._reset();
|
|
}
|
|
|
|
_resetWebSQL() {
|
|
const queryViews = this._databaseQueryViews.valuesArray();
|
|
for (let i = 0; i < queryViews.length; ++i) {
|
|
queryViews[i].removeEventListener(
|
|
Resources.DatabaseQueryView.Events.SchemaUpdated, this._updateDatabaseTables, this);
|
|
}
|
|
this._databaseTableViews.clear();
|
|
this._databaseQueryViews.clear();
|
|
this._databaseTreeElements.clear();
|
|
this.databasesListTreeElement.removeChildren();
|
|
this.databasesListTreeElement.setExpandable(false);
|
|
}
|
|
|
|
_resetAppCache() {
|
|
for (const frameId of Object.keys(this._applicationCacheFrameElements)) {
|
|
this._applicationCacheFrameManifestRemoved({data: frameId});
|
|
}
|
|
this.applicationCacheListTreeElement.setExpandable(false);
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_treeElementAdded(event) {
|
|
const selection = this._panel.lastSelectedItemPath();
|
|
if (!selection.length) {
|
|
return;
|
|
}
|
|
const element = event.data;
|
|
const index = selection.indexOf(element.itemURL);
|
|
if (index < 0) {
|
|
return;
|
|
}
|
|
for (let parent = element.parent; parent; parent = parent.parent) {
|
|
parent.expand();
|
|
}
|
|
if (index > 0) {
|
|
element.expand();
|
|
}
|
|
element.select();
|
|
}
|
|
|
|
_reset() {
|
|
this._domains = {};
|
|
this._resetWebSQL();
|
|
this.cookieListTreeElement.removeChildren();
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_frameNavigated(event) {
|
|
const frame = /** @type {!SDK.ResourceTreeFrame} */ (event.data);
|
|
|
|
if (frame.isTopFrame()) {
|
|
this._reset();
|
|
}
|
|
|
|
const applicationCacheFrameTreeElement = this._applicationCacheFrameElements[frame.id];
|
|
if (applicationCacheFrameTreeElement) {
|
|
applicationCacheFrameTreeElement.frameNavigated(frame);
|
|
}
|
|
this._addCookieDocument(frame);
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_databaseAdded(event) {
|
|
const database = /** @type {!Resources.Database} */ (event.data);
|
|
const databaseTreeElement = new Resources.DatabaseTreeElement(this, database);
|
|
this._databaseTreeElements.set(database, databaseTreeElement);
|
|
this.databasesListTreeElement.appendChild(databaseTreeElement);
|
|
}
|
|
|
|
/**
|
|
* @param {!SDK.ResourceTreeFrame} frame
|
|
*/
|
|
_addCookieDocument(frame) {
|
|
const parsedURL = frame.url.asParsedURL();
|
|
if (!parsedURL || (parsedURL.scheme !== 'http' && parsedURL.scheme !== 'https' && parsedURL.scheme !== 'file')) {
|
|
return;
|
|
}
|
|
|
|
const domain = parsedURL.securityOrigin();
|
|
if (!this._domains[domain]) {
|
|
this._domains[domain] = true;
|
|
const cookieDomainTreeElement = new Resources.CookieTreeElement(this._panel, frame, domain);
|
|
this.cookieListTreeElement.appendChild(cookieDomainTreeElement);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_domStorageAdded(event) {
|
|
const domStorage = /** @type {!Resources.DOMStorage} */ (event.data);
|
|
this._addDOMStorage(domStorage);
|
|
}
|
|
|
|
/**
|
|
* @param {!Resources.DOMStorage} domStorage
|
|
*/
|
|
_addDOMStorage(domStorage) {
|
|
console.assert(!this._domStorageTreeElements.get(domStorage));
|
|
|
|
const domStorageTreeElement = new Resources.DOMStorageTreeElement(this._panel, domStorage);
|
|
this._domStorageTreeElements.set(domStorage, domStorageTreeElement);
|
|
if (domStorage.isLocalStorage) {
|
|
this.localStorageListTreeElement.appendChild(domStorageTreeElement);
|
|
} else {
|
|
this.sessionStorageListTreeElement.appendChild(domStorageTreeElement);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_domStorageRemoved(event) {
|
|
const domStorage = /** @type {!Resources.DOMStorage} */ (event.data);
|
|
this._removeDOMStorage(domStorage);
|
|
}
|
|
|
|
/**
|
|
* @param {!Resources.DOMStorage} domStorage
|
|
*/
|
|
_removeDOMStorage(domStorage) {
|
|
const treeElement = this._domStorageTreeElements.get(domStorage);
|
|
if (!treeElement) {
|
|
return;
|
|
}
|
|
const wasSelected = treeElement.selected;
|
|
const parentListTreeElement = treeElement.parent;
|
|
parentListTreeElement.removeChild(treeElement);
|
|
if (wasSelected) {
|
|
parentListTreeElement.select();
|
|
}
|
|
this._domStorageTreeElements.remove(domStorage);
|
|
}
|
|
|
|
/**
|
|
* @param {!Resources.Database} database
|
|
*/
|
|
selectDatabase(database) {
|
|
if (database) {
|
|
this._showDatabase(database);
|
|
this._databaseTreeElements.get(database).select();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {!SDK.Resource} resource
|
|
* @param {number=} line
|
|
* @param {number=} column
|
|
* @return {!Promise}
|
|
*/
|
|
async showResource(resource, line, column) {
|
|
await this._resourcesSection.revealResource(resource, line, column);
|
|
}
|
|
|
|
/**
|
|
* @param {!Resources.Database} database
|
|
* @param {string=} tableName
|
|
*/
|
|
_showDatabase(database, tableName) {
|
|
if (!database) {
|
|
return;
|
|
}
|
|
|
|
let view;
|
|
if (tableName) {
|
|
let tableViews = this._databaseTableViews.get(database);
|
|
if (!tableViews) {
|
|
tableViews = /** @type {!Object.<string, !Resources.DatabaseTableView>} */ ({});
|
|
this._databaseTableViews.set(database, tableViews);
|
|
}
|
|
view = tableViews[tableName];
|
|
if (!view) {
|
|
view = new Resources.DatabaseTableView(database, tableName);
|
|
tableViews[tableName] = view;
|
|
}
|
|
} else {
|
|
view = this._databaseQueryViews.get(database);
|
|
if (!view) {
|
|
view = new Resources.DatabaseQueryView(database);
|
|
this._databaseQueryViews.set(database, view);
|
|
view.addEventListener(Resources.DatabaseQueryView.Events.SchemaUpdated, this._updateDatabaseTables, this);
|
|
}
|
|
}
|
|
|
|
this._innerShowView(view);
|
|
}
|
|
|
|
_showApplicationCache(frameId) {
|
|
if (!this._applicationCacheViews[frameId]) {
|
|
this._applicationCacheViews[frameId] =
|
|
new Resources.ApplicationCacheItemsView(this._applicationCacheModel, frameId);
|
|
}
|
|
|
|
this._innerShowView(this._applicationCacheViews[frameId]);
|
|
}
|
|
|
|
/**
|
|
* @param {!UI.Widget} view
|
|
*/
|
|
showFileSystem(view) {
|
|
this._innerShowView(view);
|
|
}
|
|
|
|
_innerShowView(view) {
|
|
this._panel.showView(view);
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
async _updateDatabaseTables(event) {
|
|
const database = /** @type {!Resources.Database} */ (event.data);
|
|
|
|
if (!database) {
|
|
return;
|
|
}
|
|
|
|
const databasesTreeElement = this._databaseTreeElements.get(database);
|
|
if (!databasesTreeElement) {
|
|
return;
|
|
}
|
|
|
|
databasesTreeElement.invalidateChildren();
|
|
const tableViews = this._databaseTableViews.get(database);
|
|
|
|
if (!tableViews) {
|
|
return;
|
|
}
|
|
|
|
const tableNamesHash = {};
|
|
const panel = this._panel;
|
|
const tableNames = await database.tableNames();
|
|
const tableNamesLength = tableNames.length;
|
|
|
|
for (let i = 0; i < tableNamesLength; ++i) {
|
|
tableNamesHash[tableNames[i]] = true;
|
|
}
|
|
|
|
for (const tableName in tableViews) {
|
|
if (!(tableName in tableNamesHash)) {
|
|
if (panel.visibleView === tableViews[tableName]) {
|
|
panel.showView(null);
|
|
}
|
|
delete tableViews[tableName];
|
|
}
|
|
}
|
|
|
|
await databasesTreeElement.updateChildren();
|
|
}
|
|
|
|
/**
|
|
* @param {!SDK.ResourceTreeModel} resourceTreeModel
|
|
*/
|
|
_populateApplicationCacheTree(resourceTreeModel) {
|
|
this._applicationCacheModel = this._target.model(Resources.ApplicationCacheModel);
|
|
|
|
this._applicationCacheViews = {};
|
|
this._applicationCacheFrameElements = {};
|
|
this._applicationCacheManifestElements = {};
|
|
|
|
this._applicationCacheModel.addEventListener(
|
|
Resources.ApplicationCacheModel.Events.FrameManifestAdded, this._applicationCacheFrameManifestAdded, this);
|
|
this._applicationCacheModel.addEventListener(
|
|
Resources.ApplicationCacheModel.Events.FrameManifestRemoved, this._applicationCacheFrameManifestRemoved, this);
|
|
this._applicationCacheModel.addEventListener(
|
|
Resources.ApplicationCacheModel.Events.FrameManifestsReset, this._resetAppCache, this);
|
|
|
|
this._applicationCacheModel.addEventListener(
|
|
Resources.ApplicationCacheModel.Events.FrameManifestStatusUpdated,
|
|
this._applicationCacheFrameManifestStatusChanged, this);
|
|
this._applicationCacheModel.addEventListener(
|
|
Resources.ApplicationCacheModel.Events.NetworkStateChanged, this._applicationCacheNetworkStateChanged, this);
|
|
}
|
|
|
|
_applicationCacheFrameManifestAdded(event) {
|
|
const frameId = event.data;
|
|
const manifestURL = this._applicationCacheModel.frameManifestURL(frameId);
|
|
|
|
let manifestTreeElement = this._applicationCacheManifestElements[manifestURL];
|
|
if (!manifestTreeElement) {
|
|
manifestTreeElement = new Resources.ApplicationCacheManifestTreeElement(this._panel, manifestURL);
|
|
this.applicationCacheListTreeElement.appendChild(manifestTreeElement);
|
|
this._applicationCacheManifestElements[manifestURL] = manifestTreeElement;
|
|
}
|
|
|
|
const model = this._target.model(SDK.ResourceTreeModel);
|
|
const frameTreeElement =
|
|
new Resources.ApplicationCacheFrameTreeElement(this, model.frameForId(frameId), manifestURL);
|
|
manifestTreeElement.appendChild(frameTreeElement);
|
|
manifestTreeElement.expand();
|
|
this._applicationCacheFrameElements[frameId] = frameTreeElement;
|
|
}
|
|
|
|
_applicationCacheFrameManifestRemoved(event) {
|
|
const frameId = event.data;
|
|
const frameTreeElement = this._applicationCacheFrameElements[frameId];
|
|
if (!frameTreeElement) {
|
|
return;
|
|
}
|
|
|
|
const manifestURL = frameTreeElement.manifestURL;
|
|
delete this._applicationCacheFrameElements[frameId];
|
|
delete this._applicationCacheViews[frameId];
|
|
frameTreeElement.parent.removeChild(frameTreeElement);
|
|
|
|
const manifestTreeElement = this._applicationCacheManifestElements[manifestURL];
|
|
if (manifestTreeElement.childCount()) {
|
|
return;
|
|
}
|
|
|
|
delete this._applicationCacheManifestElements[manifestURL];
|
|
manifestTreeElement.parent.removeChild(manifestTreeElement);
|
|
}
|
|
|
|
_applicationCacheFrameManifestStatusChanged(event) {
|
|
const frameId = event.data;
|
|
const status = this._applicationCacheModel.frameManifestStatus(frameId);
|
|
|
|
if (this._applicationCacheViews[frameId]) {
|
|
this._applicationCacheViews[frameId].updateStatus(status);
|
|
}
|
|
}
|
|
|
|
_applicationCacheNetworkStateChanged(event) {
|
|
const isNowOnline = event.data;
|
|
|
|
for (const manifestURL in this._applicationCacheViews) {
|
|
this._applicationCacheViews[manifestURL].updateNetworkState(isNowOnline);
|
|
}
|
|
}
|
|
|
|
showView(view) {
|
|
if (view) {
|
|
this.showResource(view.resource);
|
|
}
|
|
}
|
|
|
|
_onmousemove(event) {
|
|
const nodeUnderMouse = event.target;
|
|
if (!nodeUnderMouse) {
|
|
return;
|
|
}
|
|
|
|
const listNode = nodeUnderMouse.enclosingNodeOrSelfWithNodeName('li');
|
|
if (!listNode) {
|
|
return;
|
|
}
|
|
|
|
const element = listNode.treeElement;
|
|
if (this._previousHoveredElement === element) {
|
|
return;
|
|
}
|
|
|
|
if (this._previousHoveredElement) {
|
|
this._previousHoveredElement.hovered = false;
|
|
delete this._previousHoveredElement;
|
|
}
|
|
|
|
if (element instanceof Resources.FrameTreeElement) {
|
|
this._previousHoveredElement = element;
|
|
element.hovered = true;
|
|
}
|
|
}
|
|
|
|
_onmouseleave(event) {
|
|
if (this._previousHoveredElement) {
|
|
this._previousHoveredElement.hovered = false;
|
|
delete this._previousHoveredElement;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @unrestricted
|
|
*/
|
|
Resources.BaseStorageTreeElement = class extends UI.TreeElement {
|
|
/**
|
|
* @param {!Resources.ResourcesPanel} storagePanel
|
|
* @param {string} title
|
|
* @param {boolean} expandable
|
|
*/
|
|
constructor(storagePanel, title, expandable) {
|
|
super(title, expandable);
|
|
this._storagePanel = storagePanel;
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @return {boolean}
|
|
*/
|
|
onselect(selectedByUser) {
|
|
if (!selectedByUser) {
|
|
return false;
|
|
}
|
|
|
|
const path = [];
|
|
for (let el = this; el; el = el.parent) {
|
|
const url = el.itemURL;
|
|
if (!url) {
|
|
break;
|
|
}
|
|
path.push(url);
|
|
}
|
|
this._storagePanel.setLastSelectedItemPath(path);
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @protected
|
|
* @param {?UI.Widget} view
|
|
*/
|
|
showView(view) {
|
|
this._storagePanel.showView(view);
|
|
}
|
|
};
|
|
|
|
Resources.StorageCategoryTreeElement = class extends Resources.BaseStorageTreeElement {
|
|
/**
|
|
* @param {!Resources.ResourcesPanel} storagePanel
|
|
* @param {string} categoryName
|
|
* @param {string} settingsKey
|
|
*/
|
|
constructor(storagePanel, categoryName, settingsKey) {
|
|
super(storagePanel, categoryName, false);
|
|
this._expandedSetting =
|
|
Common.settings.createSetting('resources' + settingsKey + 'Expanded', settingsKey === 'Frames');
|
|
this._categoryName = categoryName;
|
|
this._categoryLink = null;
|
|
}
|
|
|
|
get itemURL() {
|
|
return 'category://' + this._categoryName;
|
|
}
|
|
|
|
/**
|
|
* @param {string} link
|
|
*/
|
|
setLink(link) {
|
|
this._categoryLink = link;
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @return {boolean}
|
|
*/
|
|
onselect(selectedByUser) {
|
|
super.onselect(selectedByUser);
|
|
this._storagePanel.showCategoryView(this._categoryName, this._categoryLink);
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
onattach() {
|
|
super.onattach();
|
|
if (this._expandedSetting.get()) {
|
|
this.expand();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
onexpand() {
|
|
this._expandedSetting.set(true);
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
oncollapse() {
|
|
this._expandedSetting.set(false);
|
|
}
|
|
};
|
|
|
|
Resources.BackgroundServiceTreeElement = class extends Resources.BaseStorageTreeElement {
|
|
/**
|
|
* @param {!Resources.ResourcesPanel} storagePanel
|
|
* @param {!Protocol.BackgroundService.ServiceName} serviceName
|
|
*/
|
|
constructor(storagePanel, serviceName) {
|
|
super(storagePanel, Resources.BackgroundServiceView.getUIString(serviceName), false);
|
|
|
|
/** @const {!Protocol.BackgroundService.ServiceName} */
|
|
this._serviceName = serviceName;
|
|
|
|
/** @type {boolean} Whether the element has been selected. */
|
|
this._selected = false;
|
|
|
|
/** @type {?Resources.BackgroundServiceView} */
|
|
this._view = null;
|
|
|
|
/** @private {?Resources.BackgroundServiceModel} */
|
|
this._model = null;
|
|
|
|
const backgroundServiceIcon = UI.Icon.create(this._getIconType(), 'resource-tree-item');
|
|
this.setLeadingIcons([backgroundServiceIcon]);
|
|
}
|
|
|
|
/**
|
|
* @return {string}
|
|
*/
|
|
_getIconType() {
|
|
switch (this._serviceName) {
|
|
case Protocol.BackgroundService.ServiceName.BackgroundFetch:
|
|
return 'mediumicon-fetch';
|
|
case Protocol.BackgroundService.ServiceName.BackgroundSync:
|
|
return 'mediumicon-sync';
|
|
case Protocol.BackgroundService.ServiceName.PushMessaging:
|
|
return 'mediumicon-cloud';
|
|
case Protocol.BackgroundService.ServiceName.Notifications:
|
|
return 'mediumicon-bell';
|
|
case Protocol.BackgroundService.ServiceName.PaymentHandler:
|
|
return 'mediumicon-payment';
|
|
case Protocol.BackgroundService.ServiceName.PeriodicBackgroundSync:
|
|
return 'mediumicon-schedule';
|
|
default:
|
|
console.error(`Service ${this._serviceName} does not have a dedicated icon`);
|
|
return 'mediumicon-table';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {?Resources.BackgroundServiceModel} model
|
|
*/
|
|
_initialize(model) {
|
|
this._model = model;
|
|
// Show the view if the model was initialized after selection.
|
|
if (this._selected && !this._view) {
|
|
this.onselect(false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return {string}
|
|
*/
|
|
get itemURL() {
|
|
return `background-service://${this._serviceName}`;
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @return {boolean}
|
|
*/
|
|
onselect(selectedByUser) {
|
|
super.onselect(selectedByUser);
|
|
this._selected = true;
|
|
|
|
if (!this._model) {
|
|
return false;
|
|
}
|
|
|
|
if (!this._view) {
|
|
this._view = new Resources.BackgroundServiceView(this._serviceName, this._model);
|
|
}
|
|
this.showView(this._view);
|
|
UI.context.setFlavor(Resources.BackgroundServiceView, this._view);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @unrestricted
|
|
*/
|
|
Resources.DatabaseTreeElement = class extends Resources.BaseStorageTreeElement {
|
|
/**
|
|
* @param {!Resources.ApplicationPanelSidebar} sidebar
|
|
* @param {!Resources.Database} database
|
|
*/
|
|
constructor(sidebar, database) {
|
|
super(sidebar._panel, database.name, true);
|
|
this._sidebar = sidebar;
|
|
this._database = database;
|
|
|
|
const icon = UI.Icon.create('mediumicon-database', 'resource-tree-item');
|
|
this.setLeadingIcons([icon]);
|
|
}
|
|
|
|
get itemURL() {
|
|
return 'database://' + encodeURI(this._database.name);
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @return {boolean}
|
|
*/
|
|
onselect(selectedByUser) {
|
|
super.onselect(selectedByUser);
|
|
this._sidebar._showDatabase(this._database);
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
onexpand() {
|
|
this.updateChildren();
|
|
}
|
|
|
|
async updateChildren() {
|
|
this.removeChildren();
|
|
const tableNames = await this._database.tableNames();
|
|
for (const tableName of tableNames) {
|
|
this.appendChild(new Resources.DatabaseTableTreeElement(this._sidebar, this._database, tableName));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @unrestricted
|
|
*/
|
|
Resources.DatabaseTableTreeElement = class extends Resources.BaseStorageTreeElement {
|
|
/**
|
|
* @param {!Resources.ApplicationPanelSidebar} sidebar
|
|
* @param {!Resources.Database} database
|
|
* @param {string} tableName
|
|
*/
|
|
constructor(sidebar, database, tableName) {
|
|
super(sidebar._panel, tableName, false);
|
|
this._sidebar = sidebar;
|
|
this._database = database;
|
|
this._tableName = tableName;
|
|
const icon = UI.Icon.create('mediumicon-table', 'resource-tree-item');
|
|
this.setLeadingIcons([icon]);
|
|
}
|
|
|
|
get itemURL() {
|
|
return 'database://' + encodeURI(this._database.name) + '/' + encodeURI(this._tableName);
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @return {boolean}
|
|
*/
|
|
onselect(selectedByUser) {
|
|
super.onselect(selectedByUser);
|
|
this._sidebar._showDatabase(this._database, this._tableName);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @unrestricted
|
|
*/
|
|
Resources.ServiceWorkerCacheTreeElement = class extends Resources.StorageCategoryTreeElement {
|
|
/**
|
|
* @param {!Resources.ResourcesPanel} storagePanel
|
|
*/
|
|
constructor(storagePanel) {
|
|
super(storagePanel, Common.UIString('Cache Storage'), 'CacheStorage');
|
|
const icon = UI.Icon.create('mediumicon-database', 'resource-tree-item');
|
|
this.setLeadingIcons([icon]);
|
|
/** @type {?SDK.ServiceWorkerCacheModel} */
|
|
this._swCacheModel = null;
|
|
}
|
|
|
|
/**
|
|
* @param {?SDK.ServiceWorkerCacheModel} model
|
|
*/
|
|
_initialize(model) {
|
|
/** @type {!Array.<!Resources.SWCacheTreeElement>} */
|
|
this._swCacheTreeElements = [];
|
|
this._swCacheModel = model;
|
|
if (model) {
|
|
for (const cache of model.caches()) {
|
|
this._addCache(model, cache);
|
|
}
|
|
}
|
|
SDK.targetManager.addModelListener(
|
|
SDK.ServiceWorkerCacheModel, SDK.ServiceWorkerCacheModel.Events.CacheAdded, this._cacheAdded, this);
|
|
SDK.targetManager.addModelListener(
|
|
SDK.ServiceWorkerCacheModel, SDK.ServiceWorkerCacheModel.Events.CacheRemoved, this._cacheRemoved, this);
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
onattach() {
|
|
super.onattach();
|
|
this.listItemElement.addEventListener('contextmenu', this._handleContextMenuEvent.bind(this), true);
|
|
}
|
|
|
|
_handleContextMenuEvent(event) {
|
|
const contextMenu = new UI.ContextMenu(event);
|
|
contextMenu.defaultSection().appendItem(Common.UIString('Refresh Caches'), this._refreshCaches.bind(this));
|
|
contextMenu.show();
|
|
}
|
|
|
|
_refreshCaches() {
|
|
if (this._swCacheModel) {
|
|
this._swCacheModel.refreshCacheNames();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_cacheAdded(event) {
|
|
const cache = /** @type {!SDK.ServiceWorkerCacheModel.Cache} */ (event.data.cache);
|
|
const model = /** @type {!SDK.ServiceWorkerCacheModel} */ (event.data.model);
|
|
this._addCache(model, cache);
|
|
}
|
|
|
|
/**
|
|
* @param {!SDK.ServiceWorkerCacheModel} model
|
|
* @param {!SDK.ServiceWorkerCacheModel.Cache} cache
|
|
*/
|
|
_addCache(model, cache) {
|
|
const swCacheTreeElement = new Resources.SWCacheTreeElement(this._storagePanel, model, cache);
|
|
this._swCacheTreeElements.push(swCacheTreeElement);
|
|
this.appendChild(swCacheTreeElement);
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_cacheRemoved(event) {
|
|
const cache = /** @type {!SDK.ServiceWorkerCacheModel.Cache} */ (event.data.cache);
|
|
const model = /** @type {!SDK.ServiceWorkerCacheModel} */ (event.data.model);
|
|
|
|
const swCacheTreeElement = this._cacheTreeElement(model, cache);
|
|
if (!swCacheTreeElement) {
|
|
return;
|
|
}
|
|
|
|
this.removeChild(swCacheTreeElement);
|
|
this._swCacheTreeElements.remove(swCacheTreeElement);
|
|
this.setExpandable(this.childCount() > 0);
|
|
}
|
|
|
|
/**
|
|
* @param {!SDK.ServiceWorkerCacheModel} model
|
|
* @param {!SDK.ServiceWorkerCacheModel.Cache} cache
|
|
* @return {?Resources.SWCacheTreeElement}
|
|
*/
|
|
_cacheTreeElement(model, cache) {
|
|
let index = -1;
|
|
let i;
|
|
for (i = 0; i < this._swCacheTreeElements.length; ++i) {
|
|
if (this._swCacheTreeElements[i]._cache.equals(cache) && this._swCacheTreeElements[i]._model === model) {
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
if (index !== -1) {
|
|
return this._swCacheTreeElements[i];
|
|
}
|
|
return null;
|
|
}
|
|
};
|
|
|
|
Resources.SWCacheTreeElement = class extends Resources.BaseStorageTreeElement {
|
|
/**
|
|
* @param {!Resources.ResourcesPanel} storagePanel
|
|
* @param {!SDK.ServiceWorkerCacheModel} model
|
|
* @param {!SDK.ServiceWorkerCacheModel.Cache} cache
|
|
*/
|
|
constructor(storagePanel, model, cache) {
|
|
super(storagePanel, cache.cacheName + ' - ' + cache.securityOrigin, false);
|
|
this._model = model;
|
|
this._cache = cache;
|
|
/** @type {?Resources.ServiceWorkerCacheView} */
|
|
this._view = null;
|
|
const icon = UI.Icon.create('mediumicon-table', 'resource-tree-item');
|
|
this.setLeadingIcons([icon]);
|
|
}
|
|
|
|
get itemURL() {
|
|
// I don't think this will work at all.
|
|
return 'cache://' + this._cache.cacheId;
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
onattach() {
|
|
super.onattach();
|
|
this.listItemElement.addEventListener('contextmenu', this._handleContextMenuEvent.bind(this), true);
|
|
}
|
|
|
|
_handleContextMenuEvent(event) {
|
|
const contextMenu = new UI.ContextMenu(event);
|
|
contextMenu.defaultSection().appendItem(Common.UIString('Delete'), this._clearCache.bind(this));
|
|
contextMenu.show();
|
|
}
|
|
|
|
_clearCache() {
|
|
this._model.deleteCache(this._cache);
|
|
}
|
|
|
|
/**
|
|
* @param {!SDK.ServiceWorkerCacheModel.Cache} cache
|
|
*/
|
|
update(cache) {
|
|
this._cache = cache;
|
|
if (this._view) {
|
|
this._view.update(cache);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @return {boolean}
|
|
*/
|
|
onselect(selectedByUser) {
|
|
super.onselect(selectedByUser);
|
|
if (!this._view) {
|
|
this._view = new Resources.ServiceWorkerCacheView(this._model, this._cache);
|
|
}
|
|
|
|
this.showView(this._view);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @unrestricted
|
|
*/
|
|
Resources.ServiceWorkersTreeElement = class extends Resources.BaseStorageTreeElement {
|
|
/**
|
|
* @param {!Resources.ResourcesPanel} storagePanel
|
|
*/
|
|
constructor(storagePanel) {
|
|
super(storagePanel, Common.UIString('Service Workers'), false);
|
|
const icon = UI.Icon.create('mediumicon-service-worker', 'resource-tree-item');
|
|
this.setLeadingIcons([icon]);
|
|
}
|
|
|
|
/**
|
|
* @return {string}
|
|
*/
|
|
get itemURL() {
|
|
return 'service-workers://';
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @return {boolean}
|
|
*/
|
|
onselect(selectedByUser) {
|
|
super.onselect(selectedByUser);
|
|
if (!this._view) {
|
|
this._view = new Resources.ServiceWorkersView();
|
|
}
|
|
this.showView(this._view);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @unrestricted
|
|
*/
|
|
Resources.AppManifestTreeElement = class extends Resources.BaseStorageTreeElement {
|
|
/**
|
|
* @param {!Resources.ResourcesPanel} storagePanel
|
|
*/
|
|
constructor(storagePanel) {
|
|
super(storagePanel, Common.UIString('Manifest'), false);
|
|
const icon = UI.Icon.create('mediumicon-manifest', 'resource-tree-item');
|
|
this.setLeadingIcons([icon]);
|
|
}
|
|
|
|
/**
|
|
* @return {string}
|
|
*/
|
|
get itemURL() {
|
|
return 'manifest://';
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @return {boolean}
|
|
*/
|
|
onselect(selectedByUser) {
|
|
super.onselect(selectedByUser);
|
|
if (!this._view) {
|
|
this._view = new Resources.AppManifestView();
|
|
}
|
|
this.showView(this._view);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @unrestricted
|
|
*/
|
|
Resources.ClearStorageTreeElement = class extends Resources.BaseStorageTreeElement {
|
|
/**
|
|
* @param {!Resources.ResourcesPanel} storagePanel
|
|
*/
|
|
constructor(storagePanel) {
|
|
super(storagePanel, Common.UIString('Clear storage'), false);
|
|
const icon = UI.Icon.create('mediumicon-clear-storage', 'resource-tree-item');
|
|
this.setLeadingIcons([icon]);
|
|
}
|
|
|
|
/**
|
|
* @return {string}
|
|
*/
|
|
get itemURL() {
|
|
return 'clear-storage://';
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @return {boolean}
|
|
*/
|
|
onselect(selectedByUser) {
|
|
super.onselect(selectedByUser);
|
|
if (!this._view) {
|
|
this._view = new Resources.ClearStorageView();
|
|
}
|
|
this.showView(this._view);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @unrestricted
|
|
*/
|
|
Resources.IndexedDBTreeElement = class extends Resources.StorageCategoryTreeElement {
|
|
/**
|
|
* @param {!Resources.ResourcesPanel} storagePanel
|
|
*/
|
|
constructor(storagePanel) {
|
|
super(storagePanel, Common.UIString('IndexedDB'), 'IndexedDB');
|
|
const icon = UI.Icon.create('mediumicon-database', 'resource-tree-item');
|
|
this.setLeadingIcons([icon]);
|
|
}
|
|
|
|
_initialize() {
|
|
SDK.targetManager.addModelListener(
|
|
Resources.IndexedDBModel, Resources.IndexedDBModel.Events.DatabaseAdded, this._indexedDBAdded, this);
|
|
SDK.targetManager.addModelListener(
|
|
Resources.IndexedDBModel, Resources.IndexedDBModel.Events.DatabaseRemoved, this._indexedDBRemoved, this);
|
|
SDK.targetManager.addModelListener(
|
|
Resources.IndexedDBModel, Resources.IndexedDBModel.Events.DatabaseLoaded, this._indexedDBLoaded, this);
|
|
SDK.targetManager.addModelListener(
|
|
Resources.IndexedDBModel, Resources.IndexedDBModel.Events.IndexedDBContentUpdated,
|
|
this._indexedDBContentUpdated, this);
|
|
/** @type {!Array.<!Resources.IDBDatabaseTreeElement>} */
|
|
this._idbDatabaseTreeElements = [];
|
|
|
|
for (const indexedDBModel of SDK.targetManager.models(Resources.IndexedDBModel)) {
|
|
const databases = indexedDBModel.databases();
|
|
for (let j = 0; j < databases.length; ++j) {
|
|
this._addIndexedDB(indexedDBModel, databases[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {!Resources.IndexedDBModel} model
|
|
*/
|
|
removeIndexedDBForModel(model) {
|
|
const idbDatabaseTreeElements = this._idbDatabaseTreeElements.filter(element => element._model === model);
|
|
for (const idbDatabaseTreeElement of idbDatabaseTreeElements) {
|
|
this._removeIDBDatabaseTreeElement(idbDatabaseTreeElement);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
onattach() {
|
|
super.onattach();
|
|
this.listItemElement.addEventListener('contextmenu', this._handleContextMenuEvent.bind(this), true);
|
|
}
|
|
|
|
_handleContextMenuEvent(event) {
|
|
const contextMenu = new UI.ContextMenu(event);
|
|
contextMenu.defaultSection().appendItem(Common.UIString('Refresh IndexedDB'), this.refreshIndexedDB.bind(this));
|
|
contextMenu.show();
|
|
}
|
|
|
|
refreshIndexedDB() {
|
|
for (const indexedDBModel of SDK.targetManager.models(Resources.IndexedDBModel)) {
|
|
indexedDBModel.refreshDatabaseNames();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_indexedDBAdded(event) {
|
|
const databaseId = /** @type {!Resources.IndexedDBModel.DatabaseId} */ (event.data.databaseId);
|
|
const model = /** @type {!Resources.IndexedDBModel} */ (event.data.model);
|
|
this._addIndexedDB(model, databaseId);
|
|
}
|
|
|
|
/**
|
|
* @param {!Resources.IndexedDBModel} model
|
|
* @param {!Resources.IndexedDBModel.DatabaseId} databaseId
|
|
*/
|
|
_addIndexedDB(model, databaseId) {
|
|
const idbDatabaseTreeElement = new Resources.IDBDatabaseTreeElement(this._storagePanel, model, databaseId);
|
|
this._idbDatabaseTreeElements.push(idbDatabaseTreeElement);
|
|
this.appendChild(idbDatabaseTreeElement);
|
|
model.refreshDatabase(databaseId);
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_indexedDBRemoved(event) {
|
|
const databaseId = /** @type {!Resources.IndexedDBModel.DatabaseId} */ (event.data.databaseId);
|
|
const model = /** @type {!Resources.IndexedDBModel} */ (event.data.model);
|
|
|
|
const idbDatabaseTreeElement = this._idbDatabaseTreeElement(model, databaseId);
|
|
if (!idbDatabaseTreeElement) {
|
|
return;
|
|
}
|
|
this._removeIDBDatabaseTreeElement(idbDatabaseTreeElement);
|
|
}
|
|
|
|
/**
|
|
* @param {!Resources.IDBDatabaseTreeElement} idbDatabaseTreeElement
|
|
*/
|
|
_removeIDBDatabaseTreeElement(idbDatabaseTreeElement) {
|
|
idbDatabaseTreeElement.clear();
|
|
this.removeChild(idbDatabaseTreeElement);
|
|
this._idbDatabaseTreeElements.remove(idbDatabaseTreeElement);
|
|
this.setExpandable(this.childCount() > 0);
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_indexedDBLoaded(event) {
|
|
const database = /** @type {!Resources.IndexedDBModel.Database} */ (event.data.database);
|
|
const model = /** @type {!Resources.IndexedDBModel} */ (event.data.model);
|
|
const entriesUpdated = /** @type {boolean} */ (event.data.entriesUpdated);
|
|
|
|
const idbDatabaseTreeElement = this._idbDatabaseTreeElement(model, database.databaseId);
|
|
if (!idbDatabaseTreeElement) {
|
|
return;
|
|
}
|
|
idbDatabaseTreeElement.update(database, entriesUpdated);
|
|
this._indexedDBLoadedForTest();
|
|
}
|
|
|
|
_indexedDBLoadedForTest() {
|
|
// For sniffing in tests.
|
|
}
|
|
|
|
/**
|
|
* @param {!Common.Event} event
|
|
*/
|
|
_indexedDBContentUpdated(event) {
|
|
const databaseId = /** @type {!Resources.IndexedDBModel.DatabaseId} */ (event.data.databaseId);
|
|
const objectStoreName = /** @type {string} */ (event.data.objectStoreName);
|
|
const model = /** @type {!Resources.IndexedDBModel} */ (event.data.model);
|
|
|
|
const idbDatabaseTreeElement = this._idbDatabaseTreeElement(model, databaseId);
|
|
if (!idbDatabaseTreeElement) {
|
|
return;
|
|
}
|
|
idbDatabaseTreeElement.indexedDBContentUpdated(objectStoreName);
|
|
}
|
|
|
|
/**
|
|
* @param {!Resources.IndexedDBModel} model
|
|
* @param {!Resources.IndexedDBModel.DatabaseId} databaseId
|
|
* @return {?Resources.IDBDatabaseTreeElement}
|
|
*/
|
|
_idbDatabaseTreeElement(model, databaseId) {
|
|
return this._idbDatabaseTreeElements.find(x => x._databaseId.equals(databaseId) && x._model === model) || null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @unrestricted
|
|
*/
|
|
Resources.IDBDatabaseTreeElement = class extends Resources.BaseStorageTreeElement {
|
|
/**
|
|
* @param {!Resources.ResourcesPanel} storagePanel
|
|
* @param {!Resources.IndexedDBModel} model
|
|
* @param {!Resources.IndexedDBModel.DatabaseId} databaseId
|
|
*/
|
|
constructor(storagePanel, model, databaseId) {
|
|
super(storagePanel, databaseId.name + ' - ' + databaseId.securityOrigin, false);
|
|
this._model = model;
|
|
this._databaseId = databaseId;
|
|
this._idbObjectStoreTreeElements = {};
|
|
const icon = UI.Icon.create('mediumicon-database', 'resource-tree-item');
|
|
this.setLeadingIcons([icon]);
|
|
this._model.addEventListener(Resources.IndexedDBModel.Events.DatabaseNamesRefreshed, this._refreshIndexedDB, this);
|
|
}
|
|
|
|
get itemURL() {
|
|
return 'indexedDB://' + this._databaseId.securityOrigin + '/' + this._databaseId.name;
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
onattach() {
|
|
super.onattach();
|
|
this.listItemElement.addEventListener('contextmenu', this._handleContextMenuEvent.bind(this), true);
|
|
}
|
|
|
|
_handleContextMenuEvent(event) {
|
|
const contextMenu = new UI.ContextMenu(event);
|
|
contextMenu.defaultSection().appendItem(Common.UIString('Refresh IndexedDB'), this._refreshIndexedDB.bind(this));
|
|
contextMenu.show();
|
|
}
|
|
|
|
_refreshIndexedDB() {
|
|
this._model.refreshDatabase(this._databaseId);
|
|
}
|
|
|
|
/**
|
|
* @param {string} objectStoreName
|
|
*/
|
|
indexedDBContentUpdated(objectStoreName) {
|
|
if (this._idbObjectStoreTreeElements[objectStoreName]) {
|
|
this._idbObjectStoreTreeElements[objectStoreName].markNeedsRefresh();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {!Resources.IndexedDBModel.Database} database
|
|
* @param {boolean} entriesUpdated
|
|
*/
|
|
update(database, entriesUpdated) {
|
|
this._database = database;
|
|
const objectStoreNames = {};
|
|
const objectStoreNamesSorted = Object.keys(this._database.objectStores).sort();
|
|
for (const objectStoreName of objectStoreNamesSorted) {
|
|
const objectStore = this._database.objectStores[objectStoreName];
|
|
objectStoreNames[objectStore.name] = true;
|
|
if (!this._idbObjectStoreTreeElements[objectStore.name]) {
|
|
const idbObjectStoreTreeElement =
|
|
new Resources.IDBObjectStoreTreeElement(this._storagePanel, this._model, this._databaseId, objectStore);
|
|
this._idbObjectStoreTreeElements[objectStore.name] = idbObjectStoreTreeElement;
|
|
this.appendChild(idbObjectStoreTreeElement);
|
|
}
|
|
this._idbObjectStoreTreeElements[objectStore.name].update(objectStore, entriesUpdated);
|
|
}
|
|
for (const objectStoreName in this._idbObjectStoreTreeElements) {
|
|
if (!objectStoreNames[objectStoreName]) {
|
|
this._objectStoreRemoved(objectStoreName);
|
|
}
|
|
}
|
|
|
|
if (this._view) {
|
|
this._view.update(database);
|
|
}
|
|
|
|
this._updateTooltip();
|
|
}
|
|
|
|
_updateTooltip() {
|
|
if (Object.keys(this._idbObjectStoreTreeElements).length === 0) {
|
|
this.tooltip = ls`Version: ${this._database.version} (empty)`;
|
|
} else {
|
|
this.tooltip = ls`Version: ${this._database.version}`;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @return {boolean}
|
|
*/
|
|
onselect(selectedByUser) {
|
|
super.onselect(selectedByUser);
|
|
if (!this._view) {
|
|
this._view = new Resources.IDBDatabaseView(this._model, this._database);
|
|
}
|
|
|
|
this.showView(this._view);
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @param {string} objectStoreName
|
|
*/
|
|
_objectStoreRemoved(objectStoreName) {
|
|
const objectStoreTreeElement = this._idbObjectStoreTreeElements[objectStoreName];
|
|
objectStoreTreeElement.clear();
|
|
this.removeChild(objectStoreTreeElement);
|
|
delete this._idbObjectStoreTreeElements[objectStoreName];
|
|
this._updateTooltip();
|
|
}
|
|
|
|
clear() {
|
|
for (const objectStoreName in this._idbObjectStoreTreeElements) {
|
|
this._objectStoreRemoved(objectStoreName);
|
|
}
|
|
}
|
|
};
|
|
|
|
Resources.IDBObjectStoreTreeElement = class extends Resources.BaseStorageTreeElement {
|
|
/**
|
|
* @param {!Resources.ResourcesPanel} storagePanel
|
|
* @param {!Resources.IndexedDBModel} model
|
|
* @param {!Resources.IndexedDBModel.DatabaseId} databaseId
|
|
* @param {!Resources.IndexedDBModel.ObjectStore} objectStore
|
|
*/
|
|
constructor(storagePanel, model, databaseId, objectStore) {
|
|
super(storagePanel, objectStore.name, false);
|
|
this._model = model;
|
|
this._databaseId = databaseId;
|
|
this._idbIndexTreeElements = {};
|
|
this._objectStore = objectStore;
|
|
/** @type {?Resources.IDBDataView} */
|
|
this._view = null;
|
|
const icon = UI.Icon.create('mediumicon-table', 'resource-tree-item');
|
|
this.setLeadingIcons([icon]);
|
|
}
|
|
|
|
get itemURL() {
|
|
return 'indexedDB://' + this._databaseId.securityOrigin + '/' + this._databaseId.name + '/' +
|
|
this._objectStore.name;
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
onattach() {
|
|
super.onattach();
|
|
this.listItemElement.addEventListener('contextmenu', this._handleContextMenuEvent.bind(this), true);
|
|
}
|
|
|
|
markNeedsRefresh() {
|
|
if (this._view) {
|
|
this._view.markNeedsRefresh();
|
|
}
|
|
for (const indexName in this._idbIndexTreeElements) {
|
|
this._idbIndexTreeElements[indexName].markNeedsRefresh();
|
|
}
|
|
}
|
|
|
|
_handleContextMenuEvent(event) {
|
|
const contextMenu = new UI.ContextMenu(event);
|
|
contextMenu.defaultSection().appendItem(Common.UIString('Clear'), this._clearObjectStore.bind(this));
|
|
contextMenu.show();
|
|
}
|
|
|
|
_refreshObjectStore() {
|
|
if (this._view) {
|
|
this._view.refreshData();
|
|
}
|
|
for (const indexName in this._idbIndexTreeElements) {
|
|
this._idbIndexTreeElements[indexName].refreshIndex();
|
|
}
|
|
}
|
|
|
|
async _clearObjectStore() {
|
|
await this._model.clearObjectStore(this._databaseId, this._objectStore.name);
|
|
this.update(this._objectStore, true);
|
|
}
|
|
|
|
/**
|
|
* @param {!Resources.IndexedDBModel.ObjectStore} objectStore
|
|
* @param {boolean} entriesUpdated
|
|
*/
|
|
update(objectStore, entriesUpdated) {
|
|
this._objectStore = objectStore;
|
|
|
|
const indexNames = {};
|
|
for (const indexName in this._objectStore.indexes) {
|
|
const index = this._objectStore.indexes[indexName];
|
|
indexNames[index.name] = true;
|
|
if (!this._idbIndexTreeElements[index.name]) {
|
|
const idbIndexTreeElement = new Resources.IDBIndexTreeElement(
|
|
this._storagePanel, this._model, this._databaseId, this._objectStore, index,
|
|
this._refreshObjectStore.bind(this));
|
|
this._idbIndexTreeElements[index.name] = idbIndexTreeElement;
|
|
this.appendChild(idbIndexTreeElement);
|
|
}
|
|
this._idbIndexTreeElements[index.name].update(this._objectStore, index, entriesUpdated);
|
|
}
|
|
for (const indexName in this._idbIndexTreeElements) {
|
|
if (!indexNames[indexName]) {
|
|
this._indexRemoved(indexName);
|
|
}
|
|
}
|
|
for (const indexName in this._idbIndexTreeElements) {
|
|
if (!indexNames[indexName]) {
|
|
this.removeChild(this._idbIndexTreeElements[indexName]);
|
|
delete this._idbIndexTreeElements[indexName];
|
|
}
|
|
}
|
|
|
|
if (this.childCount()) {
|
|
this.expand();
|
|
}
|
|
|
|
if (this._view && entriesUpdated) {
|
|
this._view.update(this._objectStore, null);
|
|
}
|
|
|
|
this._updateTooltip();
|
|
}
|
|
|
|
_updateTooltip() {
|
|
const keyPathString = this._objectStore.keyPathString;
|
|
let tooltipString = keyPathString !== null ? ls`Key path: ${keyPathString}` : '';
|
|
if (this._objectStore.autoIncrement) {
|
|
tooltipString += '\n' + Common.UIString('autoIncrement');
|
|
}
|
|
this.tooltip = tooltipString;
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @return {boolean}
|
|
*/
|
|
onselect(selectedByUser) {
|
|
super.onselect(selectedByUser);
|
|
if (!this._view) {
|
|
this._view = new Resources.IDBDataView(
|
|
this._model, this._databaseId, this._objectStore, null, this._refreshObjectStore.bind(this));
|
|
}
|
|
|
|
this.showView(this._view);
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @param {string} indexName
|
|
*/
|
|
_indexRemoved(indexName) {
|
|
const indexTreeElement = this._idbIndexTreeElements[indexName];
|
|
indexTreeElement.clear();
|
|
this.removeChild(indexTreeElement);
|
|
delete this._idbIndexTreeElements[indexName];
|
|
}
|
|
|
|
clear() {
|
|
for (const indexName in this._idbIndexTreeElements) {
|
|
this._indexRemoved(indexName);
|
|
}
|
|
if (this._view) {
|
|
this._view.clear();
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @unrestricted
|
|
*/
|
|
Resources.IDBIndexTreeElement = class extends Resources.BaseStorageTreeElement {
|
|
/**
|
|
* @param {!Resources.ResourcesPanel} storagePanel
|
|
* @param {!Resources.IndexedDBModel} model
|
|
* @param {!Resources.IndexedDBModel.DatabaseId} databaseId
|
|
* @param {!Resources.IndexedDBModel.ObjectStore} objectStore
|
|
* @param {!Resources.IndexedDBModel.Index} index
|
|
* @param {function()} refreshObjectStore
|
|
*/
|
|
constructor(storagePanel, model, databaseId, objectStore, index, refreshObjectStore) {
|
|
super(storagePanel, index.name, false);
|
|
this._model = model;
|
|
this._databaseId = databaseId;
|
|
this._objectStore = objectStore;
|
|
this._index = index;
|
|
this._refreshObjectStore = refreshObjectStore;
|
|
}
|
|
|
|
get itemURL() {
|
|
return 'indexedDB://' + this._databaseId.securityOrigin + '/' + this._databaseId.name + '/' +
|
|
this._objectStore.name + '/' + this._index.name;
|
|
}
|
|
|
|
markNeedsRefresh() {
|
|
if (this._view) {
|
|
this._view.markNeedsRefresh();
|
|
}
|
|
}
|
|
|
|
refreshIndex() {
|
|
if (this._view) {
|
|
this._view.refreshData();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {!Resources.IndexedDBModel.ObjectStore} objectStore
|
|
* @param {!Resources.IndexedDBModel.Index} index
|
|
* @param {boolean} entriesUpdated
|
|
*/
|
|
update(objectStore, index, entriesUpdated) {
|
|
this._objectStore = objectStore;
|
|
this._index = index;
|
|
|
|
if (this._view && entriesUpdated) {
|
|
this._view.update(this._objectStore, this._index);
|
|
}
|
|
|
|
this._updateTooltip();
|
|
}
|
|
|
|
_updateTooltip() {
|
|
const tooltipLines = [];
|
|
const keyPathString = this._index.keyPathString;
|
|
tooltipLines.push(ls`Key path: ${keyPathString}`);
|
|
if (this._index.unique) {
|
|
tooltipLines.push(Common.UIString('unique'));
|
|
}
|
|
if (this._index.multiEntry) {
|
|
tooltipLines.push(Common.UIString('multiEntry'));
|
|
}
|
|
this.tooltip = tooltipLines.join('\n');
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @return {boolean}
|
|
*/
|
|
onselect(selectedByUser) {
|
|
super.onselect(selectedByUser);
|
|
if (!this._view) {
|
|
this._view = new Resources.IDBDataView(
|
|
this._model, this._databaseId, this._objectStore, this._index, this._refreshObjectStore);
|
|
}
|
|
|
|
this.showView(this._view);
|
|
return false;
|
|
}
|
|
|
|
clear() {
|
|
if (this._view) {
|
|
this._view.clear();
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @unrestricted
|
|
*/
|
|
Resources.DOMStorageTreeElement = class extends Resources.BaseStorageTreeElement {
|
|
/**
|
|
* @param {!Resources.ResourcesPanel} storagePanel
|
|
* @param {!Resources.DOMStorage} domStorage
|
|
*/
|
|
constructor(storagePanel, domStorage) {
|
|
super(storagePanel, domStorage.securityOrigin ? domStorage.securityOrigin : Common.UIString('Local Files'), false);
|
|
this._domStorage = domStorage;
|
|
const icon = UI.Icon.create('mediumicon-table', 'resource-tree-item');
|
|
this.setLeadingIcons([icon]);
|
|
}
|
|
|
|
get itemURL() {
|
|
return 'storage://' + this._domStorage.securityOrigin + '/' +
|
|
(this._domStorage.isLocalStorage ? 'local' : 'session');
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @return {boolean}
|
|
*/
|
|
onselect(selectedByUser) {
|
|
super.onselect(selectedByUser);
|
|
this._storagePanel.showDOMStorage(this._domStorage);
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
onattach() {
|
|
super.onattach();
|
|
this.listItemElement.addEventListener('contextmenu', this._handleContextMenuEvent.bind(this), true);
|
|
}
|
|
|
|
_handleContextMenuEvent(event) {
|
|
const contextMenu = new UI.ContextMenu(event);
|
|
contextMenu.defaultSection().appendItem(Common.UIString('Clear'), () => this._domStorage.clear());
|
|
contextMenu.show();
|
|
}
|
|
};
|
|
|
|
Resources.CookieTreeElement = class extends Resources.BaseStorageTreeElement {
|
|
/**
|
|
* @param {!Resources.ResourcesPanel} storagePanel
|
|
* @param {!SDK.ResourceTreeFrame} frame
|
|
* @param {string} cookieDomain
|
|
*/
|
|
constructor(storagePanel, frame, cookieDomain) {
|
|
super(storagePanel, cookieDomain ? cookieDomain : Common.UIString('Local Files'), false);
|
|
this._target = frame.resourceTreeModel().target();
|
|
this._cookieDomain = cookieDomain;
|
|
this.tooltip = ls`cookies used by frames from ${cookieDomain}`;
|
|
const icon = UI.Icon.create('mediumicon-cookie', 'resource-tree-item');
|
|
this.setLeadingIcons([icon]);
|
|
}
|
|
|
|
get itemURL() {
|
|
return 'cookies://' + this._cookieDomain;
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
onattach() {
|
|
super.onattach();
|
|
this.listItemElement.addEventListener('contextmenu', this._handleContextMenuEvent.bind(this), true);
|
|
}
|
|
|
|
/**
|
|
* @param {!Event} event
|
|
*/
|
|
_handleContextMenuEvent(event) {
|
|
const contextMenu = new UI.ContextMenu(event);
|
|
contextMenu.defaultSection().appendItem(
|
|
Common.UIString('Clear'), () => this._storagePanel.clearCookies(this._target, this._cookieDomain));
|
|
contextMenu.show();
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @return {boolean}
|
|
*/
|
|
onselect(selectedByUser) {
|
|
super.onselect(selectedByUser);
|
|
this._storagePanel.showCookies(this._target, this._cookieDomain);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @unrestricted
|
|
*/
|
|
Resources.ApplicationCacheManifestTreeElement = class extends Resources.BaseStorageTreeElement {
|
|
constructor(storagePanel, manifestURL) {
|
|
const title = new Common.ParsedURL(manifestURL).displayName;
|
|
super(storagePanel, title, false);
|
|
this.tooltip = manifestURL;
|
|
this._manifestURL = manifestURL;
|
|
}
|
|
|
|
get itemURL() {
|
|
return 'appcache://' + this._manifestURL;
|
|
}
|
|
|
|
get manifestURL() {
|
|
return this._manifestURL;
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @return {boolean}
|
|
*/
|
|
onselect(selectedByUser) {
|
|
super.onselect(selectedByUser);
|
|
this._storagePanel.showCategoryView(this._manifestURL, null);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @unrestricted
|
|
*/
|
|
Resources.ApplicationCacheFrameTreeElement = class extends Resources.BaseStorageTreeElement {
|
|
/**
|
|
* @param {!Resources.ApplicationPanelSidebar} sidebar
|
|
* @param {!SDK.ResourceTreeFrame} frame
|
|
* @param {string} manifestURL
|
|
*/
|
|
constructor(sidebar, frame, manifestURL) {
|
|
super(sidebar._panel, '', false);
|
|
this._sidebar = sidebar;
|
|
this._frameId = frame.id;
|
|
this._manifestURL = manifestURL;
|
|
this._refreshTitles(frame);
|
|
|
|
const icon = UI.Icon.create('largeicon-navigator-folder', 'navigator-tree-item');
|
|
icon.classList.add('navigator-folder-tree-item');
|
|
this.setLeadingIcons([icon]);
|
|
}
|
|
|
|
get itemURL() {
|
|
return 'appcache://' + this._manifestURL + '/' + encodeURI(this.titleAsText());
|
|
}
|
|
|
|
get frameId() {
|
|
return this._frameId;
|
|
}
|
|
|
|
get manifestURL() {
|
|
return this._manifestURL;
|
|
}
|
|
|
|
/**
|
|
* @param {!SDK.ResourceTreeFrame} frame
|
|
*/
|
|
_refreshTitles(frame) {
|
|
this.title = frame.displayName();
|
|
}
|
|
|
|
/**
|
|
* @param {!SDK.ResourceTreeFrame} frame
|
|
*/
|
|
frameNavigated(frame) {
|
|
this._refreshTitles(frame);
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @return {boolean}
|
|
*/
|
|
onselect(selectedByUser) {
|
|
super.onselect(selectedByUser);
|
|
this._sidebar._showApplicationCache(this._frameId);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @unrestricted
|
|
*/
|
|
Resources.StorageCategoryView = class extends UI.VBox {
|
|
constructor() {
|
|
super();
|
|
|
|
this.element.classList.add('storage-view');
|
|
this._emptyWidget = new UI.EmptyWidget('');
|
|
this._linkElement = null;
|
|
this._emptyWidget.show(this.element);
|
|
}
|
|
|
|
/**
|
|
* @param {string} text
|
|
*/
|
|
setText(text) {
|
|
this._emptyWidget.text = text;
|
|
}
|
|
|
|
/**
|
|
* @param {?string} link
|
|
*/
|
|
setLink(link) {
|
|
if (link && !this._linkElement) {
|
|
this._linkElement = this._emptyWidget.appendLink(link);
|
|
}
|
|
if (!link && this._linkElement) {
|
|
this._linkElement.classList.add('hidden');
|
|
}
|
|
if (link && this._linkElement) {
|
|
this._linkElement.setAttribute('href', link);
|
|
this._linkElement.classList.remove('hidden');
|
|
}
|
|
}
|
|
};
|