From 0f6622a9e9b3c55cd1c1e104f63b9c98e0c9eed2 Mon Sep 17 00:00:00 2001 From: "Fischer.json" Date: Mon, 19 Dec 2016 14:26:21 +0800 Subject: [PATCH] Bug 1323391 - Sort sites listed in Settings of Site Data, r=Gijs MozReview-Commit-ID: ExHvd6OJNF7 --HG-- extra : rebase_source : b2db5d0fffebdd83ed118c1e09004404d4d6345a --- .../tests/browser_advanced_siteData.js | 155 +++++++++++++++++- .../preferences/siteDataSettings.js | 66 ++++++-- .../preferences/siteDataSettings.xul | 6 +- 3 files changed, 212 insertions(+), 15 deletions(-) diff --git a/browser/components/preferences/in-content/tests/browser_advanced_siteData.js b/browser/components/preferences/in-content/tests/browser_advanced_siteData.js index b5b71f0062e7..72178050889c 100644 --- a/browser/components/preferences/in-content/tests/browser_advanced_siteData.js +++ b/browser/components/preferences/in-content/tests/browser_advanced_siteData.js @@ -33,6 +33,58 @@ const mockOfflineAppCacheHelper = { } }; +const mockSiteDataManager = { + sites: new Map([ + [ + "https://shopping.xyz.com/", + { + usage: 102400, + host: "shopping.xyz.com", + status: Ci.nsIPermissionManager.ALLOW_ACTION + } + ], + [ + "https://music.bar.com/", + { + usage: 10240, + host: "music.bar.com", + status: Ci.nsIPermissionManager.ALLOW_ACTION + } + ], + [ + "https://news.foo.com/", + { + usage: 1024, + host: "news.foo.com", + status: Ci.nsIPermissionManager.DENY_ACTION + } + ] + ]), + + _originalGetSites: null, + + getSites() { + let list = []; + this.sites.forEach((data, origin) => { + list.push({ + usage: data.usage, + status: data.status, + uri: NetUtil.newURI(origin) + }); + }); + return Promise.resolve(list); + }, + + register() { + this._originalGetSites = SiteDataManager.getSites; + SiteDataManager.getSites = this.getSites.bind(this); + }, + + unregister() { + SiteDataManager.getSites = this._originalGetSites; + } +}; + function addPersistentStoragePerm(origin) { let uri = NetUtil.newURI(origin); let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {}); @@ -91,7 +143,7 @@ add_task(function* () { yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_BASE_URL + "site_data_test.html"); yield waitForEvent(gBrowser.selectedBrowser.contentWindow, "test-indexedDB-done"); - gBrowser.removeCurrentTab(); + yield BrowserTestUtils.removeTab(gBrowser.selectedTab); yield openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true }); @@ -151,5 +203,104 @@ add_task(function* () { is(totalUsage, 0, "The total usage should be removed"); // Test accepting "Clear All Data" ends - gBrowser.removeCurrentTab(); + yield BrowserTestUtils.removeTab(gBrowser.selectedTab); }); + +add_task(function* () { + yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]}); + + mockSiteDataManager.register(); + let updatePromise = promiseSitesUpdated(); + yield openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true }); + yield updatePromise; + + // Open the siteDataSettings subdialog + let doc = gBrowser.selectedBrowser.contentDocument; + let settingsBtn = doc.getElementById("siteDataSettings"); + let dialogOverlay = doc.getElementById("dialogOverlay"); + let dialogPromise = promiseLoadSubDialog("chrome://browser/content/preferences/siteDataSettings.xul"); + settingsBtn.doCommand(); + yield dialogPromise; + is(dialogOverlay.style.visibility, "visible", "The dialog should be visible"); + + let dialogFrame = doc.getElementById("dialogFrame"); + let frameDoc = dialogFrame.contentDocument; + let hostCol = frameDoc.getElementById("hostCol"); + let usageCol = frameDoc.getElementById("usageCol"); + let statusCol = frameDoc.getElementById("statusCol"); + let sitesList = frameDoc.getElementById("sitesList"); + let mockSites = mockSiteDataManager.sites; + + // Test default sorting + assertSortByHost("ascending"); + + // Test sorting on the host column + hostCol.click(); + assertSortByHost("descending"); + hostCol.click(); + assertSortByHost("ascending"); + + // Test sorting on the permission status column + statusCol.click(); + assertSortByStatus("ascending"); + statusCol.click(); + assertSortByStatus("descending"); + + // Test sorting on the usage column + usageCol.click(); + assertSortByUsage("ascending"); + usageCol.click(); + assertSortByUsage("descending"); + + mockSiteDataManager.unregister(); + yield BrowserTestUtils.removeTab(gBrowser.selectedTab); + + function assertSortByHost(order) { + let siteItems = sitesList.getElementsByTagName("richlistitem"); + for (let i = 0; i < siteItems.length - 1; ++i) { + let aOrigin = siteItems[i].getAttribute("data-origin"); + let bOrigin = siteItems[i + 1].getAttribute("data-origin"); + let a = mockSites.get(aOrigin); + let b = mockSites.get(bOrigin); + let result = a.host.localeCompare(b.host); + if (order == "ascending") { + Assert.lessOrEqual(result, 0, "Should sort sites in the ascending order by host"); + } else { + Assert.greaterOrEqual(result, 0, "Should sort sites in the descending order by host"); + } + } + } + + function assertSortByStatus(order) { + let siteItems = sitesList.getElementsByTagName("richlistitem"); + for (let i = 0; i < siteItems.length - 1; ++i) { + let aOrigin = siteItems[i].getAttribute("data-origin"); + let bOrigin = siteItems[i + 1].getAttribute("data-origin"); + let a = mockSites.get(aOrigin); + let b = mockSites.get(bOrigin); + let result = a.status - b.status; + if (order == "ascending") { + Assert.lessOrEqual(result, 0, "Should sort sites in the ascending order by permission status"); + } else { + Assert.greaterOrEqual(result, 0, "Should sort sites in the descending order by permission status"); + } + } + } + + function assertSortByUsage(order) { + let siteItems = sitesList.getElementsByTagName("richlistitem"); + for (let i = 0; i < siteItems.length - 1; ++i) { + let aOrigin = siteItems[i].getAttribute("data-origin"); + let bOrigin = siteItems[i + 1].getAttribute("data-origin"); + let a = mockSites.get(aOrigin); + let b = mockSites.get(bOrigin); + let result = a.usage - b.usage; + if (order == "ascending") { + Assert.lessOrEqual(result, 0, "Should sort sites in the ascending order by usage"); + } else { + Assert.greaterOrEqual(result, 0, "Should sort sites in the descending order by usage"); + } + } + } +}); + diff --git a/browser/components/preferences/siteDataSettings.js b/browser/components/preferences/siteDataSettings.js index 7a24289056cc..3de805e61308 100644 --- a/browser/components/preferences/siteDataSettings.js +++ b/browser/components/preferences/siteDataSettings.js @@ -25,27 +25,68 @@ let gSiteDataSettings = { _list: null, init() { + function setEventListener(id, eventType, callback) { + document.getElementById(id) + .addEventListener(eventType, callback.bind(gSiteDataSettings)); + } + this._list = document.getElementById("sitesList"); SiteDataManager.getSites().then(sites => { this._sites = sites; - this._sortSites(this._sites, "decending"); + let sortCol = document.getElementById("hostCol"); + this._sortSites(this._sites, sortCol); this._buildSitesList(this._sites); }); + + setEventListener("hostCol", "click", this.onClickTreeCol); + setEventListener("usageCol", "click", this.onClickTreeCol); + setEventListener("statusCol", "click", this.onClickTreeCol); }, /** - * Sort sites by usages - * * @param sites {Array} - * @param order {String} indicate to sort in the "decending" or "ascending" order + * @param col {XULElement} the being sorted on */ - _sortSites(sites, order) { - sites.sort((a, b) => { - if (order === "ascending") { - return a.usage - b.usage; - } - return b.usage - a.usage; + _sortSites(sites, col) { + let isCurrentSortCol = col.getAttribute("data-isCurrentSortCol") + let sortDirection = col.getAttribute("data-last-sortDirection") || "ascending"; + if (isCurrentSortCol) { + // Sort on the current column, flip the sorting direction + sortDirection = sortDirection === "ascending" ? "descending" : "ascending"; + } + + let sortFunc = null; + switch (col.id) { + case "hostCol": + sortFunc = (a, b) => { + let aHost = a.uri.host.toLowerCase(); + let bHost = b.uri.host.toLowerCase(); + return aHost.localeCompare(bHost); + } + break; + + case "statusCol": + sortFunc = (a, b) => a.status - b.status; + break; + + case "usageCol": + sortFunc = (a, b) => a.usage - b.usage; + break; + } + if (sortDirection === "descending") { + sites.sort((a, b) => sortFunc(b, a)); + } else { + sites.sort(sortFunc); + } + + let cols = this._list.querySelectorAll("treecol"); + cols.forEach(c => { + c.removeAttribute("sortDirection"); + c.removeAttribute("data-isCurrentSortCol"); }); + col.setAttribute("data-isCurrentSortCol", true); + col.setAttribute("sortDirection", sortDirection); + col.setAttribute("data-last-sortDirection", sortDirection); }, _buildSitesList(sites) { @@ -65,5 +106,10 @@ let gSiteDataSettings = { item.setAttribute("usage", prefStrBundle.getFormattedString("siteUsage", size)); this._list.appendChild(item); } + }, + + onClickTreeCol(e) { + this._sortSites(this._sites, e.target); + this._buildSitesList(this._sites); } }; diff --git a/browser/components/preferences/siteDataSettings.xul b/browser/components/preferences/siteDataSettings.xul index 06f98f284c3b..addb12816b42 100644 --- a/browser/components/preferences/siteDataSettings.xul +++ b/browser/components/preferences/siteDataSettings.xul @@ -28,9 +28,9 @@ - - - + + +