Bug 1379338 - scriptify preferences XBL; r?jaws draft
authorMyk Melez <myk@mykzilla.org>
Thu, 21 Dec 2017 12:59:32 -0800
changeset 714150 fa1848b4bf8f1b27ddc294d3ee4faea277746585
parent 713529 2ff08db67b917fba1558986f3f2f796260f970f8
child 744542 9339d4d48f011f4fd692d0cc3b23a0c868f2ab55
push id93870
push userbmo:myk@mykzilla.org
push dateThu, 21 Dec 2017 21:00:30 +0000
reviewersjaws
bugs1379338
milestone59.0a1
Bug 1379338 - scriptify preferences XBL; r?jaws Converts the XBL bindings for Preferences to either JS singletons/classes or variants of more general bindings, as appropriate, so that we can remove the XBL bindings from the codebase as part of our XBL removal project. MozReview-Commit-ID: 5YoiOsaVmjF
browser/base/content/sanitize.xul
browser/base/content/sanitizeDialog.js
browser/base/content/test/general/browser_sanitizeDialog.js
browser/base/content/utilityOverlay.js
browser/components/preferences/applicationManager.xul
browser/components/preferences/colors.js
browser/components/preferences/colors.xul
browser/components/preferences/connection.js
browser/components/preferences/connection.xul
browser/components/preferences/donottrack.xul
browser/components/preferences/fonts.js
browser/components/preferences/fonts.xul
browser/components/preferences/in-content/containers.xul
browser/components/preferences/in-content/main.js
browser/components/preferences/in-content/main.xul
browser/components/preferences/in-content/preferences.js
browser/components/preferences/in-content/preferences.xul
browser/components/preferences/in-content/privacy.js
browser/components/preferences/in-content/privacy.xul
browser/components/preferences/in-content/search.js
browser/components/preferences/in-content/search.xul
browser/components/preferences/in-content/sync.js
browser/components/preferences/in-content/sync.xul
browser/components/preferences/in-content/tests/browser_basic_rebuild_fonts_test.js
browser/components/preferences/in-content/tests/browser_bug731866.js
browser/components/preferences/in-content/tests/browser_bug795764_cachedisabled.js
browser/components/preferences/in-content/tests/browser_connection.js
browser/components/preferences/in-content/tests/browser_connection_bug388287.js
browser/components/preferences/in-content/tests/browser_fluent.js
browser/components/preferences/in-content/tests/browser_sanitizeOnShutdown_prefLocked.js
browser/components/preferences/in-content/tests/privacypane_tests_perwindow.js
browser/components/preferences/jar.mn
browser/components/preferences/languages.js
browser/components/preferences/languages.xul
browser/components/preferences/sanitize.js
browser/components/preferences/sanitize.xul
browser/extensions/shield-recipe-client/lib/ShieldPreferences.jsm
browser/locales/en-US/chrome/browser/preferences/donottrack.dtd
browser/locales/jar.mn
browser/themes/linux/preferences/preferences.css
browser/themes/linux/sanitizeDialog.css
browser/themes/osx/preferences/in-content/dialog.css
browser/themes/osx/preferences/preferences.css
browser/themes/osx/sanitizeDialog.css
browser/themes/shared/incontentprefs/dialog.inc.css
browser/themes/shared/incontentprefs/preferences.inc.css
browser/themes/windows/preferences/preferences.css
browser/themes/windows/sanitizeDialog.css
toolkit/content/jar.mn
toolkit/content/preferencesBindings.js
toolkit/content/resetProfile.xul
toolkit/content/tests/chrome/test_preferences.xul
toolkit/content/tests/chrome/test_preferences_beforeaccept.xul
toolkit/content/tests/chrome/test_preferences_onsyncfrompreference.xul
toolkit/content/tests/chrome/window_preferences.xul
toolkit/content/tests/chrome/window_preferences2.xul
toolkit/content/tests/chrome/window_preferences3.xul
toolkit/content/tests/chrome/window_preferences_beforeaccept.xul
toolkit/content/tests/chrome/window_preferences_commandretarget.xul
toolkit/content/tests/chrome/window_preferences_onsyncfrompreference.xul
toolkit/content/widgets/dialog.xml
toolkit/content/widgets/preferences.xml
toolkit/content/xul.css
toolkit/mozapps/preferences/fontbuilder.js
toolkit/themes/linux/global/global.css
toolkit/themes/linux/global/jar.mn
toolkit/themes/linux/global/preferences.css
toolkit/themes/mobile/jar.mn
toolkit/themes/osx/global/global.css
toolkit/themes/osx/global/jar.mn
toolkit/themes/osx/global/preferences.css
toolkit/themes/shared/in-content/common.inc.css
toolkit/themes/windows/global/global.css
toolkit/themes/windows/global/jar.mn
toolkit/themes/windows/global/preferences.css
--- a/browser/base/content/sanitize.xul
+++ b/browser/base/content/sanitize.xul
@@ -1,64 +1,58 @@
 <?xml version="1.0"?>
 
 <!-- -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -->
 <!-- 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/. -->
 
 <?xml-stylesheet href="chrome://global/skin/"?>
+<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
 <?xml-stylesheet href="chrome://browser/skin/sanitizeDialog.css"?>
 
 
 <?xml-stylesheet href="chrome://browser/content/sanitizeDialog.css"?>
 
