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 99e8743744b6..4a80d35aa481 100644 --- a/browser/components/preferences/in-content/tests/browser_advanced_siteData.js +++ b/browser/components/preferences/in-content/tests/browser_advanced_siteData.js @@ -12,6 +12,7 @@ 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", {}); @@ -187,6 +188,22 @@ function promiseCookiesCleared() { }); } +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; @@ -370,28 +387,18 @@ add_task(function* () { 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 @@ -478,19 +485,23 @@ add_task(function* () { 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"); } }); @@ -512,7 +523,6 @@ add_task(function* () { yield updatePromise; yield openSettingsDialog(); - const removeDialogURL = "chrome://browser/content/preferences/siteDataRemoveSelected.xul"; let doc = gBrowser.selectedBrowser.contentDocument; let frameDoc = null; let saveBtn = null; @@ -521,44 +531,44 @@ add_task(function* () { 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)); @@ -578,17 +588,48 @@ add_task(function* () { } }); } - - 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); }); diff --git a/browser/components/preferences/siteDataSettings.js b/browser/components/preferences/siteDataSettings.js index 084d35bf49b2..a8d88d101005 100644 --- a/browser/components/preferences/siteDataSettings.js +++ b/browser/components/preferences/siteDataSettings.js @@ -40,23 +40,25 @@ let gSiteDataSettings = { 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; }, /** @@ -136,30 +138,22 @@ let gSiteDataSettings = { item.setAttribute("usage", prefStrBundle.getFormattedString("siteUsage", size)); this._list.appendChild(item); } + this._updateButtonsState(); }, - onClickTreeCol(e) { - this._sortSites(this._sites, e.target); - this._buildSitesList(this._sites); - }, - - 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() { @@ -235,5 +229,28 @@ let gSiteDataSettings = { 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); + } } }; diff --git a/browser/components/preferences/siteDataSettings.xul b/browser/components/preferences/siteDataSettings.xul index 6dd4904c7bbc..096201cefc57 100644 --- a/browser/components/preferences/siteDataSettings.xul +++ b/browser/components/preferences/siteDataSettings.xul @@ -44,6 +44,7 @@