Bug 1497725 - Add a search field to the new "about:config" page. r=paolo
authorLuke Schwalfenberg <lschwalfenberg@gmail.com>
Mon, 19 Nov 2018 13:52:08 +0000
changeset 488764 4ef55dde9b9310f0f1060943700a76955b94d688
parent 488763 58d0df7129383a0984e87ea333d6b6ea198a8b55
child 488765 640b09ec036ea40e164b2193172bf247475d9930
child 488783 62c4741625fed62804f105d8d979f4b5b3d0f191
push id131
push usersfraser@mozilla.com
push dateTue, 20 Nov 2018 10:19:35 +0000
reviewerspaolo
bugs1497725
milestone65.0a1
Bug 1497725 - Add a search field to the new "about:config" page. r=paolo Differential Revision: https://phabricator.services.mozilla.com/D11843
browser/components/aboutconfig/content/aboutconfig.css
browser/components/aboutconfig/content/aboutconfig.html
browser/components/aboutconfig/content/aboutconfig.js
browser/components/aboutconfig/content/aboutconfig.notftl
browser/components/aboutconfig/test/browser/browser.ini
browser/components/aboutconfig/test/browser/browser_search.js
--- a/browser/components/aboutconfig/content/aboutconfig.css
+++ b/browser/components/aboutconfig/content/aboutconfig.css
@@ -1,12 +1,26 @@
 /* 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/. */
 
+#search {
+  position: sticky;
+  top: 0;
+  margin: 10px;
+  box-sizing: border-box;
+  width: calc(100% - 20px);
+  min-width: 644px;
+  background-image: url("chrome://global/skin/icons/search-textbox.svg");
+  background-repeat: no-repeat;
+  background-position: 9px center;
+  background-size: 12px 12px;
+  padding-left: 30px;
+}
+
 #prefs {
   background-color: var(--in-content-box-background);
   color: var(--in-content-text-color);
   margin: 10px;
   min-width: 644px;
   /* To stay consistent with about:preferences (664px - 20px margin). */
   border: 1px solid var(--in-content-box-border-color);
   border-radius: 2px;
--- a/browser/components/aboutconfig/content/aboutconfig.html
+++ b/browser/components/aboutconfig/content/aboutconfig.html
@@ -11,11 +11,12 @@
     <link rel="stylesheet" type="text/css"
           href="chrome://browser/content/aboutconfig/aboutconfig.css">
     <link rel="localization" href="browser/aboutConfig.ftl">
     <script type="application/javascript"
             src="chrome://browser/content/aboutconfig/aboutconfig.js"></script>
     <title data-l10n-id="about-config-title"></title>
   </head>
   <body onload="onLoad();">
+    <input type="text" id="search" data-l10n-id="about-config-search">
     <table id="prefs"></table>
   </body>
 </html>
--- a/browser/components/aboutconfig/content/aboutconfig.js
+++ b/browser/components/aboutconfig/content/aboutconfig.js
@@ -24,18 +24,35 @@ function onLoad() {
     } catch (ex) {
       pref.value = "";
     }
     return pref;
   });
 
   gPrefArray.sort((a, b) => a.name > b.name);
 