-<!DOCTYPE prefwindow [
+<!DOCTYPE dialog [
+  <!ENTITY % preferencesDTD SYSTEM "chrome://global/locale/preferences.dtd">
+  <!ENTITY % globalKeysDTD SYSTEM "chrome://global/locale/globalKeys.dtd">
   <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
   <!ENTITY % sanitizeDTD SYSTEM "chrome://browser/locale/sanitize.dtd">
+  %preferencesDTD;
+  %globalKeysDTD;
   %brandDTD;
   %sanitizeDTD;
 ]>
 
-<prefwindow id="SanitizeDialog" type="child"
-            xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-            dlgbuttons="accept,cancel"
-            title="&sanitizeDialog2.title;"
-            noneverythingtitle="&sanitizeDialog2.title;"
-            style="width: &sanitizeDialog2.width;;"
-            ondialogaccept="return gSanitizePromptDialog.sanitize();">
+<dialog id="SanitizeDialog" class="prefwindow" type="child"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        buttons="accept,cancel"
+        persist="lastSelected screenX screenY"
+        closebuttonlabel="&preferencesCloseButton.label;"
+        closebuttonaccesskey="&preferencesCloseButton.accesskey;"
+        role="dialog"
+        title="&sanitizeDialog2.title;"
+        noneverythingtitle="&sanitizeDialog2.title;"
+        style="width: &sanitizeDialog2.width;;"
+        onload="gSanitizePromptDialog.init();"
+        ondialogaccept="return gSanitizePromptDialog.sanitize();">
 
-  <prefpane id="SanitizeDialogPane" onpaneload="gSanitizePromptDialog.init();">
+  <vbox id="SanitizeDialogPane" class="prefpane">
     <stringbundle id="bundleBrowser"
                   src="chrome://browser/locale/browser.properties"/>
 
     <script type="application/javascript"
             src="chrome://browser/content/sanitize.js"/>
 
-
+    <script type="application/javascript"
+            src="chrome://global/content/preferencesBindings.js"/>
     <script type="application/javascript"
             src="chrome://browser/content/sanitizeDialog.js"/>
 
-    <preferences id="sanitizePreferences">
-      <preference id="privacy.cpd.history"               name="privacy.cpd.history"               type="bool"/>
-      <preference id="privacy.cpd.formdata"              name="privacy.cpd.formdata"              type="bool"/>
-      <preference id="privacy.cpd.downloads"             name="privacy.cpd.downloads"             type="bool" disabled="true"/>
-      <preference id="privacy.cpd.cookies"               name="privacy.cpd.cookies"               type="bool"/>
-      <preference id="privacy.cpd.cache"                 name="privacy.cpd.cache"                 type="bool"/>
-      <preference id="privacy.cpd.sessions"              name="privacy.cpd.sessions"              type="bool"/>
-      <preference id="privacy.cpd.offlineApps"           name="privacy.cpd.offlineApps"           type="bool"/>
-      <preference id="privacy.cpd.siteSettings"          name="privacy.cpd.siteSettings"          type="bool"/>
-    </preferences>
-    
-    <preferences id="nonItemPreferences">
-      <preference id="privacy.sanitize.timeSpan"
-                  name="privacy.sanitize.timeSpan"
-                  type="int"/>
-    </preferences>
-
     <hbox id="SanitizeDurationBox" align="center">
       <label value="&clearTimeDuration.label;"
              accesskey="&clearTimeDuration.accesskey;"
              control="sanitizeDurationChoice"
              id="sanitizeDurationLabel"/>
       <menulist id="sanitizeDurationChoice"
                 preference="privacy.sanitize.timeSpan"
                 onselect="gSanitizePromptDialog.selectByTimespan();"
@@ -139,10 +133,10 @@
       <listitem label="&itemSitePreferences.label;"
                 type="checkbox"
                 accesskey="&itemSitePreferences.accesskey;"
                 preference="privacy.cpd.siteSettings"
                 noduration="true"
                 onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
     </listbox>
 
-  </prefpane>
-</prefwindow>
+  </vbox>
+</dialog>
--- a/browser/base/content/sanitizeDialog.js
+++ b/browser/base/content/sanitizeDialog.js
@@ -1,40 +1,46 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* 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/. */
 
+/* import-globals-from ../../../toolkit/content/preferencesBindings.js */
+
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 var Cu = Components.utils;
 
 var {Sanitizer} = Cu.import("resource:///modules/Sanitizer.jsm", {});
 
+Preferences.addAll([
+  { id: "privacy.cpd.history", type: "bool" },
+  { id: "privacy.cpd.formdata", type: "bool" },
+  { id: "privacy.cpd.downloads", type: "bool", disabled: true },
+  { id: "privacy.cpd.cookies", type: "bool" },
+  { id: "privacy.cpd.cache", type: "bool" },
+  { id: "privacy.cpd.sessions", type: "bool" },
+  { id: "privacy.cpd.offlineApps", type: "bool" },
+  { id: "privacy.cpd.siteSettings", type: "bool" },
+  { id: "privacy.sanitize.timeSpan", type: "int" },
+]);
+
 var gSanitizePromptDialog = {
 
   get bundleBrowser() {
     if (!this._bundleBrowser)
       this._bundleBrowser = document.getElementById("bundleBrowser");
     return this._bundleBrowser;
   },
 
   get selectedTimespan() {
     var durList = document.getElementById("sanitizeDurationChoice");
     return parseInt(durList.value);
   },
 
-  get sanitizePreferences() {
-    if (!this._sanitizePreferences) {
-      this._sanitizePreferences =
-        document.getElementById("sanitizePreferences");
-    }
-    return this._sanitizePreferences;
-  },
-
   get warningBox() {
     return document.getElementById("sanitizeEverythingWarningBox");
   },
 
   init() {
     // This is used by selectByTimespan() to determine if the window has loaded.
     this._inited = true;
 
@@ -136,73 +142,72 @@ var gSanitizePromptDialog = {
     }
 
     var warningDesc = document.getElementById("sanitizeEverythingWarning");
     warningDesc.textContent =
       this.bundleBrowser.getString(warningStringID);
   },
 
   /**
+   * Return the boolean prefs that enable/disable clearing of various kinds
+   * of history.  The only pref this excludes is privacy.sanitize.timeSpan.
+   */
+  _getItemPrefs() {
+    return Preferences.getAll().filter(p => p.id !== "privacy.sanitize.timeSpan");
+  },
+
+  /**
    * Called when the value of a preference element is synced from the actual
    * pref.  Enables or disables the OK button appropriately.
    */
   onReadGeneric() {
-    var found = false;
-
-    // Find any other pref that's checked and enabled.
-    var i = 0;
-    while (!found && i < this.sanitizePreferences.childNodes.length) {
-      var preference = this.sanitizePreferences.childNodes[i];
-
-      found = !!preference.value &&
-              !preference.disabled;
-      i++;
-    }
+    // Find any other pref that's checked and enabled (except for
+    // privacy.sanitize.timeSpan, which doesn't affect the button's status).
+    var found = this._getItemPrefs().some(pref => !!pref.value && !pref.disabled);
 
     try {
       document.documentElement.getButton("accept").disabled = !found;
     } catch (e) { }
 
     // Update the warning prompt if needed
     this.prepareWarning(true);
 
     return undefined;
   },
 
   /**
    * Sanitizer.prototype.sanitize() requires the prefs to be up-to-date.
    * Because the type of this prefwindow is "child" -- and that's needed because
    * without it the dialog has no OK and Cancel buttons -- the prefs are not
-   * updated on dialogaccept on platforms that don't support instant-apply
-   * (i.e., Windows).  We must therefore manually set the prefs from their
-   * corresponding preference elements.
+   * updated on dialogaccept.  We must therefore manually set the prefs
+   * from their corresponding preference elements.
    */
   updatePrefs() {
     Sanitizer.prefs.setIntPref("timeSpan", this.selectedTimespan);
 
     // Keep the pref for the download history in sync with the history pref.
-    document.getElementById("privacy.cpd.downloads").value =
-      document.getElementById("privacy.cpd.history").value;
+    Preferences.get("privacy.cpd.downloads").value =
+      Preferences.get("privacy.cpd.history").value;
 
     // Now manually set the prefs from their corresponding preference
     // elements.
-    var prefs = this.sanitizePreferences.rootBranch;
-    for (let i = 0; i < this.sanitizePreferences.childNodes.length; ++i) {
-      var p = this.sanitizePreferences.childNodes[i];
-      prefs.setBoolPref(p.name, p.value);
+    var prefs = this._getItemPrefs();
+    for (let i = 0; i < prefs.length; ++i) {
+      var p = prefs[i];
+      Services.prefs.setBoolPref(p.name, p.value);
     }
   },
 
   /**
    * Check if all of the history items have been selected like the default status.
    */
   hasNonSelectedItems() {
     let checkboxes = document.querySelectorAll("#itemList > [preference]");
     for (let i = 0; i < checkboxes.length; ++i) {
-      let pref = document.getElementById(checkboxes[i].getAttribute("preference"));
+      let pref = Preferences.get(checkboxes[i].getAttribute("preference"));
       if (!pref.value)
         return true;
     }
     return false;
   },
 
   /**
    * Show the history items list.
--- a/browser/base/content/test/general/browser_sanitizeDialog.js
+++ b/browser/base/content/test/general/browser_sanitizeDialog.js
@@ -710,17 +710,17 @@ WindowHelper.prototype = {
 
   /**
    * Makes sure all the checkboxes are checked.
    */
   _checkAllCheckboxesCustom(check) {
     var cb = this.win.document.querySelectorAll("#itemList > [preference]");
     ok(cb.length > 1, "found checkboxes for preferences");
     for (var i = 0; i < cb.length; ++i) {
-      var pref = this.win.document.getElementById(cb[i].getAttribute("preference"));
+      var pref = this.win.Preferences.get(cb[i].getAttribute("preference"));
       if (!!pref.value ^ check)
         cb[i].click();
     }
   },
 
   checkAllCheckboxes() {
     this._checkAllCheckboxesCustom(true);
   },
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -930,17 +930,17 @@ function openHelpLink(aHelpTopic, aCalle
   openUILinkIn(url, where);
 }
 
 function openPrefsHelp() {
   // non-instant apply prefwindows are usually modal, so we can't open in the topmost window,
   // since its probably behind the window.
   var instantApply = getBoolPref("browser.preferences.instantApply");
 
-  var helpTopic = document.getElementsByTagName("prefwindow")[0].currentPane.helpTopic;
+  var helpTopic = document.documentElement.getAttribute("helpTopic");
   openHelpLink(helpTopic, !instantApply);
 }
 
 function trimURL(aURL) {
   // This function must not modify the given URL such that calling
   // nsIURIFixup::createFixupURI with the result will produce a different URI.
 
   // remove single trailing slash for http/https/ftp URLs
--- a/browser/components/preferences/applicationManager.xul
+++ b/browser/components/preferences/applicationManager.xul
@@ -15,16 +15,18 @@
         ondialogcancel="gAppManagerDialog.onCancel();"
         title="&appManager.title;"
         style="&appManager.style;"
         persist="screenX screenY">
 
   <script type="application/javascript"
           src="chrome://browser/content/utilityOverlay.js"/>
   <script type="application/javascript"
+          src="chrome://global/content/preferencesBindings.js"/>
+  <script type="application/javascript"
           src="chrome://browser/content/preferences/applicationManager.js"/>
 
   <commandset id="appManagerCommandSet">
     <command id="cmd_remove"
              oncommand="gAppManagerDialog.remove();"
              disabled="true"/>
   </commandset>
 
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/colors.js
@@ -0,0 +1,15 @@
+/* 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/. */
+
+/* import-globals-from ../../../toolkit/content/preferencesBindings.js */
+
+Preferences.addAll([
+  { id: "browser.display.document_color_use", type: "int" },
+  { id: "browser.anchor_color", type: "string" },
+  { id: "browser.visited_color", type: "string" },
+  { id: "browser.underline_anchors", type: "bool" },
+  { id: "browser.display.foreground_color", type: "string" },
+  { id: "browser.display.background_color", type: "string" },
+  { id: "browser.display.use_system_colors", type: "bool" },
+]);
--- a/browser/components/preferences/colors.xul
+++ b/browser/components/preferences/colors.xul
@@ -1,46 +1,51 @@
 <?xml version="1.0"?>
 
 # -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 # 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/.
 
 <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-#ifdef XP_MACOSX
 <?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
-#endif
 
-<!DOCTYPE prefwindow SYSTEM "chrome://browser/locale/preferences/colors.dtd" >
+<!DOCTYPE dialog [
+  <!ENTITY % preferencesDTD SYSTEM "chrome://global/locale/preferences.dtd">
+  %preferencesDTD;
+  <!ENTITY % colorsDTD SYSTEM "chrome://browser/locale/preferences/colors.dtd">
+  %colorsDTD;
+]>
 
-<prefwindow id="ColorsDialog" type="child"
-            xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-            title="&colorsDialog.title;"
-            dlgbuttons="accept,cancel,help"
-            ondialoghelp="openPrefsHelp()"
+<dialog id="ColorsDialog" type="child" class="prefwindow"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        title="&colorsDialog.title;"
+        buttons="accept,cancel,help"
+        persist="lastSelected screenX screenY"
+        closebuttonlabel="&preferencesCloseButton.label;"
+        closebuttonaccesskey="&preferencesCloseButton.accesskey;"
+        role="dialog"
+        helpTopic="prefs-fonts-and-colors"
+        ondialoghelp="openPrefsHelp()"
 #ifdef XP_MACOSX
-            style="width: &window.macWidth; !important;">
+        style="width: &window.macWidth; !important;">
 #else
-            style="width: &window.width; !important;">
+        style="width: &window.width; !important;">
 #endif
 
   <script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/>
-  <prefpane id="ColorsDialogPane"
-            helpTopic="prefs-fonts-and-colors">
+  <script type="application/javascript" src="chrome://global/content/preferencesBindings.js"/>
 
-    <preferences>
-      <preference id="browser.display.document_color_use"   name="browser.display.document_color_use"   type="int"/>
-      <preference id="browser.anchor_color"                 name="browser.anchor_color"                 type="string"/>
-      <preference id="browser.visited_color"                name="browser.visited_color"                type="string"/>
-      <preference id="browser.underline_anchors"            name="browser.underline_anchors"            type="bool"/>
-      <preference id="browser.display.foreground_color"     name="browser.display.foreground_color"     type="string"/>
-      <preference id="browser.display.background_color"     name="browser.display.background_color"     type="string"/>
-      <preference id="browser.display.use_system_colors"    name="browser.display.use_system_colors"    type="bool"/>
-    </preferences>
+  <keyset>
+    <key key="&windowClose.key;" modifiers="accel" oncommand="Preferences.close(event)"/>
+  </keyset>
+
+  <vbox id="ColorsDialogPane" class="prefpane">
+
+    <script type="application/javascript" src="chrome://browser/content/preferences/colors.js"/>
 
     <hbox>
       <groupbox flex="1">
         <caption><label>&color;</label></caption>
         <hbox align="center">
           <label accesskey="&textColor2.accesskey;" control="foregroundtextmenu">&textColor2.label;</label>
           <spacer flex="1"/>
           <colorpicker type="button" id="foregroundtextmenu" palettename="standard"
@@ -95,10 +100,10 @@
             <menuitem label="&overrideDefaultPageColors.auto.label;"
                       value="0" id="documentColorAutomatic"/>
             <menuitem label="&overrideDefaultPageColors.never.label;"
                       value="1" id="documentColorNever"/>
           </menupopup>
         </menulist>
       </hbox>
     </vbox>
-  </prefpane>
-</prefwindow>
+  </vbox>
+</dialog>
--- a/browser/components/preferences/connection.js
+++ b/browser/components/preferences/connection.js
@@ -1,51 +1,84 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
 /* 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/. */
 
 /* import-globals-from ../../base/content/utilityOverlay.js */
+/* import-globals-from ../../../toolkit/content/preferencesBindings.js */
+
+Preferences.addAll([
+  { id: "network.proxy.type", type: "int" },
+  { id: "network.proxy.http", type: "string" },
+  { id: "network.proxy.http_port", type: "int" },
+  { id: "network.proxy.ftp", type: "string" },
+  { id: "network.proxy.ftp_port", type: "int" },
+  { id: "network.proxy.ssl", type: "string" },
+  { id: "network.proxy.ssl_port", type: "int" },
+  { id: "network.proxy.socks", type: "string" },
+  { id: "network.proxy.socks_port", type: "int" },
+  { id: "network.proxy.socks_version", type: "int" },
+  { id: "network.proxy.socks_remote_dns", type: "bool" },
+  { id: "network.proxy.no_proxies_on", type: "string" },
+  { id: "network.proxy.autoconfig_url", type: "string" },
+  { id: "network.proxy.share_proxy_settings", type: "bool" },
+  { id: "signon.autologin.proxy", type: "bool" },
+  { id: "pref.advanced.proxies.disable_button.reload", type: "bool" },
+  { id: "network.proxy.backup.ftp", type: "string" },
+  { id: "network.proxy.backup.ftp_port", type: "int" },
+  { id: "network.proxy.backup.ssl", type: "string" },
+  { id: "network.proxy.backup.ssl_port", type: "int" },
+  { id: "network.proxy.backup.socks", type: "string" },
+  { id: "network.proxy.backup.socks_port", type: "int" },
+]);
+
+window.addEventListener("DOMContentLoaded", () => {
+  Preferences.get("network.proxy.type").on("change",
+    gConnectionsDialog.proxyTypeChanged.bind(gConnectionsDialog));
+  Preferences.get("network.proxy.socks_version").on("change",
+    gConnectionsDialog.updateDNSPref.bind(gConnectionsDialog));
+}, { once: true, capture: true });
 
 var gConnectionsDialog = {
   beforeAccept() {
-    var proxyTypePref = document.getElementById("network.proxy.type");
+    var proxyTypePref = Preferences.get("network.proxy.type");
     if (proxyTypePref.value == 2) {
       this.doAutoconfigURLFixup();
       return true;
     }
 
     if (proxyTypePref.value != 1)
       return true;
 
-    var httpProxyURLPref = document.getElementById("network.proxy.http");
-    var httpProxyPortPref = document.getElementById("network.proxy.http_port");
-    var shareProxiesPref = document.getElementById("network.proxy.share_proxy_settings");
+    var httpProxyURLPref = Preferences.get("network.proxy.http");
+    var httpProxyPortPref = Preferences.get("network.proxy.http_port");
+    var shareProxiesPref = Preferences.get("network.proxy.share_proxy_settings");
 
     // If the port is 0 and the proxy server is specified, focus on the port and cancel submission.
     for (let prefName of ["http", "ssl", "ftp", "socks"]) {
-      let proxyPortPref = document.getElementById("network.proxy." + prefName + "_port");
-      let proxyPref = document.getElementById("network.proxy." + prefName);
+      let proxyPortPref = Preferences.get("network.proxy." + prefName + "_port");
+      let proxyPref = Preferences.get("network.proxy." + prefName);
       // Only worry about ports which are currently active. If the share option is on, then ignore
       // all ports except the HTTP port
       if (proxyPref.value != "" && proxyPortPref.value == 0 &&
             (prefName == "http" || !shareProxiesPref.value)) {
         document.getElementById("networkProxy" + prefName.toUpperCase() + "_Port").focus();
         return false;
       }
     }
 
     // In the case of a shared proxy preference, backup the current values and update with the HTTP value
     if (shareProxiesPref.value) {
       var proxyPrefs = ["ssl", "ftp", "socks"];
       for (var i = 0; i < proxyPrefs.length; ++i) {
-        var proxyServerURLPref = document.getElementById("network.proxy." + proxyPrefs[i]);
-        var proxyPortPref = document.getElementById("network.proxy." + proxyPrefs[i] + "_port");
-        var backupServerURLPref = document.getElementById("network.proxy.backup." + proxyPrefs[i]);
-        var backupPortPref = document.getElementById("network.proxy.backup." + proxyPrefs[i] + "_port");
+        var proxyServerURLPref = Preferences.get("network.proxy." + proxyPrefs[i]);
+        var proxyPortPref = Preferences.get("network.proxy." + proxyPrefs[i] + "_port");
+        var backupServerURLPref = Preferences.get("network.proxy.backup." + proxyPrefs[i]);
+        var backupPortPref = Preferences.get("network.proxy.backup." + proxyPrefs[i] + "_port");
         backupServerURLPref.value = backupServerURLPref.value || proxyServerURLPref.value;
         backupPortPref.value = backupPortPref.value || proxyPortPref.value;
         proxyServerURLPref.value = httpProxyURLPref.value;
         proxyPortPref.value = httpProxyPortPref.value;
       }
     }
 
     this.sanitizeNoProxiesPref();
@@ -54,145 +87,145 @@ var gConnectionsDialog = {
   },
 
   checkForSystemProxy() {
     if ("@mozilla.org/system-proxy-settings;1" in Components.classes)
       document.getElementById("systemPref").removeAttribute("hidden");
   },
 
   proxyTypeChanged() {
-    var proxyTypePref = document.getElementById("network.proxy.type");
+    var proxyTypePref = Preferences.get("network.proxy.type");
 
     // Update http
-    var httpProxyURLPref = document.getElementById("network.proxy.http");
+    var httpProxyURLPref = Preferences.get("network.proxy.http");
     httpProxyURLPref.disabled = proxyTypePref.value != 1;
-    var httpProxyPortPref = document.getElementById("network.proxy.http_port");
+    var httpProxyPortPref = Preferences.get("network.proxy.http_port");
     httpProxyPortPref.disabled = proxyTypePref.value != 1;
 
     // Now update the other protocols
     this.updateProtocolPrefs();
 
-    var shareProxiesPref = document.getElementById("network.proxy.share_proxy_settings");
+    var shareProxiesPref = Preferences.get("network.proxy.share_proxy_settings");
     shareProxiesPref.disabled = proxyTypePref.value != 1;
-    var autologinProxyPref = document.getElementById("signon.autologin.proxy");
+    var autologinProxyPref = Preferences.get("signon.autologin.proxy");
     autologinProxyPref.disabled = proxyTypePref.value == 0;
-    var noProxiesPref = document.getElementById("network.proxy.no_proxies_on");
+    var noProxiesPref = Preferences.get("network.proxy.no_proxies_on");
     noProxiesPref.disabled = proxyTypePref.value != 1;
 
-    var autoconfigURLPref = document.getElementById("network.proxy.autoconfig_url");
+    var autoconfigURLPref = Preferences.get("network.proxy.autoconfig_url");
     autoconfigURLPref.disabled = proxyTypePref.value != 2;
 
     this.updateReloadButton();
   },
 
   updateDNSPref() {
-    var socksVersionPref = document.getElementById("network.proxy.socks_version");
-    var socksDNSPref = document.getElementById("network.proxy.socks_remote_dns");
-    var proxyTypePref = document.getElementById("network.proxy.type");
+    var socksVersionPref = Preferences.get("network.proxy.socks_version");
+    var socksDNSPref = Preferences.get("network.proxy.socks_remote_dns");
+    var proxyTypePref = Preferences.get("network.proxy.type");
     var isDefinitelySocks4 = !socksVersionPref.disabled && socksVersionPref.value == 4;
     socksDNSPref.disabled = (isDefinitelySocks4 || proxyTypePref.value == 0);
     return undefined;
   },
 
   updateReloadButton() {
     // Disable the "Reload PAC" button if the selected proxy type is not PAC or
     // if the current value of the PAC textbox does not match the value stored
     // in prefs.  Likewise, disable the reload button if PAC is not configured
     // in prefs.
 
     var typedURL = document.getElementById("networkProxyAutoconfigURL").value;
-    var proxyTypeCur = document.getElementById("network.proxy.type").value;
+    var proxyTypeCur = Preferences.get("network.proxy.type").value;
 
     var pacURL = Services.prefs.getCharPref("network.proxy.autoconfig_url");
     var proxyType = Services.prefs.getIntPref("network.proxy.type");
 
     var disableReloadPref =
-        document.getElementById("pref.advanced.proxies.disable_button.reload");
+        Preferences.get("pref.advanced.proxies.disable_button.reload");
     disableReloadPref.disabled =
         (proxyTypeCur != 2 || proxyType != 2 || typedURL != pacURL);
   },
 
   readProxyType() {
     this.proxyTypeChanged();
     return undefined;
   },
 
   updateProtocolPrefs() {
-    var proxyTypePref = document.getElementById("network.proxy.type");
-    var shareProxiesPref = document.getElementById("network.proxy.share_proxy_settings");
+    var proxyTypePref = Preferences.get("network.proxy.type");
+    var shareProxiesPref = Preferences.get("network.proxy.share_proxy_settings");
     var proxyPrefs = ["ssl", "ftp", "socks"];
     for (var i = 0; i < proxyPrefs.length; ++i) {
-      var proxyServerURLPref = document.getElementById("network.proxy." + proxyPrefs[i]);
-      var proxyPortPref = document.getElementById("network.proxy." + proxyPrefs[i] + "_port");
+      var proxyServerURLPref = Preferences.get("network.proxy." + proxyPrefs[i]);
+      var proxyPortPref = Preferences.get("network.proxy." + proxyPrefs[i] + "_port");
 
       // Restore previous per-proxy custom settings, if present.
       if (!shareProxiesPref.value) {
-        var backupServerURLPref = document.getElementById("network.proxy.backup." + proxyPrefs[i]);
-        var backupPortPref = document.getElementById("network.proxy.backup." + proxyPrefs[i] + "_port");
+        var backupServerURLPref = Preferences.get("network.proxy.backup." + proxyPrefs[i]);
+        var backupPortPref = Preferences.get("network.proxy.backup." + proxyPrefs[i] + "_port");
         if (backupServerURLPref.hasUserValue) {
           proxyServerURLPref.value = backupServerURLPref.value;
           backupServerURLPref.reset();
         }
         if (backupPortPref.hasUserValue) {
           proxyPortPref.value = backupPortPref.value;
           backupPortPref.reset();
         }
       }
 
       proxyServerURLPref.updateElements();
       proxyPortPref.updateElements();
       proxyServerURLPref.disabled = proxyTypePref.value != 1 || shareProxiesPref.value;
       proxyPortPref.disabled = proxyServerURLPref.disabled;
     }
-    var socksVersionPref = document.getElementById("network.proxy.socks_version");
+    var socksVersionPref = Preferences.get("network.proxy.socks_version");
     socksVersionPref.disabled = proxyTypePref.value != 1 || shareProxiesPref.value;
     this.updateDNSPref();
     return undefined;
   },
 
   readProxyProtocolPref(aProtocol, aIsPort) {
-    var shareProxiesPref = document.getElementById("network.proxy.share_proxy_settings");
+    var shareProxiesPref = Preferences.get("network.proxy.share_proxy_settings");
     if (shareProxiesPref.value) {
-      var pref = document.getElementById("network.proxy.http" + (aIsPort ? "_port" : ""));
+      var pref = Preferences.get("network.proxy.http" + (aIsPort ? "_port" : ""));
       return pref.value;
     }
 
-    var backupPref = document.getElementById("network.proxy.backup." + aProtocol + (aIsPort ? "_port" : ""));
+    var backupPref = Preferences.get("network.proxy.backup." + aProtocol + (aIsPort ? "_port" : ""));
     return backupPref.hasUserValue ? backupPref.value : undefined;
   },
 
   reloadPAC() {
     Components.classes["@mozilla.org/network/protocol-proxy-service;1"].
         getService().reloadPAC();
   },
 
   doAutoconfigURLFixup() {
     var autoURL = document.getElementById("networkProxyAutoconfigURL");
-    var autoURLPref = document.getElementById("network.proxy.autoconfig_url");
+    var autoURLPref = Preferences.get("network.proxy.autoconfig_url");
     try {
       autoURLPref.value = autoURL.value =
         Services.uriFixup.createFixupURI(autoURL.value, 0).spec;
     } catch (ex) {}
   },
 
   sanitizeNoProxiesPref() {
-    var noProxiesPref = document.getElementById("network.proxy.no_proxies_on");
+    var noProxiesPref = Preferences.get("network.proxy.no_proxies_on");
     // replace substrings of ; and \n with commas if they're neither immediately
     // preceded nor followed by a valid separator character
     noProxiesPref.value = noProxiesPref.value.replace(/([^, \n;])[;\n]+(?![,\n;])/g, "$1,");
     // replace any remaining ; and \n since some may follow commas, etc.
     noProxiesPref.value = noProxiesPref.value.replace(/[;\n]/g, "");
   },
 
   readHTTPProxyServer() {
-    var shareProxiesPref = document.getElementById("network.proxy.share_proxy_settings");
+    var shareProxiesPref = Preferences.get("network.proxy.share_proxy_settings");
     if (shareProxiesPref.value)
       this.updateProtocolPrefs();
     return undefined;
   },
 
   readHTTPProxyPort() {
-    var shareProxiesPref = document.getElementById("network.proxy.share_proxy_settings");
+    var shareProxiesPref = Preferences.get("network.proxy.share_proxy_settings");
     if (shareProxiesPref.value)
       this.updateProtocolPrefs();
     return undefined;
   }
 };
--- a/browser/components/preferences/connection.xul
+++ b/browser/components/preferences/connection.xul
@@ -1,73 +1,54 @@
 <?xml version="1.0"?>
 
 <!-- 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/. -->
 
-<!DOCTYPE prefwindow SYSTEM "chrome://browser/locale/preferences/connection.dtd">
+<!DOCTYPE dialog [
+  <!ENTITY % preferencesDTD SYSTEM "chrome://global/locale/preferences.dtd">
+  %preferencesDTD;
+  <!ENTITY % connectionDTD SYSTEM "chrome://browser/locale/preferences/connection.dtd">
+  %connectionDTD;
+]>
 
 <?xml-stylesheet href="chrome://global/skin/"?>
+<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
 
-<prefwindow id="ConnectionsDialog" type="child"
-            xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-            title="&connectionsDialog.title;"
-            dlgbuttons="accept,cancel,help"
-            onbeforeaccept="return gConnectionsDialog.beforeAccept();"
-            onload="gConnectionsDialog.checkForSystemProxy();"
-            ondialoghelp="openPrefsHelp()"
+<dialog id="ConnectionsDialog" type="child" class="prefwindow"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        title="&connectionsDialog.title;"
+        buttons="accept,cancel,help"
+        persist="lastSelected screenX screenY"
+        closebuttonlabel="&preferencesCloseButton.label;"
+        closebuttonaccesskey="&preferencesCloseButton.accesskey;"
+        role="dialog"
+        onbeforeaccept="return gConnectionsDialog.beforeAccept();"
+        onload="gConnectionsDialog.checkForSystemProxy();"
+        helpTopic="prefs-connection-settings"
+        ondialoghelp="openPrefsHelp()"
+
 #ifdef XP_MACOSX
-            style="width: &window.macWidth2; !important;">
+        style="width: &window.macWidth2; !important;">
 #else
-            style="width: &window.width2; !important;">
+        style="width: &window.width2; !important;">
 #endif
 
   <script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/>
-
-  <prefpane id="ConnectionsDialogPane"
-            class="largeDialogContainer"
-            helpTopic="prefs-connection-settings">
+  <script type="application/javascript" src="chrome://global/content/preferencesBindings.js"/>
 
-    <preferences>
-      <preference id="network.proxy.type"         name="network.proxy.type"         type="int" onchange="gConnectionsDialog.proxyTypeChanged();"/>
-      <preference id="network.proxy.http"         name="network.proxy.http"         type="string"/>
-      <preference id="network.proxy.http_port"    name="network.proxy.http_port"    type="int"/>
-      <preference id="network.proxy.ftp"          name="network.proxy.ftp"          type="string"/>
-      <preference id="network.proxy.ftp_port"     name="network.proxy.ftp_port"     type="int"/>
-      <preference id="network.proxy.ssl"          name="network.proxy.ssl"          type="string"/>
-      <preference id="network.proxy.ssl_port"     name="network.proxy.ssl_port"     type="int"/>
-      <preference id="network.proxy.socks"        name="network.proxy.socks"        type="string"/>
-      <preference id="network.proxy.socks_port"   name="network.proxy.socks_port"   type="int"/>
-      <preference id="network.proxy.socks_version"  name="network.proxy.socks_version"  type="int" onchange="gConnectionsDialog.updateDNSPref();"/>
-      <preference id="network.proxy.socks_remote_dns"  name="network.proxy.socks_remote_dns"  type="bool"/>
-      <preference id="network.proxy.no_proxies_on"  name="network.proxy.no_proxies_on"  type="string"/>
-      <preference id="network.proxy.autoconfig_url" name="network.proxy.autoconfig_url" type="string"/>
-      <preference id="network.proxy.share_proxy_settings"
-                  name="network.proxy.share_proxy_settings"
-                  type="bool"/>
-      <preference id="signon.autologin.proxy"
-                  name="signon.autologin.proxy"
-                  type="bool"/>
+  <keyset>
+    <key key="&windowClose.key;" modifiers="accel" oncommand="Preferences.close(event)"/>
+  </keyset>
 
-      <preference id="pref.advanced.proxies.disable_button.reload"
-                  name="pref.advanced.proxies.disable_button.reload"
-                  type="bool"/>
-
-      <preference id="network.proxy.backup.ftp"          name="network.proxy.backup.ftp"          type="string"/>
-      <preference id="network.proxy.backup.ftp_port"     name="network.proxy.backup.ftp_port"     type="int"/>
-      <preference id="network.proxy.backup.ssl"          name="network.proxy.backup.ssl"          type="string"/>
-      <preference id="network.proxy.backup.ssl_port"     name="network.proxy.backup.ssl_port"     type="int"/>
-      <preference id="network.proxy.backup.socks"        name="network.proxy.backup.socks"        type="string"/>
-      <preference id="network.proxy.backup.socks_port"   name="network.proxy.backup.socks_port"   type="int"/>
-    </preferences>
-
-    <script type="application/javascript" src="chrome://browser/content/preferences/connection.js"/>
+  <vbox id="ConnectionsDialogPane" class="prefpane largeDialogContainer">
 
     <stringbundle id="preferencesBundle" src="chrome://browser/locale/preferences/preferences.properties"/>
+    <script type="application/javascript" src="chrome://browser/content/preferences/connection.js"/>
 
     <groupbox>
       <caption><label>&proxyTitle.label;</label></caption>
 
       <radiogroup id="networkProxyType" preference="network.proxy.type"
                   onsyncfrompreference="return gConnectionsDialog.readProxyType();">
         <radio value="0" label="&noProxyTypeRadio.label;" accesskey="&noProxyTypeRadio.accesskey;"/>
         <radio value="4" label="&WPADTypeRadio.label;" accesskey="&WPADTypeRadio.accesskey;"/>
@@ -164,10 +145,10 @@
     <separator class="thin"/>
     <checkbox id="autologinProxy"
               label="&autologinproxy.label;"
               accesskey="&autologinproxy.accesskey;"
               preference="signon.autologin.proxy"
               tooltiptext="&autologinproxy.tooltip;"/>
     <checkbox id="networkProxySOCKSRemoteDNS"  preference="network.proxy.socks_remote_dns" label="&socksRemoteDNS.label2;" accesskey="&socksRemoteDNS.accesskey;" />
     <separator/>
-  </prefpane>
-</prefwindow>
+  </vbox>
+</dialog>
deleted file mode 100644
--- a/browser/components/preferences/donottrack.xul
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0"?>
-
-<!-- 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/. -->
-
-<?xml-stylesheet href="chrome://global/skin/"?>
-<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
-
-<!DOCTYPE prefwindow [
-<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
-<!ENTITY % doNotTrackDTD SYSTEM "chrome://browser/locale/preferences/donottrack.dtd">
-%brandDTD;
-%doNotTrackDTD;
-]>
-
-<prefwindow id="DoNotTrackDialog" type="child"
-            xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-            xmlns:html="http://www.w3.org/1999/xhtml"
-            title="&window.title;"
-            style="width: &window.width;; height: &window.height;;"
-            dlgbuttons="accept,cancel">
-  <prefpane>
-    <preferences>
-      <preference id="privacy.donottrackheader.enabled"
-                  name="privacy.donottrackheader.enabled"
-                  type="bool"/>
-    </preferences>
-    <hbox align="center" pack="start">
-      <!-- Work around focus ring not showing properly. -->
-      <spacer style="width: 1em;"/>
-      <checkbox label="&doNotTrackCheckbox2.label;"
-                accesskey="&doNotTrackCheckbox2.accesskey;"
-                preference="privacy.donottrackheader.enabled"/>
-    </hbox>
-    <description flex="1" class="doNotTrackLearnMore">
-      &doNotTrackTPInfo.description;
-      <label class="text-link"
-             href="https://www.mozilla.org/dnt">&doNotTrackLearnMore.label;</label>
-    </description>
-  </prefpane>
-</prefwindow>
--- a/browser/components/preferences/fonts.js
+++ b/browser/components/preferences/fonts.js
@@ -13,16 +13,22 @@ const kFontNameFmtSansSerif     = "font.
 const kFontNameFmtMonospace     = "font.name.monospace.%LANG%";
 const kFontNameListFmtSerif     = "font.name-list.serif.%LANG%";
 const kFontNameListFmtSansSerif = "font.name-list.sans-serif.%LANG%";
 const kFontNameListFmtMonospace = "font.name-list.monospace.%LANG%";
 const kFontSizeFmtVariable      = "font.size.variable.%LANG%";
 const kFontSizeFmtFixed         = "font.size.fixed.%LANG%";
 const kFontMinSizeFmt           = "font.minimum-size.%LANG%";
 
+Preferences.addAll([
+  { id: "font.language.group", type: "wstring" },
+  { id: "browser.display.use_document_fonts", type: "int" },
+  { id: "intl.charset.fallback.override", type: "string" },
+]);
+
 var gFontsDialog = {
   _selectLanguageGroupPromise: Promise.resolve(),
 
   _selectLanguageGroup(aLanguageGroup) {
     this._selectLanguageGroupPromise = (async () => {
       // Avoid overlapping language group selections by awaiting the resolution
       // of the previous one.  We do this because this function is re-entrant,
       // as inserting <preference> elements into the DOM sometimes triggers a call
@@ -39,26 +45,21 @@ var gFontsDialog = {
         { format: kFontNameFmtMonospace,     type: "fontname", element: "monospace",  fonttype: "monospace"   },
         { format: kFontNameListFmtSerif,     type: "unichar",  element: null,         fonttype: "serif"       },
         { format: kFontNameListFmtSansSerif, type: "unichar",  element: null,         fonttype: "sans-serif"  },
         { format: kFontNameListFmtMonospace, type: "unichar",  element: null,         fonttype: "monospace"   },
         { format: kFontSizeFmtVariable,      type: "int",      element: "sizeVar",    fonttype: null          },
         { format: kFontSizeFmtFixed,         type: "int",      element: "sizeMono",   fonttype: null          },
         { format: kFontMinSizeFmt,           type: "int",      element: "minSize",    fonttype: null          }
       ];
-      var preferences = document.getElementById("fontPreferences");
       for (var i = 0; i < prefs.length; ++i) {
-        var preference = document.getElementById(prefs[i].format.replace(/%LANG%/, aLanguageGroup));
+        var name = prefs[i].format.replace(/%LANG%/, aLanguageGroup);
+        var preference = Preferences.get(name);
         if (!preference) {
-          preference = document.createElement("preference");
-          var name = prefs[i].format.replace(/%LANG%/, aLanguageGroup);
-          preference.id = name;
-          preference.setAttribute("name", name);
-          preference.setAttribute("type", prefs[i].type);
-          preferences.appendChild(preference);
+          preference = Preferences.add({ id: name, type: prefs[i].type });
         }
 
         if (!prefs[i].element)
           continue;
 
         var element = document.getElementById(prefs[i].element);
         if (element) {
           element.setAttribute("preference", preference.id);
@@ -69,39 +70,38 @@ var gFontsDialog = {
           preference.setElementValue(element);
         }
       }
     })()
       .catch(Components.utils.reportError);
   },
 
   readFontLanguageGroup() {
-    var languagePref = document.getElementById("font.language.group");
+    var languagePref = Preferences.get("font.language.group");
     this._selectLanguageGroup(languagePref.value);
     return undefined;
   },
 
   readUseDocumentFonts() {
-    var preference = document.getElementById("browser.display.use_document_fonts");
+    var preference = Preferences.get("browser.display.use_document_fonts");
     return preference.value == 1;
   },
 
   writeUseDocumentFonts() {
     var useDocumentFonts = document.getElementById("useDocumentFonts");
     return useDocumentFonts.checked ? 1 : 0;
   },
 
   onBeforeAccept() {
-    let preferences = document.querySelectorAll("preference[id*='font.minimum-size']");
     // It would be good if we could avoid touching languages the pref pages won't use, but
     // unfortunately the language group APIs (deducing language groups from language codes)
     // are C++ - only. So we just check all the things the user touched:
     // Don't care about anything up to 24px, or if this value is the same as set previously:
-    preferences = Array.filter(preferences, prefEl => {
-      return prefEl.value > 24 && prefEl.value != prefEl.valueFromPreferences;
+    let preferences = Preferences.getAll().filter(pref => {
+      return pref.id.includes("font.minimum-size") && pref.value > 24 && pref.value != pref.valueFromPreferences;
     });
     if (!preferences.length) {
       return true;
     }
 
     let strings = document.getElementById("bundlePreferences");
     let title = strings.getString("veryLargeMinimumFontTitle");
     let confirmLabel = strings.getString("acceptVeryLargeMinimumFont");
--- a/browser/components/preferences/fonts.xul
+++ b/browser/components/preferences/fonts.xul
@@ -1,43 +1,45 @@
 <?xml version="1.0"?>
 
-# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
-# 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/.
+<!-- -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -->
+<!-- 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/. -->
 
 <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-#ifdef XP_MACOSX
 <?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
-#endif
 
-<!DOCTYPE prefwindow SYSTEM "chrome://browser/locale/preferences/fonts.dtd" >
+<!DOCTYPE dialog [
+  <!ENTITY % preferencesDTD SYSTEM "chrome://global/locale/preferences.dtd">
+  %preferencesDTD;
+  <!ENTITY % fontsDTD SYSTEM "chrome://browser/locale/preferences/fonts.dtd">
+  %fontsDTD;
+]>
 
-<prefwindow id="FontsDialog" type="child"
-            xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-            title="&fontsDialog.title;"
-            dlgbuttons="accept,cancel,help"
-            ondialoghelp="openPrefsHelp()"
-            onbeforeaccept="return gFontsDialog.onBeforeAccept();"
-            style="">
+<dialog id="FontsDialog" type="child" class="prefwindow"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        title="&fontsDialog.title;"
+        buttons="accept,cancel,help"
+        persist="lastSelected screenX screenY"
+        closebuttonlabel="&preferencesCloseButton.label;"
+        closebuttonaccesskey="&preferencesCloseButton.accesskey;"
+        role="dialog"
+        helpTopic="prefs-fonts-and-colors"
+        ondialoghelp="openPrefsHelp()"
+        onbeforeaccept="return gFontsDialog.onBeforeAccept();">
 
   <script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/>
-
-  <prefpane id="FontsDialogPane"
-            class="largeDialogContainer"
-            helpTopic="prefs-fonts-and-colors">
+  <script type="application/javascript" src="chrome://global/content/preferencesBindings.js"/>
 
-    <preferences id="fontPreferences">
-      <preference id="font.language.group"  name="font.language.group"  type="wstring"/>
-      <preference id="browser.display.use_document_fonts"
-                  name="browser.display.use_document_fonts"
-                  type="int"/>
-      <preference id="intl.charset.fallback.override" name="intl.charset.fallback.override" type="string"/>
-    </preferences>
+  <keyset>
+    <key key="&windowClose.key;" modifiers="accel" oncommand="Preferences.close(event)"/>
+  </keyset>
+
+  <vbox id="FontsDialogPane" class="prefpane largeDialogContainer">
 
     <stringbundle id="bundlePreferences" src="chrome://browser/locale/preferences/preferences.properties"/>
     <script type="application/javascript" src="chrome://mozapps/content/preferences/fontbuilder.js"/>
     <script type="application/javascript" src="chrome://browser/content/preferences/fonts.js"/>
 
     <!-- Fonts for: [ Language ] -->
     <groupbox>
       <caption>
@@ -292,10 +294,10 @@
               <menuitem label="&languages.customize.Fallback.turkish;"     value="windows-1254"/>
               <menuitem label="&languages.customize.Fallback.vietnamese;"  value="windows-1258"/>
               <menuitem label="&languages.customize.Fallback.other;"       value="windows-1252"/>
             </menupopup>
           </menulist>
         </hbox>
       </hbox>
     </groupbox>
-  </prefpane>
-</prefwindow>
+  </vbox>
+</dialog>
--- a/browser/components/preferences/in-content/containers.xul
+++ b/browser/components/preferences/in-content/containers.xul
@@ -2,24 +2,16 @@
 # 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/.
 
 <!-- Containers panel -->
 
 <script type="application/javascript"
         src="chrome://browser/content/preferences/in-content/containers.js"/>
 
-<preferences id="containerPreferences" hidden="true" data-category="paneContainer">
-  <!-- Containers -->
-  <preference id="privacy.userContext.enabled"
-              name="privacy.userContext.enabled"
-              type="bool"/>
-
-</preferences>
-
 <hbox hidden="true"
       class="container-header-links"
       data-category="paneContainers">
   <label class="text-link" id="backContainersLink">&backLink2.label;</label>
 </hbox>
 
 <hbox id="header-containers"
       class="header"
--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -98,16 +98,154 @@ const APP_ICON_ATTR_NAME = "appHandlerIc
 XPCOMUtils.defineLazyModuleGetter(this, "OS",
   "resource://gre/modules/osfile.jsm");
 
 if (AppConstants.MOZ_DEV_EDITION) {
   XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
     "resource://gre/modules/FxAccounts.jsm");
 }
 
+Preferences.addAll([
+  // Startup
+  { id: "browser.startup.page", type: "int" },
+  { id: "browser.startup.homepage", type: "wstring" },
+
+  { id: "pref.browser.homepage.disable_button.current_page", type: "bool" },
+  { id: "pref.browser.homepage.disable_button.bookmark_page", type: "bool" },
+  { id: "pref.browser.homepage.disable_button.restore_default", type: "bool" },
+
+  { id: "browser.privatebrowsing.autostart", type: "bool" },
+
+  // Downloads
+  { id: "browser.download.useDownloadDir", type: "bool" },
+  { id: "browser.download.folderList", type: "int" },
+  { id: "browser.download.dir", type: "file" },
+
+  /* Tab preferences
+  Preferences:
+
+  browser.link.open_newwindow
+      1 opens such links in the most recent window or tab,
+      2 opens such links in a new window,
+      3 opens such links in a new tab
+  browser.tabs.loadInBackground
+  - true if display should switch to a new tab which has been opened from a
+    link, false if display shouldn't switch
+  browser.tabs.warnOnClose
+  - true if when closing a window with multiple tabs the user is warned and
+    allowed to cancel the action, false to just close the window
+  browser.tabs.warnOnOpen
+  - true if the user should be warned if he attempts to open a lot of tabs at
+    once (e.g. a large folder of bookmarks), false otherwise
+  browser.taskbar.previews.enable
+  - true if tabs are to be shown in the Windows 7 taskbar
+  */
+
+  { id: "browser.link.open_newwindow", type: "int" },
+  { id: "browser.tabs.loadInBackground", type: "bool", inverted: true },
+  { id: "browser.tabs.warnOnClose", type: "bool" },
+  { id: "browser.tabs.warnOnOpen", type: "bool" },
+  { id: "browser.sessionstore.restore_on_demand", type: "bool" },
+  { id: "browser.ctrlTab.previews", type: "bool" },
+
+  // Fonts
+  { id: "font.language.group", type: "wstring" },
+
+  // Languages
+  { id: "browser.translation.detectLanguage", type: "bool" },
+
+  // General tab
+
+  /* Accessibility
+   * accessibility.browsewithcaret
+     - true enables keyboard navigation and selection within web pages using a
+       visible caret, false uses normal keyboard navigation with no caret
+   * accessibility.typeaheadfind
+     - when set to true, typing outside text areas and input boxes will
+       automatically start searching for what's typed within the current
+       document; when set to false, no search action happens */
+  { id: "accessibility.browsewithcaret", type: "bool" },
+  { id: "accessibility.typeaheadfind", type: "bool" },
+  { id: "accessibility.blockautorefresh", type: "bool" },
+
+  /* Browsing
+   * general.autoScroll
+     - when set to true, clicking the scroll wheel on the mouse activates a
+       mouse mode where moving the mouse down scrolls the document downward with
+       speed correlated with the distance of the cursor from the original
+       position at which the click occurred (and likewise with movement upward);
+       if false, this behavior is disabled
+   * general.smoothScroll
+     - set to true to enable finer page scrolling than line-by-line on page-up,
+       page-down, and other such page movements */
+  { id: "general.autoScroll", type: "bool" },
+  { id: "general.smoothScroll", type: "bool" },
+  { id: "layout.spellcheckDefault", type: "int" },
+
+  { id: "browser.preferences.defaultPerformanceSettings.enabled", type: "bool" },
+  { id: "dom.ipc.processCount", type: "int" },
+  { id: "dom.ipc.processCount.web", type: "int" },
+  { id: "layers.acceleration.disabled", type: "bool", inverted: true },
+
+  // Files and Applications
+  { id: "browser.feeds.handler", type: "string" },
+  { id: "browser.feeds.handler.default", type: "string" },
+  { id: "browser.feeds.handlers.application", type: "file" },
+  { id: "browser.feeds.handlers.webservice", type: "string" },
+
+  { id: "browser.videoFeeds.handler", type: "string" },
+  { id: "browser.videoFeeds.handler.default", type: "string" },
+  { id: "browser.videoFeeds.handlers.application", type: "file" },
+  { id: "browser.videoFeeds.handlers.webservice", type: "string" },
+
+  { id: "browser.audioFeeds.handler", type: "string" },
+  { id: "browser.audioFeeds.handler.default", type: "string" },
+  { id: "browser.audioFeeds.handlers.application", type: "file" },
+  { id: "browser.audioFeeds.handlers.webservice", type: "string" },
+
+  { id: "pref.downloads.disable_button.edit_actions", type: "bool" },
+
+  // DRM content
+  { id: "media.eme.enabled", type: "bool" },
+
+  // Update
+  { id: "browser.preferences.advanced.selectedTabIndex", type: "int" },
+  { id: "browser.search.update", type: "bool" },
+
+  { id: "privacy.userContext.enabled", type: "bool" },
+]);
+
+if (AppConstants.HAVE_SHELL_SERVICE) {
+  Preferences.addAll([
+    { id: "browser.shell.checkDefaultBrowser", type: "bool" },
+    { id: "pref.general.disable_button.default_browser", type: "bool" },
+  ]);
+}
+
+if (AppConstants.platform === "win") {
+  Preferences.addAll([
+    { id: "browser.taskbar.previews.enable", type: "bool" },
+    { id: "ui.osk.enabled", type: "bool" },
+  ]);
+}
+
+if (AppConstants.MOZ_UPDATER) {
+  Preferences.addAll([
+    { id: "app.update.enabled", type: "bool" },
+    { id: "app.update.auto", type: "bool" },
+    { id: "app.update.disable_button.showUpdateHistory", type: "bool" },
+  ]);
+
+  if (AppConstants.MOZ_MAINTENANCE_SERVICE) {
+    Preferences.addAll([
+      { id: "app.update.service.enabled", type: "bool" },
+    ]);
+  }
+}
+
 // A promise that resolves when the list of application handlers is loaded.
 // We store this in a global so tests can await it.
 var promiseLoadHandlersList;
 
 var gMainPane = {
   // The set of types the app knows how to handle.  A hash of HandlerInfoWrapper
   // objects, indexed by type.
   _handledTypes: {},
@@ -203,18 +341,18 @@ var gMainPane = {
 
     let performanceSettingsLink = document.getElementById("performanceSettingsLearnMore");
     let performanceSettingsUrl = Services.urlFormatter.formatURLPref("app.support.baseURL") + "performance";
     performanceSettingsLink.setAttribute("href", performanceSettingsUrl);
 
     this.updateDefaultPerformanceSettingsPref();
 
     let defaultPerformancePref =
-      document.getElementById("browser.preferences.defaultPerformanceSettings.enabled");
-    defaultPerformancePref.addEventListener("change", () => {
+      Preferences.get("browser.preferences.defaultPerformanceSettings.enabled");
+    defaultPerformancePref.on("change", () => {
       this.updatePerformanceSettingsBox({ duringChangeEvent: true });
     });
     this.updatePerformanceSettingsBox({ duringChangeEvent: false });
 
     // set up the "use current page" label-changing listener
     this._updateUseCurrentButton();
     window.addEventListener("focus", this._updateUseCurrentButton.bind(this));
 
@@ -244,18 +382,18 @@ var gMainPane = {
     // &brandShortName;" warnings provide options for not showing these
     // warnings again. When the user disabled them, we provide checkboxes to
     // re-enable the warnings.
     if (!TransientPrefs.prefShouldBeVisible("browser.tabs.warnOnClose"))
       document.getElementById("warnCloseMultiple").hidden = true;
     if (!TransientPrefs.prefShouldBeVisible("browser.tabs.warnOnOpen"))
       document.getElementById("warnOpenMany").hidden = true;
 
-    setEventListener("browser.privatebrowsing.autostart", "change",
-      gMainPane.updateBrowserStartupLastSession);
+    Preferences.get("browser.privatebrowsing.autostart").on("change",
+      gMainPane.updateBrowserStartupLastSession.bind(gMainPane));
     if (AppConstants.HAVE_SHELL_SERVICE) {
       setEventListener("setDefaultButton", "command",
         gMainPane.setDefaultBrowser);
     }
     setEventListener("useCurrent", "command",
       gMainPane.setHomePageToCurrent);
     setEventListener("useBookmark", "command",
       gMainPane.setHomePageToBookmark);
@@ -268,24 +406,24 @@ var gMainPane = {
     setEventListener("disableNewTabExtension", "command",
                      makeDisableControllingExtension(URL_OVERRIDES_TYPE, NEW_TAB_KEY));
     setEventListener("chooseLanguage", "command",
       gMainPane.showLanguages);
     setEventListener("translationAttributionImage", "click",
       gMainPane.openTranslationProviderAttribution);
     setEventListener("translateButton", "command",
       gMainPane.showTranslationExceptions);
-    setEventListener("font.language.group", "change",
-      gMainPane._rebuildFonts);
+    Preferences.get("font.language.group").on("change",
+      gMainPane._rebuildFonts.bind(gMainPane));
     setEventListener("advancedFonts", "command",
       gMainPane.configureFonts);
     setEventListener("colors", "command",
       gMainPane.configureColors);
-    setEventListener("layers.acceleration.disabled", "change",
-      gMainPane.updateHardwareAcceleration);
+    Preferences.get("layers.acceleration.disabled").on("change",
+      gMainPane.updateHardwareAcceleration.bind(gMainPane));
     setEventListener("connectionSettings", "command",
       gMainPane.showConnections);
     setEventListener("browserContainersCheckbox", "command",
       gMainPane.checkBrowserContainers);
     setEventListener("browserContainersSettings", "command",
       gMainPane.showContainerSettings);
     setEventListener("browserHomePage", "input",
       gMainPane.onBrowserHomePageChange);
@@ -415,18 +553,18 @@ var gMainPane = {
     Services.prefs.addObserver(PREF_AUDIO_FEED_SELECTED_READER, this);
 
     setEventListener("filter", "command", gMainPane.filter);
     setEventListener("handlersView", "select",
       gMainPane.onSelectionChanged);
     setEventListener("typeColumn", "click", gMainPane.sort);
     setEventListener("actionColumn", "click", gMainPane.sort);
     setEventListener("chooseFolder", "command", gMainPane.chooseFolder);
-    setEventListener("browser.download.dir", "change", gMainPane.displayDownloadDirPref);
-    setEventListener("saveWhere", "command", gMainPane.handleSaveToCommand);
+    Preferences.get("browser.download.dir").on("change",
+      gMainPane.displayDownloadDirPref.bind(gMainPane));
 
     // Listen for window unload so we can remove our preference observers.
     window.addEventListener("unload", this);
 
     // Figure out how we should be sorting the list.  We persist sort settings
     // across sessions, so we can't assume the default sort column/direction.
     // XXX should we be using the XUL sort service instead?
     if (document.getElementById("actionColumn").hasAttribute("sortDirection")) {
@@ -479,17 +617,17 @@ var gMainPane = {
    * privacy.userContext.enabled
    * - true if containers is enabled
    */
 
   /**
    * Enables/disables the Settings button used to configure containers
    */
   readBrowserContainersCheckbox() {
-    const pref = document.getElementById("privacy.userContext.enabled");
+    const pref = Preferences.get("privacy.userContext.enabled");
     const settings = document.getElementById("browserContainersSettings");
 
     settings.disabled = !pref.value;
     const containersEnabled = Services.prefs.getBoolPref("privacy.userContext.enabled");
     const containersCheckbox = document.getElementById("browserContainersCheckbox");
     containersCheckbox.checked = containersEnabled;
     handleControllingExtension(PREF_SETTING_TYPE, CONTAINERS_KEY)
       .then((isControlled) => {
@@ -602,26 +740,26 @@ var gMainPane = {
    *     3: windows and tabs from the last session (a.k.a. session restore)
    *
    *   The deprecated option is not exposed in UI; however, if the user has it
    *   selected and doesn't change the UI for this preference, the deprecated
    *   option is preserved.
    */
 
   syncFromHomePref() {
-    let homePref = document.getElementById("browser.startup.homepage");
+    let homePref = Preferences.get("browser.startup.homepage");
 
     // Set the "Use Current Page(s)" button's text and enabled state.
     this._updateUseCurrentButton();
 
     function setInputDisabledStates(isControlled) {
       // Disable or enable the inputs based on if this is controlled by an extension.
       document.querySelectorAll("#browserHomePage, .homepage-button")
         .forEach((element) => {
-          let isLocked = document.getElementById(element.getAttribute("preference")).locked;
+          let isLocked = Preferences.get(element.getAttribute("preference")).locked;
           element.disabled = isLocked || isControlled;
         });
     }
 
     if (homePref.locked) {
       // An extension can't control these settings if they're locked.
       hideControllingExtension(HOMEPAGE_OVERRIDE_KEY);
       setInputDisabledStates(false);
@@ -663,17 +801,17 @@ var gMainPane = {
   },
 
   /**
    * Sets the home page to the current displayed page (or frontmost tab, if the
    * most recent browser window contains multiple tabs), updating preference
    * window UI to reflect this.
    */
   setHomePageToCurrent() {
-    let homePage = document.getElementById("browser.startup.homepage");
+    let homePage = Preferences.get("browser.startup.homepage");
     let tabs = this._getTabsForHomePage();
     function getTabURI(t) {
       return t.linkedBrowser.currentURI.spec;
     }
 
     // FIXME Bug 244192: using dangerous "|" joiner!
     if (tabs.length) {
       homePage.value = tabs.map(getTabURI).join("|");
@@ -710,17 +848,17 @@ var gMainPane = {
       }, 3000);
     }
   },
 
   _setHomePageToBookmarkClosed(rv, aEvent) {
     if (aEvent.detail.button != "accept")
       return;
     if (rv.urls && rv.names) {
-      var homePage = document.getElementById("browser.startup.homepage");
+      var homePage = Preferences.get("browser.startup.homepage");
 
       // XXX still using dangerous "|" joiner!
       homePage.value = rv.urls.join("|");
     }
   },
 
   /**
    * Switches the "Use Current Page" button between its singular and plural
@@ -738,17 +876,17 @@ var gMainPane = {
     // If the homepage is controlled by an extension then you can't use this.
     if (await getControllingExtensionInfo(PREF_SETTING_TYPE, HOMEPAGE_OVERRIDE_KEY)) {
       useCurrent.disabled = true;
       return;
     }
 
     // In this case, the button's disabled state is set by preferences.xml.
     let prefName = "pref.browser.homepage.disable_button.current_page";
-    if (document.getElementById(prefName).locked)
+    if (Preferences.get(prefName).locked)
       return;
 
     useCurrent.disabled = !tabs.length;
   },
 
   _getTabsForHomePage() {
     var win;
     var tabs = [];
@@ -773,38 +911,38 @@ var gMainPane = {
   isNotAboutPreferences(aElement, aIndex, aArray) {
     return !aElement.linkedBrowser.currentURI.spec.startsWith("about:preferences");
   },
 
   /**
    * Restores the default home page as the user's home page.
    */
   restoreDefaultHomePage() {
-    var homePage = document.getElementById("browser.startup.homepage");
+    var homePage = Preferences.get("browser.startup.homepage");
     homePage.value = homePage.defaultValue;
   },
 
   /**
    * Utility function to enable/disable the button specified by aButtonID based
    * on the value of the Boolean preference specified by aPreferenceID.
    */
   updateButtons(aButtonID, aPreferenceID) {
     var button = document.getElementById(aButtonID);
-    var preference = document.getElementById(aPreferenceID);
+    var preference = Preferences.get(aPreferenceID);
     button.disabled = preference.value != true;
     return undefined;
   },
 
   /**
    * Hide/show the "Show my windows and tabs from last time" option based
    * on the value of the browser.privatebrowsing.autostart pref.
    */
   updateBrowserStartupLastSession() {
-    let pbAutoStartPref = document.getElementById("browser.privatebrowsing.autostart");
-    let startupPref = document.getElementById("browser.startup.page");
+    let pbAutoStartPref = Preferences.get("browser.privatebrowsing.autostart");
+    let startupPref = Preferences.get("browser.startup.page");
     let group = document.getElementById("browserStartupPage");
     let option = document.getElementById("browserStartupLastSession");
     if (pbAutoStartPref.value) {
       option.setAttribute("disabled", "true");
       if (option.selected) {
         group.selectedItem = document.getElementById("browserStartupHomePage");
       }
     } else {
@@ -839,17 +977,17 @@ var gMainPane = {
    */
 
   /**
    * Determines where a link which opens a new window will open.
    *
    * @returns |true| if such links should be opened in new tabs
    */
   readLinkTarget() {
-    var openNewWindow = document.getElementById("browser.link.open_newwindow");
+    var openNewWindow = Preferences.get("browser.link.open_newwindow");
     return openNewWindow.value != 2;
   },
 
   /**
    * Determines where a link which opens a new window will open.
    *
    * @returns 2 if such links should be opened in new windows,
    *          3 if such links should be opened in new tabs
@@ -887,17 +1025,17 @@ var gMainPane = {
     }
   },
 
   /**
    * Set browser as the operating system default browser.
    */
   setDefaultBrowser() {
     if (AppConstants.HAVE_SHELL_SERVICE) {
-      let alwaysCheckPref = document.getElementById("browser.shell.checkDefaultBrowser");
+      let alwaysCheckPref = Preferences.get("browser.shell.checkDefaultBrowser");
       alwaysCheckPref.value = true;
 
       // Reset exponential backoff delay time in order to do visual update in pollForDefaultBrowser.
       this._backoffIndex = 0;
 
       let shellSvc = getShellService();
       if (!shellSvc)
         return;
@@ -1019,41 +1157,32 @@ var gMainPane = {
   },
 
   // FONTS
 
   /**
    * Populates the default font list in UI.
    */
   _rebuildFonts() {
-    var preferences = document.getElementById("mainPreferences");
-    // Ensure preferences are "visible" to ensure bindings work.
-    preferences.hidden = false;
-    // Force flush:
-    preferences.clientHeight;
-    var langGroupPref = document.getElementById("font.language.group");
+    var langGroupPref = Preferences.get("font.language.group");
     var isSerif = this._readDefaultFontTypeForLanguage(langGroupPref.value) == "serif";
     this._selectDefaultLanguageGroup(langGroupPref.value, isSerif);
   },
 
   /**
    * Returns the type of the current default font for the language denoted by
    * aLanguageGroup.
    */
   _readDefaultFontTypeForLanguage(aLanguageGroup) {
     const kDefaultFontType = "font.default.%LANG%";
     var defaultFontTypePref = kDefaultFontType.replace(/%LANG%/, aLanguageGroup);
-    var preference = document.getElementById(defaultFontTypePref);
+    var preference = Preferences.get(defaultFontTypePref);
     if (!preference) {
-      preference = document.createElement("preference");
-      preference.id = defaultFontTypePref;
-      preference.setAttribute("name", defaultFontTypePref);
-      preference.setAttribute("type", "string");
-      preference.setAttribute("onchange", "gMainPane._rebuildFonts();");
-      document.getElementById("mainPreferences").appendChild(preference);
+      preference = Preferences.add({ id: defaultFontTypePref, type: "string" });
+      preference.on("change", gMainPane._rebuildFonts.bind(gMainPane));
     }
     return preference.value;
   },
 
   _selectDefaultLanguageGroupPromise: Promise.resolve(),
 
   _selectDefaultLanguageGroup(aLanguageGroup, aIsSerif) {
     this._selectDefaultLanguageGroupPromise = (async () => {
@@ -1067,17 +1196,16 @@ var gMainPane = {
       await this._selectDefaultLanguageGroupPromise;
 
       const kFontNameFmtSerif = "font.name.serif.%LANG%";
       const kFontNameFmtSansSerif = "font.name.sans-serif.%LANG%";
       const kFontNameListFmtSerif = "font.name-list.serif.%LANG%";
       const kFontNameListFmtSansSerif = "font.name-list.sans-serif.%LANG%";
       const kFontSizeFmtVariable = "font.size.variable.%LANG%";
 
-      var preferences = document.getElementById("mainPreferences");
       var prefs = [{
         format: aIsSerif ? kFontNameFmtSerif : kFontNameFmtSansSerif,
         type: "fontname",
         element: "defaultFont",
         fonttype: aIsSerif ? "serif" : "sans-serif"
       },
       {
         format: aIsSerif ? kFontNameListFmtSerif : kFontNameListFmtSansSerif,
@@ -1087,24 +1215,20 @@ var gMainPane = {
       },
       {
         format: kFontSizeFmtVariable,
         type: "int",
         element: "defaultFontSize",
         fonttype: null
       }];
       for (var i = 0; i < prefs.length; ++i) {
-        var preference = document.getElementById(prefs[i].format.replace(/%LANG%/, aLanguageGroup));
+        var preference = Preferences.get(prefs[i].format.replace(/%LANG%/, aLanguageGroup));
         if (!preference) {
-          preference = document.createElement("preference");
           var name = prefs[i].format.replace(/%LANG%/, aLanguageGroup);
-          preference.id = name;
-          preference.setAttribute("name", name);
-          preference.setAttribute("type", prefs[i].type);
-          preferences.appendChild(preference);
+          preference = Preferences.add({ id: name, type: prefs[i].type });
         }
 
         if (!prefs[i].element)
           continue;
 
         var element = document.getElementById(prefs[i].element);
         if (element) {
           element.setAttribute("preference", preference.id);
@@ -1132,17 +1256,17 @@ var gMainPane = {
    *
    * layout.spellcheckDefault
    * - an integer:
    *     0  disables spellchecking
    *     1  enables spellchecking, but only for multiline text fields
    *     2  enables spellchecking for all text fields
    */
   readCheckSpelling() {
-    var pref = document.getElementById("layout.spellcheckDefault");
+    var pref = Preferences.get("layout.spellcheckDefault");
     this._storedSpellCheck = pref.value;
 
     return (pref.value != 0);
   },
 
   /**
    * Returns the value of the spellchecking preference represented by UI,
    * preserving the preference's "hidden" value if the preference is
@@ -1156,44 +1280,44 @@ var gMainPane = {
       }
       return 1;
     }
     return 0;
   },
 
   updateDefaultPerformanceSettingsPref() {
     let defaultPerformancePref =
-      document.getElementById("browser.preferences.defaultPerformanceSettings.enabled");
-    let processCountPref = document.getElementById("dom.ipc.processCount");
-    let accelerationPref = document.getElementById("layers.acceleration.disabled");
+      Preferences.get("browser.preferences.defaultPerformanceSettings.enabled");
+    let processCountPref = Preferences.get("dom.ipc.processCount");
+    let accelerationPref = Preferences.get("layers.acceleration.disabled");
     if (processCountPref.value != processCountPref.defaultValue ||
       accelerationPref.value != accelerationPref.defaultValue) {
       defaultPerformancePref.value = false;
     }
   },
 
   updatePerformanceSettingsBox({ duringChangeEvent }) {
     let defaultPerformancePref =
-      document.getElementById("browser.preferences.defaultPerformanceSettings.enabled");
+      Preferences.get("browser.preferences.defaultPerformanceSettings.enabled");
     let performanceSettings = document.getElementById("performanceSettings");
-    let processCountPref = document.getElementById("dom.ipc.processCount");
+    let processCountPref = Preferences.get("dom.ipc.processCount");
     if (defaultPerformancePref.value) {
-      let accelerationPref = document.getElementById("layers.acceleration.disabled");
+      let accelerationPref = Preferences.get("layers.acceleration.disabled");
       // Unset the value so process count will be decided by the platform.
       processCountPref.value = processCountPref.defaultValue;
       accelerationPref.value = accelerationPref.defaultValue;
       performanceSettings.hidden = true;
     } else {
       performanceSettings.hidden = false;
     }
   },
 
   buildContentProcessCountMenuList() {
     if (Services.appinfo.browserTabsRemoteAutostart) {
-      let processCountPref = document.getElementById("dom.ipc.processCount");
+      let processCountPref = Preferences.get("dom.ipc.processCount");
       let defaultProcessCount = processCountPref.defaultValue;
       let bundlePreferences = document.getElementById("bundlePreferences");
 
       let contentProcessCount =
         document.querySelector(`#contentProcessCount > menupopup >
                                 menuitem[value="${defaultProcessCount}"]`);
 
       // New localization API experiment (October 2017).
@@ -1255,18 +1379,18 @@ var gMainPane = {
    * Element           pref  value  locked  disabled
    * radiogroup        i     t/f    f       false
    *                   i     t/f    *t*     *true*
    *                   ii    t/f    f       false
    *                   ii    t/f    *t*     *true*
    */
   updateReadPrefs() {
     if (AppConstants.MOZ_UPDATER) {
-      var enabledPref = document.getElementById("app.update.enabled");
-      var autoPref = document.getElementById("app.update.auto");
+      var enabledPref = Preferences.get("app.update.enabled");
+      var autoPref = Preferences.get("app.update.auto");
       var radiogroup = document.getElementById("updateRadioGroup");
 
       if (!enabledPref.value) // Don't care for autoPref.value in this case.
         radiogroup.value = "manual"; // 3. Never check for updates.
       else if (autoPref.value) // enabledPref.value && autoPref.value
         radiogroup.value = "auto"; // 1. Automatically install updates
       else // enabledPref.value && !autoPref.value
         radiogroup.value = "checkOnly"; // 2. Check, but let me choose
@@ -1300,18 +1424,18 @@ var gMainPane = {
     }
   },
 
   /**
    * Sets the pref values based on the selected item of the radiogroup.
    */
   updateWritePrefs() {
     if (AppConstants.MOZ_UPDATER) {
-      var enabledPref = document.getElementById("app.update.enabled");
-      var autoPref = document.getElementById("app.update.auto");
+      var enabledPref = Preferences.get("app.update.enabled");
+      var autoPref = Preferences.get("app.update.auto");
       var radiogroup = document.getElementById("updateRadioGroup");
       switch (radiogroup.value) {
         case "auto": // 1. Automatically install updates for Desktop only
           enabledPref.value = true;
           autoPref.value = true;
           break;
         case "checkOnly": // 2. Check, but let me choose
           enabledPref.value = true;
@@ -2322,17 +2446,17 @@ var gMainPane = {
 
   /**
    * Enables/disables the folder field and Browse button based on whether a
    * default download directory is being used.
    */
   readUseDownloadDir() {
     var downloadFolder = document.getElementById("downloadFolder");
     var chooseFolder = document.getElementById("chooseFolder");
-    var preference = document.getElementById("browser.download.useDownloadDir");
+    var preference = Preferences.get("browser.download.useDownloadDir");
     downloadFolder.disabled = !preference.value || preference.locked;
     chooseFolder.disabled = !preference.value || preference.locked;
 
     this.readCloudStorage().catch(Components.utils.reportError);
     // don't override the preference's value in UI
     return undefined;
   },
 
@@ -2350,18 +2474,18 @@ var gMainPane = {
     if (providerDisplayName) {
       // Show cloud storage radio button with provider name in label
       let saveToCloudRadio = document.getElementById("saveToCloud");
       let cloudStrings = Services.strings.createBundle("resource://cloudstorage/preferences.properties");
       saveToCloudRadio.label = cloudStrings.formatStringFromName("saveFilesToCloudStorage",
         [providerDisplayName], 1);
       saveToCloudRadio.hidden = false;
 
-      let useDownloadDirPref = document.getElementById("browser.download.useDownloadDir");
-      let folderListPref = document.getElementById("browser.download.folderList");
+      let useDownloadDirPref = Preferences.get("browser.download.useDownloadDir");
+      let folderListPref = Preferences.get("browser.download.folderList");
 
       // Check if useDownloadDir is true and folderListPref is set to Cloud Storage value 3
       // before selecting cloudStorageradio button. Disable folder field and Browse button if
       // 'Save to Cloud Storage Provider' radio option is selected
       if (useDownloadDirPref.value && folderListPref.value === 3) {
         document.getElementById("saveWhere").selectedItem = saveToCloudRadio;
         document.getElementById("downloadFolder").disabled = true;
         document.getElementById("chooseFolder").disabled = true;
@@ -2385,53 +2509,53 @@ var gMainPane = {
     // Check if Save To Cloud Storage Provider radio option is displayed in UI
     // before continuing.
     let saveToCloudRadio = document.getElementById("saveToCloud");
     if (!saveToCloudRadio.hidden) {
       // When switching between SaveTo and SaveToCloud radio button
       // with useDownloadDirPref value true, if selectedIndex is other than
       // SaveTo radio button disable downloadFolder filefield and chooseFolder button
       let saveWhere = document.getElementById("saveWhere");
-      let useDownloadDirPref = document.getElementById("browser.download.useDownloadDir");
+      let useDownloadDirPref = Preferences.get("browser.download.useDownloadDir");
       if (useDownloadDirPref.value) {
         let downloadFolder = document.getElementById("downloadFolder");
         let chooseFolder = document.getElementById("chooseFolder");
         downloadFolder.disabled = saveWhere.selectedIndex || useDownloadDirPref.locked;
         chooseFolder.disabled = saveWhere.selectedIndex || useDownloadDirPref.locked;
       }
 
       // Set folderListPref value depending on radio option
       // selected. folderListPref should be set to 3 if Save To Cloud Storage Provider
       // option is selected. If user switch back to 'Save To' custom path or system
       // default Downloads, check pref 'browser.download.dir' before setting respective
       // folderListPref value. If currentDirPref is unspecified folderList should
       // default to 1
-      let folderListPref = document.getElementById("browser.download.folderList");
+      let folderListPref = Preferences.get("browser.download.folderList");
       let saveTo = document.getElementById("saveTo");
       if (saveWhere.selectedItem == saveToCloudRadio) {
         folderListPref.value = 3;
       } else if (saveWhere.selectedItem == saveTo) {
-        let currentDirPref = document.getElementById("browser.download.dir");
+        let currentDirPref = Preferences.get("browser.download.dir");
         folderListPref.value = currentDirPref.value ? await this._folderToIndex(currentDirPref.value) : 1;
       }
     }
   },
 
   /**
    * Displays a file picker in which the user can choose the location where
    * downloads are automatically saved, updating preferences and UI in
    * response to the choice, if one is made.
    */
   chooseFolder() {
     return this.chooseFolderTask().catch(Components.utils.reportError);
   },
   async chooseFolderTask() {
     let bundlePreferences = document.getElementById("bundlePreferences");
     let title = bundlePreferences.getString("chooseDownloadFolderTitle");
-    let folderListPref = document.getElementById("browser.download.folderList");
+    let folderListPref = Preferences.get("browser.download.folderList");
     let currentDirPref = await this._indexToFolder(folderListPref.value);
     let defDownloads = await this._indexToFolder(1);
     let fp = Components.classes["@mozilla.org/filepicker;1"].
       createInstance(Components.interfaces.nsIFilePicker);
 
     fp.init(window, title, Components.interfaces.nsIFilePicker.modeGetFolder);
     fp.appendFilters(Components.interfaces.nsIFilePicker.filterAll);
     // First try to open what's currently configured
@@ -2445,17 +2569,17 @@ var gMainPane = {
       fp.displayDirectory = await this._indexToFolder(0);
     }
 
     let result = await new Promise(resolve => fp.open(resolve));
     if (result != Components.interfaces.nsIFilePicker.returnOK) {
       return;
     }
 
-    let downloadDirPref = document.getElementById("browser.download.dir");
+    let downloadDirPref = Preferences.get("browser.download.dir");
     downloadDirPref.value = fp.file;
     folderListPref.value = await this._folderToIndex(fp.file);
     // Note, the real prefs will not be updated yet, so dnld manager's
     // userDownloadsDirectory may not return the right folder after
     // this code executes. displayDownloadDirPref will be called on
     // the assignment above to update the UI.
   },
 
@@ -2466,20 +2590,20 @@ var gMainPane = {
   displayDownloadDirPref() {
     this.displayDownloadDirPrefTask().catch(Components.utils.reportError);
 
     // don't override the preference's value in UI
     return undefined;
   },
 
   async displayDownloadDirPrefTask() {
-    var folderListPref = document.getElementById("browser.download.folderList");
+    var folderListPref = Preferences.get("browser.download.folderList");
     var bundlePreferences = document.getElementById("bundlePreferences");
     var downloadFolder = document.getElementById("downloadFolder");
-    var currentDirPref = document.getElementById("browser.download.dir");
+    var currentDirPref = Preferences.get("browser.download.dir");
 
     // Used in defining the correct path to the folder icon.
     var fph = Services.io.getProtocolHandler("file")
       .QueryInterface(Components.interfaces.nsIFileProtocolHandler);
     var iconUrlSpec;
 
     let folderIndex = folderListPref.value;
     if (folderIndex == 3) {
@@ -2565,17 +2689,17 @@ var gMainPane = {
    */
   _indexToFolder(aIndex) {
     switch (aIndex) {
       case 0:
         return this._getDownloadsFolder("Desktop");
       case 1:
         return this._getDownloadsFolder("Downloads");
     }
-    var currentDirPref = document.getElementById("browser.download.dir");
+    var currentDirPref = Preferences.get("browser.download.dir");
     return currentDirPref.value;
   }
 };
 
 // Utilities
 
 function getFileDisplayName(file) {
   if (AppConstants.platform == "win") {
@@ -2968,46 +3092,46 @@ FeedHandlerInfo.prototype = {
 
   // nsIHandlerInfo
 
   get description() {
     return this.element("bundlePreferences").getString(this._appPrefLabel);
   },
 
   get preferredApplicationHandler() {
-    switch (this.element(this._prefSelectedReader).value) {
+    switch (Preferences.get(this._prefSelectedReader).value) {
       case "client":
-        var file = this.element(this._prefSelectedApp).value;
+        var file = Preferences.get(this._prefSelectedApp).value;
         if (file)
           return getLocalHandlerApp(file);
 
         return null;
 
       case "web":
-        var uri = this.element(this._prefSelectedWeb).value;
+        var uri = Preferences.get(this._prefSelectedWeb).value;
         if (!uri)
           return null;
         return this._converterSvc.getWebContentHandlerByURI(this.type, uri);
 
       case "bookmarks":
       default:
         // When the pref is set to bookmarks, we handle feeds internally,
         // we don't forward them to a local or web handler app, so there is
         // no preferred handler.
         return null;
     }
   },
 
   set preferredApplicationHandler(aNewValue) {
     if (aNewValue instanceof Ci.nsILocalHandlerApp) {
-      this.element(this._prefSelectedApp).value = aNewValue.executable;
-      this.element(this._prefSelectedReader).value = "client";
+      Preferences.get(this._prefSelectedApp).value = aNewValue.executable;
+      Preferences.get(this._prefSelectedReader).value = "client";
     } else if (aNewValue instanceof Ci.nsIWebContentHandlerInfo) {
-      this.element(this._prefSelectedWeb).value = aNewValue.uri;
-      this.element(this._prefSelectedReader).value = "web";
+      Preferences.get(this._prefSelectedWeb).value = aNewValue.uri;
+      Preferences.get(this._prefSelectedReader).value = "web";
       // Make the web handler be the new "auto handler" for feeds.
       // Note: we don't have to unregister the auto handler when the user picks
       // a non-web handler (local app, Live Bookmarks, etc.) because the service
       // only uses the "auto handler" when the selected reader is a web handler.
       // We also don't have to unregister it when the user turns on "always ask"
       // (i.e. preview in browser), since that also overrides the auto handler.
       this._converterSvc.setAutoHandler(this.type, aNewValue);
     }
@@ -3057,17 +3181,17 @@ FeedHandlerInfo.prototype = {
     };
 
     // Add the selected local app if it's different from the OS default handler.
     // Unlike for other types, we can store only one local app at a time for the
     // feed type, since we store it in a preference that historically stores
     // only a single path.  But we display all the local apps the user chooses
     // while the prefpane is open, only dropping the list when the user closes
     // the prefpane, for maximum usability and consistency with other types.
-    var preferredAppFile = this.element(this._prefSelectedApp).value;
+    var preferredAppFile = Preferences.get(this._prefSelectedApp).value;
     if (preferredAppFile) {
       let preferredApp = getLocalHandlerApp(preferredAppFile);
       let defaultApp = this._defaultApplicationHandler;
       if (!defaultApp || !defaultApp.equals(preferredApp))
         this._possibleApplicationHandlers.appendElement(preferredApp);
     }
 
     // Add the registered web handlers.  There can be any number of these.
@@ -3125,17 +3249,17 @@ FeedHandlerInfo.prototype = {
       return this._defaultApplicationHandler.name;
 
     // Should we instead return null?
     return "";
   },
 
   // What to do with content of this type.
   get preferredAction() {
-    switch (this.element(this._prefSelectedAction).value) {
+    switch (Preferences.get(this._prefSelectedAction).value) {
 
       case "bookmarks":
         return Ci.nsIHandlerInfo.handleInternally;
 
       case "reader": {
         let preferredApp = this.preferredApplicationHandler;
         let defaultApp = this._defaultApplicationHandler;
 
@@ -3163,41 +3287,41 @@ FeedHandlerInfo.prototype = {
         return Ci.nsIHandlerInfo.handleInternally;
     }
   },
 
   set preferredAction(aNewValue) {
     switch (aNewValue) {
 
       case Ci.nsIHandlerInfo.handleInternally:
-        this.element(this._prefSelectedReader).value = "bookmarks";
+        Preferences.get(this._prefSelectedReader).value = "bookmarks";
         break;
 
       case Ci.nsIHandlerInfo.useHelperApp:
-        this.element(this._prefSelectedAction).value = "reader";
+        Preferences.get(this._prefSelectedAction).value = "reader";
         // The controller has already set preferredApplicationHandler
         // to the new helper app.
         break;
 
       case Ci.nsIHandlerInfo.useSystemDefault:
-        this.element(this._prefSelectedAction).value = "reader";
+        Preferences.get(this._prefSelectedAction).value = "reader";
         this.preferredApplicationHandler = this._defaultApplicationHandler;
         break;
     }
   },
 
   get alwaysAskBeforeHandling() {
-    return this.element(this._prefSelectedAction).value == "ask";
+    return Preferences.get(this._prefSelectedAction).value == "ask";
   },
 
   set alwaysAskBeforeHandling(aNewValue) {
     if (aNewValue == true)
-      this.element(this._prefSelectedAction).value = "ask";
+      Preferences.get(this._prefSelectedAction).value = "ask";
     else
-      this.element(this._prefSelectedAction).value = "reader";
+      Preferences.get(this._prefSelectedAction).value = "reader";
   },
 
   // Whether or not we are currently storing the action selected by the user.
   // We use this to suppress notification-triggered updates to the list when
   // we make changes that may spawn such updates, specifically when we change
   // the action for the feed type, which results in feed preference updates,
   // which spawn "pref changed" notifications that would otherwise cause us
   // to rebuild the view unnecessarily.
@@ -3216,17 +3340,17 @@ FeedHandlerInfo.prototype = {
   // Changes to the preferred action and handler take effect immediately
   // (we write them out to the preferences right as they happen),
   // so we when the controller calls store() after modifying the handlers,
   // the only thing we need to store is the removal of possible handlers
   // XXX Should we hold off on making the changes until this method gets called?
   store() {
     for (let app of this._possibleApplicationHandlers._removed) {
       if (app instanceof Ci.nsILocalHandlerApp) {
-        let pref = this.element(PREF_FEED_SELECTED_APP);
+        let pref = Preferences.get(PREF_FEED_SELECTED_APP);
         var preferredAppFile = pref.value;
         if (preferredAppFile) {
           let preferredApp = getLocalHandlerApp(preferredAppFile);
           if (app.equals(preferredApp))
             pref.reset();
         }
       } else {
         app.QueryInterface(Ci.nsIWebContentHandlerInfo);
--- a/browser/components/preferences/in-content/main.xul
+++ b/browser/components/preferences/in-content/main.xul
@@ -14,255 +14,16 @@
   <script type="application/javascript" src="chrome://browser/content/aboutDialog-appUpdater.js"/>
 #endif
 
 <script type="application/javascript"
         src="chrome://mozapps/content/preferences/fontbuilder.js"/>
 
 <stringbundle id="bundlePreferences" src="chrome://browser/locale/preferences.properties"/>
 
-<preferences id="mainPreferences" hidden="true" data-category="paneGeneral">
-
-    <!-- Startup -->
-    <preference id="browser.startup.page"
-                name="browser.startup.page"
-                type="int"/>
-    <preference id="browser.startup.homepage"
-                name="browser.startup.homepage"
-                type="wstring"/>
-
-#ifdef HAVE_SHELL_SERVICE
-    <preference id="browser.shell.checkDefaultBrowser"
-                name="browser.shell.checkDefaultBrowser"
-                type="bool"/>
-
-    <preference id="pref.general.disable_button.default_browser"
-                name="pref.general.disable_button.default_browser"
-                type="bool"/>
-#endif
-
-    <preference id="pref.browser.homepage.disable_button.current_page"
-                name="pref.browser.homepage.disable_button.current_page"
-                type="bool"/>
-    <preference id="pref.browser.homepage.disable_button.bookmark_page"
-                name="pref.browser.homepage.disable_button.bookmark_page"
-                type="bool"/>
-    <preference id="pref.browser.homepage.disable_button.restore_default"
-                name="pref.browser.homepage.disable_button.restore_default"
-                type="bool"/>
-
-    <preference id="browser.privatebrowsing.autostart"
-                name="browser.privatebrowsing.autostart"
-                type="bool"/>
-
-    <!-- Downloads -->
-    <preference id="browser.download.useDownloadDir"
-                name="browser.download.useDownloadDir"
-                type="bool"/>
-
-    <preference id="browser.download.folderList"
-                name="browser.download.folderList"
-                type="int"/>
-    <preference id="browser.download.dir"
-                name="browser.download.dir"
-                type="file"/>
-    <!-- Tab preferences
-    Preferences:
-
-    browser.link.open_newwindow
-        1 opens such links in the most recent window or tab,
-        2 opens such links in a new window,
-        3 opens such links in a new tab
-    browser.tabs.loadInBackground
-    - true if display should switch to a new tab which has been opened from a
-      link, false if display shouldn't switch
-    browser.tabs.warnOnClose
-    - true if when closing a window with multiple tabs the user is warned and
-      allowed to cancel the action, false to just close the window
-    browser.tabs.warnOnOpen
-    - true if the user should be warned if he attempts to open a lot of tabs at
-      once (e.g. a large folder of bookmarks), false otherwise
-    browser.taskbar.previews.enable
-    - true if tabs are to be shown in the Windows 7 taskbar
-    -->
-
-    <preference id="browser.link.open_newwindow"
-                name="browser.link.open_newwindow"
-                type="int"/>
-    <preference id="browser.tabs.loadInBackground"
-                name="browser.tabs.loadInBackground"
-                type="bool"
-                inverted="true"/>
-    <preference id="browser.tabs.warnOnClose"
-                name="browser.tabs.warnOnClose"
-                type="bool"/>
-    <preference id="browser.tabs.warnOnOpen"
-                name="browser.tabs.warnOnOpen"
-                type="bool"/>
-    <preference id="browser.sessionstore.restore_on_demand"
-                name="browser.sessionstore.restore_on_demand"
-                type="bool"/>
-#ifdef XP_WIN
-    <preference id="browser.taskbar.previews.enable"
-                name="browser.taskbar.previews.enable"
-                type="bool"/>
-#endif
-    <preference id="browser.ctrlTab.previews"
-                name="browser.ctrlTab.previews"
-                type="bool"/>
-
-  <!-- Fonts -->
-  <preference id="font.language.group"
-              name="font.language.group"
-              type="wstring"/>
-
-  <!-- Languages -->
-  <preference id="browser.translation.detectLanguage"
-              name="browser.translation.detectLanguage"
-              type="bool"/>
-
-  <!-- General tab -->
-
-  <!-- Accessibility
-   * accessibility.browsewithcaret
-     - true enables keyboard navigation and selection within web pages using a
-       visible caret, false uses normal keyboard navigation with no caret
-   * accessibility.typeaheadfind
-     - when set to true, typing outside text areas and input boxes will
-       automatically start searching for what's typed within the current
-       document; when set to false, no search action happens -->
-  <preference id="accessibility.browsewithcaret"
-              name="accessibility.browsewithcaret"
-              type="bool"/>
-  <preference id="accessibility.typeaheadfind"
-              name="accessibility.typeaheadfind"
-              type="bool"/>
-  <preference id="accessibility.blockautorefresh"
-              name="accessibility.blockautorefresh"
-              type="bool"/>
-#ifdef XP_WIN
-  <preference id="ui.osk.enabled"
-              name="ui.osk.enabled"
-              type="bool"/>
-#endif
-  <!-- Browsing
-   * general.autoScroll
-     - when set to true, clicking the scroll wheel on the mouse activates a
-       mouse mode where moving the mouse down scrolls the document downward with
-       speed correlated with the distance of the cursor from the original
-       position at which the click occurred (and likewise with movement upward);
-       if false, this behavior is disabled
-   * general.smoothScroll
-     - set to true to enable finer page scrolling than line-by-line on page-up,
-       page-down, and other such page movements -->
-  <preference id="general.autoScroll"
-              name="general.autoScroll"
-              type="bool"/>
-  <preference id="general.smoothScroll"
-              name="general.smoothScroll"
-              type="bool"/>
-  <preference id="layout.spellcheckDefault"
-              name="layout.spellcheckDefault"
-              type="int"/>
-
-  <preference id="browser.preferences.defaultPerformanceSettings.enabled"
-              name="browser.preferences.defaultPerformanceSettings.enabled"
-              type="bool"/>
-
-  <preference id="dom.ipc.processCount"
-              name="dom.ipc.processCount"
-              type="int"/>
-
-  <preference id="dom.ipc.processCount.web"
-              name="dom.ipc.processCount.web"
-              type="int"/>
-
-  <preference id="layers.acceleration.disabled"
-              name="layers.acceleration.disabled"
-              type="bool"
-              inverted="true"/>
-
-  <!-- Files and Applications -->
-  <preference id="browser.feeds.handler"
-              name="browser.feeds.handler"
-              type="string"/>
-  <preference id="browser.feeds.handler.default"
-              name="browser.feeds.handler.default"
-              type="string"/>
-  <preference id="browser.feeds.handlers.application"
-              name="browser.feeds.handlers.application"
-              type="file"/>
-  <preference id="browser.feeds.handlers.webservice"
-              name="browser.feeds.handlers.webservice"
-              type="string"/>
-
-  <preference id="browser.videoFeeds.handler"
-              name="browser.videoFeeds.handler"
-              type="string"/>
-  <preference id="browser.videoFeeds.handler.default"
-              name="browser.videoFeeds.handler.default"
-              type="string"/>
-  <preference id="browser.videoFeeds.handlers.application"
-              name="browser.videoFeeds.handlers.application"
-              type="file"/>
-  <preference id="browser.videoFeeds.handlers.webservice"
-              name="browser.videoFeeds.handlers.webservice"
-              type="string"/>
-
-  <preference id="browser.audioFeeds.handler"
-              name="browser.audioFeeds.handler"
-              type="string"/>
-  <preference id="browser.audioFeeds.handler.default"
-              name="browser.audioFeeds.handler.default"
-              type="string"/>
-  <preference id="browser.audioFeeds.handlers.application"
-              name="browser.audioFeeds.handlers.application"
-              type="file"/>
-  <preference id="browser.audioFeeds.handlers.webservice"
-              name="browser.audioFeeds.handlers.webservice"
-              type="string"/>
-
-  <preference id="pref.downloads.disable_button.edit_actions"
-              name="pref.downloads.disable_button.edit_actions"
-              type="bool"/>
-
-  <!-- DRM content -->
-  <preference id="media.eme.enabled"
-              name="media.eme.enabled"
-              type="bool"/>
-
-  <!-- Update -->
-  <preference id="browser.preferences.advanced.selectedTabIndex"
-              name="browser.preferences.advanced.selectedTabIndex"
-              type="int"/>
-
-#ifdef MOZ_UPDATER
-  <preference id="app.update.enabled"
-              name="app.update.enabled"
-              type="bool"/>
-  <preference id="app.update.auto"
-              name="app.update.auto"
-              type="bool"/>
-
-  <preference id="app.update.disable_button.showUpdateHistory"
-              name="app.update.disable_button.showUpdateHistory"
-              type="bool"/>
-
-#ifdef MOZ_MAINTENANCE_SERVICE
-  <preference id="app.update.service.enabled"
-              name="app.update.service.enabled"
-              type="bool"/>
-#endif
-#endif
-
-  <preference id="browser.search.update"
-              name="browser.search.update"
-              type="bool"/>
-</preferences>
-
 <hbox id="generalCategory"
       class="subcategory"
       hidden="true"
       data-category="paneGeneral">
   <label class="header-name" flex="1">&paneGeneral.title;</label>
 </hbox>
 
 <!-- Startup -->
--- a/browser/components/preferences/in-content/preferences.js
+++ b/browser/components/preferences/in-content/preferences.js
@@ -6,16 +6,17 @@
 /* import-globals-from subdialogs.js */
 /* import-globals-from main.js */
 /* import-globals-from search.js */
 /* import-globals-from containers.js */
 /* import-globals-from privacy.js */
 /* import-globals-from sync.js */
 /* import-globals-from findInPage.js */
 /* import-globals-from ../../../base/content/utilityOverlay.js */
+/* import-globals-from ../../../../toolkit/content/preferencesBindings.js */
 
 "use strict";
 
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 var Cu = Components.utils;
 var Cr = Components.results;
 
@@ -52,17 +53,17 @@ function register_module(categoryName, c
       this.inited = true;
     }
   });
 }
 
 document.addEventListener("DOMContentLoaded", init_all, {once: true});
 
 function init_all() {
-  document.documentElement.instantApply = true;
+  Preferences.forceEnableInstantApply();
 
   gSubDialog.init();
   register_module("paneGeneral", gMainPane);
   register_module("paneSearch", gSearchPane);
   register_module("panePrivacy", gPrivacyPane);
   register_module("paneContainers", gContainersPane);
   register_module("paneSync", gSyncPane);
   register_module("paneSearchResults", gSearchResultsPane);
@@ -313,24 +314,16 @@ function scrollContentTo(element) {
   let mainContent = document.querySelector(".main-content");
   let top = element.getBoundingClientRect().top - SEARCH_CONTAINER_HEIGHT;
   mainContent.scroll({
     top,
     behavior: "smooth",
   });
 }
 
-function helpButtonCommand() {
-  let pane = history.state;
-  let categories = document.getElementById("categories");
-  let helpTopic = categories.querySelector(".category[value=" + pane + "]")
-                            .getAttribute("helpTopic");
-  openHelpLink(helpTopic);
-}
-
 function friendlyPrefCategoryNameToInternalName(aName) {
   if (aName.startsWith("pane"))
     return aName;
   return "pane" + aName.substring(0, 1).toUpperCase() + aName.substr(1);
 }
 
 // This function is duplicated inside of utilityOverlay.js's openPreferences.
 function internalPrefCategoryNameToFriendlyName(aName) {
--- a/browser/components/preferences/in-content/preferences.xul
+++ b/browser/components/preferences/in-content/preferences.xul
@@ -96,16 +96,18 @@
 #endif
 
   <html:link rel="shortcut icon"
               href="chrome://browser/skin/settings.svg"/>
 
   <script type="application/javascript"
           src="chrome://browser/content/utilityOverlay.js"/>
   <script type="application/javascript"
+          src="chrome://global/content/preferencesBindings.js"/>
+  <script type="application/javascript"
           src="chrome://browser/content/preferences/in-content/preferences.js"/>
   <script src="chrome://browser/content/preferences/in-content/findInPage.js"/>
   <script src="chrome://browser/content/preferences/in-content/subdialogs.js"/>
 
   <stringbundle id="bundleBrand"
                 src="chrome://branding/locale/brand.properties"/>
   <stringbundle id="bundlePreferences"
                 src="chrome://browser/locale/preferences/preferences.properties"/>
@@ -187,24 +189,24 @@
       <key key="&focusSearch1.key;" modifiers="accel" id="focusSearch1" oncommand="gSearchResultsPane.searchInput.focus();"/>
     </keyset>
 
     <vbox class="main-content" flex="1" align="start">
       <vbox class="pane-container">
         <hbox class="search-container" pack="end">
           <textbox type="search" id="searchInput" style="width: &searchField.width;" hidden="true" clickSelectsAll="true"/>
         </hbox>
-        <prefpane id="mainPrefPane">
+        <vbox id="mainPrefPane" class="prefpane prefwindow">
 #include searchResults.xul
 #include main.xul
 #include search.xul
 #include privacy.xul
 #include containers.xul
 #include sync.xul
-        </prefpane>
+        </vbox>
       </vbox>
     </vbox>
   </hbox>
 
   <stack id="dialogStack" hidden="true"/>
   <vbox id="dialogTemplate" class="dialogOverlay" align="center" pack="center" topmost="true" hidden="true">
     <groupbox class="dialogBox"
               orient="vertical"
--- a/browser/components/preferences/in-content/privacy.js
+++ b/browser/components/preferences/in-content/privacy.js
@@ -29,16 +29,97 @@ XPCOMUtils.defineLazyGetter(this, "Alert
     // This will throw if manualDoNotDisturb isn't implemented.
     alertsService.manualDoNotDisturb;
     return alertsService;
   } catch (ex) {
     return undefined;
   }
 });
 
+Preferences.addAll([
+  // Tracking
+  { id: "privacy.trackingprotection.enabled", type: "bool" },
+  { id: "privacy.trackingprotection.pbmode.enabled", type: "bool" },
+
+  // Button prefs
+  { id: "pref.privacy.disable_button.cookie_exceptions", type: "bool" },
+  { id: "pref.privacy.disable_button.view_cookies", type: "bool" },
+  { id: "pref.privacy.disable_button.change_blocklist", type: "bool" },
+  { id: "pref.privacy.disable_button.tracking_protection_exceptions", type: "bool" },
+
+  // Location Bar
+  { id: "browser.urlbar.autocomplete.enabled", type: "bool" },
+  { id: "browser.urlbar.suggest.bookmark", type: "bool" },
+  { id: "browser.urlbar.suggest.history", type: "bool" },
+  { id: "browser.urlbar.suggest.openpage", type: "bool" },
+
+  // History
+  { id: "places.history.enabled", type: "bool" },
+  { id: "browser.formfill.enable", type: "bool" },
+  { id: "privacy.history.custom", type: "bool" },
+  // Cookies
+  { id: "network.cookie.cookieBehavior", type: "int" },
+  { id: "network.cookie.lifetimePolicy", type: "int" },
+  { id: "network.cookie.blockFutureCookies", type: "bool" },
+  // Clear Private Data
+  { id: "privacy.sanitize.sanitizeOnShutdown", type: "bool" },
+  { id: "privacy.sanitize.timeSpan", type: "int" },
+  // Do not track
+  { id: "privacy.donottrackheader.enabled", type: "bool" },
+
+  // Popups
+  { id: "dom.disable_open_during_load", type: "bool" },
+  // Passwords
+  { id: "signon.rememberSignons", type: "bool" },
+
+  // Buttons
+  { id: "pref.privacy.disable_button.view_passwords", type: "bool" },
+  { id: "pref.privacy.disable_button.view_passwords_exceptions", type: "bool" },
+
+  /* Certificates tab
+   * security.default_personal_cert
+   *   - a string:
+   *       "Select Automatically"   select a certificate automatically when a site
+   *                                requests one
+   *       "Ask Every Time"         present a dialog to the user so he can select
+   *                                the certificate to use on a site which
+   *                                requests one
+   */
+  { id: "security.default_personal_cert", type: "string" },
+
+  { id: "security.disable_button.openCertManager", type: "bool" },
+
+  { id: "security.disable_button.openDeviceManager", type: "bool" },
+
+  { id: "security.OCSP.enabled", type: "int" },
+
+  // Add-ons, malware, phishing
+  { id: "xpinstall.whitelist.required", type: "bool" },
+
+  { id: "browser.safebrowsing.malware.enabled", type: "bool" },
+  { id: "browser.safebrowsing.phishing.enabled", type: "bool" },
+
+  { id: "browser.safebrowsing.downloads.enabled", type: "bool" },
+
+  { id: "urlclassifier.malwareTable", type: "string" },
+
+  { id: "browser.safebrowsing.downloads.remote.block_potentially_unwanted", type: "bool" },
+  { id: "browser.safebrowsing.downloads.remote.block_uncommon", type: "bool" },
+
+  // Network tab
+  { id: "browser.cache.disk.capacity", type: "int" },
+
+  { id: "browser.cache.disk.smart_size.enabled", type: "bool", inverted: "true" },
+]);
+
+// Data Choices tab
+if (AppConstants.MOZ_CRASHREPORTER) {
+  Preferences.add({ id: "browser.crashReports.unsubmittedCheck.autoSubmit", type: "bool" });
+}
+
 var gPrivacyPane = {
   _pane: null,
 
   /**
    * Whether the use has selected the auto-start private browsing mode in the UI.
    */
   _autoStartPrivateBrowsing: false,
 
@@ -99,20 +180,20 @@ var gPrivacyPane = {
     this.initializeHistoryMode();
     this.updateHistoryModePane();
     this.updatePrivacyMicroControls();
     this.initAutoStartPrivateBrowsingReverter();
     this._initTrackingProtection();
     this._initTrackingProtectionPBM();
     this._initAutocomplete();
 
-    setEventListener("privacy.sanitize.sanitizeOnShutdown", "change",
-      gPrivacyPane._updateSanitizeSettingsButton);
-    setEventListener("browser.privatebrowsing.autostart", "change",
-      gPrivacyPane.updatePrivacyMicroControls);
+    Preferences.get("privacy.sanitize.sanitizeOnShutdown").on("change",
+      gPrivacyPane._updateSanitizeSettingsButton.bind(gPrivacyPane));
+    Preferences.get("browser.privatebrowsing.autostart").on("change",
+      gPrivacyPane.updatePrivacyMicroControls.bind(gPrivacyPane));
     setEventListener("historyMode", "command", function() {
       gPrivacyPane.updateHistoryModePane();
       gPrivacyPane.updateHistoryModePrefs();
       gPrivacyPane.updatePrivacyMicroControls();
       gPrivacyPane.updateAutostart();
     });
     setEventListener("historyRememberClear", "click", function(event) {
       if (event.button == 0) {
@@ -321,36 +402,36 @@ var gPrivacyPane = {
   },
 
   // TRACKING PROTECTION MODE
 
   /**
    * Selects the right item of the Tracking Protection radiogroup.
    */
   trackingProtectionReadPrefs() {
-    let enabledPref = document.getElementById("privacy.trackingprotection.enabled");
-    let pbmPref = document.getElementById("privacy.trackingprotection.pbmode.enabled");
+    let enabledPref = Preferences.get("privacy.trackingprotection.enabled");
+    let pbmPref = Preferences.get("privacy.trackingprotection.pbmode.enabled");
     let radiogroup = document.getElementById("trackingProtectionRadioGroup");
 
     // Global enable takes precedence over enabled in Private Browsing.
     if (enabledPref.value) {
       radiogroup.value = "always";
     } else if (pbmPref.value) {
       radiogroup.value = "private";
     } else {
       radiogroup.value = "never";
     }
   },
 
   /**
    * Sets the pref values based on the selected item of the radiogroup.
    */
   trackingProtectionWritePrefs() {
-    let enabledPref = document.getElementById("privacy.trackingprotection.enabled");
-    let pbmPref = document.getElementById("privacy.trackingprotection.pbmode.enabled");
+    let enabledPref = Preferences.get("privacy.trackingprotection.enabled");
+    let pbmPref = Preferences.get("privacy.trackingprotection.pbmode.enabled");
     let radiogroup = document.getElementById("trackingProtectionRadioGroup");
 
     switch (radiogroup.value) {
       case "always":
         enabledPref.value = true;
         pbmPref.value = true;
         break;
       case "private":
@@ -406,28 +487,28 @@ var gPrivacyPane = {
    * Check whether preferences values are set to keep history
    *
    * @param aPrefs an array of pref names to check for
    * @returns boolean true if all of the prefs are set to keep history,
    *                  false otherwise
    */
   _checkHistoryValues(aPrefs) {
     for (let pref of Object.keys(aPrefs)) {
-      if (document.getElementById(pref).value != aPrefs[pref])
+      if (Preferences.get(pref).value != aPrefs[pref])
         return false;
     }
     return true;
   },
 
   /**
    * Initialize the history mode menulist based on the privacy preferences
    */
   initializeHistoryMode() {
     let mode;
-    let getVal = aPref => document.getElementById(aPref).value;
+    let getVal = aPref => Preferences.get(aPref).value;
 
     if (getVal("privacy.history.custom"))
       mode = "custom";
     else if (this._checkHistoryValues(this.prefsForKeepingHistory)) {
       if (getVal("browser.privatebrowsing.autostart"))
         mode = "dontremember";
       else
         mode = "remember";
@@ -449,93 +530,93 @@ var gPrivacyPane = {
       case "dontremember":
         selectedIndex = 1;
         break;
       case "custom":
         selectedIndex = 2;
         break;
     }
     document.getElementById("historyPane").selectedIndex = selectedIndex;
-    document.getElementById("privacy.history.custom").value = selectedIndex == 2;
+    Preferences.get("privacy.history.custom").value = selectedIndex == 2;
   },
 
   /**
    * Update the private browsing auto-start pref and the history mode
    * micro-management prefs based on the history mode menulist
    */
   updateHistoryModePrefs() {
-    let pref = document.getElementById("browser.privatebrowsing.autostart");
+    let pref = Preferences.get("browser.privatebrowsing.autostart");
     switch (document.getElementById("historyMode").value) {
       case "remember":
         if (pref.value)
           pref.value = false;
 
         // select the remember history option if needed
-        document.getElementById("places.history.enabled").value = true;
+        Preferences.get("places.history.enabled").value = true;
 
         // select the remember forms history option
-        document.getElementById("browser.formfill.enable").value = true;
+        Preferences.get("browser.formfill.enable").value = true;
 
         // select the allow cookies option
-        document.getElementById("network.cookie.cookieBehavior").value = 0;
+        Preferences.get("network.cookie.cookieBehavior").value = 0;
         // select the cookie lifetime policy option
-        document.getElementById("network.cookie.lifetimePolicy").value = 0;
+        Preferences.get("network.cookie.lifetimePolicy").value = 0;
 
         // select the clear on close option
-        document.getElementById("privacy.sanitize.sanitizeOnShutdown").value = false;
+        Preferences.get("privacy.sanitize.sanitizeOnShutdown").value = false;
         break;
       case "dontremember":
         if (!pref.value)
           pref.value = true;
         break;
     }
   },
 
   /**
    * Update the privacy micro-management controls based on the
    * value of the private browsing auto-start checkbox.
    */
   updatePrivacyMicroControls() {
     if (document.getElementById("historyMode").value == "custom") {
       let disabled = this._autoStartPrivateBrowsing =
-        document.getElementById("browser.privatebrowsing.autostart").value;
+        Preferences.get("browser.privatebrowsing.autostart").value;
       this.dependentControls.forEach(function(aElement) {
         let control = document.getElementById(aElement);
         let preferenceId = control.getAttribute("preference");
         if (!preferenceId) {
           let dependentControlId = control.getAttribute("control");
           if (dependentControlId) {
             let dependentControl = document.getElementById(dependentControlId);
             preferenceId = dependentControl.getAttribute("preference");
           }
         }
 
-        let preference = preferenceId ? document.getElementById(preferenceId) : {};
+        let preference = preferenceId ? Preferences.get(preferenceId) : {};
         control.disabled = disabled || preference.locked;
       });
 
       // adjust the cookie controls status
       this.readAcceptCookies();
-      let lifetimePolicy = document.getElementById("network.cookie.lifetimePolicy").value;
+      let lifetimePolicy = Preferences.get("network.cookie.lifetimePolicy").value;
       if (lifetimePolicy != Ci.nsICookieService.ACCEPT_NORMALLY &&
         lifetimePolicy != Ci.nsICookieService.ACCEPT_SESSION &&
         lifetimePolicy != Ci.nsICookieService.ACCEPT_FOR_N_DAYS) {
         lifetimePolicy = Ci.nsICookieService.ACCEPT_NORMALLY;
       }
       document.getElementById("keepCookiesUntil").value = disabled ? 2 : lifetimePolicy;
 
       // adjust the checked state of the sanitizeOnShutdown checkbox
       document.getElementById("alwaysClear").checked = disabled ? false :
-        document.getElementById("privacy.sanitize.sanitizeOnShutdown").value;
+        Preferences.get("privacy.sanitize.sanitizeOnShutdown").value;
 
       // adjust the checked state of the remember history checkboxes
       document.getElementById("rememberHistory").checked = disabled ? false :
-        document.getElementById("places.history.enabled").value;
+        Preferences.get("places.history.enabled").value;
       document.getElementById("rememberForms").checked = disabled ? false :
-        document.getElementById("browser.formfill.enable").value;
+        Preferences.get("browser.formfill.enable").value;
 
       if (!disabled) {
         // adjust the Settings button for sanitizeOnShutdown
         this._updateSanitizeSettingsButton();
       }
     }
   },
 
@@ -551,17 +632,17 @@ var gPrivacyPane = {
     this._lastCheckState = autoStart.hasAttribute("checked");
   },
 
   _lastMode: null,
   _lastCheckState: null,
   updateAutostart() {
     let mode = document.getElementById("historyMode");
     let autoStart = document.getElementById("privateBrowsingAutoStart");
-    let pref = document.getElementById("browser.privatebrowsing.autostart");
+    let pref = Preferences.get("browser.privatebrowsing.autostart");
     if ((mode.value == "custom" && this._lastCheckState == autoStart.checked) ||
       (mode.value == "remember" && !this._lastCheckState) ||
       (mode.value == "dontremember" && this._lastCheckState)) {
       // These are all no-op changes, so we don't need to prompt.
       this._lastMode = mode.selectedIndex;
       this._lastCheckState = autoStart.hasAttribute("checked");
       return;
     }
@@ -619,24 +700,16 @@ var gPrivacyPane = {
       brandShortName: brandName,
       windowTitle: bundlePreferences.getString("blockliststitle"),
       introText: bundlePreferences.getString("blockliststext")
     };
     gSubDialog.open("chrome://browser/content/preferences/blocklists.xul",
       null, params);
   },
 
-  /**
-   * Displays the Do Not Track settings dialog.
-   */
-  showDoNotTrackSettings() {
-    gSubDialog.open("chrome://browser/content/preferences/donottrack.xul",
-      "resizable=no");
-  },
-
   // HISTORY
 
   /*
    * Preferences:
    *
    * places.history.enabled
    * - whether history is enabled or not
    * browser.formfill.enable
@@ -663,17 +736,17 @@ var gPrivacyPane = {
    */
 
   /**
    * Reads the network.cookie.cookieBehavior preference value and
    * enables/disables the rest of the cookie UI accordingly, returning true
    * if cookies are enabled.
    */
   readAcceptCookies() {
-    var pref = document.getElementById("network.cookie.cookieBehavior");
+    var pref = Preferences.get("network.cookie.cookieBehavior");
     var acceptThirdPartyLabel = document.getElementById("acceptThirdPartyLabel");
     var acceptThirdPartyMenu = document.getElementById("acceptThirdPartyMenu");
     var keepUntil = document.getElementById("keepUntil");
     var menu = document.getElementById("keepCookiesUntil");
 
     // enable the rest of the UI for anything other than "disable all cookies"
     var acceptCookies = (pref.value != 2);
 
@@ -697,17 +770,17 @@ var gPrivacyPane = {
 
     return accept.checked ? 0 : 2;
   },
 
   /**
    * Converts between network.cookie.cookieBehavior and the third-party cookie UI
    */
   readAcceptThirdPartyCookies() {
-    var pref = document.getElementById("network.cookie.cookieBehavior");
+    var pref = Preferences.get("network.cookie.cookieBehavior");
     switch (pref.value) {
       case 0:
         return "always";
       case 1:
         return "never";
       case 2:
         return "never";
       case 3:
@@ -774,17 +847,17 @@ var gPrivacyPane = {
   },
 
 
   /**
    * Displays a dialog from which individual parts of private data may be
    * cleared.
    */
   clearPrivateDataNow(aClearEverything) {
-    var ts = document.getElementById("privacy.sanitize.timeSpan");
+    var ts = Preferences.get("privacy.sanitize.timeSpan");
     var timeSpanOrig = ts.value;
 
     if (aClearEverything) {
       ts.value = 0;
     }
 
     gSubDialog.open("chrome://browser/content/sanitize.xul", "resizable=no", null, () => {
       // reset the timeSpan pref
@@ -797,17 +870,17 @@ var gPrivacyPane = {
   },
 
   /**
    * Enables or disables the "Settings..." button depending
    * on the privacy.sanitize.sanitizeOnShutdown preference value
    */
   _updateSanitizeSettingsButton() {
     var settingsButton = document.getElementById("clearDataSettings");
-    var sanitizeOnShutdownPref = document.getElementById("privacy.sanitize.sanitizeOnShutdown");
+    var sanitizeOnShutdownPref = Preferences.get("privacy.sanitize.sanitizeOnShutdown");
 
     settingsButton.disabled = !sanitizeOnShutdownPref.value;
   },
 
   toggleDoNotDisturbNotifications(event) {
     AlertsServiceDND.manualDoNotDisturb = event.target.checked;
   },
 
@@ -903,17 +976,17 @@ var gPrivacyPane = {
   // UTILITY FUNCTIONS
 
   /**
    * Utility function to enable/disable the button specified by aButtonID based
    * on the value of the Boolean preference specified by aPreferenceID.
    */
   updateButtons(aButtonID, aPreferenceID) {
     var button = document.getElementById(aButtonID);
-    var preference = document.getElementById(aPreferenceID);
+    var preference = Preferences.get(aPreferenceID);
     button.disabled = preference.value != true;
     return undefined;
   },
 
   // BEGIN UI CODE
 
   /*
    * Preferences:
@@ -1021,17 +1094,17 @@ var gPrivacyPane = {
   },
 
   /**
    * Enables/disables the Exceptions button used to configure sites where
    * passwords are never saved. When browser is set to start in Private
    * Browsing mode, the "Remember passwords" UI is useless, so we disable it.
    */
   readSavePasswords() {
-    var pref = document.getElementById("signon.rememberSignons");
+    var pref = Preferences.get("signon.rememberSignons");
     var excepts = document.getElementById("passwordExceptions");
 
     if (PrivateBrowsingUtils.permanentPrivateBrowsing) {
       document.getElementById("savePasswords").disabled = true;
       excepts.disabled = true;
       return false;
     }
     excepts.disabled = !pref.value;
@@ -1039,38 +1112,38 @@ var gPrivacyPane = {
     return undefined;
   },
 
   /**
    * Enables/disables the add-ons Exceptions button depending on whether
    * or not add-on installation warnings are displayed.
    */
   readWarnAddonInstall() {
-    var warn = document.getElementById("xpinstall.whitelist.required");
+    var warn = Preferences.get("xpinstall.whitelist.required");
     var exceptions = document.getElementById("addonExceptions");
 
     exceptions.disabled = !warn.value;
 
     // don't override the preference value
     return undefined;
   },
 
   _initSafeBrowsing() {
     let enableSafeBrowsing = document.getElementById("enableSafeBrowsing");
     let blockDownloads = document.getElementById("blockDownloads");
     let blockUncommonUnwanted = document.getElementById("blockUncommonUnwanted");
 
-    let safeBrowsingPhishingPref = document.getElementById("browser.safebrowsing.phishing.enabled");
-    let safeBrowsingMalwarePref = document.getElementById("browser.safebrowsing.malware.enabled");
+    let safeBrowsingPhishingPref = Preferences.get("browser.safebrowsing.phishing.enabled");
+    let safeBrowsingMalwarePref = Preferences.get("browser.safebrowsing.malware.enabled");
 
-    let blockDownloadsPref = document.getElementById("browser.safebrowsing.downloads.enabled");
-    let malwareTable = document.getElementById("urlclassifier.malwareTable");
+    let blockDownloadsPref = Preferences.get("browser.safebrowsing.downloads.enabled");
+    let malwareTable = Preferences.get("urlclassifier.malwareTable");
 
-    let blockUnwantedPref = document.getElementById("browser.safebrowsing.downloads.remote.block_potentially_unwanted");
-    let blockUncommonPref = document.getElementById("browser.safebrowsing.downloads.remote.block_uncommon");
+    let blockUnwantedPref = Preferences.get("browser.safebrowsing.downloads.remote.block_potentially_unwanted");
+    let blockUncommonPref = Preferences.get("browser.safebrowsing.downloads.remote.block_uncommon");
 
     let learnMoreLink = document.getElementById("enableSafeBrowsingLearnMore");
     let phishingUrl = Services.urlFormatter.formatURLPref("app.support.baseURL") + "phishing-malware";
     learnMoreLink.setAttribute("href", phishingUrl);
 
     enableSafeBrowsing.addEventListener("command", function() {
       safeBrowsingPhishingPref.value = enableSafeBrowsing.checked;
       safeBrowsingMalwarePref.value = enableSafeBrowsing.checked;
@@ -1194,17 +1267,17 @@ var gPrivacyPane = {
    * values for "security.OCSP.enabled" are:
    * 0: fetching is disabled
    * 1: fetch for all certificates
    * 2: fetch only for EV certificates
    * Hence, if "security.OCSP.enabled" is non-zero, the checkbox should be
    * checked. Otherwise, it should be unchecked.
    */
   readEnableOCSP() {
-    var preference = document.getElementById("security.OCSP.enabled");
+    var preference = Preferences.get("security.OCSP.enabled");
     // This is the case if the preference is the default value.
     if (preference.value === undefined) {
       return true;
     }
     return preference.value != 0;
   },
 
   /**
@@ -1307,47 +1380,47 @@ var gPrivacyPane = {
     document.getElementById("useCacheBefore").disabled = smartSizeEnabled;
     document.getElementById("cacheSize").disabled = smartSizeEnabled;
     document.getElementById("useCacheAfter").disabled = smartSizeEnabled;
   },
 
   readSmartSizeEnabled() {
     // The smart_size.enabled preference element is inverted="true", so its
     // value is the opposite of the actual pref value
-    var disabled = document.getElementById("browser.cache.disk.smart_size.enabled").value;
+    var disabled = Preferences.get("browser.cache.disk.smart_size.enabled").value;
     this.updateCacheSizeUI(!disabled);
   },
 
   /**
    * Converts the cache size from units of KB to units of MB and stores it in
    * the textbox element.
    *
    * Preferences:
    *
    * browser.cache.disk.capacity
    * - the size of the browser cache in KB
    * - Only used if browser.cache.disk.smart_size.enabled is disabled
    */
   updateCacheSizeInputField() {
     let cacheSizeElem = document.getElementById("cacheSize");
-    let cachePref = document.getElementById("browser.cache.disk.capacity");
+    let cachePref = Preferences.get("browser.cache.disk.capacity");
     cacheSizeElem.value = cachePref.value / 1024;
     if (cachePref.locked)
       cacheSizeElem.disabled = true;
   },
 
   /**
    * Updates the cache size preference once user enters a new value.
    * We intentionally do not set preference="browser.cache.disk.capacity"
    * onto the textbox directly, as that would update the pref at each keypress
    * not only after the final value is entered.
    */
   updateCacheSizePref() {
     let cacheSizeElem = document.getElementById("cacheSize");
-    let cachePref = document.getElementById("browser.cache.disk.capacity");
+    let cachePref = Preferences.get("browser.cache.disk.capacity");
     // Converts the cache size as specified in UI (in MB) to KB.
     let intValue = parseInt(cacheSizeElem.value, 10);
     cachePref.value = isNaN(intValue) ? 0 : intValue * 1024;
   },
 
   clearSiteData() {
     let flags =
       Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0 +
--- a/browser/components/preferences/in-content/privacy.xul
+++ b/browser/components/preferences/in-content/privacy.xul
@@ -1,175 +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/.
 
 <!-- Privacy panel -->
 
 <script type="application/javascript"
         src="chrome://browser/content/preferences/in-content/privacy.js"/>
-
-<preferences id="privacyPreferences" hidden="true" data-category="panePrivacy">
-
-  <!-- Tracking -->
-  <preference id="privacy.trackingprotection.enabled"
-              name="privacy.trackingprotection.enabled"
-              type="bool"/>
-  <preference id="privacy.trackingprotection.pbmode.enabled"
-              name="privacy.trackingprotection.pbmode.enabled"
-              type="bool"/>
-
-  <!-- XXX button prefs -->
-  <preference id="pref.privacy.disable_button.cookie_exceptions"
-              name="pref.privacy.disable_button.cookie_exceptions"
-              type="bool"/>
-  <preference id="pref.privacy.disable_button.view_cookies"
-              name="pref.privacy.disable_button.view_cookies"
-              type="bool"/>
-  <preference id="pref.privacy.disable_button.change_blocklist"
-              name="pref.privacy.disable_button.change_blocklist"
-              type="bool"/>
-  <preference id="pref.privacy.disable_button.tracking_protection_exceptions"
-              name="pref.privacy.disable_button.tracking_protection_exceptions"
-              type="bool"/>
-
-  <!-- Location Bar -->
-  <preference id="browser.urlbar.autocomplete.enabled"
-              name="browser.urlbar.autocomplete.enabled"
-              type="bool"/>
-  <preference id="browser.urlbar.suggest.bookmark"
-              name="browser.urlbar.suggest.bookmark"
-              type="bool"/>
-  <preference id="browser.urlbar.suggest.history"
-              name="browser.urlbar.suggest.history"
-              type="bool"/>
-  <preference id="browser.urlbar.suggest.openpage"
-              name="browser.urlbar.suggest.openpage"
-              type="bool"/>
-
-  <!-- History -->
-  <preference id="places.history.enabled"
-              name="places.history.enabled"
-              type="bool"/>
-  <preference id="browser.formfill.enable"
-              name="browser.formfill.enable"
-              type="bool"/>
-  <preference id="privacy.history.custom"
-              name="privacy.history.custom"
-              type="bool"/>
-  <!-- Cookies -->
-  <preference id="network.cookie.cookieBehavior"
-              name="network.cookie.cookieBehavior"
-              type="int"/>
-  <preference id="network.cookie.lifetimePolicy"
-              name="network.cookie.lifetimePolicy"
-              type="int"/>
-  <preference id="network.cookie.blockFutureCookies"
-              name="network.cookie.blockFutureCookies"
-              type="bool"/>
-  <!-- Clear Private Data -->
-  <preference id="privacy.sanitize.sanitizeOnShutdown"
-              name="privacy.sanitize.sanitizeOnShutdown"
-              type="bool"/>
-  <preference id="privacy.sanitize.timeSpan"
-              name="privacy.sanitize.timeSpan"
-              type="int"/>
-  <!-- Private Browsing -->
-  <preference id="browser.privatebrowsing.autostart"
-              name="browser.privatebrowsing.autostart"
-              type="bool"/>
-  <!-- Do not track -->
-  <preference id="privacy.donottrackheader.enabled"
-              name="privacy.donottrackheader.enabled"
-              type="bool"/>
-  <!-- Popups -->
-  <preference id="dom.disable_open_during_load"
-              name="dom.disable_open_during_load"
-              type="bool"/>
-  <!-- Passwords -->
-  <preference id="signon.rememberSignons" name="signon.rememberSignons" type="bool"/>
-
-  <!-- XXX buttons -->
-  <preference id="pref.privacy.disable_button.view_passwords"
-              name="pref.privacy.disable_button.view_passwords"
-              type="bool"/>
-  <preference id="pref.privacy.disable_button.view_passwords_exceptions"
-              name="pref.privacy.disable_button.view_passwords_exceptions"
-              type="bool"/>
-
-  <!-- Certificates tab
-   * security.default_personal_cert
-     - a string:
-         "Select Automatically"   select a certificate automatically when a site
-                                  requests one
-         "Ask Every Time"         present a dialog to the user so he can select
-                                  the certificate to use on a site which
-                                  requests one -->
-  <preference id="security.default_personal_cert"
-              name="security.default_personal_cert"
-              type="string"/>
-
-  <preference id="security.disable_button.openCertManager"
-              name="security.disable_button.openCertManager"
-              type="bool"/>
-
-  <preference id="security.disable_button.openDeviceManager"
-              name="security.disable_button.openDeviceManager"
-              type="bool"/>
-
-  <preference id="security.OCSP.enabled"
-              name="security.OCSP.enabled"
-              type="int"/>
-
-  <!-- Add-ons, malware, phishing -->
-  <preference id="xpinstall.whitelist.required"
-              name="xpinstall.whitelist.required"
-              type="bool"/>
-
-  <preference id="browser.safebrowsing.malware.enabled"
-              name="browser.safebrowsing.malware.enabled"
-              type="bool"/>
-  <preference id="browser.safebrowsing.phishing.enabled"
-              name="browser.safebrowsing.phishing.enabled"
-              type="bool"/>
-
-  <preference id="browser.safebrowsing.downloads.enabled"
-              name="browser.safebrowsing.downloads.enabled"
-              type="bool"/>
-
-  <preference id="urlclassifier.malwareTable"
-              name="urlclassifier.malwareTable"
-              type="string"/>
-
-  <preference id="browser.safebrowsing.downloads.remote.block_potentially_unwanted"
-              name="browser.safebrowsing.downloads.remote.block_potentially_unwanted"
-              type="bool"/>
-  <preference id="browser.safebrowsing.downloads.remote.block_uncommon"
-              name="browser.safebrowsing.downloads.remote.block_uncommon"
-              type="bool"/>
-
-  <!-- Network tab -->
-  <preference id="browser.cache.disk.capacity"
-              name="browser.cache.disk.capacity"
-              type="int"/>
-
-  <preference id="browser.cache.disk.smart_size.enabled"
-              name="browser.cache.disk.smart_size.enabled"
-              inverted="true"
-              type="bool"/>
-
-  <!-- Data Choices tab -->
-#ifdef MOZ_CRASHREPORTER
-  <preference id="browser.crashReports.unsubmittedCheck.autoSubmit"
-              name="browser.crashReports.unsubmittedCheck.autoSubmit"
-              type="bool"/>
-#endif
-
-</preferences>
-
 <stringbundle id="bundlePreferences" src="chrome://browser/locale/preferences/preferences.properties"/>
 <stringbundle id="signonBundle" src="chrome://passwordmgr/locale/passwordmgr.properties"/>
 
 <hbox id="browserPrivacyCategory"
       class="subcategory"
       hidden="true"
       data-category="panePrivacy">
   <label class="header-name" flex="1">&browserPrivacy.label;</label>
--- a/browser/components/preferences/in-content/search.js
+++ b/browser/components/preferences/in-content/search.js
@@ -5,16 +5,23 @@
 /* import-globals-from preferences.js */
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
                                   "resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionSettingsStore",
                                   "resource://gre/modules/ExtensionSettingsStore.jsm");
 
+Preferences.addAll([
+  { id: "browser.search.suggest.enabled", type: "bool" },
+  { id: "browser.urlbar.suggest.searches", type: "bool" },
+  { id: "browser.search.hiddenOneOffs", type: "unichar" },
+  { id: "browser.search.widget.inNavBar", type: "bool" },
+]);
+
 const ENGINE_FLAVOR = "text/x-moz-search-engine";
 const SEARCH_TYPE = "default_search";
 const SEARCH_KEY = "defaultSearch";
 
 var gEngineView = null;
 
 var gSearchPane = {
 
@@ -45,34 +52,29 @@ var gSearchPane = {
 
     Services.obs.addObserver(this, "browser-search-engine-modified");
     window.addEventListener("unload", () => {
       Services.obs.removeObserver(this, "browser-search-engine-modified");
     });
 
     this._initAutocomplete();
 
-    let suggestsPref =
-      document.getElementById("browser.search.suggest.enabled");
-    suggestsPref.addEventListener("change", () => {
-      this.updateSuggestsCheckbox();
-    });
+    let suggestsPref = Preferences.get("browser.search.suggest.enabled");
+    suggestsPref.on("change", this.updateSuggestsCheckbox.bind(this));
     this.updateSuggestsCheckbox();
   },
 
   updateSuggestsCheckbox() {
-    let suggestsPref =
-      document.getElementById("browser.search.suggest.enabled");
+    let suggestsPref = Preferences.get("browser.search.suggest.enabled");
     let permanentPB =
       Services.prefs.getBoolPref("browser.privatebrowsing.autostart");
     let urlbarSuggests = document.getElementById("urlBarSuggestion");
     urlbarSuggests.disabled = !suggestsPref.value || permanentPB;
 
-    let urlbarSuggestsPref =
-      document.getElementById("browser.urlbar.suggest.searches");
+    let urlbarSuggestsPref = Preferences.get("browser.urlbar.suggest.searches");
     urlbarSuggests.checked = urlbarSuggestsPref.value;
     if (urlbarSuggests.disabled) {
       urlbarSuggests.checked = false;
     }
 
     let permanentPBLabel =
       document.getElementById("urlBarSuggestionPermanentPBLabel");
     permanentPBLabel.hidden = urlbarSuggests.hidden || !permanentPB;
@@ -310,17 +312,17 @@ var gSearchPane = {
   },
 
   saveOneClickEnginesList() {
     let hiddenList = [];
     for (let engine of gEngineView._engineStore.engines) {
       if (!engine.shown)
         hiddenList.push(engine.name);
     }
-    document.getElementById("browser.search.hiddenOneOffs").value =
+    Preferences.get("browser.search.hiddenOneOffs").value =
       hiddenList.join(",");
   },
 
   setDefaultEngine() {
     Services.search.currentEngine =
       document.getElementById("defaultEngine").selectedItem.engine;
     ExtensionSettingsStore.setByUser(SEARCH_TYPE, SEARCH_KEY);
   }
@@ -334,17 +336,17 @@ function onDragEngineStart(event) {
   if (selectedIndex >= 0 && !gEngineView.isCheckBox(row.value, col.value)) {
     event.dataTransfer.setData(ENGINE_FLAVOR, selectedIndex.toString());
     event.dataTransfer.effectAllowed = "move";
   }
 }
 
 
 function EngineStore() {
-  let pref = document.getElementById("browser.search.hiddenOneOffs").value;
+  let pref = Preferences.get("browser.search.hiddenOneOffs").value;
   this.hiddenList = pref ? pref.split(",") : [];
 
   this._engines = Services.search.getVisibleEngines().map(this._cloneEngine, this);
   this._defaultEngines = Services.search.getDefaultEngines().map(this._cloneEngine, this);
 
   // check if we need to disable the restore defaults button
   var someHidden = this._defaultEngines.some(e => e.hidden);
   gSearchPane.showRestoreDefaults(someHidden);
--- a/browser/components/preferences/in-content/search.xul
+++ b/browser/components/preferences/in-content/search.xul
@@ -1,28 +1,8 @@
-    <preferences id="searchPreferences" hidden="true" data-category="paneSearch">
-
-      <preference id="browser.search.suggest.enabled"
-                  name="browser.search.suggest.enabled"
-                  type="bool"/>
-
-      <preference id="browser.urlbar.suggest.searches"
-                  name="browser.urlbar.suggest.searches"
-                  type="bool"/>
-
-      <preference id="browser.search.hiddenOneOffs"
-                  name="browser.search.hiddenOneOffs"
-                  type="unichar"/>
-
-      <preference id="browser.search.widget.inNavBar"
-                  name="browser.search.widget.inNavBar"
-                  type="bool"/>
-
-    </preferences>
-
     <script type="application/javascript"
             src="chrome://browser/content/preferences/in-content/search.js"/>
 
     <stringbundle id="engineManagerBundle" src="chrome://browser/locale/engineManager.properties"/>
 
     <hbox id="searchCategory"
           class="subcategory"
           hidden="true"
--- a/browser/components/preferences/in-content/sync.js
+++ b/browser/components/preferences/in-content/sync.js
@@ -23,16 +23,27 @@ const FXA_PAGE_LOGGED_IN = 1;
 // Indexes into the "login status" deck.
 // We are in a successful verified state - everything should work!
 const FXA_LOGIN_VERIFIED = 0;
 // We have logged in to an unverified account.
 const FXA_LOGIN_UNVERIFIED = 1;
 // We are logged in locally, but the server rejected our credentials.
 const FXA_LOGIN_FAILED = 2;
 
+Preferences.addAll([
+  { id: "engine.addons", name: "services.sync.engine.addons", type: "bool" },
+  { id: "engine.bookmarks", name: "services.sync.engine.bookmarks", type: "bool" },
+  { id: "engine.history", name: "services.sync.engine.history", type: "bool" },
+  { id: "engine.tabs", name: "services.sync.engine.tabs", type: "bool" },
+  { id: "engine.prefs", name: "services.sync.engine.prefs", type: "bool" },
+  { id: "engine.passwords", name: "services.sync.engine.passwords", type: "bool" },
+  { id: "engine.addresses", name: "services.sync.engine.addresses", type: "bool" },
+  { id: "engine.creditcards", name: "services.sync.engine.creditcards", type: "bool" },
+]);
+
 var gSyncPane = {
   get page() {
     return document.getElementById("weavePrefsDeck").selectedIndex;
   },
 
   set page(val) {
     document.getElementById("weavePrefsDeck").selectedIndex = val;
   },
--- a/browser/components/preferences/in-content/sync.xul
+++ b/browser/components/preferences/in-content/sync.xul
@@ -1,41 +1,14 @@
 # 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/.
 
 <!-- Sync panel -->
 
-<preferences id="syncEnginePrefs" hidden="true" data-category="paneSync">
-  <preference id="engine.addons"
-              name="services.sync.engine.addons"
-              type="bool"/>
-  <preference id="engine.bookmarks"
-              name="services.sync.engine.bookmarks"
-              type="bool"/>
-  <preference id="engine.history"
-              name="services.sync.engine.history"
-              type="bool"/>
-  <preference id="engine.tabs"
-              name="services.sync.engine.tabs"
-              type="bool"/>
-  <preference id="engine.prefs"
-              name="services.sync.engine.prefs"
-              type="bool"/>
-  <preference id="engine.passwords"
-              name="services.sync.engine.passwords"
-              type="bool"/>
-  <preference id="engine.addresses"
-              name="services.sync.engine.addresses"
-              type="bool"/>
-  <preference id="engine.creditcards"
-              name="services.sync.engine.creditcards"
-              type="bool"/>
-</preferences>
-
 <script type="application/javascript"
         src="chrome://browser/content/preferences/in-content/sync.js"/>
 
 <hbox id="firefoxAccountCategory"
       class="subcategory"
       hidden="true"
       data-category="paneSync">
   <label class="header-name" flex="1">&paneSync1.title;</label>
--- a/browser/components/preferences/in-content/tests/browser_basic_rebuild_fonts_test.js
+++ b/browser/components/preferences/in-content/tests/browser_basic_rebuild_fonts_test.js
@@ -5,18 +5,20 @@ registerCleanupFunction(function() {
 });
 
 add_task(async function() {
   await openPreferencesViaOpenPreferencesAPI("general", { leaveOpen: true });
   // eslint-disable-next-line mozilla/no-cpows-in-tests
   await gBrowser.contentWindow.gMainPane._selectDefaultLanguageGroupPromise;
   // eslint-disable-next-line mozilla/no-cpows-in-tests
   let doc = gBrowser.contentDocument;
+  // eslint-disable-next-line mozilla/no-cpows-in-tests
+  let contentWindow = gBrowser.contentWindow;
   var langGroup = Services.prefs.getComplexValue("font.language.group", Ci.nsIPrefLocalizedString).data;
-  is(doc.getElementById("font.language.group").value, langGroup,
+  is(contentWindow.Preferences.get("font.language.group").value, langGroup,
      "Language group should be set correctly.");
 
   let defaultFontType = Services.prefs.getCharPref("font.default." + langGroup);
   let fontFamily = Services.prefs.getCharPref("font.name." + defaultFontType + "." + langGroup);
   let fontFamilyField = doc.getElementById("defaultFont");
   is(fontFamilyField.value, fontFamily, "Font family should be set correctly.");
 
   let defaultFontSize = Services.prefs.getIntPref("font.size.variable." + langGroup);
@@ -39,17 +41,17 @@ add_task(async function() {
       return Promise.resolve(this._list);
     },
     getDefaultFont() { return this._defaultFont; },
     getStandardFamilyName(name) { return name; },
   };
   win.FontBuilder._allFonts = null;
   win.FontBuilder._langGroupSupported = false;
 
-  let langGroupElement = doc.getElementById("font.language.group");
+  let langGroupElement = win.Preferences.get("font.language.group");
   let selectLangsField = doc.getElementById("selectLangs");
   let serifField = doc.getElementById("serif");
   let armenian = "x-armn";
   let western = "x-western";
 
   // Await rebuilding of the font lists, which happens asynchronously in
   // gFontsDialog._selectLanguageGroup.  Testing code needs to call this
   // function and await its resolution after changing langGroupElement's value
@@ -58,17 +60,17 @@ add_task(async function() {
     return win.gFontsDialog._selectLanguageGroupPromise;
   }
 
   langGroupElement.value = armenian;
   await fontListsRebuilt();
   selectLangsField.value = armenian;
   is(serifField.value, "", "Font family should not be set.");
 
-  let armenianSerifElement = doc.getElementById("font.name.serif.x-armn");
+  let armenianSerifElement = win.Preferences.get("font.name.serif.x-armn");
 
   langGroupElement.value = western;
   await fontListsRebuilt();
   selectLangsField.value = western;
 
   // Simulate a font backend supporting language-specific enumeration.
   // NB: FontBuilder has cached the return value from EnumerateAllFonts(),
   // so _allFonts will always have 3 elements regardless of subsequent
--- a/browser/components/preferences/in-content/tests/browser_bug731866.js
+++ b/browser/components/preferences/in-content/tests/browser_bug731866.js
@@ -11,20 +11,19 @@ function test() {
   waitForExplicitFinish();
   open_preferences(runTest);
 }
 
 var gElements;
 
 function checkElements(expectedPane) {
   for (let element of gElements) {
-    // keyset and preferences elements fail is_element_visible checks because they are never visible.
+    // keyset elements fail is_element_visible checks because they are never visible.
     // special-case the drmGroup item because its visibility depends on pref + OS version
     if (element.nodeName == "keyset" ||
-        element.nodeName == "preferences" ||
         element.id === "drmGroup") {
       continue;
     }
     // The siteDataGroup in the Storage Management project is currently only pref-on on Nightly for testing purpose.
     // During the test and the transition period, we have to check the pref to see if the siteDataGroup
     // should be hidden always. This would be a bit bothersome, same as the offlineGroup as below.
     // However, this checking is necessary to make sure we don't leak the siteDataGroup into beta/release build
     if (element.id == "siteDataGroup" && storageManagerDisabled) {
--- a/browser/components/preferences/in-content/tests/browser_bug795764_cachedisabled.js
+++ b/browser/components/preferences/in-content/tests/browser_bug795764_cachedisabled.js
@@ -29,19 +29,16 @@ function runTest(win) {
   is(gBrowser.currentURI.spec, "about:preferences", "about:preferences loaded");
 
   let tab = win.document;
   let elements = tab.getElementById("mainPrefPane").children;
 
   // Test if privacy pane is opened correctly
   win.gotoPref("panePrivacy");
   for (let element of elements) {
-    if (element.nodeName == "preferences") {
-      continue;
-    }
     let attributeValue = element.getAttribute("data-category");
     if (attributeValue == "panePrivacy") {
       is_element_visible(element, `Privacy element of id=${element.id} should be visible`);
     } else {
       is_element_hidden(element, `Non-Privacy element of id=${element.id} should be hidden`);
     }
   }
 
--- a/browser/components/preferences/in-content/tests/browser_connection.js
+++ b/browser/components/preferences/in-content/tests/browser_connection.js
@@ -43,18 +43,18 @@ function test() {
     finish();
   });
 }
 
 // run a bunch of tests on the window containing connection.xul
 function runConnectionTests(win) {
   let doc = win.document;
   let networkProxyNone = doc.getElementById("networkProxyNone");
-  let networkProxyNonePref = doc.getElementById("network.proxy.no_proxies_on");
-  let networkProxyTypePref = doc.getElementById("network.proxy.type");
+  let networkProxyNonePref = win.Preferences.get("network.proxy.no_proxies_on");
+  let networkProxyTypePref = win.Preferences.get("network.proxy.type");
 
   // make sure the networkProxyNone textbox is formatted properly
   is(networkProxyNone.getAttribute("multiline"), "true",
      "networkProxyNone textbox is multiline");
   is(networkProxyNone.getAttribute("rows"), "2",
      "networkProxyNone textbox has two rows");
 
   // check if sanitizing the given input for the no_proxies_on pref results in
--- a/browser/components/preferences/in-content/tests/browser_connection_bug388287.js
+++ b/browser/components/preferences/in-content/tests/browser_connection_bug388287.js
@@ -48,22 +48,22 @@ function test() {
         finish();
         return;
       }
 
       dialog = await openAndLoadSubDialog(connectionURL);
       dialogClosingPromise = waitForEvent(dialog.document.documentElement, "dialogclosing");
 
       doc = dialog.document;
-      proxyTypePref = doc.getElementById("network.proxy.type");
-      sharePref = doc.getElementById("network.proxy.share_proxy_settings");
-      httpPref = doc.getElementById("network.proxy.http");
-      httpPortPref = doc.getElementById("network.proxy.http_port");
-      ftpPref = doc.getElementById("network.proxy.ftp");
-      ftpPortPref = doc.getElementById("network.proxy.ftp_port");
+      proxyTypePref = dialog.Preferences.get("network.proxy.type");
+      sharePref = dialog.Preferences.get("network.proxy.share_proxy_settings");
+      httpPref = dialog.Preferences.get("network.proxy.http");
+      httpPortPref = dialog.Preferences.get("network.proxy.http_port");
+      ftpPref = dialog.Preferences.get("network.proxy.ftp");
+      ftpPortPref = dialog.Preferences.get("network.proxy.ftp_port");
     }
 
     // This batch of tests should not close the dialog
     await setDoc();
 
     // Testing HTTP port 0 with share on
     proxyTypePref.value = 1;
     sharePref.value = true;
--- a/browser/components/preferences/in-content/tests/browser_fluent.js
+++ b/browser/components/preferences/in-content/tests/browser_fluent.js
@@ -20,19 +20,20 @@ add_task(async function() {
   }
 
   await Promise.all([
     openPreferencesViaOpenPreferencesAPI("general", {leaveOpen: true}),
     whenMainPaneLoadedFinished(),
   ]);
 
   let doc = gBrowser.contentDocument;
+  let win = gBrowser.contentWindow;
   await doc.l10n.ready;
 
-  let processCountPref = doc.getElementById("dom.ipc.processCount");
+  let processCountPref = win.Preferences.get("dom.ipc.processCount");
   let defaultProcessCount = processCountPref.defaultValue;
 
   let [ msg ] = await doc.l10n.formatMessages([
     ["default-content-process-count", { num: defaultProcessCount }]
   ]);
 
   let elem = doc.querySelector(
     `#contentProcessCount > menupopup > menuitem[value="${defaultProcessCount}"]`);
--- a/browser/components/preferences/in-content/tests/browser_sanitizeOnShutdown_prefLocked.js
+++ b/browser/components/preferences/in-content/tests/browser_sanitizeOnShutdown_prefLocked.js
@@ -9,17 +9,17 @@ function switchToCustomHistoryMode(doc) 
 
 function testPrefStateMatchesLockedState() {
   // eslint-disable-next-line mozilla/no-cpows-in-tests
   let win = gBrowser.contentWindow;
   let doc = win.document;
   switchToCustomHistoryMode(doc);
 
   let checkbox = doc.getElementById("alwaysClear");
-  let preference = doc.getElementById("privacy.sanitize.sanitizeOnShutdown");
+  let preference = win.Preferences.get("privacy.sanitize.sanitizeOnShutdown");
   is(checkbox.disabled, preference.locked, "Always Clear checkbox should be enabled when preference is not locked.");
 
   Services.prefs.clearUserPref("privacy.history.custom");
   gBrowser.removeCurrentTab();
 }
 
 add_task(function setup() {
   registerCleanupFunction(function resetPreferences() {
--- a/browser/components/preferences/in-content/tests/privacypane_tests_perwindow.js
+++ b/browser/components/preferences/in-content/tests/privacypane_tests_perwindow.js
@@ -215,17 +215,17 @@ function test_dependent_prefs(win) {
   });
 
   let thirdPartyCookieMenu = win.document.getElementById("acceptThirdPartyMenu");
   ok(thirdPartyCookieMenu, "the third-party cookie control should exist");
 
   function expect_checked(checked) {
     controls.forEach(function(control) {
       is(control.checked, checked,
-        control.getAttribute("id") + " should " + (checked ? "not " : "") + "be checked");
+        control.getAttribute("id") + " should " + (checked ? "" : "not ") + "be checked");
     });
 
     is(thirdPartyCookieMenu.value == "always" || thirdPartyCookieMenu.value == "visited", checked, "third-party cookies should " + (checked ? "not " : "") + "be limited");
   }
 
   // controls should be checked in remember mode
   historymode.value = "remember";
   controlChanged(historymode);
@@ -306,23 +306,23 @@ function test_locbar_suggestion_retentio
     is(Services.prefs.getBoolPref("browser.urlbar.autocomplete.enabled"), autocomplete,
        "browser.urlbar.autocomplete.enabled pref should be " + autocomplete);
   };
 }
 
 const gPrefCache = new Map();
 
 function cache_preferences(win) {
-  let prefs = win.document.querySelectorAll("#privacyPreferences > preference");
+  let prefs = win.Preferences.getAll();
   for (let pref of prefs)
     gPrefCache.set(pref.name, pref.value);
 }
 
 function reset_preferences(win) {
-  let prefs = win.document.querySelectorAll("#privacyPreferences > preference");
+  let prefs = win.Preferences.getAll();
   for (let pref of prefs)
     pref.value = gPrefCache.get(pref.name);
 }
 
 function run_test_subset(subset) {
   info("subset: " + Array.from(subset, x => x.name).join(",") + "\n");
   SpecialPowers.pushPrefEnv({"set": [["browser.preferences.instantApply", true]]});
 
--- a/browser/components/preferences/jar.mn
+++ b/browser/components/preferences/jar.mn
@@ -3,26 +3,26 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 browser.jar:
     content/browser/preferences/applicationManager.xul
     content/browser/preferences/applicationManager.js
     content/browser/preferences/blocklists.xul
     content/browser/preferences/blocklists.js
 *   content/browser/preferences/colors.xul
+    content/browser/preferences/colors.js
 *   content/browser/preferences/cookies.xul
     content/browser/preferences/cookies.js
 *   content/browser/preferences/connection.xul
     content/browser/preferences/connection.js
-    content/browser/preferences/donottrack.xul
-*   content/browser/preferences/fonts.xul
+    content/browser/preferences/fonts.xul
     content/browser/preferences/fonts.js
     content/browser/preferences/handlers.xml
     content/browser/preferences/handlers.css
-*   content/browser/preferences/languages.xul
+    content/browser/preferences/languages.xul
     content/browser/preferences/languages.js
     content/browser/preferences/permissions.xul
     content/browser/preferences/sitePermissions.xul
     content/browser/preferences/sitePermissions.js
     content/browser/preferences/sitePermissions.css
     content/browser/preferences/containers.xul
     content/browser/preferences/containers.js
     content/browser/preferences/permissions.js
--- a/browser/components/preferences/languages.js
+++ b/browser/components/preferences/languages.js
@@ -1,15 +1,25 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
 /* 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/. */
 
+/* import-globals-from ../../../toolkit/content/preferencesBindings.js */
+
 Components.utils.import("resource://gre/modules/Services.jsm");
 
+Preferences.addAll([
+  { id: "intl.accept_languages", type: "wstring" },
+  { id: "pref.browser.language.disable_button.up", type: "bool" },
+  { id: "pref.browser.language.disable_button.down", type: "bool" },
+  { id: "pref.browser.language.disable_button.remove", type: "bool" },
+  { id: "privacy.spoof_english", type: "int" },
+]);
+
 var gLanguagesDialog = {
 
   _availableLanguagesList: [],
   _acceptLanguages: { },
 
   _selectedItemID: null,
 
   init() {
@@ -121,17 +131,17 @@ var gLanguagesDialog = {
     }
   },
 
   readAcceptLanguages() {
     while (this._activeLanguages.hasChildNodes())
       this._activeLanguages.firstChild.remove();
 
     var selectedIndex = 0;
-    var preference = document.getElementById("intl.accept_languages");
+    var preference = Preferences.get("intl.accept_languages");
     if (preference.value == "")
       return undefined;
     var languages = preference.value.toLowerCase().split(/\s*,\s*/);
     for (var i = 0; i < languages.length; ++i) {
       var name = this._getLanguageName(languages[i]);
       if (!name)
         name = "[" + languages[i] + "]";
       var listitem = document.createElement("listitem");
@@ -168,17 +178,17 @@ var gLanguagesDialog = {
     addButton.disabled = availableLanguages.disabled ||
                          availableLanguages.selectedIndex < 0;
 
     this._availableLanguages.removeAttribute("accesskey");
   },
 
   addLanguage() {
     var selectedID = this._availableLanguages.selectedItem.id;
-    var preference = document.getElementById("intl.accept_languages");
+    var preference = Preferences.get("intl.accept_languages");
     var arrayOfPrefs = preference.value.toLowerCase().split(/\s*,\s*/);
     for (var i = 0; i < arrayOfPrefs.length; ++i ) {
       if (arrayOfPrefs[i] == selectedID)
         return;
     }
 
     this._selectedItemID = selectedID;
 
@@ -214,17 +224,17 @@ var gLanguagesDialog = {
     var selection = this._activeLanguages.selectedItems;
     var lastSelected = selection[selection.length - 1];
     var selectItem = lastSelected.nextSibling || lastSelected.previousSibling;
     selectItem = selectItem ? selectItem.id : null;
 
     this._selectedItemID = selectItem;
 
     // Update the preference and force a UI rebuild
-    var preference = document.getElementById("intl.accept_languages");
+    var preference = Preferences.get("intl.accept_languages");
     preference.value = string;
 
     this._buildAvailableLanguageList();
   },
 
   _getLanguageName(aABCD) {
     if (!this._availableLanguagesList.length)
       this._loadAvailableLanguages();
@@ -249,17 +259,17 @@ var gLanguagesDialog = {
         string += previousItem.id;
       else
         string += item.id;
     }
 
     this._selectedItemID = selectedItem.id;
 
     // Update the preference and force a UI rebuild
-    var preference = document.getElementById("intl.accept_languages");
+    var preference = Preferences.get("intl.accept_languages");
     preference.value = string;
   },
 
   moveDown() {
     var selectedItem = this._activeLanguages.selectedItems[0];
     var nextItem = selectedItem.nextSibling;
 
     var string = "";
@@ -272,17 +282,17 @@ var gLanguagesDialog = {
         string += nextItem.id;
       else
         string += item.id;
     }
 
     this._selectedItemID = selectedItem.id;
 
     // Update the preference and force a UI rebuild
-    var preference = document.getElementById("intl.accept_languages");
+    var preference = Preferences.get("intl.accept_languages");
     preference.value = string;
   },
 
   onLanguageSelect() {
     var upButton = document.getElementById("up");
     var downButton = document.getElementById("down");
     var removeButton = document.getElementById("remove");
     switch (this._activeLanguages.selectedCount) {
@@ -330,9 +340,8 @@ var gLanguagesDialog = {
       return false;
     }
   },
 
   writeSpoofEnglish() {
     return document.getElementById("spoofEnglish").checked ? 2 : 1;
   }
 };
-
--- a/browser/components/preferences/languages.xul
+++ b/browser/components/preferences/languages.xul
@@ -1,56 +1,52 @@
 <?xml version="1.0"?>
 
-# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
-# 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/.
+<!-- -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -->
+<!-- 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/. -->
 
-<!DOCTYPE prefwindow SYSTEM "chrome://browser/locale/preferences/languages.dtd">
+<!DOCTYPE dialog [
+  <!ENTITY % preferencesDTD SYSTEM "chrome://global/locale/preferences.dtd">
+  %preferencesDTD;
+  <!ENTITY % languagesDTD SYSTEM "chrome://browser/locale/preferences/languages.dtd">
+  %languagesDTD;
+]>
 
 <?xml-stylesheet href="chrome://global/skin/"?>
-#ifdef XP_MACOSX
 <?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
-#endif
 
-<prefwindow id="LanguagesDialog" type="child"
-            xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-            title="&languages.customize.Header;"
-            dlgbuttons="accept,cancel,help"
-            ondialoghelp="openPrefsHelp()"
-            style="width: &window.width;"
-# hack around XUL bug 1194844 by triggering extra reflow (see bug 1194346):
-            onfocus="gLanguagesDialog.forceReflow()"
-            onresize="gLanguagesDialog.forceReflow()">
+<dialog id="LanguagesDialog" type="child" class="prefwindow"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        title="&languages.customize.Header;"
+        buttons="accept,cancel,help"
+        persist="lastSelected screenX screenY"
+        closebuttonlabel="&preferencesCloseButton.label;"
+        closebuttonaccesskey="&preferencesCloseButton.accesskey;"
+        role="dialog"
+        onload="gLanguagesDialog.init();"
+        helpTopic="prefs-languages"
+        ondialoghelp="openPrefsHelp()"
+        style="width: &window.width;"
+        onfocus="gLanguagesDialog.forceReflow()"
+        onresize="gLanguagesDialog.forceReflow()">
+
+<!-- The onfocus and onresize handlers above hack around XUL bug 1194844
+   - by triggering extra reflow (see bug 1194346). -->
 
   <script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/>
-
-  <prefpane id="LanguagesDialogPane"
-            class="largeDialogContainer"
-            onpaneload="gLanguagesDialog.init();"
-            helpTopic="prefs-languages">
+  <script type="application/javascript" src="chrome://global/content/preferencesBindings.js"/>
+  <script type="application/javascript" src="chrome://browser/content/preferences/languages.js"/>
 
-    <preferences>
-      <preference id="intl.accept_languages" name="intl.accept_languages" type="wstring"/>
-      <preference id="pref.browser.language.disable_button.up"
-                  name="pref.browser.language.disable_button.up"
-                  type="bool"/>
-      <preference id="pref.browser.language.disable_button.down"
-                  name="pref.browser.language.disable_button.down"
-                  type="bool"/>
-      <preference id="pref.browser.language.disable_button.remove"
-                  name="pref.browser.language.disable_button.remove"
-                  type="bool"/>
-      <preference id="privacy.spoof_english"
-                  name="privacy.spoof_english"
-                  type="int"/>
-    </preferences>
+  <keyset>
+    <key key="&windowClose.key;" modifiers="accel" oncommand="Preferences.close(event)"/>
+  </keyset>
 
-    <script type="application/javascript" src="chrome://browser/content/preferences/languages.js"/>
+  <vbox id="LanguagesDialogPane" class="prefpane largeDialogContainer">
 
     <stringbundleset id="languageSet">
       <stringbundle id="bundleRegions"      src="chrome://global/locale/regionNames.properties"/>
       <stringbundle id="bundleLanguages"    src="chrome://global/locale/languageNames.properties"/>
       <stringbundle id="bundlePreferences"  src="chrome://browser/locale/preferences/preferences.properties"/>
       <stringbundle id="bundleAccepted"     src="resource://gre/res/language.properties"/>
     </stringbundleset>
 
@@ -102,11 +98,10 @@
           <button id="addButton" oncommand="gLanguagesDialog.addLanguage();" disabled="true"
                   label="&languages.customize.addButton.label;"
                   accesskey="&languages.customize.addButton.accesskey;"/>
         </row>
       </rows>
     </grid>
     <separator/>
     <separator/>
-  </prefpane>
-</prefwindow>
-
+  </vbox>
+</dialog>
--- a/browser/components/preferences/sanitize.js
+++ b/browser/components/preferences/sanitize.js
@@ -1,21 +1,36 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
 /* 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/. */
 
+/* import-globals-from ../../../toolkit/content/preferencesBindings.js */
+
+Preferences.addAll([
+  { id: "privacy.clearOnShutdown.history", type: "bool" },
+  { id: "privacy.clearOnShutdown.formdata", type: "bool" },
+  { id: "privacy.clearOnShutdown.downloads", type: "bool" },
+  { id: "privacy.clearOnShutdown.cookies", type: "bool" },
+  { id: "privacy.clearOnShutdown.cache", type: "bool" },
+  { id: "privacy.clearOnShutdown.offlineApps", type: "bool" },
+  { id: "privacy.clearOnShutdown.sessions", type: "bool" },
+  { id: "privacy.clearOnShutdown.siteSettings", type: "bool" },
+]);
+
 var gSanitizeDialog = Object.freeze({
   init() {
     let customWidthElements = document.getElementsByAttribute("dialogWidth", "*");
     let isInSubdialog = document.documentElement.hasAttribute("subdialog");
     for (let element of customWidthElements) {
       element.style.width = element.getAttribute(isInSubdialog ? "subdialogWidth" : "dialogWidth");
     }
     this.onClearHistoryChanged();
+
+    Preferences.get("privacy.clearOnShutdown.history").on("change", this.onClearHistoryChanged.bind(this));
   },
 
   onClearHistoryChanged() {
-    let downloadsPref = document.getElementById("privacy.clearOnShutdown.downloads");
-    let historyPref = document.getElementById("privacy.clearOnShutdown.history");
+    let downloadsPref = Preferences.get("privacy.clearOnShutdown.downloads");
+    let historyPref = Preferences.get("privacy.clearOnShutdown.history");
     downloadsPref.value = historyPref.value;
   }
 });
--- a/browser/components/preferences/sanitize.xul
+++ b/browser/components/preferences/sanitize.xul
@@ -1,51 +1,51 @@
 <?xml version="1.0"?>
 
 <!-- -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -->
 <!-- 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/. -->
 
 <?xml-stylesheet href="chrome://global/skin/"?>
-<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
 
 <!DOCTYPE dialog [
+  <!ENTITY % preferencesDTD SYSTEM "chrome://global/locale/preferences.dtd">
+  %preferencesDTD;
   <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
+  %brandDTD;
   <!ENTITY % sanitizeDTD SYSTEM "chrome://browser/locale/sanitize.dtd">
-  %brandDTD;
   %sanitizeDTD;
 ]>
 
-<prefwindow id="SanitizeDialog" type="child"
-            xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-            dlgbuttons="accept,cancel,help"
-            ondialoghelp="openPrefsHelp()"
-            dialogWidth="&sanitizePrefs2.modal.width;"
-            subdialogWidth="&sanitizePrefs2.inContent.dialog.width;"
-            title="&sanitizePrefs2.title;"
-            onload="gSanitizeDialog.init();">
+<dialog id="SanitizeDialog" type="child" class="prefwindow"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        buttons="accept,cancel,help"
+        persist="lastSelected screenX screenY"
+        closebuttonlabel="&preferencesCloseButton.label;"
+        closebuttonaccesskey="&preferencesCloseButton.accesskey;"
+        role="dialog"
+        ondialoghelp="openPrefsHelp()"
+        dialogWidth="&sanitizePrefs2.modal.width;"
+        subdialogWidth="&sanitizePrefs2.inContent.dialog.width;"
+        title="&sanitizePrefs2.title;"
+        helpTopic="prefs-clear-private-data"
+        onload="gSanitizeDialog.init();">
 
   <script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/>
-  <script type="application/javascript" src="chrome://browser/content/preferences/sanitize.js"/>
-
-  <prefpane id="SanitizeDialogPane"
-            helpTopic="prefs-clear-private-data">
+  <script type="application/javascript" src="chrome://global/content/preferencesBindings.js"/>
 
-    <preferences>
-      <preference id="privacy.clearOnShutdown.history"               name="privacy.clearOnShutdown.history"               type="bool"
-                  onchange="return gSanitizeDialog.onClearHistoryChanged();"/>
-      <preference id="privacy.clearOnShutdown.formdata"              name="privacy.clearOnShutdown.formdata"              type="bool"/>
-      <preference id="privacy.clearOnShutdown.downloads"             name="privacy.clearOnShutdown.downloads"             type="bool"/>
-      <preference id="privacy.clearOnShutdown.cookies"               name="privacy.clearOnShutdown.cookies"               type="bool"/>
-      <preference id="privacy.clearOnShutdown.cache"                 name="privacy.clearOnShutdown.cache"                 type="bool"/>
-      <preference id="privacy.clearOnShutdown.offlineApps"           name="privacy.clearOnShutdown.offlineApps"           type="bool"/>
-      <preference id="privacy.clearOnShutdown.sessions"              name="privacy.clearOnShutdown.sessions"              type="bool"/>
-      <preference id="privacy.clearOnShutdown.siteSettings"          name="privacy.clearOnShutdown.siteSettings"          type="bool"/>
-    </preferences>
+  <keyset>
+    <key key="&windowClose.key;" modifiers="accel" oncommand="Preferences.close(event)"/>
+  </keyset>
+
+  <vbox id="SanitizeDialogPane" class="prefpane">
+
+    <script type="application/javascript" src="chrome://browser/content/preferences/sanitize.js"/>
 
     <description>&clearDataSettings3.label;</description>
 
     <groupbox orient="horizontal">
       <caption><label>&historySection.label;</label></caption>
       <grid flex="1">
         <columns>
           <column dialogWidth="&sanitizePrefs2.column.width;"
@@ -92,10 +92,10 @@
                       preference="privacy.clearOnShutdown.siteSettings"/>
             <checkbox label="&itemOfflineApps.label;"
                       accesskey="&itemOfflineApps.accesskey;"
                       preference="privacy.clearOnShutdown.offlineApps"/>
           </row>
         </rows>
       </grid>
     </groupbox>
-  </prefpane>
-</prefwindow>
+  </vbox>
+</dialog>
--- a/browser/extensions/shield-recipe-client/lib/ShieldPreferences.jsm
+++ b/browser/extensions/shield-recipe-client/lib/ShieldPreferences.jsm
@@ -115,34 +115,29 @@ this.ShieldPreferences = {
     const viewStudies = doc.createElementNS(XUL_NS, "label");
     viewStudies.setAttribute("id", "viewShieldStudies");
     viewStudies.setAttribute("href", "about:studies");
     viewStudies.setAttribute("useoriginprincipal", true);
     viewStudies.textContent = "View Firefox Studies";
     viewStudies.classList.add("learnMore", "text-link");
     hContainer.appendChild(viewStudies);
 
-    // <prefrence> elements for prefs that we need to monitor while the page is open.
     const optOutPref = doc.createElementNS(XUL_NS, "preference");
     optOutPref.setAttribute("id", OPT_OUT_STUDIES_ENABLED_PREF);
     optOutPref.setAttribute("name", OPT_OUT_STUDIES_ENABLED_PREF);
     optOutPref.setAttribute("type", "bool");
 
+    // Preference instances for prefs that we need to monitor while the page is open.
+    doc.defaultView.Preferences.add({ id: OPT_OUT_STUDIES_ENABLED_PREF, type: "bool" });
+
     // Weirdly, FHR doesn't have a <preference> element on the page, so we create it.
-    const fhrPref = doc.createElementNS(XUL_NS, "preference");
-    fhrPref.setAttribute("id", FHR_UPLOAD_ENABLED_PREF);
-    fhrPref.setAttribute("name", FHR_UPLOAD_ENABLED_PREF);
-    fhrPref.setAttribute("type", "bool");
-    fhrPref.addEventListener("change", function(event) {
+    const fhrPref = doc.defaultView.Preferences.add({ id: FHR_UPLOAD_ENABLED_PREF, type: "bool" });
+    fhrPref.on("change", function(event) {
       // Avoid reference to the document directly, to avoid leaks.
       const eventTargetCheckbox = event.target.ownerDocument.getElementById("optOutStudiesEnabled");
       eventTargetCheckbox.disabled = !Services.prefs.getBoolPref(FHR_UPLOAD_ENABLED_PREF);
     });
 
     // Actually inject the elements we've created.
     const parent = doc.getElementById("submitHealthReportBox").closest("vbox");
     parent.appendChild(container);
-
-    const preferences = doc.getElementById("privacyPreferences");
-    preferences.appendChild(optOutPref);
-    preferences.appendChild(fhrPref);
   },
 };
deleted file mode 100644
--- a/browser/locales/en-US/chrome/browser/preferences/donottrack.dtd
+++ /dev/null
@@ -1,13 +0,0 @@
-<!-- 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/. -->
-
-<!ENTITY window.title                 "Do Not Track">
-<!ENTITY window.width                 "50em">
-<!ENTITY window.height                "10em">
-
-<!ENTITY doNotTrackCheckbox2.label    "Always apply Do Not Track">
-<!ENTITY doNotTrackCheckbox2.accesskey "A">
-
-<!ENTITY doNotTrackTPInfo.description "&brandShortName; will send a signal that you don’t want to be tracked whenever Tracking Protection is on.">
-<!ENTITY doNotTrackLearnMore.label    "Learn More">
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -67,17 +67,16 @@
     locale/browser/preferences/applications.dtd       (%chrome/browser/preferences/applications.dtd)
     locale/browser/preferences/blocklists.dtd         (%chrome/browser/preferences/blocklists.dtd)
     locale/browser/preferences/colors.dtd             (%chrome/browser/preferences/colors.dtd)
     locale/browser/preferences/connection.dtd         (%chrome/browser/preferences/connection.dtd)
     locale/browser/preferences/containers.dtd         (%chrome/browser/preferences/containers.dtd)
     locale/browser/preferences/containers.properties     (%chrome/browser/preferences/containers.properties)
     locale/browser/preferences/content.dtd            (%chrome/browser/preferences/content.dtd)
     locale/browser/preferences/cookies.dtd            (%chrome/browser/preferences/cookies.dtd)
-    locale/browser/preferences/donottrack.dtd         (%chrome/browser/preferences/donottrack.dtd)
     locale/browser/preferences/fonts.dtd              (%chrome/browser/preferences/fonts.dtd)
     locale/browser/preferences/languages.dtd          (%chrome/browser/preferences/languages.dtd)
     locale/browser/preferences/main.dtd               (%chrome/browser/preferences/main.dtd)
     locale/browser/preferences/permissions.dtd        (%chrome/browser/preferences/permissions.dtd)
     locale/browser/preferences/preferences.dtd        (%chrome/browser/preferences/preferences.dtd)
     locale/browser/preferences/preferences.properties     (%chrome/browser/preferences/preferences.properties)
     locale/browser/preferences/privacy.dtd            (%chrome/browser/preferences/privacy.dtd)
     locale/browser/preferences/search.dtd             (%chrome/browser/preferences/search.dtd)
--- a/browser/themes/linux/preferences/preferences.css
+++ b/browser/themes/linux/preferences/preferences.css
@@ -1,15 +1,42 @@
 /*
 # -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 # 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/.
 */
 
+/* Pref Window & Pane */
+.prefwindow {
+  padding: 0px;
+}
+
+.prefwindow[type="child"] {
+  padding: 8px;
+}
+
+.prefpane {
+  padding: 8px;
+}
+
+.prefwindow[type="child"] > .prefpane {
+  padding: 0px;
+}
+
+.dialog-button-box {
+  padding-bottom: 8px;
+  padding-inline-start: 8px;
+  padding-inline-end: 8px;
+}
+
+.prefwindow[type="child"] .dialog-button-box {
+  padding: 0px;
+}
+
 /* General Pane */
 #useFirefoxSync,
 #getStarted {
   font-size: 90%;
 }
 
 #isNotDefaultLabel {
   font-weight: bold;
@@ -18,17 +45,17 @@
 /* Content Pane */
 #translationAttributionImage {
   width: 70px;
   cursor: pointer;
 }
 
 /* Modeless Window Dialogs */
 .windowDialog,
-.windowDialog prefpane {
+.windowDialog .prefpane {
   padding: 0px;
 }
 
 .contentPane {
   margin: 9px 8px 5px 8px;
 }
 
 .actionButtons {
--- a/browser/themes/linux/sanitizeDialog.css
+++ b/browser/themes/linux/sanitizeDialog.css
@@ -94,14 +94,14 @@
    attribute is set to the total number of listitems, as it is currently.  See
    bug 489958 comment 14 and bug 491788. */
 #itemList > listitem {
   padding: 1px 0;
 }
 
 
 /* Align the last dialog button with the end of the warning box */
-.prefWindow-dlgbuttons {
+.dialog-button-box {
   margin-inline-end: 0;
 }
 .dialog-button[dlgtype="accept"] {
   margin-inline-end: 0;
 }
--- a/browser/themes/osx/preferences/in-content/dialog.css
+++ b/browser/themes/osx/preferences/in-content/dialog.css
@@ -1,18 +1,14 @@
 /* - 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/. */
 
 %include ../../../shared/incontentprefs/dialog.inc.css
 
-prefwindow,
+.prefwindow,
 .windowDialog {
   font: message-box !important;
 }
 
 :root > * {
   font-size: 1.18em;
 }
-
-.prefWindow-dlgbuttons {
-  margin: 0;
-}
--- a/browser/themes/osx/preferences/preferences.css
+++ b/browser/themes/osx/preferences/preferences.css
@@ -7,22 +7,50 @@
 
 %include ../../../../toolkit/themes/osx/global/shared.inc
 
 .windowDialog {
   padding: 12px;
   font: -moz-dialog;
 }
 
-/* ----- APPLICATIONS PREFPANE ----- */
+.prefwindow {
+  padding: 0;
+  font: -moz-dialog !important;
+}
+
+.prefwindow[type="child"] {
+  padding-top: 18px;
+  padding-bottom: 15px;
+  padding-inline-start: 18px;
+  padding-inline-end: 20px;
+}
+
+.dialog-button-box {
+  margin: 0 12px 12px;
+  padding-top: 0 !important;
+}
+
 description {
   margin-bottom: 4px !important;
 }
 
-prefpane .groupbox-body {
+.prefpane {
+  padding-top: 12px;
+  padding-bottom: 12px;
+  padding-inline-start: 0;
+  padding-inline-end: 12px;
+}
+
+.prefwindow[type="child"] > .prefpane {
+  padding: 0;
+}
+
+.prefpane .groupbox-body,
+.prefpane .groupbox-body {
   -moz-appearance: none;
   padding: 8px 4px 4px 4px;
 }
 
 tabpanels {
   padding: 20px 7px 7px;
 }
 
--- a/browser/themes/osx/sanitizeDialog.css
+++ b/browser/themes/osx/sanitizeDialog.css
@@ -78,14 +78,14 @@
    attribute is set to the total number of listitems, as it is currently.  See
    bug 489958 comment 14 and bug 491788. */
 #itemList > listitem {
   padding: 1px 0;
 }
 
 
 /* Align the last dialog button with the end of the warning box */
-.prefWindow-dlgbuttons {
+.dialog-button-box {
   margin-inline-end: 0;
 }
 .dialog-button[dlgtype="accept"] {
   margin-inline-end: 0;
 }
--- a/browser/themes/shared/incontentprefs/dialog.inc.css
+++ b/browser/themes/shared/incontentprefs/dialog.inc.css
@@ -1,18 +1,17 @@
 %if 0
 /* - 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/. */
 %endif
 
 dialog,
 window,
-prefpane,
-prefwindow,
+.prefpane,
 .windowDialog {
   -moz-appearance: none;
   background-color: #fbfbfb;
   color: #424e5a;
   margin: 0;
   padding: 0;
 }
 
@@ -52,17 +51,17 @@ caption {
 groupbox {
   margin-top: 0;
   margin-right: 4px;
   margin-left: 4px;
   padding-top: 0;
   padding-bottom: 5px;
 }
 
-prefpane .groupbox-body {
+.prefpane .groupbox-body {
   padding: 0 0 5px;
 }
 
 groupbox description {
   margin-right: 0;
   margin-left: 0;
 }
 
--- a/browser/themes/shared/incontentprefs/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs/preferences.inc.css
@@ -23,17 +23,22 @@
   width: 664px;
 }
 
 #mainPrefPane {
   width: 100%;
   padding: 0;
 }
 
-prefpane > groupbox + groupbox {
+.prefwindow[type="child"] > .prefpane {
+  -moz-box-flex: 1;
+  overflow: -moz-hidden-unscrollable;
+}
+
+.prefpane > groupbox + groupbox {
   margin-top: 16px;
 }
 
 groupbox + groupbox > .groupbox-body,
 groupbox + vbox groupbox > .groupbox-body {
   margin-top: 4px;
 }
 
--- a/browser/themes/windows/preferences/preferences.css
+++ b/browser/themes/windows/preferences/preferences.css
@@ -1,15 +1,48 @@
 /*
 # -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 # 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/.
 */
 
+/* Pref Window & Pane */
+.prefwindow {
+  padding: 0px;
+}
+
+.prefwindow[type="child"] {
+  padding-top: 8px;
+  padding-bottom: 10px;
+  padding-inline-start: 8px;
+  padding-inline-end: 10px;
+}
+
+.prefpane {
+  padding-top: 8px;
+  padding-bottom: 10px;
+  padding-inline-start: 8px;
+  padding-inline-end: 10px;
+}
+
+.prefwindow[type="child"] > .prefpane {
+  padding: 0px;
+}
+
+.dialog-button-box {
+  padding-bottom: 10px;
+  padding-inline-start: 8px;
+  padding-inline-end: 10px;
+}
+
+.prefwindow[type="child"] .dialog-button-box {
+  padding: 0px;
+}
+
 /* General Pane */
 
 #useFirefoxSync,
 #getStarted {
   font-size: 90%;
 }
 
 #isNotDefaultLabel {
@@ -18,18 +51,17 @@
 
 /* Content Pane */
 #translationAttributionImage {
   width: 70px;
   cursor: pointer;
 }
 
 /* Modeless Window Dialogs */
-.windowDialog,
-.windowDialog prefpane {
+.windowDialog {
   padding: 0;
 }
 
 .contentPane {
   margin: 9px 8px 5px;
 }
 
 .actionButtons {
--- a/browser/themes/windows/sanitizeDialog.css
+++ b/browser/themes/windows/sanitizeDialog.css
@@ -80,14 +80,14 @@
 /* Make the item list the same width as the warning box */
 #itemList {
   margin-inline-start: 0;
   margin-inline-end: 0;
 }
 
 
 /* Align the last dialog button with the end of the warning box */
-.prefWindow-dlgbuttons {
+.dialog-button-box {
   margin-inline-end: 0;
 }
 .dialog-button[dlgtype="cancel"] {
   margin-inline-end: 0;
 }
--- a/toolkit/content/jar.mn
+++ b/toolkit/content/jar.mn
@@ -51,16 +51,17 @@ toolkit.jar:
 *  content/global/editMenuOverlay.xul
    content/global/finddialog.js
 *  content/global/finddialog.xul
    content/global/findUtils.js
 #endif
    content/global/filepicker.properties
    content/global/globalOverlay.js
    content/global/mozilla.xhtml
+   content/global/preferencesBindings.js
    content/global/process-content.js
    content/global/resetProfile.css
    content/global/resetProfile.js
    content/global/resetProfile.xul
    content/global/resetProfileProgress.xul
    content/global/TopLevelVideoDocument.js
    content/global/timepicker.xhtml
    content/global/treeUtils.js
@@ -85,17 +86,16 @@ toolkit.jar:
    content/global/bindings/general.xml         (widgets/general.xml)
    content/global/bindings/groupbox.xml        (widgets/groupbox.xml)
    content/global/bindings/listbox.xml         (widgets/listbox.xml)
    content/global/bindings/menu.xml            (widgets/menu.xml)
    content/global/bindings/menulist.xml        (widgets/menulist.xml)
    content/global/bindings/notification.xml    (widgets/notification.xml)
    content/global/bindings/numberbox.xml       (widgets/numberbox.xml)
    content/global/bindings/popup.xml           (widgets/popup.xml)
-*  content/global/bindings/preferences.xml     (widgets/preferences.xml)
    content/global/bindings/progressmeter.xml   (widgets/progressmeter.xml)
    content/global/bindings/radio.xml           (widgets/radio.xml)
    content/global/bindings/remote-browser.xml  (widgets/remote-browser.xml)
    content/global/bindings/resizer.xml         (widgets/resizer.xml)
    content/global/bindings/richlistbox.xml     (widgets/richlistbox.xml)
    content/global/bindings/scale.xml           (widgets/scale.xml)
    content/global/bindings/scrollbar.xml       (widgets/scrollbar.xml)
    content/global/bindings/scrollbox.xml       (widgets/scrollbox.xml)
new file mode 100644
--- /dev/null
+++ b/toolkit/content/preferencesBindings.js
@@ -0,0 +1,615 @@
+/* - 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/. */
+
+"use strict";
+
+// We attach Preferences to the window object so other contexts (tests, JSMs)
+// have access to it.
+const Preferences = window.Preferences = (function() {
+  const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
+
+  Cu.import("resource://gre/modules/EventEmitter.jsm");
+  Cu.import("resource://gre/modules/Services.jsm");
+  Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+  XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask",
+                                    "resource://gre/modules/DeferredTask.jsm");
+
+  function getElementsByAttribute(name, value) {
+    // If we needed to defend against arbitrary values, we would escape
+    // double quotes (") and escape characters (\) in them, i.e.:
+    //   ${value.replace(/["\\]/g, '\\$&')}
+    return value ? document.querySelectorAll(`[${name}="${value}"]`)
+                 : document.querySelectorAll(`[${name}]`);
+  }
+
+  const domContentLoadedPromise = new Promise(resolve => {
+    window.addEventListener("DOMContentLoaded", resolve, { capture: true, once: true });
+  });
+
+  const Preferences = {
+    _all: {},
+
+    _add(prefInfo) {
+      if (this._all[prefInfo.id]) {
+        throw new Error(`preference with id '${prefInfo.id}' already added`);
+      }
+      const pref = new Preference(prefInfo);
+      this._all[pref.id] = pref;
+      domContentLoadedPromise.then(() => { pref.updateElements(); });
+      return pref;
+    },
+
+    add(prefInfo) {
+      const pref = this._add(prefInfo);
+      return pref;
+    },
+
+    addAll(prefInfos) {
+      prefInfos.map(prefInfo => this._add(prefInfo));
+    },
+
+    get(id) {
+      return this._all[id] || null;
+    },
+
+    getAll() {
+      return Object.values(this._all);
+    },
+
+    defaultBranch: Services.prefs.getDefaultBranch(""),
+
+    get type() {
+      return document.documentElement.getAttribute("type") || "";
+    },
+
+    get instantApply() {
+      // The about:preferences page forces instantApply.
+      if (this._instantApplyForceEnabled) {
+        return true;
+      }
+
+      // Dialogs of type="child" are never instantApply.
+      if (this.type === "child") {
+        return false;
+      }
+
+      // All other pref windows observe the value of the instantApply
+      // preference.  Note that, as of this writing, the only such windows
+      // are in tests, so it should be possible to remove the pref
+      // (and forceEnableInstantApply) in favor of always applying in a parent
+      // and never applying in a child.
+      return Services.prefs.getBoolPref("browser.preferences.instantApply");
+    },
+
+    _instantApplyForceEnabled: false,
+
+    // Override the computed value of instantApply for this window.
+    forceEnableInstantApply() {
+      this._instantApplyForceEnabled = true;
+    },
+
+    observe(subject, topic, data) {
+      const pref = this._all[data];
+      if (pref) {
+        pref.value = pref.valueFromPreferences;
+      }
+    },
+
+    onDOMContentLoaded() {
+      // Iterate elements with a "preference" attribute and log an error
+      // if there isn't a corresponding Preference object in order to catch
+      // any cases of elements referencing preferences that haven't (yet?)
+      // been registered.
+      //
+      // TODO: remove this code once we determine that there are no such
+      // elements (or resolve any bugs that cause this behavior).
+      //
+      const elements = getElementsByAttribute("preference");
+      for (const element of elements) {
+        const id = element.getAttribute("preference");
+        const pref = this.get(id);
+        if (!pref) {
+          console.error(`Missing preference for ID ${id}`);
+        }
+      }
+    },
+
+    onUnload() {
+      Services.prefs.removeObserver("", this);
+    },
+
+    QueryInterface: XPCOMUtils.generateQI([
+      Ci.nsITimerCallback,
+      Ci.nsIObserver,
+    ]),
+
+    _deferredValueUpdateElements: new Set(),
+
+    writePreferences(aFlushToDisk) {
+      // Write all values to preferences.
+      if (this._deferredValueUpdateElements.size) {
+        this._finalizeDeferredElements();
+      }
+
+      const preferences = Preferences.getAll();
+      for (const preference of preferences) {
+        preference.batching = true;
+        preference.valueFromPreferences = preference.value;
+        preference.batching = false;
+      }
+      if (aFlushToDisk) {
+        Services.prefs.savePrefFile(null);
+      }
+    },
+
+    getPreferenceElement(aStartElement) {
+      let temp = aStartElement;
+      while (temp && temp.nodeType == Node.ELEMENT_NODE &&
+             !temp.hasAttribute("preference"))
+        temp = temp.parentNode;
+      return temp && temp.nodeType == Node.ELEMENT_NODE ?
+             temp : aStartElement;
+    },
+
+    _deferredValueUpdate(aElement) {
+      delete aElement._deferredValueUpdateTask;
+      const prefID = aElement.getAttribute("preference");
+      const preference = Preferences.get(prefID);
+      const prefVal = preference.getElementValue(aElement);
+      preference.value = prefVal;
+      this._deferredValueUpdateElements.delete(aElement);
+    },
+
+    _finalizeDeferredElements() {
+      for (const el of this._deferredValueUpdateElements) {
+        if (el._deferredValueUpdateTask) {
+          el._deferredValueUpdateTask.finalize();
+        }
+      }
+    },
+
+    userChangedValue(aElement) {
+      const element = this.getPreferenceElement(aElement);
+      if (element.hasAttribute("preference")) {
+        if (element.getAttribute("delayprefsave") != "true") {
+          const preference = Preferences.get(element.getAttribute("preference"));
+          const prefVal = preference.getElementValue(element);
+          preference.value = prefVal;
+        } else {
+          if (!element._deferredValueUpdateTask) {
+            element._deferredValueUpdateTask =
+              new DeferredTask(this._deferredValueUpdate.bind(this, element), 1000);
+            this._deferredValueUpdateElements.add(element);
+          } else {
+            // Each time the preference is changed, restart the delay.
+            element._deferredValueUpdateTask.disarm();
+          }
+          element._deferredValueUpdateTask.arm();
+        }
+      }
+    },
+
+    onCommand(event) {
+      // This "command" event handler tracks changes made to preferences by
+      // the user in this window.
+      if (event.sourceEvent)
+        event = event.sourceEvent;
+      this.userChangedValue(event.target);
+    },
+
+    onSelect(event) {
+      // This "select" event handler tracks changes made to colorpicker
+      // preferences by the user in this window.
+      if (event.target.localName == "colorpicker")
+        this.userChangedValue(event.target);
+    },
+
+    onChange(event) {
+      // This "change" event handler tracks changes made to preferences by
+      // the user in this window.
+      this.userChangedValue(event.target);
+    },
+
+    onInput(event) {
+      // This "input" event handler tracks changes made to preferences by
+      // the user in this window.
+      this.userChangedValue(event.target);
+    },
+
+    _fireEvent(aEventName, aTarget) {
+      // Panel loaded, synthesize a load event.
+      try {
+        const event = document.createEvent("Events");
+        event.initEvent(aEventName, true, true);
+        let cancel = !aTarget.dispatchEvent(event);
+        if (aTarget.hasAttribute("on" + aEventName)) {
+          const fn = new Function("event", aTarget.getAttribute("on" + aEventName));
+          const rv = fn.call(aTarget, event);
+          if (rv == false)
+            cancel = true;
+        }
+        return !cancel;
+      } catch (e) {
+        Cu.reportError(e);
+      }
+      return false;
+    },
+
+    onDialogAccept(event) {
+      if (!this._fireEvent("beforeaccept", document.documentElement)) {
+        event.preventDefault();
+        return false;
+      }
+      this.writePreferences(true);
+      return true;
+    },
+
+    close(event) {
+      if (Preferences.instantApply)
+        window.close();
+      event.stopPropagation();
+      event.preventDefault();
+    },
+
+    handleEvent(event) {
+      switch (event.type) {
+        case "change": return this.onChange(event);
+        case "command": return this.onCommand(event);
+        case "dialogaccept": return this.onDialogAccept(event);
+        case "input": return this.onInput(event);
+        case "select": return this.onSelect(event);
+        case "unload": return this.onUnload(event);
+        default: return undefined;
+      }
+    },
+  };
+
+  Services.prefs.addObserver("", Preferences);
+  domContentLoadedPromise.then(result => Preferences.onDOMContentLoaded(result));
+  window.addEventListener("change", Preferences);
+  window.addEventListener("command", Preferences);
+  window.addEventListener("dialogaccept", Preferences);
+  window.addEventListener("input", Preferences);
+  window.addEventListener("select", Preferences);
+  window.addEventListener("unload", Preferences, { once: true });
+
+  class Preference extends EventEmitter {
+    constructor({ id, name, type, inverted, disabled }) {
+      super();
+      this.on("change", this.onChange.bind(this));
+
+      this._value = null;
+      this.readonly = false;
+      this._useDefault = false;
+      this.batching = false;
+
+      this.id = id;
+      this._name = name || this.id;
+      this.type = type;
+      this.inverted = !!inverted;
+      this._disabled = !!disabled;
+
+      // if the element has been inserted without the name attribute set,
+      // we have nothing to do here
+      if (!this.name) {
+        throw new Error(`preference with id '${id}' doesn't have name`);
+      }
+
+      // In non-instant apply mode, we must try and use the last saved state
+      // from any previous opens of a child dialog instead of the value from
+      // preferences, to pick up any edits a user may have made.
+
+      if (Preferences.type == "child" && window.opener &&
+          Services.scriptSecurityManager.isSystemPrincipal(window.opener.document.nodePrincipal)) {
+        // Try to find the preference in the parent window.
+        const preference = window.opener.Preferences.get(this.name);
+
+        // Don't use the value setter here, we don't want updateElements to be
+        // prematurely fired.
+        this._value = preference ? preference.value : this.valueFromPreferences;
+      } else
+        this._value = this.valueFromPreferences;
+    }
+
+    reset() {
+      // defer reset until preference update
+      this.value = undefined;
+    }
+
+    _reportUnknownType() {
+      const msg = `Preference with id=${this.id} and name=${this.name} has unknown type ${this.type}.`;
+      Services.console.logStringMessage(msg);
+    }
+
+    setElementValue(aElement) {
+      if (this.locked)
+        aElement.disabled = true;
+
+      if (!this.isElementEditable(aElement))
+        return;
+
+      let rv = undefined;
+      if (aElement.hasAttribute("onsyncfrompreference")) {
+        // Value changed, synthesize an event
+        try {
+          const event = document.createEvent("Events");
+          event.initEvent("syncfrompreference", true, true);
+          const f = new Function("event",
+                               aElement.getAttribute("onsyncfrompreference"));
+          rv = f.call(aElement, event);
+        } catch (e) {
+          Cu.reportError(e);
+        }
+      }
+      let val = rv;
+      if (val === undefined)
+        val = Preferences.instantApply ? this.valueFromPreferences : this.value;
+      // if the preference is marked for reset, show default value in UI
+      if (val === undefined)
+        val = this.defaultValue;
+
+      /**
+       * Initialize a UI element property with a value. Handles the case
+       * where an element has not yet had a XBL binding attached for it and
+       * the property setter does not yet exist by setting the same attribute
+       * on the XUL element using DOM apis and assuming the element's
+       * constructor or property getters appropriately handle this state.
+       */
+      function setValue(element, attribute, value) {
+        if (attribute in element)
+          element[attribute] = value;
+        else
+          element.setAttribute(attribute, value);
+      }
+      if (aElement.localName == "checkbox" ||
+          aElement.localName == "listitem")
+        setValue(aElement, "checked", val);
+      else if (aElement.localName == "colorpicker")
+        setValue(aElement, "color", val);
+      else if (aElement.localName == "textbox") {
+        // XXXmano Bug 303998: Avoid a caret placement issue if either the
+        // preference observer or its setter calls updateElements as a result
+        // of the input event handler.
+        if (aElement.value !== val)
+          setValue(aElement, "value", val);
+      } else
+        setValue(aElement, "value", val);
+    }
+
+    getElementValue(aElement) {
+      if (aElement.hasAttribute("onsynctopreference")) {
+        // Value changed, synthesize an event
+        try {
+          const event = document.createEvent("Events");
+          event.initEvent("synctopreference", true, true);
+          const f = new Function("event",
+                               aElement.getAttribute("onsynctopreference"));
+          const rv = f.call(aElement, event);
+          if (rv !== undefined)
+            return rv;
+        } catch (e) {
+          Cu.reportError(e);
+        }
+      }
+
+      /**
+       * Read the value of an attribute from an element, assuming the
+       * attribute is a property on the element's node API. If the property
+       * is not present in the API, then assume its value is contained in
+       * an attribute, as is the case before a binding has been attached.
+       */
+      function getValue(element, attribute) {
+        if (attribute in element)
+          return element[attribute];
+        return element.getAttribute(attribute);
+      }
+      let value;
+      if (aElement.localName == "checkbox" ||
+          aElement.localName == "listitem")
+        value = getValue(aElement, "checked");
+      else if (aElement.localName == "colorpicker")
+        value = getValue(aElement, "color");
+      else
+        value = getValue(aElement, "value");
+
+      switch (this.type) {
+      case "int":
+        return parseInt(value, 10) || 0;
+      case "bool":
+        return typeof(value) == "boolean" ? value : value == "true";
+      }
+      return value;
+    }
+
+    isElementEditable(aElement) {
+      switch (aElement.localName) {
+      case "checkbox":
+      case "colorpicker":
+      case "radiogroup":
+      case "textbox":
+      case "listitem":
+      case "listbox":
+      case "menulist":
+        return true;
+      }
+      return aElement.getAttribute("preference-editable") == "true";
+    }
+
+    updateElements() {
+      if (!this.id)
+        return;
+
+      // This "change" event handler tracks changes made to preferences by
+      // sources other than the user in this window.
+      const elements = getElementsByAttribute("preference", this.id);
+      for (const element of elements)
+        this.setElementValue(element);
+    }
+
+    onChange() {
+      this.updateElements();
+    }
+
+    get name() {
+      return this._name;
+    }
+
+    set name(val) {
+      if (val == this.name)
+        return val;
+
+      this._name = val;
+
+      return val;
+    }
+
+    get value() {
+      return this._value;
+    }
+
+    set value(val) {
+      if (this.value !== val) {
+        this._value = val;
+        if (Preferences.instantApply)
+          this.valueFromPreferences = val;
+        this.emit("change");
+      }
+      return val;
+    }
+
+    get locked() {
+      return Services.prefs.prefIsLocked(this.name);
+    }
+
+    get disabled() {
+      return this._disabled;
+    }
+
+    set disabled(val) {
+      this._disabled = !!val;
+
+      if (!this.id)
+        return val;
+
+      const elements = getElementsByAttribute("preference", this.id);
+      for (const element of elements) {
+        element.disabled = val;
+
+        const labels = getElementsByAttribute("control", element.id);
+        for (const label of labels)
+          label.disabled = val;
+      }
+
+      return val;
+    }
+
+    get hasUserValue() {
+      return Services.prefs.prefHasUserValue(this.name) &&
+             this.value !== undefined;
+    }
+
+    get defaultValue() {
+      this._useDefault = true;
+      const val = this.valueFromPreferences;
+      this._useDefault = false;
+      return val;
+    }
+
+    get _branch() {
+      return this._useDefault ? Preferences.defaultBranch : Services.prefs;
+    }
+
+    get valueFromPreferences() {
+      try {
+        // Force a resync of value with preferences.
+        switch (this.type) {
+        case "int":
+          return this._branch.getIntPref(this.name);
+        case "bool": {
+          const val = this._branch.getBoolPref(this.name);
+          return this.inverted ? !val : val;
+        }
+        case "wstring":
+          return this._branch
+                     .getComplexValue(this.name, Ci.nsIPrefLocalizedString)
+                     .data;
+        case "string":
+        case "unichar":
+          return this._branch.getStringPref(this.name);
+        case "fontname": {
+          const family = this._branch.getStringPref(this.name);
+          const fontEnumerator = Cc["@mozilla.org/gfx/fontenumerator;1"]
+                               .createInstance(Ci.nsIFontEnumerator);
+          return fontEnumerator.getStandardFamilyName(family);
+        }
+        case "file": {
+          const f = this._branch
+                      .getComplexValue(this.name, Ci.nsIFile);
+          return f;
+        }
+        default:
+          this._reportUnknownType();
+        }
+      } catch (e) { }
+      return null;
+    }
+
+    set valueFromPreferences(val) {
+      // Exit early if nothing to do.
+      if (this.readonly || this.valueFromPreferences == val)
+        return val;
+
+      // The special value undefined means 'reset preference to default'.
+      if (val === undefined) {
+        Services.prefs.clearUserPref(this.name);
+        return val;
+      }
+
+      // Force a resync of preferences with value.
+      switch (this.type) {
+      case "int":
+        Services.prefs.setIntPref(this.name, val);
+        break;
+      case "bool":
+        Services.prefs.setBoolPref(this.name, this.inverted ? !val : val);
+        break;
+      case "wstring": {
+        const pls = Cc["@mozilla.org/pref-localizedstring;1"]
+                  .createInstance(Ci.nsIPrefLocalizedString);
+        pls.data = val;
+        Services.prefs
+            .setComplexValue(this.name, Ci.nsIPrefLocalizedString, pls);
+        break;
+      }
+      case "string":
+      case "unichar":
+      case "fontname":
+        Services.prefs.setStringPref(this.name, val);
+        break;
+      case "file": {
+        let lf;
+        if (typeof(val) == "string") {
+          lf = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+          lf.persistentDescriptor = val;
+          if (!lf.exists())
+            lf.initWithPath(val);
+        } else
+          lf = val.QueryInterface(Ci.nsIFile);
+        Services.prefs
+            .setComplexValue(this.name, Ci.nsIFile, lf);
+        break;
+      }
+      default:
+        this._reportUnknownType();
+      }
+      if (!this.batching) {
+        Services.prefs.savePrefFile(null);
+      }
+      return val;
+    }
+  }
+
+  return Preferences;
+}.bind({})());
--- a/toolkit/content/resetProfile.xul
+++ b/toolkit/content/resetProfile.xul
@@ -1,15 +1,15 @@
 <?xml version="1.0"?>
 
 <!-- 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/. -->
 
-<!DOCTYPE prefwindow [
+<!DOCTYPE dialog [
 <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
 %brandDTD;
 <!ENTITY % resetProfileDTD SYSTEM "chrome://global/locale/resetProfile.dtd" >
 %resetProfileDTD;
 ]>
 
 <?xml-stylesheet href="chrome://global/skin/"?>
 <?xml-stylesheet href="chrome://global/content/resetProfile.css"?>
--- a/toolkit/content/tests/chrome/test_preferences.xul
+++ b/toolkit/content/tests/chrome/test_preferences.xul
@@ -123,38 +123,43 @@
       return result;
     }
 
     function GetXULElement(aPrefWindow, aID)
     {
       return aPrefWindow.document.getElementById(aID);
     }
 
+    function GetPreference(aPrefWindow, aID)
+    {
+      return aPrefWindow.Preferences.get(aID);
+    }
+
     function WritePrefsToPreferences(aPrefWindow, aPrefValueSet)
     {
-      // write preference data into <preference>s
-      GetXULElement(aPrefWindow, "tests.static_preference_int"    ).value = aPrefValueSet.int;
-      GetXULElement(aPrefWindow, "tests.static_preference_bool"   ).value = aPrefValueSet.bool;
-      GetXULElement(aPrefWindow, "tests.static_preference_string" ).value = aPrefValueSet.string;
-      GetXULElement(aPrefWindow, "tests.static_preference_unichar").value = aPrefValueSet.unichar;
-      GetXULElement(aPrefWindow, "tests.static_preference_wstring").value = aPrefValueSet.wstring_data;
-      GetXULElement(aPrefWindow, "tests.static_preference_file"   ).value = aPrefValueSet.file_data;
+      // write preference data into Preference instances
+      GetPreference(aPrefWindow, "tests.static_preference_int"    ).value = aPrefValueSet.int;
+      GetPreference(aPrefWindow, "tests.static_preference_bool"   ).value = aPrefValueSet.bool;
+      GetPreference(aPrefWindow, "tests.static_preference_string" ).value = aPrefValueSet.string;
+      GetPreference(aPrefWindow, "tests.static_preference_unichar").value = aPrefValueSet.unichar;
+      GetPreference(aPrefWindow, "tests.static_preference_wstring").value = aPrefValueSet.wstring_data;
+      GetPreference(aPrefWindow, "tests.static_preference_file"   ).value = aPrefValueSet.file_data;
     }
 
     function ReadPrefsFromPreferences(aPrefWindow)
     {
-      // read preference data from <preference>s
+      // read preference data from Preference instances
       var result =
       {
-        int:          GetXULElement(aPrefWindow, "tests.static_preference_int"    ).value,
-        bool:         GetXULElement(aPrefWindow, "tests.static_preference_bool"   ).value,
-        string:       GetXULElement(aPrefWindow, "tests.static_preference_string" ).value,
-        unichar:      GetXULElement(aPrefWindow, "tests.static_preference_unichar").value,
-        wstring_data: GetXULElement(aPrefWindow, "tests.static_preference_wstring").value,
-        file_data:    GetXULElement(aPrefWindow, "tests.static_preference_file"   ).value,
+        int:          GetPreference(aPrefWindow, "tests.static_preference_int"    ).value,
+        bool:         GetPreference(aPrefWindow, "tests.static_preference_bool"   ).value,
+        string:       GetPreference(aPrefWindow, "tests.static_preference_string" ).value,
+        unichar:      GetPreference(aPrefWindow, "tests.static_preference_unichar").value,
+        wstring_data: GetPreference(aPrefWindow, "tests.static_preference_wstring").value,
+        file_data:    GetPreference(aPrefWindow, "tests.static_preference_file"   ).value,
         wstring: Components.classes["@mozilla.org/pref-localizedstring;1"]
                            .createInstance(Components.interfaces.nsIPrefLocalizedString),
         file:    Components.classes["@mozilla.org/file/local;1"]
                            .createInstance(Components.interfaces.nsIFile)
       }
       result.wstring.data = result.wstring_data;
       SafeFileInit(result.file, result.file_data);
       return result;
@@ -168,17 +173,17 @@
       GetXULElement(aPrefWindow, "static_element_string" ).value   = aPrefValueSet.string;
       GetXULElement(aPrefWindow, "static_element_unichar").value   = aPrefValueSet.unichar;
       GetXULElement(aPrefWindow, "static_element_wstring").value   = aPrefValueSet.wstring_data;
       GetXULElement(aPrefWindow, "static_element_file"   ).value   = aPrefValueSet.file_data;
     }
 
     function ReadPrefsFromUI(aPrefWindow)
     {
-      // read preference data from <preference>s
+      // read preference data from Preference instances
       var result =
       {
         int:          GetXULElement(aPrefWindow, "static_element_int"    ).value,
         bool:         GetXULElement(aPrefWindow, "static_element_bool"   ).checked,
         string:       GetXULElement(aPrefWindow, "static_element_string" ).value,
         unichar:      GetXULElement(aPrefWindow, "static_element_unichar").value,
         wstring_data: GetXULElement(aPrefWindow, "static_element_wstring").value,
         file_data:    GetXULElement(aPrefWindow, "static_element_file"   ).value,
@@ -192,17 +197,17 @@
       return result;
     }
 
 
     function RunInstantPrefTest(aPrefWindow)
     {
       // remark: there's currently no UI element binding for files
 
-      // were all <preferences> correctly initialized?
+      // were all Preference instances correctly initialized?
       var expected = kPrefValueSet1;
       var found    = ReadPrefsFromPreferences(aPrefWindow);
       ok(found.int          === expected.int,          "instant pref init int"    );
       ok(found.bool         === expected.bool,         "instant pref init bool"   );
       ok(found.string       === expected.string,       "instant pref init string" );
       ok(found.unichar      === expected.unichar,      "instant pref init unichar");
       ok(found.wstring_data === expected.wstring_data, "instant pref init wstring");
       todo(found.file_data  === expected.file_data,    "instant pref init file"   );
@@ -215,17 +220,17 @@
       ok(found.unichar      == expected.unichar,      "instant element init unichar");
       ok(found.wstring_data == expected.wstring_data, "instant element init wstring");
       todo(found.file_data  == expected.file_data,    "instant element init file"   );
 
       // do some changes in the UI
       expected = kPrefValueSet2;
       WritePrefsToUI(aPrefWindow, expected);
 
-      // UI changes should get passed to the <preference>s,
+      // UI changes should get passed to the Preference instances,
       // but currently they aren't if the changes are made programmatically
       // (the handlers preference.change/prefpane.input and prefpane.change
       //  are called for manual changes, though).
       found = ReadPrefsFromPreferences(aPrefWindow);
       todo(found.int          === expected.int,          "instant change pref int"    );
       todo(found.bool         === expected.bool,         "instant change pref bool"   );
       todo(found.string       === expected.string,       "instant change pref string" );
       todo(found.unichar      === expected.unichar,      "instant change pref unichar");
@@ -238,22 +243,22 @@
       todo(found.int          === expected.int,          "instant change element int"    );
       todo(found.bool         === expected.bool,         "instant change element bool"   );
       todo(found.string       === expected.string,       "instant change element string" );
       todo(found.unichar      === expected.unichar,      "instant change element unichar");
       todo(found.wstring_data === expected.wstring_data, "instant change element wstring");
       todo(found.file_data    === expected.file_data,    "instant change element file"   );
 
       // try resetting the prefs to default values (which should be empty here)
-      GetXULElement(aPrefWindow, "tests.static_preference_int"    ).reset();
-      GetXULElement(aPrefWindow, "tests.static_preference_bool"   ).reset();
-      GetXULElement(aPrefWindow, "tests.static_preference_string" ).reset();
-      GetXULElement(aPrefWindow, "tests.static_preference_unichar").reset();
-      GetXULElement(aPrefWindow, "tests.static_preference_wstring").reset();
-      GetXULElement(aPrefWindow, "tests.static_preference_file"   ).reset();
+      GetPreference(aPrefWindow, "tests.static_preference_int"    ).reset();
+      GetPreference(aPrefWindow, "tests.static_preference_bool"   ).reset();
+      GetPreference(aPrefWindow, "tests.static_preference_string" ).reset();
+      GetPreference(aPrefWindow, "tests.static_preference_unichar").reset();
+      GetPreference(aPrefWindow, "tests.static_preference_wstring").reset();
+      GetPreference(aPrefWindow, "tests.static_preference_file"   ).reset();
 
       // check system
       expected = CreateEmptyPrefValueSet();
       found    = ReadPrefsFromSystem();
       ok(found.int          === expected.int,          "instant reset system int"    );
       ok(found.bool         === expected.bool,         "instant reset system bool"   );
       ok(found.string       === expected.string,       "instant reset system string" );
       ok(found.unichar      === expected.unichar,      "instant reset system unichar");
@@ -278,35 +283,35 @@
       ok(found.int          === expected.int,          "instant reset element int"    );
       ok(found.bool         === expected.bool,         "instant reset element bool"   );
       ok(found.string       === expected.string,       "instant reset element string" );
       ok(found.unichar      === expected.unichar,      "instant reset element unichar");
       ok(found.wstring_data === expected.wstring_data, "instant reset element wstring");
 //      ok(found.file_data    === expected.file_data,    "instant reset element file"   );
 
       // check hasUserValue
-      ok(GetXULElement(aPrefWindow, "tests.static_preference_int"    ).hasUserValue === false, "instant reset hasUserValue int"    );
-      ok(GetXULElement(aPrefWindow, "tests.static_preference_bool"   ).hasUserValue === false, "instant reset hasUserValue bool"   );
-      ok(GetXULElement(aPrefWindow, "tests.static_preference_string" ).hasUserValue === false, "instant reset hasUserValue string" );
-      ok(GetXULElement(aPrefWindow, "tests.static_preference_unichar").hasUserValue === false, "instant reset hasUserValue unichar");
-      ok(GetXULElement(aPrefWindow, "tests.static_preference_wstring").hasUserValue === false, "instant reset hasUserValue wstring");
-      ok(GetXULElement(aPrefWindow, "tests.static_preference_file"   ).hasUserValue === false, "instant reset hasUserValue file"   );
+      ok(GetPreference(aPrefWindow, "tests.static_preference_int"    ).hasUserValue === false, "instant reset hasUserValue int"    );
+      ok(GetPreference(aPrefWindow, "tests.static_preference_bool"   ).hasUserValue === false, "instant reset hasUserValue bool"   );
+      ok(GetPreference(aPrefWindow, "tests.static_preference_string" ).hasUserValue === false, "instant reset hasUserValue string" );
+      ok(GetPreference(aPrefWindow, "tests.static_preference_unichar").hasUserValue === false, "instant reset hasUserValue unichar");
+      ok(GetPreference(aPrefWindow, "tests.static_preference_wstring").hasUserValue === false, "instant reset hasUserValue wstring");
+      ok(GetPreference(aPrefWindow, "tests.static_preference_file"   ).hasUserValue === false, "instant reset hasUserValue file"   );
 
       // done with instant apply checks
     }
 
     function RunNonInstantPrefTestGeneral(aPrefWindow)
     {
       // Non-instant apply tests are harder: not only do we need to check that
       // fiddling with the values does *not* change the system settings, but
       // also that they *are* (not) set after closing (cancelling) the dialog...
 
       // remark: there's currently no UI element binding for files
 
-      // were all <preferences> correctly initialized?
+      // were all Preference instances correctly initialized?
       var expected = kPrefValueSet1;
       var found    = ReadPrefsFromPreferences(aPrefWindow);
       ok(found.int          === expected.int,          "non-instant pref init int"    );
       ok(found.bool         === expected.bool,         "non-instant pref init bool"   );
       ok(found.string       === expected.string,       "non-instant pref init string" );
       ok(found.unichar      === expected.unichar,      "non-instant pref init unichar");
       ok(found.wstring_data === expected.wstring_data, "non-instant pref init wstring");
       todo(found.file_data  === expected.file_data,    "non-instant pref init file"   );
@@ -319,17 +324,17 @@
       ok(found.unichar      == expected.unichar,      "non-instant element init unichar");
       ok(found.wstring_data == expected.wstring_data, "non-instant element init wstring");
       todo(found.file_data  == expected.file_data,    "non-instant element init file"   );
 
       // do some changes in the UI
       expected = kPrefValueSet2;
       WritePrefsToUI(aPrefWindow, expected);
 
-      // UI changes should get passed to the <preference>s,
+      // UI changes should get passed to the Preference instances,
       // but currently they aren't if the changes are made programmatically
       // (the handlers preference.change/prefpane.input and prefpane.change
       //  are called for manual changes, though).
       found = ReadPrefsFromPreferences(aPrefWindow);
       todo(found.int          === expected.int,          "non-instant change pref int"    );
       todo(found.bool         === expected.bool,         "non-instant change pref bool"   );
       todo(found.string       === expected.string,       "non-instant change pref string" );
       todo(found.unichar      === expected.unichar,      "non-instant change pref unichar");
@@ -343,22 +348,22 @@
       ok(found.int          === expected.int,          "non-instant change element int"    );
       ok(found.bool         === expected.bool,         "non-instant change element bool"   );
       ok(found.string       === expected.string,       "non-instant change element string" );
       ok(found.unichar      === expected.unichar,      "non-instant change element unichar");
       ok(found.wstring_data === expected.wstring_data, "non-instant change element wstring");
       todo(found.file_data  === expected.file_data,    "non-instant change element file"   );
 
       // try resetting the prefs to default values (which should be empty here)
-      GetXULElement(aPrefWindow, "tests.static_preference_int"    ).reset();
-      GetXULElement(aPrefWindow, "tests.static_preference_bool"   ).reset();
-      GetXULElement(aPrefWindow, "tests.static_preference_string" ).reset();
-      GetXULElement(aPrefWindow, "tests.static_preference_unichar").reset();
-      GetXULElement(aPrefWindow, "tests.static_preference_wstring").reset();
-      GetXULElement(aPrefWindow, "tests.static_preference_file"   ).reset();
+      GetPreference(aPrefWindow, "tests.static_preference_int"    ).reset();
+      GetPreference(aPrefWindow, "tests.static_preference_bool"   ).reset();
+      GetPreference(aPrefWindow, "tests.static_preference_string" ).reset();
+      GetPreference(aPrefWindow, "tests.static_preference_unichar").reset();
+      GetPreference(aPrefWindow, "tests.static_preference_wstring").reset();
+      GetPreference(aPrefWindow, "tests.static_preference_file"   ).reset();
 
       // check system: the current values *MUST NOT* change
       expected = kPrefValueSet1;
       found    = ReadPrefsFromSystem();
       ok(found.int          === expected.int,          "non-instant reset system int"    );
       ok(found.bool         === expected.bool,         "non-instant reset system bool"   );
       ok(found.string       === expected.string,       "non-instant reset system string" );
       ok(found.unichar      === expected.unichar,      "non-instant reset system unichar");
@@ -383,46 +388,46 @@
       ok(found.int          === expected.int,          "non-instant reset element int"    );
       ok(found.bool         === expected.bool,         "non-instant reset element bool"   );
       ok(found.string       === expected.string,       "non-instant reset element string" );
       ok(found.unichar      === expected.unichar,      "non-instant reset element unichar");
       ok(found.wstring_data === expected.wstring_data, "non-instant reset element wstring");
 //      ok(found.file_data    === expected.file_data,    "non-instant reset element file"   );
 
       // check hasUserValue
-      ok(GetXULElement(aPrefWindow, "tests.static_preference_int"    ).hasUserValue === false, "non-instant reset hasUserValue int"    );
-      ok(GetXULElement(aPrefWindow, "tests.static_preference_bool"   ).hasUserValue === false, "non-instant reset hasUserValue bool"   );
-      ok(GetXULElement(aPrefWindow, "tests.static_preference_string" ).hasUserValue === false, "non-instant reset hasUserValue string" );
-      ok(GetXULElement(aPrefWindow, "tests.static_preference_unichar").hasUserValue === false, "non-instant reset hasUserValue unichar");
-      ok(GetXULElement(aPrefWindow, "tests.static_preference_wstring").hasUserValue === false, "non-instant reset hasUserValue wstring");
-      ok(GetXULElement(aPrefWindow, "tests.static_preference_file"   ).hasUserValue === false, "non-instant reset hasUserValue file"   );
+      ok(GetPreference(aPrefWindow, "tests.static_preference_int"    ).hasUserValue === false, "non-instant reset hasUserValue int"    );
+      ok(GetPreference(aPrefWindow, "tests.static_preference_bool"   ).hasUserValue === false, "non-instant reset hasUserValue bool"   );
+      ok(GetPreference(aPrefWindow, "tests.static_preference_string" ).hasUserValue === false, "non-instant reset hasUserValue string" );
+      ok(GetPreference(aPrefWindow, "tests.static_preference_unichar").hasUserValue === false, "non-instant reset hasUserValue unichar");
+      ok(GetPreference(aPrefWindow, "tests.static_preference_wstring").hasUserValue === false, "non-instant reset hasUserValue wstring");
+      ok(GetPreference(aPrefWindow, "tests.static_preference_file"   ).hasUserValue === false, "non-instant reset hasUserValue file"   );
     }
 
     function RunNonInstantPrefTestClose(aPrefWindow)
     {
       WritePrefsToPreferences(aPrefWindow, kPrefValueSet2);
     }
 
     function RunCheckCommandRedirect(aPrefWindow)
     {
       GetXULElement(aPrefWindow, "checkbox").click();
-      ok(GetXULElement(aPrefWindow, "tests.static_preference_bool").value, "redirected command bool");
+      ok(GetPreference(aPrefWindow, "tests.static_preference_bool").value, "redirected command bool");
       GetXULElement(aPrefWindow, "checkbox").click();
-      ok(!GetXULElement(aPrefWindow, "tests.static_preference_bool").value, "redirected command bool");
+      ok(!GetPreference(aPrefWindow, "tests.static_preference_bool").value, "redirected command bool");
     }
 
     function RunResetPrefTest(aPrefWindow)
     {
       // try resetting the prefs to default values
-      GetXULElement(aPrefWindow, "tests.static_preference_int"    ).reset();
-      GetXULElement(aPrefWindow, "tests.static_preference_bool"   ).reset();
-      GetXULElement(aPrefWindow, "tests.static_preference_string" ).reset();
-      GetXULElement(aPrefWindow, "tests.static_preference_unichar").reset();
-      GetXULElement(aPrefWindow, "tests.static_preference_wstring").reset();
-      GetXULElement(aPrefWindow, "tests.static_preference_file"   ).reset();
+      GetPreference(aPrefWindow, "tests.static_preference_int"    ).reset();
+      GetPreference(aPrefWindow, "tests.static_preference_bool"   ).reset();
+      GetPreference(aPrefWindow, "tests.static_preference_string" ).reset();
+      GetPreference(aPrefWindow, "tests.static_preference_unichar").reset();
+      GetPreference(aPrefWindow, "tests.static_preference_wstring").reset();
+      GetPreference(aPrefWindow, "tests.static_preference_file"   ).reset();
     }
 
     function InitTestPrefs(aInstantApply)
     {
       // set instant apply mode and init prefs to set 1
       kPref.setBoolPref("browser.preferences.instantApply", aInstantApply);
       WritePrefsToSystem(kPrefValueSet1);
     }
--- a/toolkit/content/tests/chrome/test_preferences_beforeaccept.xul
+++ b/toolkit/content/tests/chrome/test_preferences_beforeaccept.xul
@@ -12,18 +12,18 @@
   <![CDATA[
     SimpleTest.waitForExplicitFinish();
     SpecialPowers.pushPrefEnv({"set":[["browser.preferences.instantApply", false]]}, function() {
 
     // No instant-apply for this test
     var prefWindow = openDialog("window_preferences_beforeaccept.xul", "", "", windowOnload);
 
     function windowOnload() {
-      var dialogShown = prefWindow.document.getElementById("tests.beforeaccept.dialogShown");
-      var called = prefWindow.document.getElementById("tests.beforeaccept.called");
+      var dialogShown = prefWindow.Preferences.get("tests.beforeaccept.dialogShown");
+      var called = prefWindow.Preferences.get("tests.beforeaccept.called");
       is(dialogShown.value, true, "dialog opened, shown pref set");
       is(dialogShown.valueFromPreferences, null, "shown pref not committed");
       is(called.value, null, "beforeaccept not yet called");
       is(called.valueFromPreferences, null, "beforeaccept not yet called, pref not committed");
 
       // try to accept the dialog, should fail the first time
       prefWindow.document.documentElement.acceptDialog();
       is(prefWindow.closed, false, "window not closed");
--- a/toolkit/content/tests/chrome/test_preferences_onsyncfrompreference.xul
+++ b/toolkit/content/tests/chrome/test_preferences_onsyncfrompreference.xul
@@ -32,17 +32,17 @@
       prefWindow.close();
     });
 
     // Onsyncfrompreference handler for the prefs
     function onSync() {
       for (let pref of PREFS) {
         // The `value` field of each <preference> element should be initialized by now.
 
-        is(SpecialPowers.getIntPref(pref), prefWindow.document.getElementById(pref).value,
+        is(SpecialPowers.getIntPref(pref), prefWindow.Preferences.get(pref).value,
            "Pref constructor was called correctly")
       }
 
       counter++;
 
       if (counter == PREFS.length) {
         SimpleTest.finish();
       }
--- a/toolkit/content/tests/chrome/window_preferences.xul
+++ b/toolkit/content/tests/chrome/window_preferences.xul
@@ -1,53 +1,44 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <!--
   XUL Widget Test for preferences window
 -->
-<prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-            title="preferences window"
-            windowtype="test:preferences"
-            buttons="accept,cancel"
-            onload="RunTest(window.arguments)"
+<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        class="prefwindow"
+        title="preferences window"
+        windowtype="test:preferences"
+        buttons="accept,cancel"
+        onload="RunTest(window.arguments)"
 >
+  <script type="application/javascript" src="chrome://global/content/preferencesBindings.js"/>
   <script type="application/javascript">
   <![CDATA[
     function RunTest(aArgs)
     {
       // run test
       aArgs[0](this);
       // close dialog
       document.documentElement[aArgs[1] ? "acceptDialog" : "cancelDialog"]();
     }
+
+    Preferences.addAll([
+      // one of each type known to Preference.valueFromPreferences
+      { id: "tests.static_preference_int", type: "int" },
+      { id: "tests.static_preference_bool", type: "bool" },
+      { id: "tests.static_preference_string", type: "string" },
+      { id: "tests.static_preference_wstring", type: "wstring" },
+      { id: "tests.static_preference_unichar", type: "unichar" },
+      { id: "tests.static_preference_file", type: "file" },
+    ]);
   ]]>
   </script>
 
-  <prefpane id="sample_pane" label="Sample Prefpane">
-    <preferences id="sample_preferences">
-      <!-- one of each type known to <preferences>.valueFromPreferences -->
-      <preference id  ="tests.static_preference_int"
-                  name="tests.static_preference_int"
-                  type="int"/>
-      <preference id  ="tests.static_preference_bool"
-                  name="tests.static_preference_bool"
-                  type="bool"/>
-      <preference id  ="tests.static_preference_string"
-                  name="tests.static_preference_string"
-                  type="string"/>
-      <preference id  ="tests.static_preference_wstring"
-                  name="tests.static_preference_wstring"
-                  type="wstring"/>
-      <preference id  ="tests.static_preference_unichar"
-                  name="tests.static_preference_unichar"
-                  type="unichar"/>
-      <preference id  ="tests.static_preference_file"
-                  name="tests.static_preference_file"
-                  type="file"/>
-    </preferences>
+  <vbox id="sample_pane" class="prefpane" label="Sample Prefpane">
 
     <!-- one element for each preference type above -->
     <hbox>
       <label flex="1" value="int"/>
       <textbox id="static_element_int"     preference="tests.static_preference_int"/>
     </hbox>
     <hbox>
       <label flex="1" value="bool"/>
@@ -64,10 +55,10 @@
     <hbox>
       <label flex="1" value="unichar"/>
       <textbox id="static_element_unichar" preference="tests.static_preference_unichar"/>
     </hbox>
     <hbox>
       <label flex="1" value="file"/>
       <textbox id="static_element_file"    preference="tests.static_preference_file"/>
     </hbox>
-  </prefpane>
-</prefwindow>
+  </vbox>
+</dialog>
--- a/toolkit/content/tests/chrome/window_preferences2.xul
+++ b/toolkit/content/tests/chrome/window_preferences2.xul
@@ -1,25 +1,27 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <!--
   XUL Widget Test for preferences window
 -->
-<prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-            title="preferences window"
-            windowtype="test:preferences2"
-            buttons="accept,cancel"
-            onload="RunTest(window.arguments)"
+<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        class="prefwindow"
+        title="preferences window"
+        windowtype="test:preferences2"
+        buttons="accept,cancel"
+        onload="RunTest(window.arguments)"
 >
+  <script type="application/javascript" src="chrome://global/content/preferencesBindings.js"/>
   <script type="application/javascript">
   <![CDATA[
     function RunTest(aArgs)
     {
       // open child
-      document.documentElement.openSubDialog("window_preferences3.xul", "", {test: aArgs[0], accept: aArgs[1]});
+      openDialog("window_preferences3.xul", "", "modal,centerscreen,resizable=no", {test: aArgs[0], accept: aArgs[1]});
       // close dialog
       document.documentElement[aArgs[1] ? "acceptDialog" : "cancelDialog"]();
     }
   ]]>
   </script>
 
-  <prefpane id="sample_pane" label="Sample Prefpane"/>
-</prefwindow>
+  <vbox id="sample_pane" class="prefpane" label="Sample Prefpane"/>
+</dialog>
--- a/toolkit/content/tests/chrome/window_preferences3.xul
+++ b/toolkit/content/tests/chrome/window_preferences3.xul
@@ -1,55 +1,45 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <!--
   XUL Widget Test for preferences window
 -->
-<prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-            title="preferences window"
-            windowtype="test:preferences3"
-            buttons="accept,cancel"
-            onload="RunTest(window.arguments)"
-            type="child"
+<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        class="prefwindow"
+        title="preferences window"
+        windowtype="test:preferences3"
+        buttons="accept,cancel"
+        onload="RunTest(window.arguments)"
+        type="child"
 >
+  <script type="application/javascript" src="chrome://global/content/preferencesBindings.js"/>
   <script type="application/javascript">
   <![CDATA[
     function RunTest(aArgs)
     {
       // run test
       aArgs[0].test(this);
       // close dialog
       document.documentElement[aArgs[0].accept ? "acceptDialog" : "cancelDialog"]();
     }
+
+    Preferences.addAll([
+      // one of each type known to Preference.valueFromPreferences
+      { id: "tests.static_preference_int", type: "int" },
+      { id: "tests.static_preference_bool", type: "bool" },
+      { id: "tests.static_preference_string", type: "string" },
+      { id: "tests.static_preference_wstring", type: "wstring" },
+      { id: "tests.static_preference_unichar", type: "unichar" },
+      { id: "tests.static_preference_file", type: "file" },
+    ]);
   ]]>
   </script>
 
-  <prefpane id="sample_pane" label="Sample Prefpane">
-    <preferences id="sample_preferences">
-      <!-- one of each type known to <preferences>.valueFromPreferences -->
-      <preference id  ="tests.static_preference_int"
-                  name="tests.static_preference_int"
-                  type="int"/>
-      <preference id  ="tests.static_preference_bool"
-                  name="tests.static_preference_bool"
-                  type="bool"/>
-      <preference id  ="tests.static_preference_string"
-                  name="tests.static_preference_string"
-                  type="string"/>
-      <preference id  ="tests.static_preference_wstring"
-                  name="tests.static_preference_wstring"
-                  type="wstring"/>
-      <preference id  ="tests.static_preference_unichar"
-                  name="tests.static_preference_unichar"
-                  type="unichar"/>
-      <preference id  ="tests.static_preference_file"
-                  name="tests.static_preference_file"
-                  type="file"/>
-    </preferences>
-
+  <vbox id="sample_pane" class="prefpane" label="Sample Prefpane">
     <!-- one element for each preference type above -->
     <hbox>
       <label flex="1" value="int"/>
       <textbox id="static_element_int"     preference="tests.static_preference_int"/>
     </hbox>
     <hbox>
       <label flex="1" value="bool"/>
       <checkbox id="static_element_bool"   preference="tests.static_preference_bool"/>
@@ -65,10 +55,10 @@
     <hbox>
       <label flex="1" value="unichar"/>
       <textbox id="static_element_unichar" preference="tests.static_preference_unichar"/>
     </hbox>
     <hbox>
       <label flex="1" value="file"/>
       <textbox id="static_element_file"    preference="tests.static_preference_file"/>
     </hbox>
-  </prefpane>
-</prefwindow>
+  </vbox>
+</dialog>
--- a/toolkit/content/tests/chrome/window_preferences_beforeaccept.xul
+++ b/toolkit/content/tests/chrome/window_preferences_beforeaccept.xul
@@ -1,45 +1,44 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <!--
   XUL Widget Test for preferences window with beforeaccept
 -->
-<prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-            title="preferences window"
-            width="300" height="300"
-            windowtype="test:preferences"
-            buttons="accept,cancel"
-            onbeforeaccept="return beforeAccept();"
-            onload="onDialogLoad();"
+<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        class="prefwindow"
+        title="preferences window"
+        width="300" height="300"
+        windowtype="test:preferences"
+        buttons="accept,cancel"
+        onbeforeaccept="return beforeAccept();"
+        onload="onDialogLoad();"
 >
+  <script type="application/javascript" src="chrome://global/content/preferencesBindings.js"/>
   <script type="application/javascript">
   <![CDATA[
     function onDialogLoad() {
-      var pref = document.getElementById("tests.beforeaccept.dialogShown");
+      var pref = Preferences.get("tests.beforeaccept.dialogShown");
       pref.value = true;
 
       // call the onload handler we were passed
       window.arguments[0]();
     }
 
     function beforeAccept() {
-      var beforeAcceptPref = document.getElementById("tests.beforeaccept.called");
+      var beforeAcceptPref = Preferences.get("tests.beforeaccept.called");
       var oldValue = beforeAcceptPref.value;
       beforeAcceptPref.value = true;
 
       return !!oldValue;
     }
+
+    Preferences.addAll([
+      { id: "tests.beforeaccept.called", type: "bool" },
+      { id: "tests.beforeaccept.dialogShown", type: "bool" },
+    ]);
   ]]>
   </script>
 
-  <prefpane id="sample_pane" label="Sample Prefpane">
-    <preferences id="sample_preferences">
-      <preference id="tests.beforeaccept.called"
-                  name="tests.beforeaccept.called"
-                  type="bool"/>
-      <preference id="tests.beforeaccept.dialogShown"
-                  name="tests.beforeaccept.dialogShown"
-                  type="bool"/>
-    </preferences>
-  </prefpane>
+  <vbox id="sample_pane" class="prefpane" label="Sample Prefpane">
+  </vbox>
   <label>Test Prefpane</label>
-</prefwindow>
+</dialog>
--- a/toolkit/content/tests/chrome/window_preferences_commandretarget.xul
+++ b/toolkit/content/tests/chrome/window_preferences_commandretarget.xul
@@ -1,36 +1,36 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <!--
   XUL Widget Test for preferences window. This particular test ensures that
   a checkbox with a command attribute properly updates even though the command
   event gets retargeted.
 -->
-<prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-            title="preferences window"
-            windowtype="test:preferences"
-            buttons="accept,cancel"
-            onload="RunTest(window.arguments)">
+<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        class="prefwindow"
+        title="preferences window"
+        windowtype="test:preferences"
+        buttons="accept,cancel"
+        onload="RunTest(window.arguments)">
+  <script type="application/javascript" src="chrome://global/content/preferencesBindings.js"/>
   <script type="application/javascript">
   <![CDATA[
     function RunTest(aArgs)
     {
       aArgs[0](this);
       document.documentElement.cancelDialog();
     }
+
+    Preferences.addAll([
+      { id: "tests.static_preference_bool", type: "bool" },
+    ]);
   ]]>
   </script>
 
-  <prefpane id="sample_pane" label="Sample Prefpane">
-    <preferences id="sample_preferences">
-      <preference id="tests.static_preference_bool"
-                  name="tests.static_preference_bool"
-                  type="bool"/>
-    </preferences>
-
+  <vbox id="sample_pane" class="prefpane" label="Sample Prefpane">
     <commandset>
       <command id="cmd_test" preference="tests.static_preference_bool"/>
     </commandset>
 
     <checkbox id="checkbox" label="Enable Option" preference="tests.static_preference_bool" command="cmd_test"/>
-  </prefpane>
-</prefwindow>
+  </vbox>
+</dialog>
--- a/toolkit/content/tests/chrome/window_preferences_onsyncfrompreference.xul
+++ b/toolkit/content/tests/chrome/window_preferences_onsyncfrompreference.xul
@@ -3,40 +3,40 @@
 <!-- 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/.  -->
 <!--
   XUL Widget Test for preferences window with onsyncfrompreference
   This test ensures that onsyncfrompreference handlers are called after all the
   values of the corresponding preference element have been set correctly
 -->
-<prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-            title="preferences window"
-            width="300" height="300"
-            windowtype="test:preferences">
+<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        class="prefwindow"
+        title="preferences window"
+        width="300" height="300"
+        windowtype="test:preferences">
 
-  <prefpane id="sample_pane" label="Sample Prefpane">
-    <preferences id="sample_preferences">
-      <preference id="tests.onsyncfrompreference.pref1"
-                  name="tests.onsyncfrompreference.pref1"
-                  type="int"/>
-      <preference id="tests.onsyncfrompreference.pref2"
-                  name="tests.onsyncfrompreference.pref2"
-                  type="int"/>
-      <preference id="tests.onsyncfrompreference.pref3"
-                  name="tests.onsyncfrompreference.pref3"
-                  type="int"/>
-    </preferences>
-  </prefpane>
+  <script type="application/javascript" src="chrome://global/content/preferencesBindings.js"/>
+  <script type="application/javascript">
+  <![CDATA[
+    Preferences.addAll([
+      { id: "tests.onsyncfrompreference.pref1", type: "int" },
+      { id: "tests.onsyncfrompreference.pref2", type: "int" },
+      { id: "tests.onsyncfrompreference.pref3", type: "int" },
+    ]);
+  ]]>
+  </script>
+  <vbox id="sample_pane" class="prefpane" label="Sample Prefpane">
+  </vbox>
   <label>Test Prefpane</label>
         <checkbox id="check1" label="Label1"
                 preference="tests.onsyncfrompreference.pref1"
                 onsyncfrompreference="return window.arguments[0]();"
                 onsynctopreference="return 1;"/>
         <checkbox id="check2" label="Label2"
                 preference="tests.onsyncfrompreference.pref2"
                 onsyncfrompreference="return window.arguments[0]();"
                 onsynctopreference="return 1;"/>
         <checkbox id="check3" label="Label3"
                 preference="tests.onsyncfrompreference.pref3"
                 onsyncfrompreference="return window.arguments[0]();"
                 onsynctopreference="return 1;"/>
-</prefwindow>
+</dialog>
--- a/toolkit/content/widgets/dialog.xml
+++ b/toolkit/content/widgets/dialog.xml
@@ -1,13 +1,17 @@
 <?xml version="1.0"?>
 <!-- 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/. -->
 
+<!DOCTYPE bindings [
+  <!ENTITY % globalKeysDTD SYSTEM "chrome://global/locale/globalKeys.dtd">
+  %globalKeysDTD;
+]>
 
 <bindings id="dialogBindings"
           xmlns="http://www.mozilla.org/xbl"
           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
           xmlns:xbl="http://www.mozilla.org/xbl">
 
   <binding id="dialog" extends="chrome://global/content/bindings/general.xml#root-element">
     <resources>
@@ -35,16 +39,26 @@
         <xul:spacer anonid="spacer" flex="1" hidden="true"/>
         <xul:button dlgtype="accept" class="dialog-button" xbl:inherits="disabled=buttondisabledaccept"/>
         <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
         <xul:button dlgtype="cancel" class="dialog-button"/>
         <xul:button dlgtype="help" class="dialog-button" hidden="true"/>
         <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
 #endif
       </xul:hbox>
+
+    <xul:keyset>
+      <xul:key phase="capturing" oncommand="document.documentElement.openHelp(event)"
+#ifdef XP_MACOSX
+           key="&openHelpMac.commandkey;" modifiers="accel"/>
+#else
+           keycode="&openHelp.commandkey;"/>
+#endif
+    </xul:keyset>
+
     </content>
 
     <implementation>
       <field name="_mStrBundle">null</field>
       <field name="_closeHandler">(function(event) {
         if (!document.documentElement.cancelDialog())
           event.preventDefault();
       })</field>
@@ -204,16 +218,30 @@
           }
 
           // Give focus after onload completes, see bug 103197.
           setTimeout(focusInit, 0);
         ]]>
         </body>
       </method>
 
+      <method name="openHelp">
+        <parameter name="event"/>
+        <body>
+        <![CDATA[
+          var helpButton = document.documentElement.getButton("help");
+          if (helpButton.disabled || helpButton.hidden)
+            return;
+          this._fireButtonEvent("help");
+          event.stopPropagation();
+          event.preventDefault();
+        ]]>
+        </body>
+      </method>
+
       <property name="mStrBundle">
         <getter>
         <![CDATA[
           if (!this._mStrBundle) {
             // need to create string bundle manually instead of using <xul:stringbundle/>
             // see bug 63370 for details
             this._mStrBundle = Components.classes["@mozilla.org/intl/stringbundle;1"]
                                          .getService(Components.interfaces.nsIStringBundleService)
deleted file mode 100644
--- a/toolkit/content/widgets/preferences.xml
+++ /dev/null
@@ -1,1409 +0,0 @@
-<?xml version="1.0"?>
-
-<!DOCTYPE bindings [
-  <!ENTITY % preferencesDTD SYSTEM "chrome://global/locale/preferences.dtd">
-  %preferencesDTD;
-  <!ENTITY % globalKeysDTD SYSTEM "chrome://global/locale/globalKeys.dtd">
-  %globalKeysDTD;
-]>
-
-<bindings id="preferencesBindings"
-          xmlns="http://www.mozilla.org/xbl"
-          xmlns:xbl="http://www.mozilla.org/xbl"
-          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-
-#
-# = Preferences Window Framework
-#
-#   The syntax for use looks something like:
-#
-#   <prefwindow>
-#     <prefpane id="prefPaneA">
-#       <preferences>
-#         <preference id="preference1" name="app.preference1" type="bool" onchange="foo();"/>
-#         <preference id="preference2" name="app.preference2" type="bool" useDefault="true"/>
-#       </preferences>
-#       <checkbox label="Preference" preference="preference1"/>
-#     </prefpane>
-#   </prefwindow>
-#
-
-  <binding id="preferences">
-    <implementation implements="nsIObserver">
-      <method name="_constructAfterChildren">
-      <body>
-      <![CDATA[
-      // This method will be called after the last of the child
-      // <preference> elements is constructed. Its purpose is to propagate
-      // the values to the associated form elements. Sometimes the code for
-      // some <preference> initializers depend on other <preference> elements
-      // being initialized so we wait and call updateElements on all of them
-      // once the last one has been constructed. See bugs 997570 and 992185.
-
-      var elements = this.getElementsByTagName("preference");
-      for (let element of elements) {
-        element.updateElements();
-      }
-
-      this._constructAfterChildrenCalled = true;
-      ]]>
-      </body>
-      </method>
-      <method name="observe">
-        <parameter name="aSubject"/>
-        <parameter name="aTopic"/>
-        <parameter name="aData"/>
-        <body>
-        <![CDATA[
-          for (var i = 0; i < this.childNodes.length; ++i) {
-            var preference = this.childNodes[i];
-            if (preference.name == aData) {
-              preference.value = preference.valueFromPreferences;
-            }
-          }
-        ]]>
-        </body>
-      </method>
-
-      <method name="fireChangedEvent">
-        <parameter name="aPreference"/>
-        <body>
-        <![CDATA[
-          // Value changed, synthesize an event
-          try {
-            var event = document.createEvent("Events");
-            event.initEvent("change", true, true);
-            aPreference.dispatchEvent(event);
-          } catch (e) {
-            Components.utils.reportError(e);
-          }
-        ]]>
-        </body>
-      </method>
-
-      <field name="service">
-        Components.classes["@mozilla.org/preferences-service;1"]
-                  .getService(Components.interfaces.nsIPrefService);
-      </field>
-      <field name="rootBranch">
-        Components.classes["@mozilla.org/preferences-service;1"]
-                  .getService(Components.interfaces.nsIPrefBranch);
-      </field>
-      <field name="defaultBranch">
-        this.service.getDefaultBranch("");
-      </field>
-      <field name="rootBranchInternal">
-        Components.classes["@mozilla.org/preferences-service;1"]
-                  .getService(Components.interfaces.nsIPrefBranch);
-      </field>
-      <property name="type" readonly="true">
-        <getter>
-          <![CDATA[
-            return document.documentElement.type || "";
-          ]]>
-        </getter>
-      </property>
-      <property name="instantApply" readonly="true">
-        <getter>
-          <![CDATA[
-            var doc = document.documentElement;
-            return this.type == "child" ? doc.instantApply
-                                        : doc.instantApply || this.rootBranch.getBoolPref("browser.preferences.instantApply");
-          ]]>
-        </getter>
-      </property>
-
-      <!-- We want to call _constructAfterChildren after all child
-           <preference> elements have been constructed. To do this, we get
-           and store the node list of all child <preference> elements in the
-           constructor, and maintain a count which is incremented in the
-           constructor of <preference>. _constructAfterChildren is called
-           when the count matches the length of the list. -->
-      <field name="_constructedChildrenCount">0</field>
-      <field name="_preferenceChildren">null</field>
-      <!-- Some <preference> elements are added dynamically after
-           _constructAfterChildren has already been called - we want to
-           avoid looping over all of them again in this case so we remember
-           if we already called it. -->
-      <field name="_constructAfterChildrenCalled">false</field>
-      <constructor>
-      <![CDATA[
-        this._preferenceChildren = this.getElementsByTagName("preference");
-      ]]>
-      </constructor>
-    </implementation>
-  </binding>
-
-  <binding id="preference">
-    <implementation>
-      <constructor>
-      <![CDATA[
-        // if the element has been inserted without the name attribute set,
-        // we have nothing to do here
-        if (!this.name)
-          return;
-
-        this.preferences.rootBranchInternal
-            .addObserver(this.name, this.preferences);
-        // In non-instant apply mode, we must try and use the last saved state
-        // from any previous opens of a child dialog instead of the value from
-        // preferences, to pick up any edits a user may have made.
-
-        var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
-                    .getService(Components.interfaces.nsIScriptSecurityManager);
-        if (this.preferences.type == "child" &&
-            !this.instantApply && window.opener &&
-            secMan.isSystemPrincipal(window.opener.document.nodePrincipal)) {
-          var pdoc = window.opener.document;
-
-          // Try to find a preference element for the same preference.
-          var preference = null;
-          var parentPreferences = pdoc.getElementsByTagName("preferences");
-          for (var k = 0; (k < parentPreferences.length && !preference); ++k) {
-            var parentPrefs = parentPreferences[k]
-                                    .getElementsByAttribute("name", this.name);
-            for (var l = 0; (l < parentPrefs.length && !preference); ++l) {
-              if (parentPrefs[l].localName == "preference")
-                preference = parentPrefs[l];
-            }
-          }
-
-          // Don't use the value setter here, we don't want updateElements to be prematurely fired.
-          this._value = preference ? preference.value : this.valueFromPreferences;
-        } else {
-          this._value = this.valueFromPreferences;
-        }
-        if (this.preferences._constructAfterChildrenCalled) {
-          // This <preference> was added after _constructAfterChildren() was already called.
-          // We can directly call updateElements().
-          this.updateElements();
-          return;
-        }
-        this.preferences._constructedChildrenCount++;
-        if (this.preferences._constructedChildrenCount ==
-            this.preferences._preferenceChildren.length) {
-          // This is the last <preference>, time to updateElements() on all of them.
-          this.preferences._constructAfterChildren();
-        }
-      ]]>
-      </constructor>
-      <destructor>
-        this.preferences.rootBranchInternal
-            .removeObserver(this.name, this.preferences);
-      </destructor>
-      <field name="_constructed">false</field>
-      <property name="instantApply">
-        <getter>
-          if (this.getAttribute("instantApply") == "false")
-            return false;
-          return this.getAttribute("instantApply") == "true" || this.preferences.instantApply;
-        </getter>
-      </property>
-
-      <property name="preferences" onget="return this.parentNode"/>
-      <property name="name" onget="return this.getAttribute('name');">
-        <setter>
-          if (val == this.name)
-            return val;
-
-          this.preferences.rootBranchInternal
-              .removeObserver(this.name, this.preferences);
-          this.setAttribute("name", val);
-          this.preferences.rootBranchInternal
-              .addObserver(val, this.preferences);
-
-          return val;
-        </setter>
-      </property>
-      <property name="type" onget="return this.getAttribute('type');"
-                            onset="this.setAttribute('type', val); return val;"/>
-      <property name="inverted" onget="return this.getAttribute('inverted') == 'true';"
-                                onset="this.setAttribute('inverted', val); return val;"/>
-      <property name="readonly" onget="return this.getAttribute('readonly') == 'true';"
-                                onset="this.setAttribute('readonly', val); return val;"/>
-
-      <field name="_value">null</field>
-      <method name="_setValue">
-        <parameter name="aValue"/>
-        <body>
-        <![CDATA[
-          if (this.value !== aValue) {
-            this._value = aValue;
-            if (this.instantApply)
-              this.valueFromPreferences = aValue;
-            this.preferences.fireChangedEvent(this);
-          }
-          return aValue;
-        ]]>
-        </body>
-      </method>
-      <property name="value" onget="return this._value" onset="return this._setValue(val);"/>
-
-      <property name="locked">
-        <getter>
-          return this.preferences.rootBranch.prefIsLocked(this.name);
-        </getter>
-      </property>
-
-      <property name="disabled">
-        <getter>
-          return this.getAttribute("disabled") == "true";
-        </getter>
-        <setter>
-        <![CDATA[
-          if (val)
-            this.setAttribute("disabled", "true");
-          else
-            this.removeAttribute("disabled");
-
-          if (!this.id)
-            return val;
-
-          var elements = document.getElementsByAttribute("preference", this.id);
-          for (var i = 0; i < elements.length; ++i) {
-            elements[i].disabled = val;
-
-            var labels = document.getElementsByAttribute("control", elements[i].id);
-            for (var j = 0; j < labels.length; ++j)
-              labels[j].disabled = val;
-          }
-
-          return val;
-        ]]>
-        </setter>
-      </property>
-
-      <property name="tabIndex">
-        <getter>
-          return parseInt(this.getAttribute("tabindex"));
-        </getter>
-        <setter>
-        <![CDATA[
-          if (val)
-            this.setAttribute("tabindex", val);
-          else
-            this.removeAttribute("tabindex");
-
-          if (!this.id)
-            return val;
-
-          var elements = document.getElementsByAttribute("preference", this.id);
-          for (var i = 0; i < elements.length; ++i) {
-            elements[i].tabIndex = val;
-
-            var labels = document.getElementsByAttribute("control", elements[i].id);
-            for (var j = 0; j < labels.length; ++j)
-              labels[j].tabIndex = val;
-          }
-
-          return val;
-        ]]>
-        </setter>
-      </property>
-
-      <property name="hasUserValue">
-        <getter>
-        <![CDATA[
-          return this.preferences.rootBranch.prefHasUserValue(this.name) &&
-                 this.value !== undefined;
-        ]]>
-        </getter>
-      </property>
-
-      <method name="reset">
-        <body>
-          // defer reset until preference update
-          this.value = undefined;
-        </body>
-      </method>
-
-      <field name="_useDefault">false</field>
-      <property name="defaultValue">
-        <getter>
-        <![CDATA[
-          this._useDefault = true;
-          var val = this.valueFromPreferences;
-          this._useDefault = false;
-          return val;
-        ]]>
-        </getter>
-      </property>
-
-      <property name="_branch">
-        <getter>
-          return this._useDefault ? this.preferences.defaultBranch : this.preferences.rootBranch;
-        </getter>
-      </property>
-
-      <field name="batching">false</field>
-
-      <method name="_reportUnknownType">
-        <body>
-        <![CDATA[
-          var consoleService = Components.classes["@mozilla.org/consoleservice;1"]
-                                         .getService(Components.interfaces.nsIConsoleService);
-          var msg = "<preference> with id='" + this.id + "' and name='" +
-                    this.name + "' has unknown type '" + this.type + "'.";
-          consoleService.logStringMessage(msg);
-        ]]>
-        </body>
-      </method>
-
-      <property name="valueFromPreferences">
-        <getter>
-        <![CDATA[
-          try {
-            // Force a resync of value with preferences.
-            switch (this.type) {
-            case "int":
-              return this._branch.getIntPref(this.name);
-            case "bool":
-              var val = this._branch.getBoolPref(this.name);
-              return this.inverted ? !val : val;
-            case "wstring":
-              return this._branch
-                         .getComplexValue(this.name, Components.interfaces.nsIPrefLocalizedString)
-                         .data;
-            case "string":
-            case "unichar":
-              return this._branch.getStringPref(this.name);
-            case "fontname":
-              var family = this._branch.getStringPref(this.name);
-              var fontEnumerator = Components.classes["@mozilla.org/gfx/fontenumerator;1"]
-                                             .createInstance(Components.interfaces.nsIFontEnumerator);
-              return fontEnumerator.getStandardFamilyName(family);
-            case "file":
-              var f = this._branch
-                          .getComplexValue(this.name, Components.interfaces.nsIFile);
-              return f;
-            default:
-              this._reportUnknownType();
-            }
-          } catch (e) { }
-          return null;
-        ]]>
-        </getter>
-        <setter>
-        <![CDATA[
-          // Exit early if nothing to do.
-          if (this.readonly || this.valueFromPreferences == val)
-            return val;
-
-          // The special value undefined means 'reset preference to default'.
-          if (val === undefined) {
-            this.preferences.rootBranch.clearUserPref(this.name);
-            return val;
-          }
-
-          // Force a resync of preferences with value.
-          switch (this.type) {
-          case "int":
-            this.preferences.rootBranch.setIntPref(this.name, val);
-            break;
-          case "bool":
-            this.preferences.rootBranch.setBoolPref(this.name, this.inverted ? !val : val);
-            break;
-          case "wstring":
-            var pls = Components.classes["@mozilla.org/pref-localizedstring;1"]
-                                .createInstance(Components.interfaces.nsIPrefLocalizedString);
-            pls.data = val;
-            this.preferences.rootBranch
-                .setComplexValue(this.name, Components.interfaces.nsIPrefLocalizedString, pls);
-            break;
-          case "string":
-          case "unichar":
-          case "fontname":
-            this.preferences.rootBranch.setStringPref(this.name, val);
-            break;
-          case "file":
-            var lf;
-            if (typeof(val) == "string") {
-              lf = Components.classes["@mozilla.org/file/local;1"]
-                             .createInstance(Components.interfaces.nsIFile);
-              lf.persistentDescriptor = val;
-              if (!lf.exists())
-                lf.initWithPath(val);
-            } else
-              lf = val.QueryInterface(Components.interfaces.nsIFile);
-            this.preferences.rootBranch
-                .setComplexValue(this.name, Components.interfaces.nsIFile, lf);
-            break;
-          default:
-            this._reportUnknownType();
-          }
-          if (!this.batching)
-            this.preferences.service.savePrefFile(null);
-          return val;
-        ]]>
-        </setter>
-      </property>
-
-      <method name="setElementValue">
-        <parameter name="aElement"/>
-        <body>
-        <![CDATA[
-          if (this.locked)
-            aElement.disabled = true;
-
-          if (!this.isElementEditable(aElement))
-            return;
-
-          var rv = undefined;
-          if (aElement.hasAttribute("onsyncfrompreference")) {
-            // Value changed, synthesize an event
-            try {
-              var event = document.createEvent("Events");
-              event.initEvent("syncfrompreference", true, true);
-              var f = new Function("event",
-                                   aElement.getAttribute("onsyncfrompreference"));
-              rv = f.call(aElement, event);
-            } catch (e) {
-              Components.utils.reportError(e);
-            }
-          }
-          var val = rv;
-          if (val === undefined)
-            val = this.instantApply ? this.valueFromPreferences : this.value;
-          // if the preference is marked for reset, show default value in UI
-          if (val === undefined)
-            val = this.defaultValue;
-
-          /**
-           * Initialize a UI element property with a value. Handles the case
-           * where an element has not yet had a XBL binding attached for it and
-           * the property setter does not yet exist by setting the same attribute
-           * on the XUL element using DOM apis and assuming the element's
-           * constructor or property getters appropriately handle this state.
-           */
-          function setValue(element, attribute, value) {
-            if (attribute in element)
-              element[attribute] = value;
-            else
-              element.setAttribute(attribute, value);
-          }
-          if (aElement.localName == "checkbox" ||
-              aElement.localName == "listitem")
-            setValue(aElement, "checked", val);
-          else if (aElement.localName == "colorpicker")
-            setValue(aElement, "color", val);
-          else if (aElement.localName == "textbox") {
-            // XXXmano Bug 303998: Avoid a caret placement issue if either the
-            // preference observer or its setter calls updateElements as a result
-            // of the input event handler.
-            if (aElement.value !== val)
-              setValue(aElement, "value", val);
-          } else
-            setValue(aElement, "value", val);
-        ]]>
-        </body>
-      </method>
-
-      <method name="getElementValue">
-        <parameter name="aElement"/>
-        <body>
-        <![CDATA[
-          if (aElement.hasAttribute("onsynctopreference")) {
-            // Value changed, synthesize an event
-            try {
-              var event = document.createEvent("Events");
-              event.initEvent("synctopreference", true, true);
-              var f = new Function("event",
-                                   aElement.getAttribute("onsynctopreference"));
-              var rv = f.call(aElement, event);
-              if (rv !== undefined)
-                return rv;
-            } catch (e) {
-              Components.utils.reportError(e);
-            }
-          }
-
-          /**
-           * Read the value of an attribute from an element, assuming the
-           * attribute is a property on the element's node API. If the property
-           * is not present in the API, then assume its value is contained in
-           * an attribute, as is the case before a binding has been attached.
-           */
-          function getValue(element, attribute) {
-            if (attribute in element)
-              return element[attribute];
-            return element.getAttribute(attribute);
-          }
-          if (aElement.localName == "checkbox" ||
-              aElement.localName == "listitem")
-            var value = getValue(aElement, "checked");
-          else if (aElement.localName == "colorpicker")
-            value = getValue(aElement, "color");
-          else
-            value = getValue(aElement, "value");
-
-          switch (this.type) {
-          case "int":
-            return parseInt(value, 10) || 0;
-          case "bool":
-            return typeof(value) == "boolean" ? value : value == "true";
-          }
-          return value;
-        ]]>
-        </body>
-      </method>
-
-      <method name="isElementEditable">
-        <parameter name="aElement"/>
-        <body>
-        <![CDATA[
-          switch (aElement.localName) {
-          case "checkbox":
-          case "colorpicker":
-          case "radiogroup":
-          case "textbox":
-          case "listitem":
-          case "listbox":
-          case "menulist":
-            return true;
-          }
-          return aElement.getAttribute("preference-editable") == "true";
-        ]]>
-        </body>
-      </method>
-
-      <method name="updateElements">
-        <body>
-        <![CDATA[
-          if (!this.id)
-            return;
-
-          // This "change" event handler tracks changes made to preferences by
-          // sources other than the user in this window.
-          var elements = document.getElementsByAttribute("preference", this.id);
-          for (var i = 0; i < elements.length; ++i)
-            this.setElementValue(elements[i]);
-        ]]>
-        </body>
-      </method>
-    </implementation>
-
-    <handlers>
-      <handler event="change">
-        this.updateElements();
-      </handler>
-    </handlers>
-  </binding>
-
-  <binding id="prefwindow"
-           extends="chrome://global/content/bindings/dialog.xml#dialog">
-    <resources>
-      <stylesheet src="chrome://global/skin/preferences.css"/>
-    </resources>
-    <content dlgbuttons="accept,cancel" persist="lastSelected screenX screenY"
-             closebuttonlabel="&preferencesCloseButton.label;"
-             closebuttonaccesskey="&preferencesCloseButton.accesskey;"
-             role="dialog"
-#ifdef XP_WIN
-             title="&preferencesDefaultTitleWin.title;">
-#else
-             title="&preferencesDefaultTitleMac.title;">
-#endif
-      <xul:windowdragbox orient="vertical">
-        <xul:radiogroup anonid="selector" orient="horizontal" class="paneSelector chromeclass-toolbar"
-                        role="listbox"/> <!-- Expose to accessibility APIs as a listbox -->
-      </xul:windowdragbox>
-      <xul:hbox flex="1" class="paneDeckContainer">
-        <xul:deck anonid="paneDeck" flex="1">
-          <children includes="prefpane"/>
-        </xul:deck>
-      </xul:hbox>
-      <xul:hbox anonid="dlg-buttons" class="prefWindow-dlgbuttons" pack="end">
-#ifdef XP_UNIX
-        <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
-        <xul:button dlgtype="help" class="dialog-button" hidden="true" icon="help"/>
-        <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
-        <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
-        <xul:spacer anonid="spacer" flex="1"/>
-        <xul:button dlgtype="cancel" class="dialog-button" icon="cancel"/>
-        <xul:button dlgtype="accept" class="dialog-button" icon="accept"/>
-#else
-        <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
-        <xul:spacer anonid="spacer" flex="1"/>
-        <xul:button dlgtype="accept" class="dialog-button" icon="accept"/>
-        <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
-        <xul:button dlgtype="cancel" class="dialog-button" icon="cancel"/>
-        <xul:button dlgtype="help" class="dialog-button" hidden="true" icon="help"/>
-        <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
-#endif
-      </xul:hbox>
-      <xul:hbox>
-        <children/>
-      </xul:hbox>
-    </content>
-    <implementation implements="nsITimerCallback">
-      <constructor>
-      <![CDATA[
-        if (this.type != "child") {
-          if (!this._instantApplyInitialized) {
-            let psvc = Components.classes["@mozilla.org/preferences-service;1"]
-                                 .getService(Components.interfaces.nsIPrefBranch);
-            this.instantApply = psvc.getBoolPref("browser.preferences.instantApply");
-          }
-          if (this.instantApply) {
-            var docElt = document.documentElement;
-            var acceptButton = docElt.getButton("accept");
-            acceptButton.hidden = true;
-            var cancelButton  = docElt.getButton("cancel");
-            if (/Mac/.test(navigator.platform)) {
-              // no buttons on Mac except Help
-              cancelButton.hidden = true;
-              // Move Help button to the end
-              document.getAnonymousElementByAttribute(this, "anonid", "spacer").hidden = true;
-              // Also, don't fire onDialogAccept on enter
-              acceptButton.disabled = true;
-            } else {
-              // morph the Cancel button into the Close button
-              cancelButton.setAttribute("icon", "close");
-              cancelButton.label = docElt.getAttribute("closebuttonlabel");
-              cancelButton.accesskey = docElt.getAttribute("closebuttonaccesskey");
-            }
-          }
-        }
-        this.setAttribute("animated", this._shouldAnimate ? "true" : "false");
-        var panes = this.preferencePanes;
-
-        var lastPane = null;
-        if (this.lastSelected) {
-          lastPane = document.getElementById(this.lastSelected);
-          if (!lastPane) {
-            this.lastSelected = "";
-          }
-        }
-
-        var paneToLoad;
-        if ("arguments" in window && window.arguments[0] && document.getElementById(window.arguments[0]) && document.getElementById(window.arguments[0]).nodeName == "prefpane") {
-          paneToLoad = document.getElementById(window.arguments[0]);
-          this.lastSelected = paneToLoad.id;
-        } else if (lastPane)
-          paneToLoad = lastPane;
-        else
-          paneToLoad = panes[0];
-
-        for (var i = 0; i < panes.length; ++i) {
-          this._makePaneButton(panes[i]);
-          if (panes[i].loaded) {
-            // Inline pane content, fire load event to force initialization.
-            this._fireEvent("paneload", panes[i]);
-          }
-        }
-        this.showPane(paneToLoad);
-
-        if (panes.length == 1)
-          this._selector.setAttribute("collapsed", "true");
-      ]]>
-      </constructor>
-
-      <destructor>
-      <![CDATA[
-        // Release timers to avoid reference cycles.
-        if (this._animateTimer) {
-          this._animateTimer.cancel();
-          this._animateTimer = null;
-        }
-        if (this._fadeTimer) {
-          this._fadeTimer.cancel();
-          this._fadeTimer = null;
-        }
-      ]]>
-      </destructor>
-
-      <!-- Derived bindings can set this to true to cause us to skip
-           reading the browser.preferences.instantApply pref in the constructor.
-           Then they can set instantApply to their wished value. -->
-      <field name="_instantApplyInitialized">false</field>
-      <!-- Controls whether changed pref values take effect immediately. -->
-      <field name="instantApply">false</field>
-
-      <property name="preferencePanes"
-                onget="return this.getElementsByTagName('prefpane');"/>
-
-      <property name="type" onget="return this.getAttribute('type');"/>
-      <property name="_paneDeck"
-                onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'paneDeck');"/>
-      <property name="_paneDeckContainer"
-                onget="return document.getAnonymousElementByAttribute(this, 'class', 'paneDeckContainer');"/>
-      <property name="_selector"
-                onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'selector');"/>
-      <property name="lastSelected"
-                onget="return this.getAttribute('lastSelected');">
-        <setter>
-          this.setAttribute("lastSelected", val);
-          document.persist(this.id, "lastSelected");
-          return val;
-        </setter>
-      </property>
-      <property name="currentPane"
-                onset="return this._currentPane = val;">
-        <getter>
-          if (!this._currentPane)
-            this._currentPane = this.preferencePanes[0];
-
-          return this._currentPane;
-        </getter>
-      </property>
-      <field name="_currentPane">null</field>
-
-
-      <method name="_makePaneButton">
-        <parameter name="aPaneElement"/>
-        <body>
-        <![CDATA[
-          var radio = document.createElement("radio");
-          radio.setAttribute("pane", aPaneElement.id);
-          radio.setAttribute("label", aPaneElement.label);
-          // Expose preference group choice to accessibility APIs as an unchecked list item
-          // The parent group is exposed to accessibility APIs as a list
-          if (aPaneElement.image)
-            radio.setAttribute("src", aPaneElement.image);
-          radio.style.listStyleImage = aPaneElement.style.listStyleImage;
-          this._selector.appendChild(radio);
-          return radio;
-        ]]>
-        </body>
-      </method>
-
-      <method name="showPane">
-        <parameter name="aPaneElement"/>
-        <body>
-        <![CDATA[
-          if (!aPaneElement)
-            return;
-
-          this._selector.selectedItem = document.getAnonymousElementByAttribute(this, "pane", aPaneElement.id);
-          if (!aPaneElement.loaded) {
-            let OverlayLoadObserver = function(aPane) {
-              this._pane = aPane;
-            };
-            OverlayLoadObserver.prototype = {
-              _outer: this,
-              observe(aSubject, aTopic, aData) {
-                this._pane.loaded = true;
-                this._outer._fireEvent("paneload", this._pane);
-                this._outer._selectPane(this._pane);
-              }
-            };
-
-            var obs = new OverlayLoadObserver(aPaneElement);
-            document.loadOverlay(aPaneElement.src, obs);
-          } else
-            this._selectPane(aPaneElement);
-        ]]>
-        </body>
-      </method>
-
-      <method name="_fireEvent">
-        <parameter name="aEventName"/>
-        <parameter name="aTarget"/>
-        <body>
-        <![CDATA[
-          // Panel loaded, synthesize a load event.
-          try {
-            var event = document.createEvent("Events");
-            event.initEvent(aEventName, true, true);
-            var cancel = !aTarget.dispatchEvent(event);
-            if (aTarget.hasAttribute("on" + aEventName)) {
-              var fn = new Function("event", aTarget.getAttribute("on" + aEventName));
-              var rv = fn.call(aTarget, event);
-              if (rv == false)
-                cancel = true;
-            }
-            return !cancel;
-          } catch (e) {
-            Components.utils.reportError(e);
-          }
-          return false;
-        ]]>
-        </body>
-      </method>
-
-      <field name="_initialized">false</field>
-      <method name="_selectPane">
-        <parameter name="aPaneElement"/>
-        <body>
-        <![CDATA[
-          if (/Mac/.test(navigator.platform)) {
-            var paneTitle = aPaneElement.label;
-            if (paneTitle != "")
-              document.title = paneTitle;
-          }
-          var helpButton = document.documentElement.getButton("help");
-          if (aPaneElement.helpTopic)
-            helpButton.hidden = false;
-          else
-            helpButton.hidden = true;
-
-          // Find this pane's index in the deck and set the deck's
-          // selectedIndex to that value to switch to it.
-          var prefpanes = this.preferencePanes;
-          for (var i = 0; i < prefpanes.length; ++i) {
-            if (prefpanes[i] == aPaneElement) {
-              this._paneDeck.selectedIndex = i;
-
-              if (this.type != "child") {
-                if (aPaneElement.hasAttribute("flex") && this._shouldAnimate &&
-                    prefpanes.length > 1)
-                  aPaneElement.removeAttribute("flex");
-                // Calling sizeToContent after the first prefpane is loaded
-                // will size the windows contents so style information is
-                // available to calculate correct sizing.
-                if (!this._initialized && prefpanes.length > 1) {
-                  if (this._shouldAnimate)
-                    this.style.minHeight = 0;
-                  window.sizeToContent();
-                }
-
-                var oldPane = this.lastSelected ? document.getElementById(this.lastSelected) : this.preferencePanes[0];
-                oldPane.selected = !(aPaneElement.selected = true);
-                this.lastSelected = aPaneElement.id;
-                this.currentPane = aPaneElement;
-                this._initialized = true;
-
-                // Only animate if we've switched between prefpanes
-                if (this._shouldAnimate && oldPane.id != aPaneElement.id) {
-                  aPaneElement.style.opacity = 0.0;
-                  this.animate(oldPane, aPaneElement);
-                } else if (!this._shouldAnimate && prefpanes.length > 1) {
-                  var targetHeight = parseInt(window.getComputedStyle(this._paneDeckContainer).height);
-                  var verticalPadding = parseInt(window.getComputedStyle(aPaneElement).paddingTop);
-                  verticalPadding += parseInt(window.getComputedStyle(aPaneElement).paddingBottom);
-                  if (aPaneElement.contentHeight > targetHeight - verticalPadding) {
-                    // To workaround the bottom border of a groupbox from being
-                    // cutoff an hbox with a class of bottomBox may enclose it.
-                    // This needs to include its padding to resize properly.
-                    // See bug 394433
-                    var bottomPadding = 0;
-                    var bottomBox = aPaneElement.getElementsByAttribute("class", "bottomBox")[0];
-                    if (bottomBox)
-                      bottomPadding = parseInt(window.getComputedStyle(bottomBox).paddingBottom);
-                    window.innerHeight += bottomPadding + verticalPadding + aPaneElement.contentHeight - targetHeight;
-                  }
-
-                  // XXX rstrong - extend the contents of the prefpane to
-                  // prevent elements from being cutoff (see bug 349098).
-                  if (aPaneElement.contentHeight + verticalPadding < targetHeight)
-                    aPaneElement._content.style.height = targetHeight - verticalPadding + "px";
-                }
-              }
-              break;
-            }
-          }
-        ]]>
-        </body>
-      </method>
-
-      <property name="_shouldAnimate">
-        <getter>
-        <![CDATA[
-          var psvc = Components.classes["@mozilla.org/preferences-service;1"]
-                               .getService(Components.interfaces.nsIPrefBranch);
-          return psvc.getBoolPref("browser.preferences.animateFadeIn",
-                                  /Mac/.test(navigator.platform));
-        ]]>
-        </getter>
-      </property>
-
-      <method name="animate">
-        <parameter name="aOldPane"/>
-        <parameter name="aNewPane"/>
-        <body>
-        <![CDATA[
-          // if we are already resizing, use currentHeight
-          var oldHeight = this._currentHeight ? this._currentHeight : aOldPane.contentHeight;
-
-          this._multiplier = aNewPane.contentHeight > oldHeight ? 1 : -1;
-          var sizeDelta = Math.abs(oldHeight - aNewPane.contentHeight);
-          this._animateRemainder = sizeDelta % this._animateIncrement;
-
-          this._setUpAnimationTimer(oldHeight);
-        ]]>
-        </body>
-      </method>
-
-      <property name="_sizeIncrement">
-        <getter>
-        <![CDATA[
-          var lastSelectedPane = document.getElementById(this.lastSelected);
-          var increment = this._animateIncrement * this._multiplier;
-          var newHeight = this._currentHeight + increment;
-          if ((this._multiplier > 0 && this._currentHeight >= lastSelectedPane.contentHeight) ||
-              (this._multiplier < 0 && this._currentHeight <= lastSelectedPane.contentHeight))
-            return 0;
-
-          if ((this._multiplier > 0 && newHeight > lastSelectedPane.contentHeight) ||
-              (this._multiplier < 0 && newHeight < lastSelectedPane.contentHeight))
-            increment = this._animateRemainder * this._multiplier;
-          return increment;
-        ]]>
-        </getter>
-      </property>
-
-      <method name="notify">
-        <parameter name="aTimer"/>
-        <body>
-        <![CDATA[
-          if (!document)
-            aTimer.cancel();
-
-          if (aTimer == this._animateTimer) {
-            var increment = this._sizeIncrement;
-            if (increment != 0) {
-              window.innerHeight += increment;
-              this._currentHeight += increment;
-            } else {
-              aTimer.cancel();
-              this._setUpFadeTimer();
-            }
-          } else if (aTimer == this._fadeTimer) {
-            var elt = document.getElementById(this.lastSelected);
-            var newOpacity = parseFloat(window.getComputedStyle(elt).opacity) + this._fadeIncrement;
-            if (newOpacity < 1.0)
-              elt.style.opacity = newOpacity;
-            else {
-              aTimer.cancel();
-              elt.style.opacity = 1.0;
-            }
-          }
-        ]]>
-        </body>
-      </method>
-
-      <method name="_setUpAnimationTimer">
-        <parameter name="aStartHeight"/>
-        <body>
-        <![CDATA[
-          if (!this._animateTimer)
-            this._animateTimer = Components.classes["@mozilla.org/timer;1"]
-                                           .createInstance(Components.interfaces.nsITimer);
-          else
-            this._animateTimer.cancel();
-          this._currentHeight = aStartHeight;
-
-          this._animateTimer.initWithCallback(this, this._animateDelay,
-                                              Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
-        ]]>
-        </body>
-      </method>
-
-      <method name="_setUpFadeTimer">
-        <body>
-        <![CDATA[
-          if (!this._fadeTimer)
-            this._fadeTimer = Components.classes["@mozilla.org/timer;1"]
-                                        .createInstance(Components.interfaces.nsITimer);
-          else
-            this._fadeTimer.cancel();
-
-          this._fadeTimer.initWithCallback(this, this._fadeDelay,
-                                           Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
-        ]]>
-        </body>
-      </method>
-
-      <field name="_animateTimer">null</field>
-      <field name="_fadeTimer">null</field>
-      <field name="_animateDelay">15</field>
-      <field name="_animateIncrement">40</field>
-      <field name="_fadeDelay">5</field>
-      <field name="_fadeIncrement">0.40</field>
-      <field name="_animateRemainder">0</field>
-      <field name="_currentHeight">0</field>
-      <field name="_multiplier">0</field>
-
-      <method name="addPane">
-        <parameter name="aPaneElement"/>
-        <body>
-        <![CDATA[
-          this.appendChild(aPaneElement);
-
-          // Set up pane button
-          this._makePaneButton(aPaneElement);
-        ]]>
-        </body>
-      </method>
-
-      <method name="openSubDialog">
-        <parameter name="aURL"/>
-        <parameter name="aFeatures"/>
-        <parameter name="aParams"/>
-        <body>
-          return openDialog(aURL, "", "modal,centerscreen,resizable=no" + (aFeatures != "" ? ("," + aFeatures) : ""), aParams);
-        </body>
-      </method>
-
-      <method name="openWindow">
-        <parameter name="aWindowType"/>
-        <parameter name="aURL"/>
-        <parameter name="aFeatures"/>
-        <parameter name="aParams"/>
-        <body>
-        <![CDATA[
-          var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
-                             .getService(Components.interfaces.nsIWindowMediator);
-          var win = aWindowType ? wm.getMostRecentWindow(aWindowType) : null;
-          if (win) {
-            if ("initWithParams" in win)
-              win.initWithParams(aParams);
-            win.focus();
-          } else {
-            var features = "resizable,dialog=no,centerscreen" + (aFeatures != "" ? ("," + aFeatures) : "");
-            var parentWindow = (this.instantApply || !window.opener || window.opener.closed) ? window : window.opener;
-            win = parentWindow.openDialog(aURL, "_blank", features, aParams);
-          }
-          return win;
-        ]]>
-        </body>
-      </method>
-    </implementation>
-    <handlers>
-      <handler event="dialogaccept">
-      <![CDATA[
-        if (!this._fireEvent("beforeaccept", this)) {
-          return false;
-        }
-
-        var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
-                    .getService(Components.interfaces.nsIScriptSecurityManager);
-        if (this.type == "child" && window.opener &&
-            secMan.isSystemPrincipal(window.opener.document.nodePrincipal)) {
-          var pdocEl = window.opener.document.documentElement;
-          if (pdocEl.instantApply) {
-            let panes = this.preferencePanes;
-            for (let i = 0; i < panes.length; ++i)
-              panes[i].writePreferences(true);
-          } else {
-            // Clone all the preferences elements from the child document and
-            // insert them into the pane collection of the parent.
-            var pdoc = window.opener.document;
-            if (pdoc.documentElement.localName == "prefwindow") {
-              var currentPane = pdoc.documentElement.currentPane;
-              var id = window.location.href + "#childprefs";
-              var childPrefs = pdoc.getElementById(id);
-              if (!childPrefs) {
-                childPrefs = pdoc.createElement("preferences");
-                currentPane.appendChild(childPrefs);
-                childPrefs.id = id;
-              }
-              let panes = this.preferencePanes;
-              for (let i = 0; i < panes.length; ++i) {
-                var preferences = panes[i].preferences;
-                for (var j = 0; j < preferences.length; ++j) {
-                  // Try to find a preference element for the same preference.
-                  var preference = null;
-                  var parentPreferences = pdoc.getElementsByTagName("preferences");
-                  for (var k = 0; (k < parentPreferences.length && !preference); ++k) {
-                    var parentPrefs = parentPreferences[k]
-                                         .getElementsByAttribute("name", preferences[j].name);
-                    for (var l = 0; (l < parentPrefs.length && !preference); ++l) {
-                      if (parentPrefs[l].localName == "preference")
-                        preference = parentPrefs[l];
-                    }
-                  }
-                  if (!preference) {
-                    // No matching preference in the parent window.
-                    preference = pdoc.createElement("preference");
-                    childPrefs.appendChild(preference);
-                    preference.name     = preferences[j].name;
-                    preference.type     = preferences[j].type;
-                    preference.inverted = preferences[j].inverted;
-                    preference.readonly = preferences[j].readonly;
-                    preference.disabled = preferences[j].disabled;
-                  }
-                  preference.value = preferences[j].value;
-                }
-              }
-            }
-          }
-        } else {
-          let panes = this.preferencePanes;
-          for (var i = 0; i < panes.length; ++i)
-            panes[i].writePreferences(false);
-
-          let psvc = Components.classes["@mozilla.org/preferences-service;1"]
-                               .getService(Components.interfaces.nsIPrefService);
-          psvc.savePrefFile(null);
-        }
-
-        return true;
-      ]]>
-      </handler>
-      <handler event="command">
-        if (event.originalTarget.hasAttribute("pane")) {
-          var pane = document.getElementById(event.originalTarget.getAttribute("pane"));
-          this.showPane(pane);
-        }
-      </handler>
-
-      <handler event="keypress" key="&windowClose.key;" modifiers="accel" phase="capturing">
-      <![CDATA[
-        if (this.instantApply)
-          window.close();
-        event.stopPropagation();
-        event.preventDefault();
-      ]]>
-      </handler>
-
-      <handler event="keypress"
-#ifdef XP_MACOSX
-               key="&openHelpMac.commandkey;" modifiers="accel"
-#else
-               keycode="&openHelp.commandkey;"
-#endif
-               phase="capturing">
-      <![CDATA[
-        var helpButton = this.getButton("help");
-        if (helpButton.disabled || helpButton.hidden)
-          return;
-        this._fireEvent("dialoghelp", this);
-        event.stopPropagation();
-        event.preventDefault();
-      ]]>
-      </handler>
-    </handlers>
-  </binding>
-
-  <binding id="prefpane">
-    <resources>
-      <stylesheet src="chrome://global/skin/preferences.css"/>
-    </resources>
-    <content>
-      <xul:vbox class="content-box" xbl:inherits="flex">
-        <children/>
-      </xul:vbox>
-    </content>
-    <implementation>
-      <method name="writePreferences">
-        <parameter name="aFlushToDisk"/>
-        <body>
-        <![CDATA[
-          // Write all values to preferences.
-          if (this._deferredValueUpdateElements.size) {
-            this._finalizeDeferredElements();
-          }
-
-          var preferences = this.preferences;
-          for (var i = 0; i < preferences.length; ++i) {
-            var preference = preferences[i];
-            preference.batching = true;
-            preference.valueFromPreferences = preference.value;
-            preference.batching = false;
-          }
-          if (aFlushToDisk) {
-            var psvc = Components.classes["@mozilla.org/preferences-service;1"]
-                                 .getService(Components.interfaces.nsIPrefService);
-            psvc.savePrefFile(null);
-          }
-        ]]>
-        </body>
-      </method>
-
-      <property name="src"
-                onget="return this.getAttribute('src');"
-                onset="this.setAttribute('src', val); return val;"/>
-      <property name="selected"
-                onget="return this.getAttribute('selected') == 'true';"
-                onset="this.setAttribute('selected', val); return val;"/>
-      <property name="image"
-                onget="return this.getAttribute('image');"
-                onset="this.setAttribute('image', val); return val;"/>
-      <property name="label"
-                onget="return this.getAttribute('label');"
-                onset="this.setAttribute('label', val); return val;"/>
-
-      <property name="preferenceElements"
-                onget="return this.getElementsByAttribute('preference', '*');"/>
-      <property name="preferences"
-                onget="return this.getElementsByTagName('preference');"/>
-
-      <property name="helpTopic">
-        <getter>
-        <![CDATA[
-          // if there are tabs, and the selected tab provides a helpTopic, return that
-          var box = this.getElementsByTagName("tabbox");
-          if (box[0]) {
-            var tab = box[0].selectedTab;
-            if (tab && tab.hasAttribute("helpTopic"))
-              return tab.getAttribute("helpTopic");
-          }
-
-          // otherwise, return the helpTopic of the current panel
-          return this.getAttribute("helpTopic");
-        ]]>
-        </getter>
-      </property>
-
-      <field name="_loaded">false</field>
-      <property name="loaded"
-                onget="return !this.src ? true : this._loaded;"
-                onset="this._loaded = val; return val;"/>
-
-      <method name="preferenceForElement">
-        <parameter name="aElement"/>
-        <body>
-          return document.getElementById(aElement.getAttribute("preference"));
-        </body>
-      </method>
-
-      <method name="getPreferenceElement">
-        <parameter name="aStartElement"/>
-        <body>
-        <![CDATA[
-          var temp = aStartElement;
-          while (temp && temp.nodeType == Node.ELEMENT_NODE &&
-                 !temp.hasAttribute("preference"))
-            temp = temp.parentNode;
-          return temp && temp.nodeType == Node.ELEMENT_NODE ?
-                 temp : aStartElement;
-        ]]>
-        </body>
-      </method>
-
-      <property name="DeferredTask" readonly="true">
-        <getter><![CDATA[
-          let module = {};
-          Components.utils.import("resource://gre/modules/DeferredTask.jsm", module);
-          Object.defineProperty(this, "DeferredTask", {
-            configurable: true,
-            enumerable: true,
-            writable: true,
-            value: module.DeferredTask
-          });
-          return module.DeferredTask;
-        ]]></getter>
-      </property>
-      <method name="_deferredValueUpdate">
-        <parameter name="aElement"/>
-        <body>
-        <![CDATA[
-          delete aElement._deferredValueUpdateTask;
-          let preference = document.getElementById(aElement.getAttribute("preference"));
-          let prefVal = preference.getElementValue(aElement);
-          preference.value = prefVal;
-          this._deferredValueUpdateElements.delete(aElement);
-        ]]>
-        </body>
-      </method>
-      <field name="_deferredValueUpdateElements">
-        new Set();
-      </field>
-      <method name="_finalizeDeferredElements">
-        <body>
-        <![CDATA[
-          for (let el of this._deferredValueUpdateElements) {
-            if (el._deferredValueUpdateTask) {
-              el._deferredValueUpdateTask.finalize();
-            }
-          }
-        ]]>
-        </body>
-      </method>
-      <method name="userChangedValue">
-        <parameter name="aElement"/>
-        <body>
-        <![CDATA[
-          let element = this.getPreferenceElement(aElement);
-          if (element.hasAttribute("preference")) {
-            if (element.getAttribute("delayprefsave") != "true") {
-              var preference = document.getElementById(element.getAttribute("preference"));
-              var prefVal = preference.getElementValue(element);
-              preference.value = prefVal;
-            } else {
-              if (!element._deferredValueUpdateTask) {
-                element._deferredValueUpdateTask = new this.DeferredTask(this._deferredValueUpdate.bind(this, element), 1000);
-                this._deferredValueUpdateElements.add(element);
-              } else {
-                // Each time the preference is changed, restart the delay.
-                element._deferredValueUpdateTask.disarm();
-              }
-              element._deferredValueUpdateTask.arm();
-            }
-          }
-        ]]>
-        </body>
-      </method>
-
-      <property name="contentHeight">
-        <getter>
-          var targetHeight = parseInt(window.getComputedStyle(this._content).height);
-          targetHeight += parseInt(window.getComputedStyle(this._content).marginTop);
-          targetHeight += parseInt(window.getComputedStyle(this._content).marginBottom);
-          return targetHeight;
-        </getter>
-      </property>
-      <field name="_content">
-        document.getAnonymousElementByAttribute(this, "class", "content-box");
-      </field>
-    </implementation>
-    <handlers>
-      <handler event="command">
-        // This "command" event handler tracks changes made to preferences by
-        // the user in this window.
-        if (event.sourceEvent)
-          event = event.sourceEvent;
-        this.userChangedValue(event.target);
-      </handler>
-      <handler event="select">
-        // This "select" event handler tracks changes made to colorpicker
-        // preferences by the user in this window.
-        if (event.target.localName == "colorpicker")
-          this.userChangedValue(event.target);
-      </handler>
-      <handler event="change">
-        // This "change" event handler tracks changes made to preferences by
-        // the user in this window.
-        this.userChangedValue(event.target);
-      </handler>
-      <handler event="input">
-        // This "input" event handler tracks changes made to preferences by
-        // the user in this window.
-        this.userChangedValue(event.target);
-      </handler>
-      <handler event="paneload">
-      <![CDATA[
-        // Initialize all values from preferences.
-        var elements = this.preferenceElements;
-        for (var i = 0; i < elements.length; ++i) {
-          try {
-            var preference = this.preferenceForElement(elements[i]);
-            preference.setElementValue(elements[i]);
-          } catch (e) {
-            dump("*** No preference found for " + elements[i].getAttribute("preference") + "\n");
-          }
-        }
-      ]]>
-      </handler>
-    </handlers>
-  </binding>
-
-  <binding id="panebutton" role="xul:listitem"
-           extends="chrome://global/content/bindings/radio.xml#radio">
-    <resources>
-      <stylesheet src="chrome://global/skin/preferences.css"/>
-    </resources>
-    <content>
-      <xul:image class="paneButtonIcon" xbl:inherits="src"/>
-      <xul:label class="paneButtonLabel" xbl:inherits="value=label"/>
-    </content>
-  </binding>
-
-</bindings>
-
-# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
-# 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/.
-
-#
-# This is PrefWindow 6. The Code Could Well Be Ready, Are You?
-#
-#    Historical References:
-#    PrefWindow V   (February 1, 2003)
-#    PrefWindow IV  (April 24, 2000)
-#    PrefWindow III (January 6, 2000)
-#    PrefWindow II  (???)
-#    PrefWindow I   (June 4, 1999)
-#
--- a/toolkit/content/xul.css
+++ b/toolkit/content/xul.css
@@ -1015,66 +1015,16 @@ wizardpage {
 .wizard-header {
   -moz-binding: url("chrome://global/content/bindings/wizard.xml#wizard-header");
 }
 
 .wizard-buttons {
   -moz-binding: url("chrome://global/content/bindings/wizard.xml#wizard-buttons");
 }
 
-/********** preferences ********/
-
-prefwindow,
-prefwindow:root /* override :root from above */ {
-  -moz-binding: url("chrome://global/content/bindings/preferences.xml#prefwindow");
-  -moz-box-orient: vertical;
-}
-
-prefpane {
-  -moz-binding: url("chrome://global/content/bindings/preferences.xml#prefpane");
-  -moz-box-orient: vertical;
-}
-
-prefwindow > .paneDeckContainer {
-  overflow: hidden;
-}
-
-prefpane > .content-box {
-  overflow: hidden;
-}
-
-prefwindow[type="child"] > .paneDeckContainer {
-  overflow: -moz-hidden-unscrollable;
-}
-
-prefwindow[type="child"] > prefpane > .content-box {
-  -moz-box-flex: 1;
-  overflow: -moz-hidden-unscrollable;
-}
-
-preferences {
-  -moz-binding: url("chrome://global/content/bindings/preferences.xml#preferences");
-  visibility: collapse;
-}
-
-preference {
-  -moz-binding: url("chrome://global/content/bindings/preferences.xml#preference");
-  visibility: collapse;
-}
-
-radio[pane] {
-  -moz-binding: url("chrome://global/content/bindings/preferences.xml#panebutton") !important;
-  -moz-box-orient: vertical;
-  -moz-box-align: center;
-}
-
-prefwindow[chromehidden~="toolbar"] .chromeclass-toolbar {
-  display: none;
-}
-
 /********** expander ********/
 
 expander {
   -moz-binding: url("chrome://global/content/bindings/expander.xml#expander");
   -moz-box-orient: vertical;
 }
 
 
--- a/toolkit/mozapps/preferences/fontbuilder.js
+++ b/toolkit/mozapps/preferences/fontbuilder.js
@@ -1,14 +1,16 @@
 // -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
 
 /* 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/. */
 
+/* import-globals-from ../../content/preferencesBindings.js */
+
 var FontBuilder = {
   _enumerator: null,
   get enumerator() {
     if (!this._enumerator) {
       this._enumerator = Components.classes["@mozilla.org/gfx/fontenumerator;1"]
                                    .createInstance(Components.interfaces.nsIFontEnumerator);
     }
     return this._enumerator;
@@ -86,17 +88,17 @@ var FontBuilder = {
     aMenuList.appendChild(popup);
   },
 
   readFontSelection(aElement) {
     // Determine the appropriate value to select, for the following cases:
     // - there is no setting
     // - the font selected by the user is no longer present (e.g. deleted from
     //   fonts folder)
-    const preference = document.getElementById(aElement.getAttribute("preference"));
+    const preference = Preferences.get(aElement.getAttribute("preference"));
     if (preference.value) {
       const fontItems = aElement.getElementsByAttribute("value", preference.value);
 
       // There is a setting that actually is in the list. Respect it.
       if (fontItems.length)
         return undefined;
     }
 
--- a/toolkit/themes/linux/global/global.css
+++ b/toolkit/themes/linux/global/global.css
@@ -36,18 +36,17 @@ progressmeter[mode="undetermined"] {
   --arrowpanel-border-color: ThreeDShadow;
 }
 
 /* ::::: root elements ::::: */
 
 window,
 page,
 dialog,
-wizard,
-prefwindow {
+wizard {
   -moz-appearance: window;
   background-color: -moz-Dialog;
   color: -moz-DialogText;
   font: message-box;
 }
 
 /* deprecated */
 window.dialog {
--- a/toolkit/themes/linux/global/jar.mn
+++ b/toolkit/themes/linux/global/jar.mn
@@ -18,17 +18,16 @@ toolkit.jar:
    skin/classic/global/groupbox.css
    skin/classic/global/listbox.css
    skin/classic/global/menu.css
    skin/classic/global/menulist.css
    skin/classic/global/netError.css
 *  skin/classic/global/notification.css
    skin/classic/global/numberbox.css
    skin/classic/global/popup.css
-   skin/classic/global/preferences.css
    skin/classic/global/printPreview.css
    skin/classic/global/radio.css
    skin/classic/global/scrollbox.css
    skin/classic/global/splitter.css
    skin/classic/global/tabbox.css
    skin/classic/global/textbox.css
    skin/classic/global/toolbar.css
    skin/classic/global/toolbarbutton.css
deleted file mode 100644
--- a/toolkit/themes/linux/global/preferences.css
+++ /dev/null
@@ -1,62 +0,0 @@
-/* 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/. */
-
-/* ===== preferences.css =====================================================
-  == Styles used by the XUL prefwindow element.
-  ======================================================================= */
-
-@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
-
-/* ::::: dialog ::::: */
-
-prefwindow {
-  padding: 0px;
-}
-
-prefpane {
-  padding: 8px;
-}
-
-prefwindow[type="child"] {
-  padding: 8px;
-}
-
-prefwindow[type="child"] > prefpane {
-  padding: 0px;
-}
-
-.prefWindow-dlgbuttons {
-  padding-bottom: 8px;
-  padding-inline-start: 8px;
-  padding-inline-end: 8px;
-}
-
-prefwindow[type="child"] .prefWindow-dlgbuttons {
-  padding: 0px;
-}
-
-radio[pane] {
-  -moz-appearance: none;
-  min-width: 4.5em;
-  margin: 0;
-  padding: 3px;
-  color: -moz-FieldText;
-}
-
-.paneSelector {
-  -moz-appearance: listbox;
-  margin: 8px 8px 0 8px;
-  padding: 0;
-}
-
-.paneButtonIcon {
-  width: 32px;
-  height: 32px;
-}
-
-radio[pane][selected="true"] {
-  background-color: Highlight;
-  color: HighlightText;
-}
-
--- a/toolkit/themes/mobile/jar.mn
+++ b/toolkit/themes/mobile/jar.mn
@@ -12,17 +12,16 @@ toolkit.jar:
    skin/classic/global/dropmarker.css                      (global/empty.css)
    skin/classic/global/global.css                          (global/empty.css)
    skin/classic/global/groupbox.css                        (global/empty.css)
    skin/classic/global/listbox.css                         (global/empty.css)
    skin/classic/global/menu.css                            (global/empty.css)
    skin/classic/global/menulist.css                        (global/empty.css)
    skin/classic/global/numberbox.css                       (global/empty.css)
    skin/classic/global/popup.css                           (global/empty.css)
-   skin/classic/global/preferences.css                     (global/empty.css)
    skin/classic/global/progressmeter.css                   (global/empty.css)
    skin/classic/global/radio.css                           (global/empty.css)
    skin/classic/global/resizer.css                         (global/empty.css)
    skin/classic/global/richlistbox.css                     (global/empty.css)
    skin/classic/global/scale.css                           (global/empty.css)
    skin/classic/global/scrollbox.css                       (global/empty.css)
    skin/classic/global/spinbuttons.css                     (global/empty.css)
    skin/classic/global/splitter.css                        (global/empty.css)
--- a/toolkit/themes/osx/global/global.css
+++ b/toolkit/themes/osx/global/global.css
@@ -25,31 +25,23 @@ menulist > menupopup {
   --focus-ring-box-shadow: @focusRingShadow@;
 }
 
 /* ::::: root elements ::::: */
 
 window,
 page,
 dialog,
-wizard,
-prefwindow {
+wizard {
   -moz-appearance: dialog;
   background-color: #FFFFFF;
   color: -moz-DialogText;
   font: message-box;
 }
 
-prefwindow[type="child"] {
-  padding-top: 18px;
-  padding-bottom: 15px;
-  padding-inline-start: 18px;
-  padding-inline-end: 20px;
-}
-
 /* deprecated */
 window.dialog {
   padding-top: 8px;
   padding-bottom: 10px;
   padding-inline-start: 8px;
   padding-inline-end: 10px;
 }
 
--- a/toolkit/themes/osx/global/jar.mn
+++ b/toolkit/themes/osx/global/jar.mn
@@ -20,17 +20,16 @@ toolkit.jar:
   skin/classic/global/groupbox.css
   skin/classic/global/listbox.css
   skin/classic/global/menu.css
   skin/classic/global/menulist.css
 * skin/classic/global/notification.css
   skin/classic/global/netError.css
   skin/classic/global/numberbox.css
   skin/classic/global/popup.css
-  skin/classic/global/preferences.css
   skin/classic/global/progressmeter.css
   skin/classic/global/radio.css
   skin/classic/global/resizer.css
   skin/classic/global/richlistbox.css
   skin/classic/global/scrollbars.css                                 (nativescrollbars.css)
   skin/classic/global/scrollbox.css
   skin/classic/global/spinbuttons.css
   skin/classic/global/splitter.css
deleted file mode 100644
--- a/toolkit/themes/osx/global/preferences.css
+++ /dev/null
@@ -1,59 +0,0 @@
-/* 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/. */
-
-@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
-
-prefwindow {
-  padding: 0;
-  font: -moz-dialog !important;
-}
-
-prefpane {
-  padding: 12px 12px 0 12px;
-}
-
-prefwindow[type="child"] > prefpane {
-  padding: 0;
-}
-
-.prefWindow-dlgbuttons {
-  margin: 0 12px 12px;
-  padding-top: 0 !important;
-}
-
-.paneSelector {
-  font: message-box;
-  padding: 1px 4px;
-  -moz-appearance: toolbar;
-  margin: 0;
-}
-
-radio[pane] {
-  border: solid transparent;
-  border-width: 0 2px;
-  padding: 5px 4px 3px;
-  margin: 0;
-  -moz-appearance: none;
-  text-shadow: rgba(255, 255, 255, 0.4) 0 1px;
-}
-
-radio[pane]:active:hover {
-  text-shadow: none;
-}
-
-radio[pane]:active:hover > .paneButtonIcon {
-  filter: brightness(0.55);
-}
-
-radio[pane][selected="true"] {
-  -moz-border-image: url("chrome://global/skin/icons/panebutton-active.png") 0 2 fill repeat stretch;
-}
-
-radio[pane][selected="true"]:-moz-window-inactive {
-  -moz-border-image: url("chrome://global/skin/icons/panebutton-inactive.png") 0 2 fill repeat stretch;
-}
-
-.paneButtonLabel {
-  margin: 0 !important;
-}
--- a/toolkit/themes/shared/in-content/common.inc.css
+++ b/toolkit/themes/shared/in-content/common.inc.css
@@ -89,20 +89,16 @@ xul|caption xul|label {
   margin: 0 !important;
 }
 
 *|*.main-content {
   padding: 40px 28px;
   overflow: auto;
 }
 
-xul|prefpane > xul|*.content-box {
-  overflow: visible;
-}
-
 /* groupboxes */
 
 xul|groupbox {
   -moz-appearance: none;
   border: none;
   margin: 0;
   padding: 0;
 }
--- a/toolkit/themes/windows/global/global.css
+++ b/toolkit/themes/windows/global/global.css
@@ -32,18 +32,17 @@ menulist > menupopup {
   }
 }
 
 /* ::::: root elements ::::: */
 
 window,
 page,
 dialog,
-wizard,
-prefwindow {
+wizard {
   -moz-appearance: window;
   background-color: -moz-Dialog;
   color: -moz-DialogText;
   font: message-box;
 }
 
 /* deprecated */
 window.dialog {
--- a/toolkit/themes/windows/global/jar.mn
+++ b/toolkit/themes/windows/global/jar.mn
@@ -19,17 +19,16 @@ toolkit.jar:
   skin/classic/global/colorpicker.css
   skin/classic/global/commonDialog.css
   skin/classic/global/findBar.css
 * skin/classic/global/global.css
   skin/classic/global/listbox.css
   skin/classic/global/netError.css
   skin/classic/global/numberbox.css
 * skin/classic/global/notification.css
-  skin/classic/global/preferences.css
   skin/classic/global/printPageSetup.css
   skin/classic/global/printPreview.css
   skin/classic/global/scrollbox.css
   skin/classic/global/splitter.css
   skin/classic/global/toolbar.css
   skin/classic/global/toolbarbutton.css
 * skin/classic/global/tree.css
 * skin/classic/global/alerts/alert.css                     (alerts/alert.css)
deleted file mode 100644
--- a/toolkit/themes/windows/global/preferences.css
+++ /dev/null
@@ -1,76 +0,0 @@
-/* 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/. */
-
-/* ===== preferences.css =====================================================
-  == Styles used by the XUL prefwindow element.
-  ======================================================================= */
-
-@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
-
-/* ::::: dialog ::::: */
-
-prefwindow {
-  padding: 0px;
-}
-
-prefpane {
-  padding-top: 8px;
-  padding-bottom: 10px;
-  padding-inline-start: 8px;
-  padding-inline-end: 10px;
-}
-
-prefwindow[type="child"] {
-  padding-top: 8px;
-  padding-bottom: 10px;
-  padding-inline-start: 8px;
-  padding-inline-end: 10px;
-}
-
-prefwindow[type="child"] > prefpane {
-  padding: 0px;
-}
-
-.prefWindow-dlgbuttons {
-  padding-bottom: 10px;
-  padding-inline-start: 8px;
-  padding-inline-end: 10px;
-}
-
-prefwindow[type="child"] .prefWindow-dlgbuttons {
-  padding: 0px;
-}
-
-radio[pane] {
-  -moz-appearance: none;
-  margin: 0px 1px 0px 1px;
-  padding: 1px 3px 1px 3px;
-  min-width: 4.5em;
-}
-
-.paneSelector {
-  border-bottom: 2px groove ThreeDFace;
-  margin: 0px;
-  padding-inline-start: 10px;
-  background-color: -moz-Field;
-  color: -moz-FieldText;
-}
-
-.paneButtonIcon {
-  width: 32px;
-  height: 32px;
-}
-
-radio[pane]:hover {
-  background-color: #E0E8F6;
-  color: black;
-  -moz-appearance: none;
-}
-
-radio[pane][selected="true"] {
-  background-color: #C1D2EE;
-  color: black; 
-  -moz-appearance: none;
-}
-