Bug 1312380 - Should be able to remove data of all sites visible on the list in Settings of Site Data, r=jaws
MozReview-Commit-ID: 5hkmYLGGkue
--- a/browser/components/preferences/in-content/tests/browser_advanced_siteData.js
+++ b/browser/components/preferences/in-content/tests/browser_advanced_siteData.js
@@ -7,16 +7,17 @@ const { classes: Cc, interfaces: Ci, uti
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
/* import-globals-from ../../../../../testing/modules/sinon-1.16.1.js */
Services.scriptloader.loadSubScript("resource://testing-common/sinon-1.16.1.js");
const TEST_HOST = "example.com";
const TEST_ORIGIN = "http://" + TEST_HOST;
const TEST_BASE_URL = TEST_ORIGIN + "/browser/browser/components/preferences/in-content/tests/";
+const REMOVE_DIALOG_URL = "chrome://browser/content/preferences/siteDataRemoveSelected.xul";
const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
const { SiteDataManager } = Cu.import("resource:///modules/SiteDataManager.jsm", {});
const { OfflineAppCacheHelper } = Cu.import("resource:///modules/offlineAppCache.jsm", {});
const mockOfflineAppCacheHelper = {
clear: null,
@@ -182,16 +183,32 @@ function promiseSitesUpdated() {
}
function promiseCookiesCleared() {
return TestUtils.topicObserved("cookie-changed", (subj, data) => {
return data === "cleared";
});
}
+function assertSitesListed(doc, origins) {
+ let frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ let removeBtn = frameDoc.getElementById("removeSelected");
+ let removeAllBtn = frameDoc.getElementById("removeAll");
+ let sitesList = frameDoc.getElementById("sitesList");
+ let totalSitesNumber = sitesList.getElementsByTagName("richlistitem").length;
+ is(totalSitesNumber, origins.length, "Should list the right sites number");
+ origins.forEach(origin => {
+ let site = sitesList.querySelector(`richlistitem[data-origin="${origin}"]`);
+ let host = site.getAttribute("host");
+ ok(origin.includes(host), `Should list the site of ${origin}`);
+ });
+ is(removeBtn.disabled, false, "Should enable the removeSelected button");
+ is(removeAllBtn.disabled, false, "Should enable the removeAllBtn button");
+}
+
registerCleanupFunction(function() {
delete window.sinon;
delete window.setImmediate;
delete window.clearImmediate;
mockOfflineAppCacheHelper.unregister();
});
add_task(function* () {
@@ -365,38 +382,28 @@ add_task(function* () {
let doc = gBrowser.selectedBrowser.contentDocument;
let frameDoc = doc.getElementById("dialogFrame").contentDocument;
let searchBox = frameDoc.getElementById("searchBox");
let mockOrigins = Array.from(mockSiteDataManager.sites.keys());
searchBox.value = "xyz";
searchBox.doCommand();
- assertSitesListed(mockOrigins.filter(o => o.includes("xyz")));
+ assertSitesListed(doc, mockOrigins.filter(o => o.includes("xyz")));
searchBox.value = "bar";
searchBox.doCommand();
- assertSitesListed(mockOrigins.filter(o => o.includes("bar")));
+ assertSitesListed(doc, mockOrigins.filter(o => o.includes("bar")));
searchBox.value = "";
searchBox.doCommand();
- assertSitesListed(mockOrigins);
+ assertSitesListed(doc, mockOrigins);
mockSiteDataManager.unregister();
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
-
- function assertSitesListed(origins) {
- let sitesList = frameDoc.getElementById("sitesList");
- let totalSitesNumber = sitesList.getElementsByTagName("richlistitem").length;
- is(totalSitesNumber, origins.length, "Should list the right sites number");
- origins.forEach(origin => {
- let site = sitesList.querySelector(`richlistitem[data-origin="${origin}"]`);
- ok(site instanceof XULElement, `Should list the site of ${origin}`);
- });
- }
});
// Test selecting and removing all sites one by one
add_task(function* () {
yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
let fakeOrigins = [
"https://news.foo.com/",
"https://mails.bar.com/",
@@ -473,29 +480,33 @@ add_task(function* () {
sites[i].click();
removeBtn.doCommand();
}
}
function assertAllSitesListed() {
frameDoc = doc.getElementById("dialogFrame").contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
+ let removeAllBtn = frameDoc.getElementById("removeAll");
let sitesList = frameDoc.getElementById("sitesList");
let sites = sitesList.getElementsByTagName("richlistitem");
is(sites.length, fakeOrigins.length, "Should list all sites");
is(removeBtn.disabled, false, "Should enable the removeSelected button");
+ is(removeAllBtn.disabled, false, "Should enable the removeAllBtn button");
}
function assertAllSitesNotListed() {
frameDoc = doc.getElementById("dialogFrame").contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
+ let removeAllBtn = frameDoc.getElementById("removeAll");
let sitesList = frameDoc.getElementById("sitesList");
let sites = sitesList.getElementsByTagName("richlistitem");
is(sites.length, 0, "Should not list all sites");
is(removeBtn.disabled, true, "Should disable the removeSelected button");
+ is(removeAllBtn.disabled, true, "Should disable the removeAllBtn button");
}
});
// Test selecting and removing partial sites
add_task(function* () {
yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
let fakeOrigins = [
"https://news.foo.com/",
@@ -507,63 +518,62 @@ add_task(function* () {
];
fakeOrigins.forEach(origin => addPersistentStoragePerm(origin));
let updatePromise = promiseSitesUpdated();
yield openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
yield updatePromise;
yield openSettingsDialog();
- const removeDialogURL = "chrome://browser/content/preferences/siteDataRemoveSelected.xul";
let doc = gBrowser.selectedBrowser.contentDocument;
let frameDoc = null;
let saveBtn = null;
let cancelBtn = null;
let removeDialogOpenPromise = null;
let settingsDialogClosePromise = null;
// Test the initial state
- assertSitesListed(fakeOrigins);
+ assertSitesListed(doc, fakeOrigins);
// Test the "Cancel" button
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = doc.getElementById("dialogFrame").contentDocument;
cancelBtn = frameDoc.getElementById("cancel");
removeSelectedSite(fakeOrigins.slice(0, 4));
- assertSitesListed(fakeOrigins.slice(4));
+ assertSitesListed(doc, fakeOrigins.slice(4));
cancelBtn.doCommand();
yield settingsDialogClosePromise;
yield openSettingsDialog();
- assertSitesListed(fakeOrigins);
+ assertSitesListed(doc, fakeOrigins);
// Test the "Save Changes" button but canceling save
- removeDialogOpenPromise = promiseWindowDialogOpen("cancel", removeDialogURL);
+ removeDialogOpenPromise = promiseWindowDialogOpen("cancel", REMOVE_DIALOG_URL);
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = doc.getElementById("dialogFrame").contentDocument;
saveBtn = frameDoc.getElementById("save");
removeSelectedSite(fakeOrigins.slice(0, 4));
- assertSitesListed(fakeOrigins.slice(4));
+ assertSitesListed(doc, fakeOrigins.slice(4));
saveBtn.doCommand();
yield removeDialogOpenPromise;
yield settingsDialogClosePromise;
yield openSettingsDialog();
- assertSitesListed(fakeOrigins);
+ assertSitesListed(doc, fakeOrigins);
// Test the "Save Changes" button and accepting save
- removeDialogOpenPromise = promiseWindowDialogOpen("accept", removeDialogURL);
+ removeDialogOpenPromise = promiseWindowDialogOpen("accept", REMOVE_DIALOG_URL);
settingsDialogClosePromise = promiseSettingsDialogClose();
frameDoc = doc.getElementById("dialogFrame").contentDocument;
saveBtn = frameDoc.getElementById("save");
removeSelectedSite(fakeOrigins.slice(0, 4));
- assertSitesListed(fakeOrigins.slice(4));
+ assertSitesListed(doc, fakeOrigins.slice(4));
saveBtn.doCommand();
yield removeDialogOpenPromise;
yield settingsDialogClosePromise;
yield openSettingsDialog();
- assertSitesListed(fakeOrigins.slice(4));
+ assertSitesListed(doc, fakeOrigins.slice(4));
// Always clean up the fake origins
fakeOrigins.forEach(origin => removePersistentStoragePerm(origin));
yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
function removeSelectedSite(origins) {
frameDoc = doc.getElementById("dialogFrame").contentDocument;
let removeBtn = frameDoc.getElementById("removeSelected");
@@ -573,22 +583,53 @@ add_task(function* () {
if (site) {
site.click();
removeBtn.doCommand();
} else {
ok(false, `Should not select and remove inexisted site of ${origin}`);
}
});
}
+});
- function assertSitesListed(origins) {
- frameDoc = doc.getElementById("dialogFrame").contentDocument;
- let removeBtn = frameDoc.getElementById("removeSelected");
- let sitesList = frameDoc.getElementById("sitesList");
- let totalSitesNumber = sitesList.getElementsByTagName("richlistitem").length;
- is(totalSitesNumber, origins.length, "Should list the right sites number");
- origins.forEach(origin => {
- let site = sitesList.querySelector(`richlistitem[data-origin="${origin}"]`);
- ok(!!site, `Should list the site of ${origin}`);
- });
- is(removeBtn.disabled, false, "Should enable the removeSelected button");
- }
+add_task(function* () {
+ yield SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
+ let fakeOrigins = [
+ "https://news.foo.com/",
+ "https://books.foo.com/",
+ "https://mails.bar.com/",
+ "https://account.bar.com/",
+ "https://videos.xyz.com/",
+ "https://shopping.xyz.com/"
+ ];
+ fakeOrigins.forEach(origin => addPersistentStoragePerm(origin));
+
+ let updatePromise = promiseSitesUpdated();
+ yield openPreferencesViaOpenPreferencesAPI("advanced", "networkTab", { leaveOpen: true });
+ yield updatePromise;
+ yield openSettingsDialog();
+
+ // Search "foo" to only list foo.com sites
+ let doc = gBrowser.selectedBrowser.contentDocument;
+ let frameDoc = doc.getElementById("dialogFrame").contentDocument;
+ let searchBox = frameDoc.getElementById("searchBox");
+ searchBox.value = "foo";
+ searchBox.doCommand();
+ assertSitesListed(doc, fakeOrigins.slice(0, 2));
+
+ // Test only removing all visible sites listed
+ updatePromise = promiseSitesUpdated();
+ let acceptRemovePromise = promiseWindowDialogOpen("accept", REMOVE_DIALOG_URL);
+ let settingsDialogClosePromise = promiseSettingsDialogClose();
+ let removeAllBtn = frameDoc.getElementById("removeAll");
+ let saveBtn = frameDoc.getElementById("save");
+ removeAllBtn.doCommand();
+ saveBtn.doCommand();
+ yield acceptRemovePromise;
+ yield settingsDialogClosePromise;
+ yield updatePromise;
+ yield openSettingsDialog();
+ assertSitesListed(doc, fakeOrigins.slice(2));
+
+ // Always clean up the fake origins
+ fakeOrigins.forEach(origin => removePersistentStoragePerm(origin));
+ yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
});
--- a/browser/components/preferences/siteDataSettings.js
+++ b/browser/components/preferences/siteDataSettings.js
@@ -35,33 +35,35 @@ let gSiteDataSettings = {
this._list = document.getElementById("sitesList");
this._searchBox = document.getElementById("searchBox");
SiteDataManager.getSites().then(sites => {
this._sites = sites;
let sortCol = document.getElementById("hostCol");
this._sortSites(this._sites, sortCol);
this._buildSitesList(this._sites);
- this._updateButtonsState();
Services.obs.notifyObservers(null, "sitedata-settings-init", null);
});
setEventListener("hostCol", "click", this.onClickTreeCol);
setEventListener("usageCol", "click", this.onClickTreeCol);
setEventListener("statusCol", "click", this.onClickTreeCol);
- setEventListener("searchBox", "command", this.onCommandSearch);
setEventListener("cancel", "command", this.close);
setEventListener("save", "command", this.saveChanges);
- setEventListener("removeSelected", "command", this.removeSelected);
+ setEventListener("searchBox", "command", this.onCommandSearch);
+ setEventListener("removeAll", "command", this.onClickRemoveAll);
+ setEventListener("removeSelected", "command", this.onClickRemoveSelected);
},
_updateButtonsState() {
let items = this._list.getElementsByTagName("richlistitem");
- let removeBtn = document.getElementById("removeSelected");
- removeBtn.disabled = !(items.length > 0);
+ let removeSelectedBtn = document.getElementById("removeSelected");
+ let removeAllBtn = document.getElementById("removeAll");
+ removeSelectedBtn.disabled = items.length == 0;
+ removeAllBtn.disabled = removeSelectedBtn.disabled;
},
/**
* @param sites {Array}
* @param col {XULElement} the <treecol> being sorted on
*/
_sortSites(sites, col) {
let isCurrentSortCol = col.getAttribute("data-isCurrentSortCol")
@@ -131,40 +133,32 @@ let gSiteDataSettings = {
let size = DownloadUtils.convertByteUnits(data.usage);
let item = document.createElement("richlistitem");
item.setAttribute("data-origin", data.uri.spec);
item.setAttribute("host", host);
item.setAttribute("status", prefStrBundle.getString(statusStrId));
item.setAttribute("usage", prefStrBundle.getFormattedString("siteUsage", size));
this._list.appendChild(item);
}
- },
-
- onClickTreeCol(e) {
- this._sortSites(this._sites, e.target);
- this._buildSitesList(this._sites);
+ this._updateButtonsState();
},
- onCommandSearch() {
- this._buildSitesList(this._sites);
- },
-
- removeSelected() {
- let selected = this._list.selectedItem;
- if (selected) {
- let origin = selected.getAttribute("data-origin");
+ _removeSiteItems(items) {
+ for (let i = items.length - 1; i >= 0; --i) {
+ let item = items[i];
+ let origin = item.getAttribute("data-origin");
for (let site of this._sites) {
if (site.uri.spec === origin) {
site.userAction = "remove";
break;
}
}
- this._list.removeChild(selected);
- this._updateButtonsState();
+ item.remove();
}
+ this._updateButtonsState();
},
saveChanges() {
let allowed = true;
// Confirm user really wants to remove site data starts
let removals = [];
this._sites = this._sites.filter(site => {
@@ -230,10 +224,33 @@ let gSiteDataSettings = {
}
// Confirm user really wants to remove site data ends
this.close();
},
close() {
window.close();
+ },
+
+ onClickTreeCol(e) {
+ this._sortSites(this._sites, e.target);
+ this._buildSitesList(this._sites);
+ },
+
+ onCommandSearch() {
+ this._buildSitesList(this._sites);
+ },
+
+ onClickRemoveSelected() {
+ let selected = this._list.selectedItem;
+ if (selected) {
+ this._removeSiteItems([selected]);
+ }
+ },
+
+ onClickRemoveAll() {
+ let siteItems = this._list.getElementsByTagName("richlistitem");
+ if (siteItems.length > 0) {
+ this._removeSiteItems(siteItems);
+ }
}
};
--- a/browser/components/preferences/siteDataSettings.xul
+++ b/browser/components/preferences/siteDataSettings.xul
@@ -39,16 +39,17 @@
<treecol flex="2" width="50" label="&statusCol.label;" id="statusCol"/>
<treecol flex="1" width="50" label="&usageCol.label;" id="usageCol"/>
</listheader>
</richlistbox>
</vbox>
<hbox align="start">
<button id="removeSelected" label="&removeSelected.label;" accesskey="&removeSelected.accesskey;"/>
+ <button id="removeAll" label="&removeAll.label;" accesskey="&removeAll.accesskey;"/>
</hbox>
<vbox align="end">
<hbox>
<button id="cancel" label="&cancel.label;" accesskey="&cancel.accesskey;"/>
<button id="save" label="&save.label;" accesskey="&save.accesskey;"/>
</hbox>
</vbox>
--- a/browser/locales/en-US/chrome/browser/preferences/siteDataSettings.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/siteDataSettings.dtd
@@ -6,15 +6,17 @@
<!ENTITY settings.description "The following websites asked to store site data in your disk. You can specify which websites are allowed to store site data. Default site data is temporary and could be deleted automatically.">
<!ENTITY hostCol.label "Site">
<!ENTITY statusCol.label "Status">
<!ENTITY usageCol.label "Storage">
<!ENTITY search.label "Search:">
<!ENTITY search.accesskey "S">
<!ENTITY removeSelected.label "Remove Selected">
<!ENTITY removeSelected.accesskey "r">
+<!ENTITY removeAll.label "Remove All">
+<!ENTITY removeAll.accesskey "e">
<!ENTITY save.label "Save Changes">
<!ENTITY save.accesskey "a">
<!ENTITY cancel.label "Cancel">
<!ENTITY cancel.accesskey "C">
<!ENTITY removingDialog.title "Removing Site Data">
<!ENTITY removingDialog.description "Removing site data will also remove cookies. This may log you out of websites and remove offline web content. Are you sure you want to make the changes?">
<!ENTITY siteTree.label "The following website cookies will be removed:">