зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1434579 - Fix infinite scrolling for indexedDB in storage inspector;r=miker
MozReview-Commit-ID: 7ZyxqDPxHTK --HG-- extra : rebase_source : e6c4fd13ad514b52b7aa38c0f507cc1438a1e893
This commit is contained in:
Родитель
8c326e567e
Коммит
d31555e033
|
@ -15,6 +15,7 @@ support-files =
|
||||||
storage-listings-usercontextid.html
|
storage-listings-usercontextid.html
|
||||||
storage-listings-with-fragment.html
|
storage-listings-with-fragment.html
|
||||||
storage-localstorage.html
|
storage-localstorage.html
|
||||||
|
storage-overflow-indexeddb.html
|
||||||
storage-overflow.html
|
storage-overflow.html
|
||||||
storage-search.html
|
storage-search.html
|
||||||
storage-secured-iframe.html
|
storage-secured-iframe.html
|
||||||
|
@ -57,6 +58,7 @@ tags = usercontextid
|
||||||
[browser_storage_indexeddb_delete.js]
|
[browser_storage_indexeddb_delete.js]
|
||||||
[browser_storage_indexeddb_delete_blocked.js]
|
[browser_storage_indexeddb_delete_blocked.js]
|
||||||
[browser_storage_indexeddb_duplicate_names.js]
|
[browser_storage_indexeddb_duplicate_names.js]
|
||||||
|
[browser_storage_indexeddb_overflow.js]
|
||||||
[browser_storage_localstorage_add.js]
|
[browser_storage_localstorage_add.js]
|
||||||
[browser_storage_localstorage_edit.js]
|
[browser_storage_localstorage_edit.js]
|
||||||
[browser_storage_localstorage_error.js]
|
[browser_storage_localstorage_error.js]
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
// Test endless scrolling when a lot of items are present in the storage
|
||||||
|
// inspector table for IndexedDB.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const ITEMS_PER_PAGE = 50;
|
||||||
|
|
||||||
|
add_task(async function() {
|
||||||
|
await openTabAndSetupStorage(MAIN_DOMAIN + "storage-overflow-indexeddb.html");
|
||||||
|
|
||||||
|
info("Run the tests with short DevTools");
|
||||||
|
await runTests();
|
||||||
|
|
||||||
|
info("Close Toolbox");
|
||||||
|
const target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||||
|
await gDevTools.closeToolbox(target);
|
||||||
|
|
||||||
|
await finishTests();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function runTests() {
|
||||||
|
gUI.tree.expandAll();
|
||||||
|
|
||||||
|
await selectTreeItem(["indexedDB",
|
||||||
|
"http://test1.example.org",
|
||||||
|
"database (default)",
|
||||||
|
"store"]);
|
||||||
|
checkCellLength(ITEMS_PER_PAGE);
|
||||||
|
|
||||||
|
await scroll();
|
||||||
|
checkCellLength(ITEMS_PER_PAGE * 2);
|
||||||
|
}
|
|
@ -1,3 +1,7 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
// Test endless scrolling when a lot of items are present in the storage
|
// Test endless scrolling when a lot of items are present in the storage
|
||||||
// inspector table.
|
// inspector table.
|
||||||
"use strict";
|
"use strict";
|
||||||
|
@ -47,14 +51,6 @@ async function runTests() {
|
||||||
checkCellValues("DEC");
|
checkCellValues("DEC");
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkCellLength(len) {
|
|
||||||
const cells = gPanelWindow.document
|
|
||||||
.querySelectorAll("#name .table-widget-cell");
|
|
||||||
const msg = `Table should initially display ${len} items`;
|
|
||||||
|
|
||||||
is(cells.length, len, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkCellValues(order) {
|
function checkCellValues(order) {
|
||||||
const cells = [...gPanelWindow.document
|
const cells = [...gPanelWindow.document
|
||||||
.querySelectorAll("#name .table-widget-cell")];
|
.querySelectorAll("#name .table-widget-cell")];
|
||||||
|
@ -63,14 +59,3 @@ function checkCellValues(order) {
|
||||||
is(cell.value, `item-${i}`, `Cell value is correct (${order}).`);
|
is(cell.value, `item-${i}`, `Cell value is correct (${order}).`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function scroll() {
|
|
||||||
const $ = id => gPanelWindow.document.querySelector(id);
|
|
||||||
const table = $("#storage-table .table-widget-body");
|
|
||||||
const cell = $("#name .table-widget-cell");
|
|
||||||
const cellHeight = cell.getBoundingClientRect().height;
|
|
||||||
|
|
||||||
const onStoresUpdate = gUI.once("store-objects-updated");
|
|
||||||
table.scrollTop += cellHeight * 50;
|
|
||||||
await onStoresUpdate;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1003,3 +1003,21 @@ async function performAdd(store) {
|
||||||
|
|
||||||
is(rowId, value, `Row '${rowId}' was successfully added.`);
|
is(rowId, value, `Row '${rowId}' was successfully added.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkCellLength(len) {
|
||||||
|
const cells = gPanelWindow.document.querySelectorAll("#name .table-widget-cell");
|
||||||
|
const msg = `Table should initially display ${len} items`;
|
||||||
|
|
||||||
|
is(cells.length, len, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function scroll() {
|
||||||
|
const $ = id => gPanelWindow.document.querySelector(id);
|
||||||
|
const table = $("#storage-table .table-widget-body");
|
||||||
|
const cell = $("#name .table-widget-cell");
|
||||||
|
const cellHeight = cell.getBoundingClientRect().height;
|
||||||
|
|
||||||
|
const onStoresUpdate = gUI.once("store-objects-updated");
|
||||||
|
table.scrollTop += cellHeight * 50;
|
||||||
|
await onStoresUpdate;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
Bug 1171903 - Storage Inspector endless scrolling
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Storage inspector endless scrolling test</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript">
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
window.setup = async function() {
|
||||||
|
await new Promise(resolve => {
|
||||||
|
const open = indexedDB.open("database", 1);
|
||||||
|
open.onupgradeneeded = function() {
|
||||||
|
const db = open.result;
|
||||||
|
const store = db.createObjectStore("store", {keyPath: "id"});
|
||||||
|
store.transaction.oncomplete = () => {
|
||||||
|
const transaction = db.transaction(["store"], "readwrite");
|
||||||
|
for (let i = 1; i < 150; i++) {
|
||||||
|
transaction.objectStore("store").add({id: i});
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction.oncomplete = function() {
|
||||||
|
db.close();
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function deleteDB(dbName, storage) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
indexedDB.deleteDatabase(dbName, { storage: storage }).onsuccess = resolve;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.clear = async function() {
|
||||||
|
await deleteDB("database", "temporary");
|
||||||
|
await deleteDB("database", "default");
|
||||||
|
await deleteDB("database", "persistent");
|
||||||
|
|
||||||
|
dump(`removed indexedDB data from ${document.location}\n`);
|
||||||
|
};
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -337,7 +337,7 @@ StorageActors.defaults = function(typeName, observationTopics) {
|
||||||
* - data - The requested values.
|
* - data - The requested values.
|
||||||
*/
|
*/
|
||||||
async getStoreObjects(host, names, options = {}) {
|
async getStoreObjects(host, names, options = {}) {
|
||||||
let offset = options.offset || 0;
|
const offset = options.offset || 0;
|
||||||
let size = options.size || MAX_STORE_OBJECT_COUNT;
|
let size = options.size || MAX_STORE_OBJECT_COUNT;
|
||||||
if (size > MAX_STORE_OBJECT_COUNT) {
|
if (size > MAX_STORE_OBJECT_COUNT) {
|
||||||
size = MAX_STORE_OBJECT_COUNT;
|
size = MAX_STORE_OBJECT_COUNT;
|
||||||
|
@ -381,6 +381,16 @@ StorageActors.defaults = function(typeName, observationTopics) {
|
||||||
}
|
}
|
||||||
|
|
||||||
toReturn.total = this.getObjectsSize(host, names, options);
|
toReturn.total = this.getObjectsSize(host, names, options);
|
||||||
|
} else {
|
||||||
|
let obj = await this.getValuesForHost(host, undefined, undefined,
|
||||||
|
this.hostVsStores, principal);
|
||||||
|
if (obj.dbs) {
|
||||||
|
obj = obj.dbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
toReturn.total = obj.length;
|
||||||
|
toReturn.data = obj;
|
||||||
|
}
|
||||||
|
|
||||||
if (offset > toReturn.total) {
|
if (offset > toReturn.total) {
|
||||||
// In this case, toReturn.data is an empty array.
|
// In this case, toReturn.data is an empty array.
|
||||||
|
@ -391,31 +401,17 @@ StorageActors.defaults = function(typeName, observationTopics) {
|
||||||
const sorted = toReturn.data.sort((a, b) => {
|
const sorted = toReturn.data.sort((a, b) => {
|
||||||
return naturalSortCaseInsensitive(a[sortOn], b[sortOn]);
|
return naturalSortCaseInsensitive(a[sortOn], b[sortOn]);
|
||||||
});
|
});
|
||||||
const sliced = sorted.slice(offset, offset + size);
|
let sliced;
|
||||||
|
if (this.typeName === "indexedDB") {
|
||||||
|
// indexedDB's getValuesForHost never returns *all* values available but only
|
||||||
|
// a slice, starting at the expected offset. Therefore the result is already
|
||||||
|
// sliced as expected.
|
||||||
|
sliced = sorted;
|
||||||
|
} else {
|
||||||
|
sliced = sorted.slice(offset, offset + size);
|
||||||
|
}
|
||||||
toReturn.data = sliced.map(a => this.toStoreObject(a));
|
toReturn.data = sliced.map(a => this.toStoreObject(a));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
let obj = await this.getValuesForHost(host, undefined, undefined,
|
|
||||||
this.hostVsStores, principal);
|
|
||||||
if (obj.dbs) {
|
|
||||||
obj = obj.dbs;
|
|
||||||
}
|
|
||||||
|
|
||||||
toReturn.total = obj.length;
|
|
||||||
|
|
||||||
if (offset > toReturn.total) {
|
|
||||||
// In this case, toReturn.data is an empty array.
|
|
||||||
toReturn.offset = offset = toReturn.total;
|
|
||||||
toReturn.data = [];
|
|
||||||
} else {
|
|
||||||
// We need to use natural sort before slicing.
|
|
||||||
const sorted = obj.sort((a, b) => {
|
|
||||||
return naturalSortCaseInsensitive(a[sortOn], b[sortOn]);
|
|
||||||
});
|
|
||||||
const sliced = sorted.slice(offset, offset + size);
|
|
||||||
toReturn.data = sliced.map(object => this.toStoreObject(object));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return toReturn;
|
return toReturn;
|
||||||
},
|
},
|
||||||
|
@ -2358,15 +2354,15 @@ var indexedDBHelpers = {
|
||||||
objectStore: objectStore,
|
objectStore: objectStore,
|
||||||
id: id,
|
id: id,
|
||||||
index: options.index,
|
index: options.index,
|
||||||
offset: 0,
|
offset: options.offset,
|
||||||
size: options.size
|
size: options.size
|
||||||
});
|
});
|
||||||
return this.backToChild("getValuesForHost", {result: result});
|
return this.backToChild("getValuesForHost", {result: result});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all or requested entries from a particular objectStore from the db
|
* Returns requested entries (or at most MAX_STORE_OBJECT_COUNT) from a particular
|
||||||
* in the given host.
|
* objectStore from the db in the given host.
|
||||||
*
|
*
|
||||||
* @param {string} host
|
* @param {string} host
|
||||||
* The given host.
|
* The given host.
|
||||||
|
|
Загрузка…
Ссылка в новой задаче