Bug 1312374 - Search sites listed in Settings of Site Data on host, r=Gijs draft
authorFischer.json <fischer.json@gmail.com>
Mon, 09 Jan 2017 11:54:14 +0800
changeset 458930 c801e3661e8ed5d09a729f0c57d2a7cbe4bfc25f
parent 458771 2963cf6be7f830c0d2155e2968cfc53585868a76
child 541794 11c43df883a09370b1135228ebb2699f230fc3c9
push id41113
push userbmo:fliu@mozilla.com
push dateWed, 11 Jan 2017 10:09:02 +0000
reviewersGijs
bugs1312374
milestone53.0a1
Bug 1312374 - Search sites listed in Settings of Site Data on host, r=Gijs MozReview-Commit-ID: J74Jg3xkJNe
browser/components/preferences/in-content/tests/browser_advanced_siteData.js
browser/components/preferences/siteDataSettings.css
browser/components/preferences/siteDataSettings.js
browser/components/preferences/siteDataSettings.xul
browser/locales/en-US/chrome/browser/preferences/siteDataSettings.dtd
--- a/browser/components/preferences/in-content/tests/browser_advanced_siteData.js
+++ b/browser/components/preferences/in-content/tests/browser_advanced_siteData.js
@@ -31,28 +31,52 @@ const mockOfflineAppCacheHelper = {
   unregister() {
     OfflineAppCacheHelper.clear = this.originalClear;
   }
 };
 
 const mockSiteDataManager = {
   sites: new Map([
     [
+      "https://account.xyz.com/",
+      {
+        usage: 1024 * 200,
+        host: "account.xyz.com",
+        status: Ci.nsIPermissionManager.ALLOW_ACTION
+      }
+    ],
+    [
       "https://shopping.xyz.com/",
       {
-        usage: 102400,
+        usage: 1024 * 100,
         host: "shopping.xyz.com",
+        status: Ci.nsIPermissionManager.DENY_ACTION
+      }
+    ],
+    [
+      "https://video.bar.com/",
+      {
+        usage: 1024 * 20,
+        host: "video.bar.com",
         status: Ci.nsIPermissionManager.ALLOW_ACTION
       }
     ],
     [
       "https://music.bar.com/",
       {
-        usage: 10240,
+        usage: 1024 * 10,
         host: "music.bar.com",
+        status: Ci.nsIPermissionManager.DENY_ACTION
+      }
+    ],
+    [
+      "https://books.foo.com/",
+      {
+        usage: 1024 * 2,
+        host: "books.foo.com",
         status: Ci.nsIPermissionManager.ALLOW_ACTION
       }
     ],
     [
       "https://news.foo.com/",
       {
         usage: 1024,
         host: "news.foo.com",
@@ -299,8 +323,54 @@ add_task(function* () {
         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");
       }
     }
   }
 });
 
+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 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")));
+
+  searchBox.value = "bar";
+  searchBox.doCommand();
+  assertSitesListed(mockOrigins.filter(o => o.includes("bar")));
+
+  searchBox.value = "";
+  searchBox.doCommand();
+  assertSitesListed(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}`);
+    });
+  }
+});
--- a/browser/components/preferences/siteDataSettings.css
+++ b/browser/components/preferences/siteDataSettings.css
@@ -1,12 +1,16 @@
 /* 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/. */
 
+#searchBoxContainer {
+  -moz-box-align: center;
+}
+
 #sitesList {
   min-height: 20em;
 }
 
 #sitesList > richlistitem {
   -moz-binding: url("chrome://browser/content/preferences/siteListItem.xml#siteListItem");
 }
 
--- a/browser/components/preferences/siteDataSettings.js
+++ b/browser/components/preferences/siteDataSettings.js
@@ -18,34 +18,37 @@ let gSiteDataSettings = {
 
   // Array of meatdata of sites. Each array element is object holding:
   // - uri: uri of site; instance of nsIURI
   // - status: persistent-storage permission status
   // - usage: disk usage which site uses
   _sites: null,
 
   _list: null,
+  _searchBox: null,
 
   init() {
     function setEventListener(id, eventType, callback) {
       document.getElementById(id)
               .addEventListener(eventType, callback.bind(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);
     });
 
     setEventListener("hostCol", "click", this.onClickTreeCol);
     setEventListener("usageCol", "click", this.onClickTreeCol);
     setEventListener("statusCol", "click", this.onClickTreeCol);
+    setEventListener("searchBox", "command", this.onCommandSearch);
   },
 
   /**
    * @param sites {Array}
    * @param col {XULElement} the <treecol> being sorted on
    */
   _sortSites(sites, col) {
     let isCurrentSortCol = col.getAttribute("data-isCurrentSortCol")
@@ -84,32 +87,46 @@ let gSiteDataSettings = {
       c.removeAttribute("sortDirection");
       c.removeAttribute("data-isCurrentSortCol");
     });
     col.setAttribute("data-isCurrentSortCol", true);
     col.setAttribute("sortDirection", sortDirection);
     col.setAttribute("data-last-sortDirection", sortDirection);
   },
 
+  /**
+   * @param sites {Array} array of metadata of sites
+   */
   _buildSitesList(sites) {
     // Clear old entries.
-    while (this._list.childNodes.length > 1) {
-      this._list.removeChild(this._list.lastChild);
+    let oldItems = this._list.querySelectorAll("richlistitem");
+    for (let item of oldItems) {
+      item.remove();
     }
 
     let prefStrBundle = document.getElementById("bundlePreferences");
+    let keyword = this._searchBox.value.toLowerCase().trim();
     for (let data of sites) {
+      let host = data.uri.host;
+      if (keyword && !host.includes(keyword)) {
+        continue;
+      }
+
       let statusStrId = data.status === Ci.nsIPermissionManager.ALLOW_ACTION ? "important" : "default";
       let size = DownloadUtils.convertByteUnits(data.usage);
       let item = document.createElement("richlistitem");
       item.setAttribute("data-origin", data.uri.spec);
-      item.setAttribute("host", data.uri.host);
+      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);
+  },
+
+  onCommandSearch() {
+    this._buildSitesList(this._sites);
   }
 };
--- a/browser/components/preferences/siteDataSettings.xul
+++ b/browser/components/preferences/siteDataSettings.xul
@@ -21,16 +21,22 @@
 
   <stringbundle id="bundlePreferences"
                 src="chrome://browser/locale/preferences/preferences.properties"/>
 
   <vbox flex="1">
     <description>&settings.description;</description>
     <separator class="thin"/>
 
+    <hbox id="searchBoxContainer">
+      <label accesskey="&search.accesskey;" control="searchBox">&search.label;</label>
+      <textbox id="searchBox" type="search" flex="1"/>
+    </hbox>
+    <separator class="thin"/>
+
     <richlistbox id="sitesList" orient="vertical" flex="1">
       <listheader>
         <treecol flex="4" width="50" label="&hostCol.label;" id="hostCol"/>
         <treecol flex="2" width="50" label="&statusCol.label;" id="statusCol"/>
         <treecol flex="1" width="50" label="&usageCol.label;" id="usageCol"/>
       </listheader>
     </richlistbox>
   </vbox>
--- a/browser/locales/en-US/chrome/browser/preferences/siteDataSettings.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/siteDataSettings.dtd
@@ -2,8 +2,10 @@
    - 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/. -->
 
 <!ENTITY     window.title                  "Settings - Site Data">
 <!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">