+  document.getElementById("search").addEventListener("keypress", function(e) {
+    if (e.code == "Enter") {
+      filterPrefs();
+    }
+  });
+
+  document.getElementById("prefs").appendChild(createPrefsFragment(gPrefArray));
+}
+
+function filterPrefs() {
+  let substring = document.getElementById("search").value.trim();
+  let fragment = createPrefsFragment(gPrefArray.filter(pref => pref.name.includes(substring)));
+  document.getElementById("prefs").textContent = "";
+  document.getElementById("prefs").appendChild(fragment);
+}
+
+function createPrefsFragment(prefArray) {
   let fragment = document.createDocumentFragment();
-  for (let pref of gPrefArray) {
+  for (let pref of prefArray) {
     let row = document.createElement("tr");
     if (pref.hasUserValue) {
       row.classList.add("has-user-value");
     }
     row.setAttribute("aria-label", pref.name);
 
     let nameCell = document.createElement("td");
     // Add <wbr> behind dots to prevent line breaking in random mid-word places.
@@ -48,10 +65,10 @@ function onLoad() {
 
     let valueCell = document.createElement("td");
     valueCell.classList.add("cell-value");
     valueCell.textContent = pref.value;
     row.appendChild(valueCell);
 
     fragment.appendChild(row);
   }
-  document.getElementById("prefs").appendChild(fragment);
+  return fragment;
 }
--- a/browser/components/aboutconfig/content/aboutconfig.notftl
+++ b/browser/components/aboutconfig/content/aboutconfig.notftl
@@ -1,5 +1,8 @@
 # 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/.
 
 about-config-title = about:config
+
+about-config-search =
+    .placeholder = Search
--- a/browser/components/aboutconfig/test/browser/browser.ini
+++ b/browser/components/aboutconfig/test/browser/browser.ini
@@ -1,3 +1,5 @@
 [DEFAULT]
 
 [browser_basic.js]
+[browser_search.js]
+skip-if = debug # Bug 1507747
new file mode 100644
--- /dev/null
+++ b/browser/components/aboutconfig/test/browser/browser_search.js
@@ -0,0 +1,77 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+ChromeUtils.import("resource://gre/modules/Preferences.jsm", this);
+
+const PAGE_URL = "chrome://browser/content/aboutconfig/aboutconfig.html";
+
+add_task(async function setup() {
+  await SpecialPowers.pushPrefEnv({
+    set: [
+      ["test.aboutconfig.a", "test value 1"],
+      ["test.aboutconfig.ab", "test value 2"],
+      ["test.aboutconfig.b", "test value 3"],
+    ],
+  });
+});
+
+add_task(async function test_search() {
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: PAGE_URL,
+  }, async browser => {
+    let prefArray = Services.prefs.getChildList("");
+
+    // Test page loaded with correct number of prefs.
+    await ContentTask.spawn(browser, prefArray, aPrefArray => {
+      Assert.equal(content.document.getElementById("prefs").childElementCount,
+                   aPrefArray.length);
+
+      // Test page search of "button" returns correct number of preferences.
+      let search = content.document.getElementById("search");
+      search.value = "button   ";
+      search.focus();
+    });
+
+    EventUtils.sendKey("return");
+    await ContentTask.spawn(browser, prefArray, aPrefArray => {
+      let filteredPrefArray =
+          aPrefArray.filter(pref => pref.includes("button"));
+      Assert.equal(content.document.getElementById("prefs").childElementCount,
+                   filteredPrefArray.length);
+
+      // Test empty search returns all preferences.
+      let search = content.document.getElementById("search");
+      search.value = "";
+      search.focus();
+    });
+
+    EventUtils.sendKey("return");
+    await ContentTask.spawn(browser, prefArray, aPrefArray => {
+      Assert.equal(content.document.getElementById("prefs").childElementCount,
+                   aPrefArray.length);
+
+      // Test invalid search returns no preferences.
+      let search = content.document.getElementById("search");
+      search.value = "aJunkValueasdf";
+      search.focus();
+    });
+
+    EventUtils.sendKey("return");
+    await ContentTask.spawn(browser, prefArray, aPrefArray => {
+      Assert.equal(content.document.getElementById("prefs").childElementCount,
+                   0);
+
+      // Test added preferences search returns 2 preferences.
+      let search = content.document.getElementById("search");
+      search.value = "test.aboutconfig.a";
+      search.focus();
+    });
+
+    EventUtils.sendKey("return");
+    await ContentTask.spawn(browser, prefArray, aPrefArray => {
+      Assert.equal(content.document.getElementById("prefs").childElementCount,
+                   2);
+    });
+  });
+});