Commit 935ce418 authored by Eugene Ostroukhov's avatar Eugene Ostroukhov Committed by Commit Bot

[DevTools] Hooking up IndexedDB live updating

Frontend for IndexedDB live updating.
Based on https://chromium-review.googlesource.com/676273 by Kristi Park.

Bug: 729793
Change-Id: I8be1c8fafa0377c22eee261b0f00ab62f4bb6cc8
Reviewed-on: https://chromium-review.googlesource.com/798211
Commit-Queue: Eugene Ostroukhov <eostroukhov@chromium.org>
Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#521737}
parent 30379143
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback1 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback1
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback2 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback2
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback3 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback3
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback4 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback4
Tests that database names are correctly loaded and saved in IndexedDBModel. Tests that database names are correctly loaded and saved in IndexedDBModel.
Dumping database names: Dumping database names:
......
...@@ -18,28 +18,61 @@ Dumping IndexedDB tree: ...@@ -18,28 +18,61 @@ Dumping IndexedDB tree:
Index: testIndex Index: testIndex
Object store: testObjectStore2 Object store: testObjectStore2
Index: testIndex Index: testIndex
Dumping ObjectStore data:
Object store: testObjectStore1
Number of entries: 0
Index: testIndex
Number of entries: 0
Object store: testObjectStore2
Number of entries: 0
Index: testIndex
Number of entries: 0
Added testObjectStore1 entry. Added testObjectStore1 entry.
Dumping ObjectStore data: Dumping ObjectStore data:
Object store: testObjectStore1 Object store: testObjectStore1
(no entries) Number of entries: 0
Index: testIndex
Number of entries: 0
Object store: testObjectStore2 Object store: testObjectStore2
(no entries) Number of entries: 0
Index: testIndex
Number of entries: 0
Refreshed database view. Refreshed database view.
Dumping ObjectStore data: Dumping ObjectStore data:
Object store: testObjectStore1 Object store: testObjectStore1
Number of entries: 1
Key = testKey, value = [object Object] Key = testKey, value = [object Object]
Index: testIndex
Number of entries: 1
Key = testKey, value = [object Object]
Object store: testObjectStore2 Object store: testObjectStore2
(no entries) Number of entries: 0
Index: testIndex
Number of entries: 0
Added testObjectStore2 entry. Added testObjectStore2 entry.
Dumping ObjectStore data: Dumping ObjectStore data:
Object store: testObjectStore1 Object store: testObjectStore1
Number of entries: 1
Key = testKey, value = [object Object] Key = testKey, value = [object Object]
Index: testIndex
Number of entries: 1
Key = testKey, value = [object Object]
Object store: testObjectStore2 Object store: testObjectStore2
(no entries) Number of entries: 0
Index: testIndex
Number of entries: 0
Right-click refreshed database. Right-click refreshed database.
Dumping ObjectStore data: Dumping ObjectStore data:
Object store: testObjectStore1 Object store: testObjectStore1
Number of entries: 1
Key = testKey, value = [object Object] Key = testKey, value = [object Object]
Index: testIndex
Number of entries: 1
Key = testKey, value = [object Object]
Object store: testObjectStore2 Object store: testObjectStore2
Number of entries: 1
Key = testKey2, value = [object Object] Key = testKey2, value = [object Object]
Index: testIndex
Number of entries: 1
Key = testKey2, value = [object Object]
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
var keyPath = 'testKey'; var keyPath = 'testKey';
var indexedDBModel = TestRunner.mainTarget.model(Resources.IndexedDBModel); var indexedDBModel = TestRunner.mainTarget.model(Resources.IndexedDBModel);
indexedDBModel._throttler._timeout = 100000; // Disable live updating.
var databaseId; var databaseId;
function waitRefreshDatabase() { function waitRefreshDatabase() {
...@@ -51,24 +52,6 @@ ...@@ -51,24 +52,6 @@
UI.panels.resources._sidebar.indexedDBListTreeElement.refreshIndexedDB(); UI.panels.resources._sidebar.indexedDBListTreeElement.refreshIndexedDB();
} }
function dumpObjectStores() {
TestRunner.addResult('Dumping ObjectStore data:');
var idbDatabaseTreeElement = UI.panels.resources._sidebar.indexedDBListTreeElement._idbDatabaseTreeElements[0];
for (var i = 0; i < idbDatabaseTreeElement.childCount(); ++i) {
var objectStoreTreeElement = idbDatabaseTreeElement.childAt(i);
TestRunner.addResult(' Object store: ' + objectStoreTreeElement.title);
var entries = objectStoreTreeElement._view._entries;
if (!entries.length) {
TestRunner.addResult(' (no entries)');
continue;
}
for (var j = 0; j < entries.length; ++j) {
TestRunner.addResult(' Key = ' + entries[j].key._value + ', value = ' + entries[j].value);
}
}
}
// Initial tree // Initial tree
ApplicationTestRunner.dumpIndexedDBTree(); ApplicationTestRunner.dumpIndexedDBTree();
...@@ -97,34 +80,34 @@ ...@@ -97,34 +80,34 @@
await waitRefreshDatabase(); await waitRefreshDatabase();
TestRunner.addResult('Created second objectstore.'); TestRunner.addResult('Created second objectstore.');
ApplicationTestRunner.dumpIndexedDBTree(); ApplicationTestRunner.dumpIndexedDBTree();
InspectorTest.dumpObjectStores();
// Load objectstore data views
for (var i = 0; i < idbDatabaseTreeElement.childCount(); ++i) {
var objectStoreTreeElement = idbDatabaseTreeElement.childAt(i);
objectStoreTreeElement.onselect(false);
}
// Add entries // Add entries
await ApplicationTestRunner.addIDBValueAsync(databaseName, objectStoreName1, 'testKey', 'testValue'); await ApplicationTestRunner.addIDBValueAsync(databaseName, objectStoreName1, 'testKey', 'testValue');
TestRunner.addResult('Added ' + objectStoreName1 + ' entry.'); TestRunner.addResult('Added ' + objectStoreName1 + ' entry.');
dumpObjectStores(); InspectorTest.dumpObjectStores();
// Refresh database view // Refresh database view
await waitRefreshDatabase(); await waitRefreshDatabase();
await waitUpdateDataView(); // Wait for second objectstore data to load on page. await waitUpdateDataView(); // Wait for indexes and second object store to refresh.
await waitUpdateDataView();
await waitUpdateDataView();
TestRunner.addResult('Refreshed database view.'); TestRunner.addResult('Refreshed database view.');
dumpObjectStores(); InspectorTest.dumpObjectStores();
// Add entries // Add entries
await ApplicationTestRunner.addIDBValueAsync(databaseName, objectStoreName2, 'testKey2', 'testValue2'); await ApplicationTestRunner.addIDBValueAsync(databaseName, objectStoreName2, 'testKey2', 'testValue2');
TestRunner.addResult('Added ' + objectStoreName2 + ' entry.'); TestRunner.addResult('Added ' + objectStoreName2 + ' entry.');
dumpObjectStores(); InspectorTest.dumpObjectStores();
// Right-click refresh database view // Right-click refresh database view
await waitRefreshDatabaseRightClick(); await waitRefreshDatabaseRightClick();
await waitUpdateDataView(); // Wait for second objectstore data to load on page. await waitUpdateDataView(); // Wait for indexes and second object store to refresh.
await waitUpdateDataView();
await waitUpdateDataView();
TestRunner.addResult('Right-click refreshed database.'); TestRunner.addResult('Right-click refreshed database.');
dumpObjectStores(); InspectorTest.dumpObjectStores();
await ApplicationTestRunner.deleteDatabaseAsync(databaseName);
TestRunner.completeTest(); TestRunner.completeTest();
})(); })();
Tests that the IndexedDB database content live updates.
Dumping IndexedDB tree:
database: database1 - http://127.0.0.1:8000
Object store: objectStore1
Index: index1
Object store marked needs refresh = false
Index marked needs refresh = false
Add entry to objectStore1:
Object store marked needs refresh = true
Index marked needs refresh = true
Dumping ObjectStore data:
Object store: objectStore1
Number of entries: 0
Index: index1
Number of entries: 0
Refresh views:
Object store marked needs refresh = false
Index marked needs refresh = false
Dumping ObjectStore data:
Object store: objectStore1
Number of entries: 1
Key = testKey, value = [object Object]
Index: index1
Number of entries: 1
Key = testKey, value = [object Object]
Delete entry from objectStore1:
Object store marked needs refresh = true
Index marked needs refresh = true
Dumping ObjectStore data:
Object store: objectStore1
Number of entries: 1
Key = testKey, value = [object Object]
Index: index1
Number of entries: 1
Key = testKey, value = [object Object]
Refresh views:
Object store marked needs refresh = false
Index marked needs refresh = false
Dumping ObjectStore data:
Object store: objectStore1
Number of entries: 0
Index: index1
Number of entries: 0
<html>
<head>
<script src="../../inspector/inspector-test.js"></script>
<script src="../../inspector/indexeddb/indexeddb-test.js"></script>
<script>
async function test() {
let indexedDBModel = TestRunner.mainTarget.model(Resources.IndexedDBModel);
indexedDBModel._throttler._timeout = 0;
var objectStore;
var objectStoreView;
var indexView;
function isMarkedNeedsRefresh() {
if (!objectStore) {
objectStore = UI.panels.resources._sidebar.indexedDBListTreeElement._idbDatabaseTreeElements[0].childAt(0);
objectStore.onselect(false);
objectStore.childAt(0).onselect(false);
objectStoreView = objectStore._view;
indexView = objectStore.childAt(0)._view;
}
TestRunner.addResult('Object store marked needs refresh = ' + objectStoreView._needsRefresh.visible());
TestRunner.addResult('Index marked needs refresh = ' + indexView._needsRefresh.visible());
}
let promise = InspectorTest.addSnifferPromise(Resources.IndexedDBTreeElement.prototype, '_addIndexedDB');
await ApplicationTestRunner.createDatabaseAsync('database1');
await promise;
promise = InspectorTest.addSnifferPromise(Resources.IDBObjectStoreTreeElement.prototype, 'update');
await ApplicationTestRunner.createObjectStoreAsync('database1', 'objectStore1', 'index1');
await promise;
ApplicationTestRunner.dumpIndexedDBTree();
isMarkedNeedsRefresh();
TestRunner.addResult('\nAdd entry to objectStore1:');
promise = InspectorTest.addSnifferPromise(Resources.IDBDataView.prototype, 'markNeedsRefresh');
await ApplicationTestRunner.addIDBValueAsync('database1', 'objectStore1', 'testKey', 'testValue');
await promise;
isMarkedNeedsRefresh();
ApplicationTestRunner.dumpObjectStores();
TestRunner.addResult('\nRefresh views:');
promise = InspectorTest.addSnifferPromise(Resources.IDBDataView.prototype, '_updatedDataForTests');
objectStoreView._updateData(true);
await promise;
promise = InspectorTest.addSnifferPromise(Resources.IDBDataView.prototype, '_updatedDataForTests');
indexView._updateData(true);
await promise;
isMarkedNeedsRefresh();
ApplicationTestRunner.dumpObjectStores();
TestRunner.addResult('\nDelete entry from objectStore1:');
promise = InspectorTest.addSnifferPromise(Resources.IDBDataView.prototype, 'markNeedsRefresh');
await ApplicationTestRunner.deleteIDBValueAsync('database1', 'objectStore1', 'testKey');
await promise;
isMarkedNeedsRefresh();
ApplicationTestRunner.dumpObjectStores();
TestRunner.addResult('\nRefresh views:');
promise = InspectorTest.addSnifferPromise(Resources.IDBDataView.prototype, '_updatedDataForTests');
objectStoreView._updateData(true);
await promise;
promise = InspectorTest.addSnifferPromise(Resources.IDBDataView.prototype, '_updatedDataForTests');
indexView._updateData(true);
await promise;
isMarkedNeedsRefresh();
ApplicationTestRunner.dumpObjectStores();
promise = InspectorTest.addSnifferPromise(Resources.IndexedDBTreeElement.prototype, 'setExpandable');
await ApplicationTestRunner.deleteDatabaseAsync('database1');
await promise;
InspectorTest.completeTest();
}
</script>
</head>
<body onload="runTest()">
<p>Tests that the IndexedDB database content live updates.</p>
</body>
</html>
Tests that the IndexedDB database list live updates.
Dumping IndexedDB tree:
(empty)
Dumping IndexedDB tree:
database: database1 - http://127.0.0.1:8000
(no object stores)
Dumping IndexedDB tree:
database: database1 - http://127.0.0.1:8000
(no object stores)
database: database2 - http://127.0.0.1:8000
(no object stores)
Dumping IndexedDB tree:
database: database1 - http://127.0.0.1:8000
Object store: objectStore1
Index: index1
database: database2 - http://127.0.0.1:8000
(no object stores)
Dumping IndexedDB tree:
database: database1 - http://127.0.0.1:8000
Object store: objectStore1
Index: index1
Object store: objectStore2
Index: index2
database: database2 - http://127.0.0.1:8000
(no object stores)
Dumping IndexedDB tree:
database: database1 - http://127.0.0.1:8000
Object store: objectStore1
Index: index1
Index: index3
Object store: objectStore2
Index: index2
database: database2 - http://127.0.0.1:8000
(no object stores)
Dumping IndexedDB tree:
database: database1 - http://127.0.0.1:8000
Object store: objectStore1
Index: index1
Object store: objectStore2
Index: index2
database: database2 - http://127.0.0.1:8000
(no object stores)
Dumping IndexedDB tree:
database: database1 - http://127.0.0.1:8000
Object store: objectStore1
Index: index1
database: database2 - http://127.0.0.1:8000
(no object stores)
Dumping IndexedDB tree:
database: database2 - http://127.0.0.1:8000
(no object stores)
Dumping IndexedDB tree:
(empty)
<html>
<head>
<script src="../../inspector/inspector-test.js"></script>
<script src="../../inspector/indexeddb/indexeddb-test.js"></script>
<script>
async function test() {
let indexedDBModel = TestRunner.mainTarget.model(Resources.IndexedDBModel);
indexedDBModel._throttler._timeout = 0;
ApplicationTestRunner.dumpIndexedDBTree();
let promise = InspectorTest.addSnifferPromise(Resources.IndexedDBTreeElement.prototype, '_addIndexedDB');
await ApplicationTestRunner.createDatabaseAsync('database1');
await promise;
ApplicationTestRunner.dumpIndexedDBTree();
promise = InspectorTest.addSnifferPromise(Resources.IndexedDBTreeElement.prototype, '_addIndexedDB');
await ApplicationTestRunner.createDatabaseAsync('database2');
await promise;
ApplicationTestRunner.dumpIndexedDBTree();
promise = InspectorTest.addSnifferPromise(Resources.IDBObjectStoreTreeElement.prototype, 'update');
await ApplicationTestRunner.createObjectStoreAsync('database1', 'objectStore1', 'index1');
await promise;
ApplicationTestRunner.dumpIndexedDBTree();
promise = InspectorTest.addSnifferPromise(Resources.IDBObjectStoreTreeElement.prototype, 'update');
await ApplicationTestRunner.createObjectStoreAsync('database1', 'objectStore2', 'index2');
await promise;
ApplicationTestRunner.dumpIndexedDBTree();
promise = InspectorTest.addSnifferPromise(Resources.IDBObjectStoreTreeElement.prototype, 'update');
await ApplicationTestRunner.createObjectStoreIndexAsync('database1', 'objectStore1', 'index3');
await promise;
ApplicationTestRunner.dumpIndexedDBTree();
promise = InspectorTest.addSnifferPromise(Resources.IDBObjectStoreTreeElement.prototype, '_indexRemoved');
await ApplicationTestRunner.deleteObjectStoreIndexAsync('database1', 'objectStore1', 'index3');
await promise;
ApplicationTestRunner.dumpIndexedDBTree();
promise = InspectorTest.addSnifferPromise(Resources.IDBObjectStoreTreeElement.prototype, 'update');
await ApplicationTestRunner.deleteObjectStoreAsync('database1', 'objectStore2');
await promise;
ApplicationTestRunner.dumpIndexedDBTree();
promise = InspectorTest.addSnifferPromise(Resources.IndexedDBTreeElement.prototype, 'setExpandable');
await ApplicationTestRunner.deleteDatabaseAsync('database1');
await promise;
ApplicationTestRunner.dumpIndexedDBTree();
promise = InspectorTest.addSnifferPromise(Resources.IndexedDBTreeElement.prototype, 'setExpandable');
await ApplicationTestRunner.deleteDatabaseAsync('database2');
await promise;
ApplicationTestRunner.dumpIndexedDBTree();
InspectorTest.completeTest();
}
</script>
</head>
<body onload="runTest()">
<p>Tests that the IndexedDB database list live updates.</p>
</body>
</html>
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback1 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback1
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback2 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback2
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback3 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback3
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback4 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback4
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback5 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback5
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback6 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback6
Tests IndexedDB tree element on resources panel. Tests IndexedDB tree element on resources panel.
Expanded IndexedDB tree element. Expanded IndexedDB tree element.
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
var mainFrameId = TestRunner.resourceTreeModel.mainFrame.id; var mainFrameId = TestRunner.resourceTreeModel.mainFrame.id;
var indexedDBModel; var indexedDBModel;
var withoutIndexedDBURL = 'http://localhost:8000/inspector/indexeddb/resources/without-indexed-db.html'; var withoutIndexedDBURL = 'http://localhost:8000/devtools/indexeddb/resources/without-indexed-db.html';
var originalURL = 'http://127.0.0.1:8000/devtools/indexeddb/resources-panel.js'; var originalURL = 'http://127.0.0.1:8000/devtools/indexeddb/resources-panel.js';
var databaseName = 'testDatabase'; var databaseName = 'testDatabase';
var objectStoreName = 'testObjectStore'; var objectStoreName = 'testObjectStore';
......
Tests that IndexedDB live update only tracks valid security origins.
Invalid Origins:
http, valid = false
test://fake, valid = false
test://fake.origin.com, valid = false
chrome://test, valid = false
Valid Origins:
http://fake.origin.com, valid = true
https://fake.origin.com, valid = true
<html>
<head>
<script src="../../inspector/inspector-test.js"></script>
<script src="../../inspector/indexeddb/indexeddb-test.js"></script>
<script>
async function test() {
let indexedDBModel = TestRunner.mainTarget.model(Resources.IndexedDBModel);
let invalidOrigins = ['http', 'test://fake', 'test://fake.origin.com', 'chrome://test'];
let validOrigins = ['http://fake.origin.com', 'https://fake.origin.com'];
InspectorTest.addResult('Invalid Origins:');
invalidOrigins.map(origin => {
InspectorTest.addResult(origin + ", valid = " + indexedDBModel._isValidSecurityOrigin(origin));
});
InspectorTest.addResult('\nValid Origins:');
validOrigins.map(origin => {
InspectorTest.addResult(origin + ", valid = " + indexedDBModel._isValidSecurityOrigin(origin));
});
InspectorTest.completeTest();
}
</script>
</head>
<body onload="runTest()">
<p>Tests that IndexedDB live update only tracks valid security origins.</p>
</body>
</html>
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback1 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback1
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback2 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback2
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback3 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback3
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback4 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback4
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback5 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback5
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback6 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback6
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback7 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback7
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback8 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback8
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback9 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback9
CONSOLE MESSAGE: line 124: InspectorTest.IndexedDB_callback10 CONSOLE MESSAGE: line 2: InspectorTest.IndexedDB_callback10
Tests that deleted databases do not get recreated. Tests that deleted databases do not get recreated.
Preparing database Preparing database
......
...@@ -42,6 +42,30 @@ ApplicationTestRunner.dumpIndexedDBTree = function() { ...@@ -42,6 +42,30 @@ ApplicationTestRunner.dumpIndexedDBTree = function() {
} }
}; };
ApplicationTestRunner.dumpObjectStores = function() {
TestRunner.addResult('Dumping ObjectStore data:');
let idbDatabaseTreeElement = UI.panels.resources._sidebar.indexedDBListTreeElement._idbDatabaseTreeElements[0];
for (let i = 0; i < idbDatabaseTreeElement.childCount(); ++i) {
let objectStoreTreeElement = idbDatabaseTreeElement.childAt(i);
objectStoreTreeElement.onselect(false);
TestRunner.addResult(' Object store: ' + objectStoreTreeElement.title);
let entries = objectStoreTreeElement._view._entries;
TestRunner.addResult(' Number of entries: ' + entries.length);
for (let j = 0; j < entries.length; ++j)
TestRunner.addResult(' Key = ' + entries[j].key._value + ', value = ' + entries[j].value);
for (let k = 0; k < objectStoreTreeElement.childCount(); ++k) {
let indexTreeElement = objectStoreTreeElement.childAt(k);
TestRunner.addResult(' Index: ' + indexTreeElement.title);
indexTreeElement.onselect(false);
let entries = indexTreeElement._view._entries;
TestRunner.addResult(' Number of entries: ' + entries.length);
for (let j = 0; j < entries.length; ++j)
TestRunner.addResult(' Key = ' + entries[j].primaryKey._value + ', value = ' + entries[j].value);
}
}
};
var lastCallbackId = 0; var lastCallbackId = 0;
var callbacks = {}; var callbacks = {};
var callbackIdPrefix = 'InspectorTest.IndexedDB_callback'; var callbackIdPrefix = 'InspectorTest.IndexedDB_callback';
...@@ -122,10 +146,28 @@ ApplicationTestRunner.createDatabaseAsync = function(databaseName) { ...@@ -122,10 +146,28 @@ ApplicationTestRunner.createDatabaseAsync = function(databaseName) {
return TestRunner.evaluateInPageAsync('createDatabaseAsync(\'' + databaseName + '\')'); return TestRunner.evaluateInPageAsync('createDatabaseAsync(\'' + databaseName + '\')');
}; };
ApplicationTestRunner.createObjectStoreAsync = function(databaseName, objectStoreName, indexName, keyPath) { ApplicationTestRunner.deleteDatabaseAsync = function(databaseName) {
return TestRunner.evaluateInPageAsync('deleteDatabaseAsync(\'' + databaseName + '\')');
};
ApplicationTestRunner.createObjectStoreAsync = function(databaseName, objectStoreName, indexName) {
return TestRunner.evaluateInPageAsync(
'createObjectStoreAsync(\'' + databaseName + '\', \'' + objectStoreName + '\', \'' + indexName + '\')');
};
ApplicationTestRunner.deleteObjectStoreAsync = function(databaseName, objectStoreName) {
return TestRunner.evaluateInPageAsync(
'deleteObjectStoreAsync(\'' + databaseName + '\', \'' + objectStoreName + '\')');
};
ApplicationTestRunner.createObjectStoreIndexAsync = function(databaseName, objectStoreName, indexName) {
return TestRunner.evaluateInPageAsync(
'createObjectStoreIndexAsync(\'' + databaseName + '\', \'' + objectStoreName + '\', \'' + indexName + '\')');
};
ApplicationTestRunner.deleteObjectStoreIndexAsync = function(databaseName, objectStoreName, indexName) {
return TestRunner.evaluateInPageAsync( return TestRunner.evaluateInPageAsync(
'createObjectStoreAsync(\'' + databaseName + '\', \'' + objectStoreName + '\', \'' + indexName + '\', \'' + 'deleteObjectStoreIndexAsync(\'' + databaseName + '\', \'' + objectStoreName + '\', \'' + indexName + '\')');
keyPath + '\')');
}; };
ApplicationTestRunner.addIDBValueAsync = function(databaseName, objectStoreName, key, value) { ApplicationTestRunner.addIDBValueAsync = function(databaseName, objectStoreName, key, value) {
...@@ -133,6 +175,16 @@ ApplicationTestRunner.addIDBValueAsync = function(databaseName, objectStoreName, ...@@ -133,6 +175,16 @@ ApplicationTestRunner.addIDBValueAsync = function(databaseName, objectStoreName,
'addIDBValueAsync(\'' + databaseName + '\', \'' + objectStoreName + '\', \'' + key + '\', \'' + value + '\')'); 'addIDBValueAsync(\'' + databaseName + '\', \'' + objectStoreName + '\', \'' + key + '\', \'' + value + '\')');
}; };
ApplicationTestRunner.addIDBValueAsync = function(databaseName, objectStoreName, key, value) {
return TestRunner.evaluateInPageAsync(
'addIDBValueAsync(\'' + databaseName + '\', \'' + objectStoreName + '\', \'' + key + '\', \'' + value + '\')');
};
ApplicationTestRunner.deleteIDBValueAsync = function(databaseName, objectStoreName, key) {
return TestRunner.evaluateInPageAsync(
'deleteIDBValueAsync(\'' + databaseName + '\', \'' + objectStoreName + '\', \'' + key + '\')');
};
TestRunner.deprecatedInitAsync(` TestRunner.deprecatedInitAsync(`
function dispatchCallback(callbackId) { function dispatchCallback(callbackId) {
console.log(callbackId); console.log(callbackId);
...@@ -286,42 +338,80 @@ TestRunner.deprecatedInitAsync(` ...@@ -286,42 +338,80 @@ TestRunner.deprecatedInitAsync(`
return promise; return promise;
} }
function createObjectStoreAsync(databaseName, objectStoreName, indexName, keyPath) { function upgradeRequestAsync(databaseName, onUpgradeNeeded, callback) {
var callback;
var promise = new Promise(fulfill => callback = fulfill);
var request = indexedDB.open(databaseName); var request = indexedDB.open(databaseName);
request.onerror = onIndexedDBError; request.onerror = onIndexedDBError;
request.onsuccess = function(event) { request.onsuccess = function(event) {
var db = request.result; var db = request.result;
var version = db.version; var version = db.version;
db.close(); db.close();
var upgradeRequest = indexedDB.open(databaseName, version + 1); var upgradeRequest = indexedDB.open(databaseName, version + 1);
upgradeRequest.onerror = onIndexedDBError; upgradeRequest.onerror = onIndexedDBError;
upgradeRequest.onupgradeneeded = function(e) { upgradeRequest.onupgradeneeded = function(e) {
onUpgradeNeeded(e.target.result, e.target.transaction, callback);
}
upgradeRequest.onsuccess = function(e) {
var upgradeDb = e.target.result; var upgradeDb = e.target.result;
upgradeDb.close();
callback();
}
}
}
var store = upgradeDb.createObjectStore(objectStoreName, { function deleteDatabaseAsync(databaseName) {
keyPath: 'test', var callback;
autoIncrement: false var promise = new Promise((fulfill) => callback = fulfill);
}); var request = indexedDB.deleteDatabase(databaseName);
request.onerror = onIndexedDBError;
request.onsuccess = callback;
return promise;
}
store.createIndex(indexName, 'test', { function createObjectStoreAsync(databaseName, objectStoreName, indexName) {
unique: false, var callback;
multiEntry: false var promise = new Promise((fulfill) => callback = fulfill);
}); var onUpgradeNeeded = function(upgradeDb, transaction, callback) {
var store = upgradeDb.createObjectStore(objectStoreName, { keyPath: "test", autoIncrement: false });
store.createIndex(indexName, "test", { unique: false, multiEntry: false });
callback();
}
upgradeRequestAsync(databaseName, onUpgradeNeeded, callback)
return promise;
}
callback(); function deleteObjectStoreAsync(databaseName, objectStoreName) {
}; var callback;
var promise = new Promise((fulfill) => callback = fulfill);
var onUpgradeNeeded = function(upgradeDb, transaction, callback) {
upgradeDb.deleteObjectStore(objectStoreName);
callback();
}
upgradeRequestAsync(databaseName, onUpgradeNeeded, callback)
return promise;
}
upgradeRequest.onsuccess = function(e) { function createObjectStoreIndexAsync(databaseName, objectStoreName, indexName) {
var upgradeDb = e.target.result; var callback;
upgradeDb.close(); var promise = new Promise((fulfill) => callback = fulfill);
callback(); var onUpgradeNeeded = function(upgradeDb, transaction, callback) {
}; var store = transaction.objectStore(objectStoreName);
}; store.createIndex(indexName, "test", { unique: false, multiEntry: false });
callback();
}
upgradeRequestAsync(databaseName, onUpgradeNeeded, callback)
return promise;
}
function deleteObjectStoreIndexAsync(databaseName, objectStoreName, indexName) {
var callback;
var promise = new Promise((fulfill) => callback = fulfill);
var onUpgradeNeeded = function(upgradeDb, transaction, callback) {
var store = transaction.objectStore(objectStoreName);
store.deleteIndex(indexName);
callback();
}
upgradeRequestAsync(databaseName, onUpgradeNeeded, callback)
return promise; return promise;
} }
...@@ -351,4 +441,24 @@ TestRunner.deprecatedInitAsync(` ...@@ -351,4 +441,24 @@ TestRunner.deprecatedInitAsync(`
return promise; return promise;
} }
function deleteIDBValueAsync(databaseName, objectStoreName, key) {
var callback;
var promise = new Promise((fulfill) => callback = fulfill);
var request = indexedDB.open(databaseName);
request.onerror = onIndexedDBError;
request.onsuccess = function(event) {
var db = request.result;
var transaction = db.transaction(objectStoreName, "readwrite");
var store = transaction.objectStore(objectStoreName);
store.delete(key);
transaction.onerror = onIndexedDBError;
transaction.oncomplete = function() {
db.close();
callback();
};
}
return promise;
}
`); `);
...@@ -1026,6 +1026,9 @@ Resources.IndexedDBTreeElement = class extends Resources.StorageCategoryTreeElem ...@@ -1026,6 +1026,9 @@ Resources.IndexedDBTreeElement = class extends Resources.StorageCategoryTreeElem
Resources.IndexedDBModel, Resources.IndexedDBModel.Events.DatabaseRemoved, this._indexedDBRemoved, this); Resources.IndexedDBModel, Resources.IndexedDBModel.Events.DatabaseRemoved, this._indexedDBRemoved, this);
SDK.targetManager.addModelListener( SDK.targetManager.addModelListener(
Resources.IndexedDBModel, Resources.IndexedDBModel.Events.DatabaseLoaded, this._indexedDBLoaded, this); 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>} */ /** @type {!Array.<!Resources.IDBDatabaseTreeElement>} */
this._idbDatabaseTreeElements = []; this._idbDatabaseTreeElements = [];
...@@ -1098,12 +1101,26 @@ Resources.IndexedDBTreeElement = class extends Resources.StorageCategoryTreeElem ...@@ -1098,12 +1101,26 @@ Resources.IndexedDBTreeElement = class extends Resources.StorageCategoryTreeElem
_indexedDBLoaded(event) { _indexedDBLoaded(event) {
var database = /** @type {!Resources.IndexedDBModel.Database} */ (event.data.database); var database = /** @type {!Resources.IndexedDBModel.Database} */ (event.data.database);
var model = /** @type {!Resources.IndexedDBModel} */ (event.data.model); var model = /** @type {!Resources.IndexedDBModel} */ (event.data.model);
var entriesUpdated = /** @type {boolean} */ (event.data.entriesUpdated);
var idbDatabaseTreeElement = this._idbDatabaseTreeElement(model, database.databaseId); var idbDatabaseTreeElement = this._idbDatabaseTreeElement(model, database.databaseId);
if (!idbDatabaseTreeElement) if (!idbDatabaseTreeElement)
return; return;
idbDatabaseTreeElement.update(database, entriesUpdated);
}
/**
* @param {!Common.Event} event
*/
_indexedDBContentUpdated(event) {
var databaseId = /** @type {!Resources.IndexedDBModel.DatabaseId} */ (event.data.databaseId);
var objectStoreName = /** @type {string} */ (event.data.objectStoreName);
var model = /** @type {!Resources.IndexedDBModel} */ (event.data.model);
idbDatabaseTreeElement.update(database); var idbDatabaseTreeElement = this._idbDatabaseTreeElement(model, databaseId);
if (!idbDatabaseTreeElement)
return;
idbDatabaseTreeElement.indexedDBContentUpdated(objectStoreName);
} }
/** /**
...@@ -1167,10 +1184,19 @@ Resources.IDBDatabaseTreeElement = class extends Resources.BaseStorageTreeElemen ...@@ -1167,10 +1184,19 @@ Resources.IDBDatabaseTreeElement = class extends Resources.BaseStorageTreeElemen
this._model.refreshDatabase(this._databaseId); this._model.refreshDatabase(this._databaseId);
} }
/**
* @param {string} objectStoreName
*/
indexedDBContentUpdated(objectStoreName) {
if (this._idbObjectStoreTreeElements[objectStoreName])
this._idbObjectStoreTreeElements[objectStoreName].markNeedsRefresh();
}
/** /**
* @param {!Resources.IndexedDBModel.Database} database * @param {!Resources.IndexedDBModel.Database} database
* @param {boolean} entriesUpdated
*/ */
update(database) { update(database, entriesUpdated) {
this._database = database; this._database = database;
var objectStoreNames = {}; var objectStoreNames = {};
for (var objectStoreName in this._database.objectStores) { for (var objectStoreName in this._database.objectStores) {
...@@ -1182,7 +1208,7 @@ Resources.IDBDatabaseTreeElement = class extends Resources.BaseStorageTreeElemen ...@@ -1182,7 +1208,7 @@ Resources.IDBDatabaseTreeElement = class extends Resources.BaseStorageTreeElemen
this._idbObjectStoreTreeElements[objectStore.name] = idbObjectStoreTreeElement; this._idbObjectStoreTreeElements[objectStore.name] = idbObjectStoreTreeElement;
this.appendChild(idbObjectStoreTreeElement); this.appendChild(idbObjectStoreTreeElement);
} }
this._idbObjectStoreTreeElements[objectStore.name].update(objectStore); this._idbObjectStoreTreeElements[objectStore.name].update(objectStore, entriesUpdated);
} }
for (var objectStoreName in this._idbObjectStoreTreeElements) { for (var objectStoreName in this._idbObjectStoreTreeElements) {
if (!objectStoreNames[objectStoreName]) if (!objectStoreNames[objectStoreName])
...@@ -1260,6 +1286,13 @@ Resources.IDBObjectStoreTreeElement = class extends Resources.BaseStorageTreeEle ...@@ -1260,6 +1286,13 @@ Resources.IDBObjectStoreTreeElement = class extends Resources.BaseStorageTreeEle
this.listItemElement.addEventListener('contextmenu', this._handleContextMenuEvent.bind(this), true); this.listItemElement.addEventListener('contextmenu', this._handleContextMenuEvent.bind(this), true);
} }
markNeedsRefresh() {
if (this._view)
this._view.markNeedsRefresh();
for (var indexName in this._idbIndexTreeElements)
this._idbIndexTreeElements[indexName].markNeedsRefresh();
}
_handleContextMenuEvent(event) { _handleContextMenuEvent(event) {
var contextMenu = new UI.ContextMenu(event); var contextMenu = new UI.ContextMenu(event);
contextMenu.defaultSection().appendItem(Common.UIString('Clear'), this._clearObjectStore.bind(this)); contextMenu.defaultSection().appendItem(Common.UIString('Clear'), this._clearObjectStore.bind(this));
...@@ -1268,13 +1301,14 @@ Resources.IDBObjectStoreTreeElement = class extends Resources.BaseStorageTreeEle ...@@ -1268,13 +1301,14 @@ Resources.IDBObjectStoreTreeElement = class extends Resources.BaseStorageTreeEle
async _clearObjectStore() { async _clearObjectStore() {
await this._model.clearObjectStore(this._databaseId, this._objectStore.name); await this._model.clearObjectStore(this._databaseId, this._objectStore.name);
this.update(this._objectStore); this.update(this._objectStore, true);
} }
/** /**
* @param {!Resources.IndexedDBModel.ObjectStore} objectStore * @param {!Resources.IndexedDBModel.ObjectStore} objectStore
* @param {boolean} entriesUpdated
*/ */
update(objectStore) { update(objectStore, entriesUpdated) {
this._objectStore = objectStore; this._objectStore = objectStore;
var indexNames = {}; var indexNames = {};
...@@ -1287,7 +1321,7 @@ Resources.IDBObjectStoreTreeElement = class extends Resources.BaseStorageTreeEle ...@@ -1287,7 +1321,7 @@ Resources.IDBObjectStoreTreeElement = class extends Resources.BaseStorageTreeEle
this._idbIndexTreeElements[index.name] = idbIndexTreeElement; this._idbIndexTreeElements[index.name] = idbIndexTreeElement;
this.appendChild(idbIndexTreeElement); this.appendChild(idbIndexTreeElement);
} }
this._idbIndexTreeElements[index.name].update(index); this._idbIndexTreeElements[index.name].update(this._objectStore, index, entriesUpdated);
} }
for (var indexName in this._idbIndexTreeElements) { for (var indexName in this._idbIndexTreeElements) {
if (!indexNames[indexName]) if (!indexNames[indexName])
...@@ -1303,7 +1337,7 @@ Resources.IDBObjectStoreTreeElement = class extends Resources.BaseStorageTreeEle ...@@ -1303,7 +1337,7 @@ Resources.IDBObjectStoreTreeElement = class extends Resources.BaseStorageTreeEle
if (this.childCount()) if (this.childCount())
this.expand(); this.expand();
if (this._view) if (this._view && entriesUpdated)
this._view.update(this._objectStore, null); this._view.update(this._objectStore, null);
this._updateTooltip(); this._updateTooltip();
...@@ -1372,14 +1406,22 @@ Resources.IDBIndexTreeElement = class extends Resources.BaseStorageTreeElement { ...@@ -1372,14 +1406,22 @@ Resources.IDBIndexTreeElement = class extends Resources.BaseStorageTreeElement {
this._objectStore.name + '/' + this._index.name; this._objectStore.name + '/' + this._index.name;
} }
markNeedsRefresh() {
if (this._view)
this._view.markNeedsRefresh();
}
/** /**
* @param {!Resources.IndexedDBModel.ObjectStore} objectStore
* @param {!Resources.IndexedDBModel.Index} index * @param {!Resources.IndexedDBModel.Index} index
* @param {boolean} entriesUpdated
*/ */
update(index) { update(objectStore, index, entriesUpdated) {
this._objectStore = objectStore;
this._index = index; this._index = index;
if (this._view) if (this._view && entriesUpdated)
this._view.update(this._index); this._view.update(this._objectStore, this._index);
this._updateTooltip(); this._updateTooltip();
} }
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
*/ */
/** /**
* @implements {Protocol.StorageDispatcher}
* @unrestricted * @unrestricted
*/ */
Resources.IndexedDBModel = class extends SDK.SDKModel { Resources.IndexedDBModel = class extends SDK.SDKModel {
...@@ -37,13 +38,18 @@ Resources.IndexedDBModel = class extends SDK.SDKModel { ...@@ -37,13 +38,18 @@ Resources.IndexedDBModel = class extends SDK.SDKModel {
*/ */
constructor(target) { constructor(target) {
super(target); super(target);
target.registerStorageDispatcher(this);
this._securityOriginManager = target.model(SDK.SecurityOriginManager); this._securityOriginManager = target.model(SDK.SecurityOriginManager);
this._agent = target.indexedDBAgent(); this._indexedDBAgent = target.indexedDBAgent();
this._storageAgent = target.storageAgent();
/** @type {!Map.<!Resources.IndexedDBModel.DatabaseId, !Resources.IndexedDBModel.Database>} */ /** @type {!Map.<!Resources.IndexedDBModel.DatabaseId, !Resources.IndexedDBModel.Database>} */
this._databases = new Map(); this._databases = new Map();
/** @type {!Object.<string, !Array.<string>>} */ /** @type {!Object.<string, !Array.<string>>} */
this._databaseNamesBySecurityOrigin = {}; this._databaseNamesBySecurityOrigin = {};
this._originsUpdated = new Set();
this._throttler = new Common.Throttler(1000);
} }
/** /**
...@@ -142,7 +148,7 @@ Resources.IndexedDBModel = class extends SDK.SDKModel { ...@@ -142,7 +148,7 @@ Resources.IndexedDBModel = class extends SDK.SDKModel {
if (this._enabled) if (this._enabled)
return; return;
this._agent.enable(); this._indexedDBAgent.enable();
this._securityOriginManager.addEventListener( this._securityOriginManager.addEventListener(
SDK.SecurityOriginManager.Events.SecurityOriginAdded, this._securityOriginAdded, this); SDK.SecurityOriginManager.Events.SecurityOriginAdded, this._securityOriginAdded, this);
this._securityOriginManager.addEventListener( this._securityOriginManager.addEventListener(
...@@ -171,7 +177,7 @@ Resources.IndexedDBModel = class extends SDK.SDKModel { ...@@ -171,7 +177,7 @@ Resources.IndexedDBModel = class extends SDK.SDKModel {
async deleteDatabase(databaseId) { async deleteDatabase(databaseId) {
if (!this._enabled) if (!this._enabled)
return; return;
await this._agent.deleteDatabase(databaseId.securityOrigin, databaseId.name); await this._indexedDBAgent.deleteDatabase(databaseId.securityOrigin, databaseId.name);
this._loadDatabaseNames(databaseId.securityOrigin); this._loadDatabaseNames(databaseId.securityOrigin);
} }
...@@ -185,7 +191,7 @@ Resources.IndexedDBModel = class extends SDK.SDKModel { ...@@ -185,7 +191,7 @@ Resources.IndexedDBModel = class extends SDK.SDKModel {
* @param {!Resources.IndexedDBModel.DatabaseId} databaseId * @param {!Resources.IndexedDBModel.DatabaseId} databaseId
*/ */
refreshDatabase(databaseId) { refreshDatabase(databaseId) {
this._loadDatabase(databaseId); this._loadDatabase(databaseId, true);
} }
/** /**
...@@ -194,7 +200,7 @@ Resources.IndexedDBModel = class extends SDK.SDKModel { ...@@ -194,7 +200,7 @@ Resources.IndexedDBModel = class extends SDK.SDKModel {
* @return {!Promise} * @return {!Promise}
*/ */
clearObjectStore(databaseId, objectStoreName) { clearObjectStore(databaseId, objectStoreName) {
return this._agent.clearObjectStore(databaseId.securityOrigin, databaseId.name, objectStoreName); return this._indexedDBAgent.clearObjectStore(databaseId.securityOrigin, databaseId.name, objectStoreName);
} }
/** /**
...@@ -220,6 +226,8 @@ Resources.IndexedDBModel = class extends SDK.SDKModel { ...@@ -220,6 +226,8 @@ Resources.IndexedDBModel = class extends SDK.SDKModel {
console.assert(!this._databaseNamesBySecurityOrigin[securityOrigin]); console.assert(!this._databaseNamesBySecurityOrigin[securityOrigin]);
this._databaseNamesBySecurityOrigin[securityOrigin] = []; this._databaseNamesBySecurityOrigin[securityOrigin] = [];
this._loadDatabaseNames(securityOrigin); this._loadDatabaseNames(securityOrigin);
if (this._isValidSecurityOrigin(securityOrigin))
this._storageAgent.trackIndexedDBForOrigin(securityOrigin);
} }
/** /**
...@@ -230,6 +238,17 @@ Resources.IndexedDBModel = class extends SDK.SDKModel { ...@@ -230,6 +238,17 @@ Resources.IndexedDBModel = class extends SDK.SDKModel {
for (var i = 0; i < this._databaseNamesBySecurityOrigin[securityOrigin].length; ++i) for (var i = 0; i < this._databaseNamesBySecurityOrigin[securityOrigin].length; ++i)
this._databaseRemoved(securityOrigin, this._databaseNamesBySecurityOrigin[securityOrigin][i]); this._databaseRemoved(securityOrigin, this._databaseNamesBySecurityOrigin[securityOrigin][i]);
delete this._databaseNamesBySecurityOrigin[securityOrigin]; delete this._databaseNamesBySecurityOrigin[securityOrigin];
if (this._isValidSecurityOrigin(securityOrigin))
this._storageAgent.untrackIndexedDBForOrigin(securityOrigin);
}
/**
* @param {string} securityOrigin
* @return {boolean}
*/
_isValidSecurityOrigin(securityOrigin) {
var parsedURL = securityOrigin.asParsedURL();
return !!parsedURL && parsedURL.scheme.startsWith('http');
} }
/** /**
...@@ -286,21 +305,25 @@ Resources.IndexedDBModel = class extends SDK.SDKModel { ...@@ -286,21 +305,25 @@ Resources.IndexedDBModel = class extends SDK.SDKModel {
/** /**
* @param {string} securityOrigin * @param {string} securityOrigin
* @return {!Promise<!Array.<string>>} databaseNames
*/ */
async _loadDatabaseNames(securityOrigin) { async _loadDatabaseNames(securityOrigin) {
var databaseNames = await this._agent.requestDatabaseNames(securityOrigin); var databaseNames = await this._indexedDBAgent.requestDatabaseNames(securityOrigin);
if (!databaseNames) if (!databaseNames)
return; return [];
if (!this._databaseNamesBySecurityOrigin[securityOrigin]) if (!this._databaseNamesBySecurityOrigin[securityOrigin])
return; return [];
this._updateOriginDatabaseNames(securityOrigin, databaseNames); this._updateOriginDatabaseNames(securityOrigin, databaseNames);
return databaseNames;
} }
/** /**
* @param {!Resources.IndexedDBModel.DatabaseId} databaseId * @param {!Resources.IndexedDBModel.DatabaseId} databaseId
* @param {boolean} entriesUpdated
*/ */
async _loadDatabase(databaseId) { async _loadDatabase(databaseId, entriesUpdated) {
var databaseWithObjectStores = await this._agent.requestDatabase(databaseId.securityOrigin, databaseId.name); var databaseWithObjectStores =
await this._indexedDBAgent.requestDatabase(databaseId.securityOrigin, databaseId.name);
if (!databaseWithObjectStores) if (!databaseWithObjectStores)
return; return;
...@@ -324,7 +347,8 @@ Resources.IndexedDBModel = class extends SDK.SDKModel { ...@@ -324,7 +347,8 @@ Resources.IndexedDBModel = class extends SDK.SDKModel {
} }
this.dispatchEventToListeners( this.dispatchEventToListeners(
Resources.IndexedDBModel.Events.DatabaseLoaded, {model: this, database: databaseModel}); Resources.IndexedDBModel.Events.DatabaseLoaded,
{model: this, database: databaseModel, entriesUpdated: entriesUpdated});
} }
/** /**
...@@ -366,7 +390,7 @@ Resources.IndexedDBModel = class extends SDK.SDKModel { ...@@ -366,7 +390,7 @@ Resources.IndexedDBModel = class extends SDK.SDKModel {
async _requestData(databaseId, databaseName, objectStoreName, indexName, idbKeyRange, skipCount, pageSize, callback) { async _requestData(databaseId, databaseName, objectStoreName, indexName, idbKeyRange, skipCount, pageSize, callback) {
var keyRange = Resources.IndexedDBModel.keyRangeFromIDBKeyRange(idbKeyRange) || undefined; var keyRange = Resources.IndexedDBModel.keyRangeFromIDBKeyRange(idbKeyRange) || undefined;
var response = await this._agent.invoke_requestData({ var response = await this._indexedDBAgent.invoke_requestData({
securityOrigin: databaseId.securityOrigin, securityOrigin: databaseId.securityOrigin,
databaseName, databaseName,
objectStoreName, objectStoreName,
...@@ -394,6 +418,58 @@ Resources.IndexedDBModel = class extends SDK.SDKModel { ...@@ -394,6 +418,58 @@ Resources.IndexedDBModel = class extends SDK.SDKModel {
} }
callback(entries, response.hasMore); callback(entries, response.hasMore);
} }
/**
* @param {string} securityOrigin
*/
async _refreshDatabaseList(securityOrigin) {
var databaseNames = await this._loadDatabaseNames(securityOrigin);
for (var databaseName of databaseNames)
this._loadDatabase(new Resources.IndexedDBModel.DatabaseId(securityOrigin, databaseName), false);
}
/**
* @param {string} securityOrigin
* @override
*/
indexedDBListUpdated(securityOrigin) {
this._originsUpdated.add(securityOrigin);
this._throttler.schedule(() => {
var promises = Array.from(this._originsUpdated, securityOrigin => {
this._refreshDatabaseList(securityOrigin);
});
this._originsUpdated.clear();
return Promise.all(promises);
});
}
/**
* @param {string} securityOrigin
* @param {string} databaseName
* @param {string} objectStoreName
* @override
*/
indexedDBContentUpdated(securityOrigin, databaseName, objectStoreName) {
var databaseId = new Resources.IndexedDBModel.DatabaseId(securityOrigin, databaseName);
this.dispatchEventToListeners(
Resources.IndexedDBModel.Events.IndexedDBContentUpdated,
{databaseId: databaseId, objectStoreName: objectStoreName, model: this});
}
/**
* @param {string} securityOrigin
* @override
*/
cacheStorageListUpdated(securityOrigin) {
}
/**
* @param {string} securityOrigin
* @override
*/
cacheStorageContentUpdated(securityOrigin) {
}
}; };
SDK.SDKModel.register(Resources.IndexedDBModel, SDK.Target.Capability.None, false); SDK.SDKModel.register(Resources.IndexedDBModel, SDK.Target.Capability.None, false);
...@@ -416,7 +492,8 @@ Resources.IndexedDBModel.Events = { ...@@ -416,7 +492,8 @@ Resources.IndexedDBModel.Events = {
DatabaseAdded: Symbol('DatabaseAdded'), DatabaseAdded: Symbol('DatabaseAdded'),
DatabaseRemoved: Symbol('DatabaseRemoved'), DatabaseRemoved: Symbol('DatabaseRemoved'),
DatabaseLoaded: Symbol('DatabaseLoaded'), DatabaseLoaded: Symbol('DatabaseLoaded'),
DatabaseNamesRefreshed: Symbol('DatabaseNamesRefreshed') DatabaseNamesRefreshed: Symbol('DatabaseNamesRefreshed'),
IndexedDBContentUpdated: Symbol('IndexedDBContentUpdated')
}; };
/** /**
......
...@@ -120,6 +120,10 @@ Resources.IDBDataView = class extends UI.SimpleView { ...@@ -120,6 +120,10 @@ Resources.IDBDataView = class extends UI.SimpleView {
this._clearButton = new UI.ToolbarButton(Common.UIString('Clear object store'), 'largeicon-clear'); this._clearButton = new UI.ToolbarButton(Common.UIString('Clear object store'), 'largeicon-clear');
this._clearButton.addEventListener(UI.ToolbarButton.Events.Click, this._clearButtonClicked, this); this._clearButton.addEventListener(UI.ToolbarButton.Events.Click, this._clearButtonClicked, this);
this._needsRefresh = new UI.ToolbarItem(UI.createLabel(Common.UIString('Data may be stale'), 'smallicon-warning'));
this._needsRefresh.setVisible(false);
this._needsRefresh.setTitle(Common.UIString('Some entries may have been modified'));
this._createEditorToolbar(); this._createEditorToolbar();
this._pageSize = 50; this._pageSize = 50;
...@@ -211,13 +215,15 @@ Resources.IDBDataView = class extends UI.SimpleView { ...@@ -211,13 +215,15 @@ Resources.IDBDataView = class extends UI.SimpleView {
this._pageForwardButton.addEventListener(UI.ToolbarButton.Events.Click, this._pageForwardButtonClicked, this); this._pageForwardButton.addEventListener(UI.ToolbarButton.Events.Click, this._pageForwardButtonClicked, this);
editorToolbar.appendToolbarItem(this._pageForwardButton); editorToolbar.appendToolbarItem(this._pageForwardButton);
this._keyInputElement = UI.createInput('key-input'); this._keyInputElement = UI.createInput('toolbar-input');
editorToolbar.element.appendChild(this._keyInputElement); editorToolbar.appendToolbarItem(new UI.ToolbarItem(this._keyInputElement));
this._keyInputElement.placeholder = Common.UIString('Start from key'); this._keyInputElement.placeholder = Common.UIString('Start from key');
this._keyInputElement.addEventListener('paste', this._keyInputChanged.bind(this), false); this._keyInputElement.addEventListener('paste', this._keyInputChanged.bind(this), false);
this._keyInputElement.addEventListener('cut', this._keyInputChanged.bind(this), false); this._keyInputElement.addEventListener('cut', this._keyInputChanged.bind(this), false);
this._keyInputElement.addEventListener('keypress', this._keyInputChanged.bind(this), false); this._keyInputElement.addEventListener('keypress', this._keyInputChanged.bind(this), false);
this._keyInputElement.addEventListener('keydown', this._keyInputChanged.bind(this), false); this._keyInputElement.addEventListener('keydown', this._keyInputChanged.bind(this), false);
editorToolbar.appendToolbarItem(this._needsRefresh);
} }
/** /**
...@@ -313,6 +319,7 @@ Resources.IDBDataView = class extends UI.SimpleView { ...@@ -313,6 +319,7 @@ Resources.IDBDataView = class extends UI.SimpleView {
this._pageBackButton.setEnabled(!!skipCount); this._pageBackButton.setEnabled(!!skipCount);
this._pageForwardButton.setEnabled(hasMore); this._pageForwardButton.setEnabled(hasMore);
this._needsRefresh.setVisible(false);
this._updatedDataForTests(); this._updatedDataForTests();
} }
...@@ -348,6 +355,10 @@ Resources.IDBDataView = class extends UI.SimpleView { ...@@ -348,6 +355,10 @@ Resources.IDBDataView = class extends UI.SimpleView {
this._updateData(true); this._updateData(true);
} }
markNeedsRefresh() {
this._needsRefresh.setVisible(true);
}
clear() { clear() {
this._dataGrid.rootNode().removeChildren(); this._dataGrid.rootNode().removeChildren();
this._entries = []; this._entries = [];
......
...@@ -39,11 +39,6 @@ ...@@ -39,11 +39,6 @@
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
} }
.indexed-db-data-view .data-view-toolbar .key-input {
margin: auto 0;
width: 200px;
}
.indexed-db-data-view .data-grid { .indexed-db-data-view .data-grid {
flex: auto; flex: auto;
} }
...@@ -83,3 +78,7 @@ ...@@ -83,3 +78,7 @@
white-space: pre-wrap; white-space: pre-wrap;
unicode-bidi: -webkit-isolate; unicode-bidi: -webkit-isolate;
} }
.resources-toolbar {
padding-right: 10px;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment