Bug 1411707 - Switch XUL findbar from a XBL binding to a Custom Element; draft
authorBrian Grinstead <bgrinstead@mozilla.com>
Wed, 04 Apr 2018 21:29:06 -0700
changeset 798406 c616c6020a2cfaff27764430c1af9c6e5352ada2
parent 798405 cfe5064256c83ffd0b4aadb0b70b94defd685b8a
child 798407 7cd5ef3f61e63587df2c27180a627943843bdd49
push id110748
push userbgrinstead@mozilla.com
push dateTue, 22 May 2018 19:46:02 +0000
bugs1411707
milestone62.0a1
Bug 1411707 - Switch XUL findbar from a XBL binding to a Custom Element; MozReview-Commit-ID: F95i9H9FvYv
browser/base/content/browser.xul
browser/themes/osx/browser.css
toolkit/components/extensions/test/browser/browser_ext_themes_findbar.js
toolkit/content/customElements.js
toolkit/content/jar.mn
toolkit/content/widgets/findbar.js
toolkit/content/widgets/findbar.xml
toolkit/content/xul.css
toolkit/locales/en-US/chrome/global/findbar.dtd
toolkit/locales/jar.mn
toolkit/themes/linux/global/global.css
toolkit/themes/osx/global/global.css
toolkit/themes/windows/global/global.css
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -57,16 +57,19 @@
         windowtype="navigator:browser"
         macanimationtype="document"
         screenX="4" screenY="4"
         fullscreenbutton="true"
         sizemode="normal"
         retargetdocumentfocus="urlbar"
         persist="screenX screenY width height sizemode">
 
+<link rel="localization" href="toolkit/main-window/findbar.ftl"/>
+<script type="application/javascript" src="chrome://global/content/l10n.js"></script>
+
 # All JS files which are needed by browser.xul and other top level windows to
 # support MacOS specific features *must* go into the global-scripts.inc file so
 # that they can be shared with macWindow.inc.xul.
 #include global-scripts.inc
 
 <script type="application/javascript">
   Services.scriptloader.loadSubScript("chrome://global/content/contentAreaUtils.js", this);
   Services.scriptloader.loadSubScript("chrome://browser/content/tabbrowser.js", this);
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -219,20 +219,20 @@
 }
 
 %include ../shared/toolbarbuttons.inc.css
 %include ../shared/toolbarbutton-icons.inc.css
 %include ../shared/menupanel.inc.css
 
 /* Override OSX-specific toolkit findbar button styles */
 .findbar-button {
-  background: none;
-  box-shadow: none;
-  border: none;
-  color: inherit;
+  background: none !important;;
+  box-shadow: none !important;
+  border: none !important;;
+  color: inherit !important;;
 }
 
 /* On Mac, native buttons keep their full opacity when they become disabled
  * and only the glyph or text on top of them becomes less opaque. */
 :root:not([customizing]) #back-button[disabled="true"] {
   opacity: 1 !important;
   /* Disabled toolbar buttons get an opacity of 0.4 which multiplies
    * their fill-opacity of 0.7. calc() doesn't work here - we'd need
--- a/toolkit/components/extensions/test/browser/browser_ext_themes_findbar.js
+++ b/toolkit/components/extensions/test/browser/browser_ext_themes_findbar.js
@@ -29,17 +29,17 @@ add_task(async function test_support_too
     files: {
       "image1.png": BACKGROUND,
     },
   });
 
   await extension.startup();
   await gBrowser.getFindBar();
 
-  let findbar_button = document.getAnonymousElementByAttribute(gFindBar, "anonid", "highlight");
+  let findbar_button = gFindBar.getElement("highlight");
 
   info("Checking findbar background is set as toolbar color");
   Assert.equal(window.getComputedStyle(gFindBar).backgroundColor,
                hexToCSS(TOOLBAR_COLOR),
                "Findbar background color should be the same as toolbar background color.");
 
   info("Checking findbar and button text color is set as toolbar text color");
   Assert.equal(window.getComputedStyle(gFindBar).color,
@@ -74,24 +74,21 @@ add_task(async function test_support_too
     files: {
       "image1.png": BACKGROUND,
     },
   });
 
   await extension.startup();
   await gBrowser.getFindBar();
 
-  let findbar_textbox =
-    document.getAnonymousElementByAttribute(gFindBar, "anonid", "findbar-textbox");
+  let findbar_textbox = gFindBar.getElement("findbar-textbox");
 
-  let findbar_prev_button =
-    document.getAnonymousElementByAttribute(gFindBar, "anonid", "find-previous");
+  let findbar_prev_button = gFindBar.getElement("find-previous");
 
-  let findbar_next_button =
-    document.getAnonymousElementByAttribute(gFindBar, "anonid", "find-next");
+  let findbar_next_button = gFindBar.getElement("find-next");
 
   info("Checking findbar textbox background is set as toolbar field background color");
   Assert.equal(window.getComputedStyle(findbar_textbox).backgroundColor,
                hexToCSS(TOOLBAR_FIELD_COLOR),
                "Findbar textbox background color should be the same as toolbar field color.");
 
   info("Checking findbar textbox color is set as toolbar field text color");
   Assert.equal(window.getComputedStyle(findbar_textbox).color,
--- a/toolkit/content/customElements.js
+++ b/toolkit/content/customElements.js
@@ -59,15 +59,23 @@ class MozXULElement extends XULElement {
     return range.extractContents();
   }
 }
 
 // Attach the base class to the window so other scripts can use it:
 window.MozXULElement = MozXULElement;
 
 for (let script of [
-  "chrome://global/content/elements/stringbundle.js",
   "chrome://global/content/elements/general.js",
 ]) {
   Services.scriptloader.loadSubScript(script, window);
 }
 
+for (let [tag, script] of [
+  ["findbar", "chrome://global/content/elements/findbar.js"],
+  ["stringbundle", "chrome://global/content/elements/stringbundle.js"],
+]) {
+  customElements.setElementCreationCallback(tag, () => {
+    Services.scriptloader.loadSubScript(script, window);
+  });
 }
+
+}
--- a/toolkit/content/jar.mn
+++ b/toolkit/content/jar.mn
@@ -70,17 +70,17 @@ toolkit.jar:
    content/global/bindings/colorpicker.xml     (widgets/colorpicker.xml)
    content/global/bindings/datekeeper.js       (widgets/datekeeper.js)
    content/global/bindings/datepicker.js       (widgets/datepicker.js)
    content/global/bindings/datetimepopup.xml   (widgets/datetimepopup.xml)
    content/global/bindings/datetimebox.xml     (widgets/datetimebox.xml)
    content/global/bindings/datetimebox.css     (widgets/datetimebox.css)
 *  content/global/bindings/dialog.xml          (widgets/dialog.xml)
    content/global/bindings/editor.xml          (widgets/editor.xml)
-*  content/global/bindings/findbar.xml         (widgets/findbar.xml)
+   content/global/bindings/findbar.xml         (widgets/findbar.xml)
    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)
@@ -96,15 +96,16 @@ toolkit.jar:
 *  content/global/bindings/textbox.xml         (widgets/textbox.xml)
    content/global/bindings/timekeeper.js       (widgets/timekeeper.js)
    content/global/bindings/timepicker.js       (widgets/timepicker.js)
    content/global/bindings/toolbar.xml         (widgets/toolbar.xml)
    content/global/bindings/toolbarbutton.xml   (widgets/toolbarbutton.xml)
 *  content/global/bindings/tree.xml            (widgets/tree.xml)
    content/global/bindings/videocontrols.xml   (widgets/videocontrols.xml)
 *  content/global/bindings/wizard.xml          (widgets/wizard.xml)
-   content/global/elements/general.js           (widgets/general.js)
+   content/global/elements/findbar.js          (widgets/findbar.js)
+   content/global/elements/general.js          (widgets/general.js)
    content/global/elements/stringbundle.js     (widgets/stringbundle.js)
 #ifdef XP_MACOSX
    content/global/macWindowMenu.js
 #endif
    content/global/gmp-sources/openh264.json    (gmp-sources/openh264.json)
    content/global/gmp-sources/widevinecdm.json (gmp-sources/widevinecdm.json)
--- a/toolkit/content/widgets/findbar.js
+++ b/toolkit/content/widgets/findbar.js
@@ -1,1208 +1,1085 @@
+/* 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/. */
 
-  <binding id="findbar">
-    <resources>
-      <stylesheet src="chrome://global/skin/findBar.css"/>
-    </resources>
+"use strict";
+
+// Wrap to prevent accidentally leaking to window scope:
+{
+
+ChromeUtils.import("resource://gre/modules/Services.jsm");
 
-    <content hidden="true">
-    <xul:hbox anonid="findbar-container" class="findbar-container" flex="1" align="center">
-      <xul:hbox anonid="findbar-textbox-wrapper" align="stretch">
-        <xul:textbox anonid="findbar-textbox"
-                     class="findbar-textbox findbar-find-fast"
-                     xbl:inherits="flash"/>
-        <xul:toolbarbutton anonid="find-previous"
-                           class="findbar-find-previous tabbable"
-                           tooltiptext="&previous.tooltip;"
-                           oncommand="onFindAgainCommand(true);"
-                           disabled="true"
-                           xbl:inherits="accesskey=findpreviousaccesskey"/>
-        <xul:toolbarbutton anonid="find-next"
-                           class="findbar-find-next tabbable"
-                           tooltiptext="&next.tooltip;"
-                           oncommand="onFindAgainCommand(false);"
-                           disabled="true"
-                           xbl:inherits="accesskey=findnextaccesskey"/>
-      </xul:hbox>
-      <xul:toolbarbutton anonid="highlight"
-                         class="findbar-highlight findbar-button tabbable"
-                         label="&highlightAll.label;"
-                         accesskey="&highlightAll.accesskey;"
-                         tooltiptext="&highlightAll.tooltiptext;"
-                         oncommand="toggleHighlight(this.checked);"
-                         type="checkbox"
-                         xbl:inherits="accesskey=highlightaccesskey"/>
-      <xul:toolbarbutton anonid="find-case-sensitive"
-                         class="findbar-case-sensitive findbar-button tabbable"
-                         label="&caseSensitive.label;"
-                         accesskey="&caseSensitive.accesskey;"
-                         tooltiptext="&caseSensitive.tooltiptext;"
-                         oncommand="_setCaseSensitivity(this.checked ? 1 : 0);"
-                         type="checkbox"
-                         xbl:inherits="accesskey=matchcaseaccesskey"/>
-      <xul:toolbarbutton anonid="find-entire-word"
-                         class="findbar-entire-word findbar-button tabbable"
-                         label="&entireWord.label;"
-                         accesskey="&entireWord.accesskey;"
-                         tooltiptext="&entireWord.tooltiptext;"
-                         oncommand="toggleEntireWord(this.checked);"
-                         type="checkbox"
-                         xbl:inherits="accesskey=entirewordaccesskey"/>
-      <xul:label anonid="match-case-status" class="findbar-find-fast"/>
-      <xul:label anonid="entire-word-status" class="findbar-find-fast"/>
-      <xul:label anonid="found-matches" class="findbar-find-fast found-matches" hidden="true"/>
-      <xul:image anonid="find-status-icon" class="findbar-find-fast find-status-icon"/>
-      <xul:description anonid="find-status"
-                       control="findbar-textbox"
-                       class="findbar-find-fast findbar-find-status">
-      <!-- Do not use value, first child is used because it provides a11y with text change events -->
-      </xul:description>
-    </xul:hbox>
-    <xul:toolbarbutton anonid="find-closebutton"
-                       class="findbar-closebutton close-icon"
-                       tooltiptext="&findCloseButton.tooltip;"
-                       oncommand="close();"/>
-    </content>
+class MozFindbar extends XULElement {
+  constructor() {
+    super();
+    this.content = MozXULElement.parseXULToFragment(`
+      <hbox anonid="findbar-container" class="findbar-container" flex="1" align="center">
+        <hbox anonid="findbar-textbox-wrapper" align="stretch">
+          <textbox anonid="findbar-textbox" class="findbar-textbox findbar-find-fast" />
+          <toolbarbutton anonid="find-previous" class="findbar-find-previous tabbable" data-l10n-attrs="tooltiptext" data-l10n-id="findbar-previous" oncommand="onFindAgainCommand(true);" disabled="true" />
+          <toolbarbutton anonid="find-next" class="findbar-find-next tabbable" data-l10n-id="findbar-next" oncommand="onFindAgainCommand(false);" disabled="true" />
+        </hbox>
+        <toolbarbutton anonid="highlight" class="findbar-highlight findbar-button tabbable" data-l10n-id="findbar-highlight-all" oncommand="toggleHighlight(this.checked);" type="checkbox" />
+        <toolbarbutton anonid="find-case-sensitive" class="findbar-case-sensitive findbar-button tabbable" data-l10n-id="findbar-case-sensitive" oncommand="_setCaseSensitivity(this.checked ? 1 : 0);" type="checkbox" />
+        <toolbarbutton anonid="find-entire-word" class="findbar-entire-word findbar-button tabbable" data-l10n-id="findbar-entire-word" oncommand="toggleEntireWord(this.checked);" type="checkbox" />
+        <label anonid="match-case-status" class="findbar-find-fast" />
+        <label anonid="entire-word-status" class="findbar-find-fast" />
+        <label anonid="found-matches" class="findbar-find-fast found-matches" hidden="true" />
+        <image anonid="find-status-icon" class="findbar-find-fast find-status-icon" />
+        <description anonid="find-status" control="findbar-textbox" class="findbar-find-fast findbar-find-status" />
+      </hbox>
+      <toolbarbutton anonid="find-closebutton" class="findbar-closebutton close-icon" data-l10n-id="findbar-find-button-close" oncommand="close();" />
+    `);
+  }
+
+  connectedCallback() {
+    this.appendChild(document.importNode(this.content, true));
+
+    this.hidden = true;
+
+    /**
+     * Please keep in sync with toolkit/content/browser-content.js
+     */
+    this.FIND_NORMAL = 0;
+
+    this.FIND_TYPEAHEAD = 1;
+
+    this.FIND_LINKS = 2;
+
+    this.__findMode = 0;
+
+    this._flashFindBar = 0;
+
+    this._initialFlashFindBarCount = 6;
+
+    /**
+     * - For tests that need to know when the find bar is finished
+     * - initializing, we store a promise to notify on.
+     */
+    this._startFindDeferred = null;
+
+    this._browser = null;
 
-    <implementation>
-      <!-- Please keep in sync with toolkit/content/browser-content.js -->
-      <field name="FIND_NORMAL">0</field>
-      <field name="FIND_TYPEAHEAD">1</field>
-      <field name="FIND_LINKS">2</field>
+    this.__prefsvc = null;
 
-      <field name="__findMode">0</field>
-      <property name="_findMode" onget="return this.__findMode;"
-                onset="this.__findMode = val; this._updateBrowserWithState(); return val;"/>
-
-      <field name="_flashFindBar">0</field>
-      <field name="_initialFlashFindBarCount">6</field>
+    this._observer = {
+      _self: this,
 
-      <!--
-        - For tests that need to know when the find bar is finished
-        - initializing, we store a promise to notify on.
-        -->
-      <field name="_startFindDeferred">null</field>
+      QueryInterface: ChromeUtils.generateQI(["nsIObserver",
+                                              "nsISupportsWeakReference"]),
 
-      <property name="prefillWithSelection"
-                onget="return this.getAttribute('prefillwithselection') != 'false'"
-                onset="this.setAttribute('prefillwithselection', val); return val;"/>
+      observe(aSubject, aTopic, aPrefName) {
+        if (aTopic != "nsPref:changed")
+          return;
 
-      <method name="getElement">
-        <parameter name="aAnonymousID"/>
-        <body><![CDATA[
-          return document.getAnonymousElementByAttribute(this,
-                                                         "anonid",
-                                                         aAnonymousID);
-        ]]></body>
-      </method>
+        let prefsvc = this._self._prefsvc;
 
-      <property name="findMode"
-                readonly="true"
-                onget="return this._findMode;"/>
-
-      <property name="hasTransactions" readonly="true">
-        <getter><![CDATA[
-          if (this._findField.value)
-            return true;
-
-          // Watch out for lazy editor init
-          if (this._findField.editor) {
-            let tm = this._findField.editor.transactionManager;
-            return !!(tm.numberOfUndoItems || tm.numberOfRedoItems);
-          }
-          return false;
-        ]]></getter>
-      </property>
+        switch (aPrefName) {
+          case "accessibility.typeaheadfind":
+            this._self._findAsYouType = prefsvc.getBoolPref(aPrefName);
+            break;
+          case "accessibility.typeaheadfind.linksonly":
+            this._self._typeAheadLinksOnly = prefsvc.getBoolPref(aPrefName);
+            break;
+          case "accessibility.typeaheadfind.casesensitive":
+            this._self._setCaseSensitivity(prefsvc.getIntPref(aPrefName));
+            break;
+          case "findbar.entireword":
+            this._self._entireWord = prefsvc.getBoolPref(aPrefName);
+            this._self.toggleEntireWord(this._self._entireWord, true);
+            break;
+          case "findbar.highlightAll":
+            this._self.toggleHighlight(prefsvc.getBoolPref(aPrefName), true);
+            break;
+          case "findbar.modalHighlight":
+            this._self._useModalHighlight = prefsvc.getBoolPref(aPrefName);
+            if (this._self.browser.finder)
+              this._self.browser.finder.onModalHighlightChange(this._self._useModalHighlight);
+            break;
+        }
+      }
+    };
 
-      <field name="_browser">null</field>
-      <property name="browser">
-        <getter><![CDATA[
-          if (!this._browser) {
-            this._browser =
-              document.getElementById(this.getAttribute("browserid"));
-          }
-          return this._browser;
-        ]]></getter>
-        <setter><![CDATA[
-          if (this._browser) {
-            if (this._browser.messageManager) {
-              this._browser.messageManager.removeMessageListener("Findbar:Keypress", this);
-              this._browser.messageManager.removeMessageListener("Findbar:Mouseup", this);
-            }
-            let finder = this._browser.finder;
-            if (finder)
-              finder.removeResultListener(this);
-          }
+    this._destroyed = false;
+
+    this._pluralForm = null;
+
+    this._strBundle = null;
+
+    this._xulBrowserWindow = null;
+
+    // These elements are accessed frequently and are therefore cached
+    this._findField = this.getElement("findbar-textbox");
+    this._foundMatches = this.getElement("found-matches");
+    this._findStatusIcon = this.getElement("find-status-icon");
+    this._findStatusDesc = this.getElement("find-status");
+
+    this._foundURL = null;
+
+    let prefsvc = this._prefsvc;
+
+    this._quickFindTimeoutLength =
+      prefsvc.getIntPref("accessibility.typeaheadfind.timeout");
+    this._flashFindBar =
+      prefsvc.getIntPref("accessibility.typeaheadfind.flashBar");
+    this._useModalHighlight = prefsvc.getBoolPref("findbar.modalHighlight");
 
-          this._browser = val;
-          if (this._browser) {
-            // Need to do this to ensure the correct initial state.
-            this._updateBrowserWithState();
-            this._browser.messageManager.addMessageListener("Findbar:Keypress", this);
-            this._browser.messageManager.addMessageListener("Findbar:Mouseup", this);
-            this._browser.finder.addResultListener(this);
-
-            this._findField.value = this._browser._lastSearchString;
-          }
-          return val;
-        ]]></setter>
-      </property>
+    prefsvc.addObserver("accessibility.typeaheadfind",
+      this._observer);
+    prefsvc.addObserver("accessibility.typeaheadfind.linksonly",
+      this._observer);
+    prefsvc.addObserver("accessibility.typeaheadfind.casesensitive",
+      this._observer);
+    prefsvc.addObserver("findbar.entireword", this._observer);
+    prefsvc.addObserver("findbar.highlightAll", this._observer);
+    prefsvc.addObserver("findbar.modalHighlight", this._observer);
 
-      <field name="__prefsvc">null</field>
-      <property name="_prefsvc">
-        <getter><![CDATA[
-          if (!this.__prefsvc) {
-            this.__prefsvc = Cc["@mozilla.org/preferences-service;1"]
-              .getService(Ci.nsIPrefBranch);
-          }
-          return this.__prefsvc;
-        ]]></getter>
-      </property>
+    this._findAsYouType =
+      prefsvc.getBoolPref("accessibility.typeaheadfind");
+    this._typeAheadLinksOnly =
+      prefsvc.getBoolPref("accessibility.typeaheadfind.linksonly");
+    this._typeAheadCaseSensitive =
+      prefsvc.getIntPref("accessibility.typeaheadfind.casesensitive");
+    this._entireWord = prefsvc.getBoolPref("findbar.entireword");
+    this._highlightAll = prefsvc.getBoolPref("findbar.highlightAll");
 
-      <field name="_observer"><![CDATA[({
-        _self: this,
-
-        QueryInterface: ChromeUtils.generateQI(["nsIObserver",
-                                                "nsISupportsWeakReference"]),
+    // Convenience
+    this.nsITypeAheadFind = Ci.nsITypeAheadFind;
+    this.nsISelectionController = Ci.nsISelectionController;
+    this._findSelection = this.nsISelectionController.SELECTION_FIND;
 
-        observe(aSubject, aTopic, aPrefName) {
-          if (aTopic != "nsPref:changed")
-            return;
+    this._findResetTimeout = -1;
 
-          let prefsvc = this._self._prefsvc;
+    // Make sure the FAYT keypress listener is attached by initializing the
+    // browser property
+    if (this.getAttribute("browserid"))
+      setTimeout(function(aSelf) { aSelf.browser = aSelf.browser; }, 0, this);
 
-          switch (aPrefName) {
-            case "accessibility.typeaheadfind":
-              this._self._findAsYouType = prefsvc.getBoolPref(aPrefName);
-              break;
-            case "accessibility.typeaheadfind.linksonly":
-              this._self._typeAheadLinksOnly = prefsvc.getBoolPref(aPrefName);
-              break;
-            case "accessibility.typeaheadfind.casesensitive":
-              this._self._setCaseSensitivity(prefsvc.getIntPref(aPrefName));
-              break;
-            case "findbar.entireword":
-              this._self._entireWord = prefsvc.getBoolPref(aPrefName);
-              this._self.toggleEntireWord(this._self._entireWord, true);
-              break;
-            case "findbar.highlightAll":
-              this._self.toggleHighlight(prefsvc.getBoolPref(aPrefName), true);
-              break;
-            case "findbar.modalHighlight":
-              this._self._useModalHighlight = prefsvc.getBoolPref(aPrefName);
-              if (this._self.browser.finder)
-                this._self.browser.finder.onModalHighlightChange(this._self._useModalHighlight);
-              break;
-          }
-        }
-      })]]></field>
+    // We have to guard against `this.close` being |null| due to an unknown
+    // issue, which is tracked in bug 957999.
+    this.addEventListener("keypress", (event) => {
+      if (event.keyCode == event.DOM_VK_ESCAPE) {
+        if (this.close)
+          this.close();
+        event.preventDefault();
+      }
+    }, true);
+
+    this.destroy = this.destroy.bind(this);
+    window.addEventListener("unload", this.destroy);
+  }
 
-      <field name="_destroyed">false</field>
+  set _findMode(val) {
+    this.__findMode = val;
+    this._updateBrowserWithState();
+    return val;
+  }
+
+  get _findMode() {
+    return this.__findMode;
+  }
 
-      <constructor><![CDATA[
-        // These elements are accessed frequently and are therefore cached
-        this._findField = this.getElement("findbar-textbox");
-        this._foundMatches = this.getElement("found-matches");
-        this._findStatusIcon = this.getElement("find-status-icon");
-        this._findStatusDesc = this.getElement("find-status");
+  set prefillWithSelection(val) {
+    this.setAttribute("prefillwithselection", val);
+    return val;
+  }
 
-        this._foundURL = null;
+  get prefillWithSelection() {
+    return this.getAttribute("prefillwithselection") != "false";
+  }
+
+  get findMode() {
+    return this._findMode;
+  }
 
-        let prefsvc = this._prefsvc;
+  get hasTransactions() {
+    if (this._findField.value)
+      return true;
 
-        this._quickFindTimeoutLength =
-          prefsvc.getIntPref("accessibility.typeaheadfind.timeout");
-        this._flashFindBar =
-          prefsvc.getIntPref("accessibility.typeaheadfind.flashBar");
-        this._useModalHighlight = prefsvc.getBoolPref("findbar.modalHighlight");
+    // Watch out for lazy editor init
+    if (this._findField.editor) {
+      let tm = this._findField.editor.transactionManager;
+      return !!(tm.numberOfUndoItems || tm.numberOfRedoItems);
+    }
+    return false;
+  }
 
-        prefsvc.addObserver("accessibility.typeaheadfind",
-                            this._observer);
-        prefsvc.addObserver("accessibility.typeaheadfind.linksonly",
-                            this._observer);
-        prefsvc.addObserver("accessibility.typeaheadfind.casesensitive",
-                            this._observer);
-        prefsvc.addObserver("findbar.entireword", this._observer);
-        prefsvc.addObserver("findbar.highlightAll", this._observer);
-        prefsvc.addObserver("findbar.modalHighlight", this._observer);
+  set browser(val) {
+    if (this._browser) {
+      if (this._browser.messageManager) {
+        this._browser.messageManager.removeMessageListener("Findbar:Keypress", this);
+        this._browser.messageManager.removeMessageListener("Findbar:Mouseup", this);
+      }
+      let finder = this._browser.finder;
+      if (finder)
+        finder.removeResultListener(this);
+    }
 
-        this._findAsYouType =
-          prefsvc.getBoolPref("accessibility.typeaheadfind");
-        this._typeAheadLinksOnly =
-          prefsvc.getBoolPref("accessibility.typeaheadfind.linksonly");
-        this._typeAheadCaseSensitive =
-          prefsvc.getIntPref("accessibility.typeaheadfind.casesensitive");
-        this._entireWord = prefsvc.getBoolPref("findbar.entireword");
-        this._highlightAll = prefsvc.getBoolPref("findbar.highlightAll");
-
-        // Convenience
-        this.nsITypeAheadFind = Ci.nsITypeAheadFind;
-        this.nsISelectionController = Ci.nsISelectionController;
-        this._findSelection = this.nsISelectionController.SELECTION_FIND;
-
-        this._findResetTimeout = -1;
+    this._browser = val;
+    if (this._browser) {
+      // Need to do this to ensure the correct initial state.
+      this._updateBrowserWithState();
+      this._browser.messageManager.addMessageListener("Findbar:Keypress", this);
+      this._browser.messageManager.addMessageListener("Findbar:Mouseup", this);
+      this._browser.finder.addResultListener(this);
 
-        // Make sure the FAYT keypress listener is attached by initializing the
-        // browser property
-        if (this.getAttribute("browserid"))
-          setTimeout(function(aSelf) { aSelf.browser = aSelf.browser; }, 0, this);
-      ]]></constructor>
+      this._findField.value = this._browser._lastSearchString;
+    }
+    return val;
+  }
 
-      <destructor><![CDATA[
-        this.destroy();
-      ]]></destructor>
+  get browser() {
+    if (!this._browser) {
+      this._browser =
+        document.getElementById(this.getAttribute("browserid"));
+    }
+    return this._browser;
+  }
 
-      <!-- This is necessary because the destructor isn't called when
-           we are removed from a document that is not destroyed. This
-           needs to be explicitly called in this case -->
-      <method name="destroy">
-        <body><![CDATA[
-          if (this._destroyed)
-            return;
-          this._destroyed = true;
+  get _prefsvc() {
+    return Services.prefs;
+  }
 
-          if (this.browser && this.browser.finder)
-            this.browser.finder.destroy();
-
-          this.browser = null;
+  get pluralForm() {
+    if (!this._pluralForm) {
+      this._pluralForm = ChromeUtils.import(
+        "resource://gre/modules/PluralForm.jsm", {}).PluralForm;
+    }
+    return this._pluralForm;
+  }
 
-          let prefsvc = this._prefsvc;
-          prefsvc.removeObserver("accessibility.typeaheadfind",
-                                 this._observer);
-          prefsvc.removeObserver("accessibility.typeaheadfind.linksonly",
-                                 this._observer);
-          prefsvc.removeObserver("accessibility.typeaheadfind.casesensitive",
-                                 this._observer);
-          prefsvc.removeObserver("findbar.entireword", this._observer);
-          prefsvc.removeObserver("findbar.highlightAll", this._observer);
-          prefsvc.removeObserver("findbar.modalHighlight", this._observer);
+  get strBundle() {
+    if (!this._strBundle) {
+      this._strBundle = Services.strings.createBundle(
+        "chrome://global/locale/findbar.properties");
+    }
+    return this._strBundle;
+  }
 
-          // Clear all timers that might still be running.
-          this._cancelTimers();
-        ]]></body>
-      </method>
+  getElement(aAnonymousID) {
+    return this.querySelector(`[anonid=${aAnonymousID}]`);
+  }
 
-      <method name="_cancelTimers">
-        <body><![CDATA[
-          if (this._flashFindBarTimeout) {
-            clearInterval(this._flashFindBarTimeout);
-            this._flashFindBarTimeout = null;
-          }
-          if (this._quickFindTimeout) {
-            clearTimeout(this._quickFindTimeout);
-            this._quickFindTimeout = null;
-          }
-          if (this._findResetTimeout) {
-            clearTimeout(this._findResetTimeout);
-            this._findResetTimeout = null;
-          }
-        ]]></body>
-      </method>
+  /**
+   * This is necessary because the destructor isn't called when
+   * we are removed from a document that is not destroyed. This
+   * needs to be explicitly called in this case
+   */
+  destroy() {
+    if (this._destroyed)
+      return;
+    window.removeEventListener("unload", this.destroy);
+    this._destroyed = true;
+
+    if (this.browser && this.browser.finder)
+      this.browser.finder.destroy();
 
-      <method name="_setFindCloseTimeout">
-        <body><![CDATA[
-          if (this._quickFindTimeout)
-            clearTimeout(this._quickFindTimeout);
+    this.browser = null;
 
-          // Don't close the find toolbar while IME is composing OR when the
-          // findbar is already hidden.
-          if (this._isIMEComposing || this.hidden) {
-            this._quickFindTimeout = null;
-            this._updateBrowserWithState();
-            return;
-          }
+    let prefsvc = this._prefsvc;
+    prefsvc.removeObserver("accessibility.typeaheadfind",
+      this._observer);
+    prefsvc.removeObserver("accessibility.typeaheadfind.linksonly",
+      this._observer);
+    prefsvc.removeObserver("accessibility.typeaheadfind.casesensitive",
+      this._observer);
+    prefsvc.removeObserver("findbar.entireword", this._observer);
+    prefsvc.removeObserver("findbar.highlightAll", this._observer);
+    prefsvc.removeObserver("findbar.modalHighlight", this._observer);
+
+    // Clear all timers that might still be running.
+    this._cancelTimers();
+  }
 
-          this._quickFindTimeout = setTimeout(() => {
-             if (this._findMode != this.FIND_NORMAL)
-               this.close();
-             this._quickFindTimeout = null;
-           }, this._quickFindTimeoutLength);
-          this._updateBrowserWithState();
-        ]]></body>
-      </method>
+  _cancelTimers() {
+    if (this._flashFindBarTimeout) {
+      clearInterval(this._flashFindBarTimeout);
+      this._flashFindBarTimeout = null;
+    }
+    if (this._quickFindTimeout) {
+      clearTimeout(this._quickFindTimeout);
+      this._quickFindTimeout = null;
+    }
+    if (this._findResetTimeout) {
+      clearTimeout(this._findResetTimeout);
+      this._findResetTimeout = null;
+    }
+  }
 
-      <field name="_pluralForm">null</field>
-      <property name="pluralForm">
-        <getter><![CDATA[
-          if (!this._pluralForm) {
-            this._pluralForm = ChromeUtils.import(
-                               "resource://gre/modules/PluralForm.jsm", {}).PluralForm;
-          }
-          return this._pluralForm;
-        ]]></getter>
-      </property>
+  _setFindCloseTimeout() {
+    if (this._quickFindTimeout)
+      clearTimeout(this._quickFindTimeout);
 
-      <!--
-        - Updates the search match count after each find operation on a new string.
-        - @param aRes
-        -        the result of the find operation
-        -->
-      <method name="_updateMatchesCount">
-        <body><![CDATA[
-          if (!this._dispatchFindEvent("matchescount"))
-            return;
+    // Don't close the find toolbar while IME is composing OR when the
+    // findbar is already hidden.
+    if (this._isIMEComposing || this.hidden) {
+      this._quickFindTimeout = null;
+      this._updateBrowserWithState();
+      return;
+    }
 
-          this.browser.finder.requestMatchesCount(this._findField.value,
-            this._findMode == this.FIND_LINKS);
-        ]]></body>
-      </method>
+    this._quickFindTimeout = setTimeout(() => {
+      if (this._findMode != this.FIND_NORMAL)
+        this.close();
+      this._quickFindTimeout = null;
+    }, this._quickFindTimeoutLength);
+    this._updateBrowserWithState();
+  }
 
-      <!--
-        - Turns highlight on or off.
-        - @param aHighlight (boolean)
-        -        Whether to turn the highlight on or off
-        - @param aFromPrefObserver (boolean)
-        -        Whether the callee is the pref observer, which means we should
-        -        not set the same pref again.
-        -->
-      <method name="toggleHighlight">
-        <parameter name="aHighlight"/>
-        <parameter name="aFromPrefObserver"/>
-        <body><![CDATA[
-          if (aHighlight === this._highlightAll) {
-            return;
-          }
+  /**
+   * - Updates the search match count after each find operation on a new string.
+   * - @param aRes
+   * -        the result of the find operation
+   */
+  _updateMatchesCount() {
+    if (!this._dispatchFindEvent("matchescount"))
+      return;
 
-          this.browser.finder.onHighlightAllChange(aHighlight);
+    this.browser.finder.requestMatchesCount(this._findField.value,
+      this._findMode == this.FIND_LINKS);
+  }
 
-          this._setHighlightAll(aHighlight, aFromPrefObserver);
-
-          if (!this._dispatchFindEvent("highlightallchange")) {
-            return;
-          }
+  /**
+   * - Turns highlight on or off.
+   * - @param aHighlight (boolean)
+   * -        Whether to turn the highlight on or off
+   * - @param aFromPrefObserver (boolean)
+   * -        Whether the callee is the pref observer, which means we should
+   * -        not set the same pref again.
+   */
+  toggleHighlight(aHighlight, aFromPrefObserver) {
+    if (aHighlight === this._highlightAll) {
+      return;
+    }
 
-          let word = this._findField.value;
-          // Bug 429723. Don't attempt to highlight ""
-          if (aHighlight && !word)
-            return;
+    this.browser.finder.onHighlightAllChange(aHighlight);
 
-          this.browser.finder.highlight(aHighlight, word,
-            this._findMode == this.FIND_LINKS);
-
-          // Update the matches count
-          this._updateMatchesCount(this.nsITypeAheadFind.FIND_FOUND);
-        ]]></body>
-      </method>
+    this._setHighlightAll(aHighlight, aFromPrefObserver);
 
-      <!--
-        - Updates the highlight-all mode of the findbar and its UI.
-        - @param aHighlight (boolean)
-        -        Whether to turn the highlight on or off.
-        - @param aFromPrefObserver (boolean)
-        -        Whether the callee is the pref observer, which means we should
-        -        not set the same pref again.
-        -->
-      <method name="_setHighlightAll">
-        <parameter name="aHighlight"/>
-        <parameter name="aFromPrefObserver"/>
-        <body><![CDATA[
-          if (typeof aHighlight != "boolean") {
-            aHighlight = this._highlightAll;
-          }
-          if (aHighlight !== this._highlightAll && !aFromPrefObserver) {
-            this._prefsvc.setBoolPref("findbar.highlightAll", aHighlight);
-          }
-          this._highlightAll = aHighlight;
-          let checkbox = this.getElement("highlight");
-          checkbox.checked = this._highlightAll;
-        ]]></body>
-      </method>
+    if (!this._dispatchFindEvent("highlightallchange")) {
+      return;
+    }
+
+    let word = this._findField.value;
+    // Bug 429723. Don't attempt to highlight ""
+    if (aHighlight && !word)
+      return;
+
+    this.browser.finder.highlight(aHighlight, word,
+      this._findMode == this.FIND_LINKS);
+
+    // Update the matches count
+    this._updateMatchesCount(this.nsITypeAheadFind.FIND_FOUND);
+  }
 
-      <!--
-        - Updates the case-sensitivity mode of the findbar and its UI.
-        - @param [optional] aString
-        -        The string for which case sensitivity might be turned on.
-        -        This only used when case-sensitivity is in auto mode,
-        -        @see _shouldBeCaseSensitive. The default value for this
-        -        parameter is the find-field value.
-        -->
-      <method name="_updateCaseSensitivity">
-        <parameter name="aString"/>
-        <body><![CDATA[
-          let val = aString || this._findField.value;
-
-          let caseSensitive = this._shouldBeCaseSensitive(val);
-          let checkbox = this.getElement("find-case-sensitive");
-          let statusLabel = this.getElement("match-case-status");
-          checkbox.checked = caseSensitive;
-
-          statusLabel.value = caseSensitive ? this._caseSensitiveStr : "";
-
-          // Show the checkbox on the full Find bar in non-auto mode.
-          // Show the label in all other cases.
-          let hideCheckbox = this._findMode != this.FIND_NORMAL ||
-            (this._typeAheadCaseSensitive != 0 &&
-             this._typeAheadCaseSensitive != 1);
-          checkbox.hidden = hideCheckbox;
-          statusLabel.hidden = !hideCheckbox;
+  /**
+   * - Updates the highlight-all mode of the findbar and its UI.
+   * - @param aHighlight (boolean)
+   * -        Whether to turn the highlight on or off.
+   * - @param aFromPrefObserver (boolean)
+   * -        Whether the callee is the pref observer, which means we should
+   * -        not set the same pref again.
+   */
+  _setHighlightAll(aHighlight, aFromPrefObserver) {
+    if (typeof aHighlight != "boolean") {
+      aHighlight = this._highlightAll;
+    }
+    if (aHighlight !== this._highlightAll && !aFromPrefObserver) {
+      this._prefsvc.setBoolPref("findbar.highlightAll", aHighlight);
+    }
+    this._highlightAll = aHighlight;
+    let checkbox = this.getElement("highlight");
+    checkbox.checked = this._highlightAll;
+  }
 
-          this.browser.finder.caseSensitive = caseSensitive;
-        ]]></body>
-      </method>
+  /**
+   * - Updates the case-sensitivity mode of the findbar and its UI.
+   * - @param [optional] aString
+   * -        The string for which case sensitivity might be turned on.
+   * -        This only used when case-sensitivity is in auto mode,
+   * -        @see _shouldBeCaseSensitive. The default value for this
+   * -        parameter is the find-field value.
+   */
+  _updateCaseSensitivity(aString) {
+    let val = aString || this._findField.value;
 
-      <!--
-        - Sets the findbar case-sensitivity mode
-        - @param aCaseSensitivity (int)
-        -   0 - case insensitive
-        -   1 - case sensitive
-        -   2 - auto = case sensitive iff match string contains upper case letters
-        -   @see _shouldBeCaseSensitive
-        -->
-      <method name="_setCaseSensitivity">
-        <parameter name="aCaseSensitivity"/>
-        <body><![CDATA[
-          this._typeAheadCaseSensitive = aCaseSensitivity;
-          this._updateCaseSensitivity();
-          this._findFailedString = null;
-          this._find();
+    let caseSensitive = this._shouldBeCaseSensitive(val);
+    let checkbox = this.getElement("find-case-sensitive");
+    let statusLabel = this.getElement("match-case-status");
+    checkbox.checked = caseSensitive;
+
+    statusLabel.value = caseSensitive ? this._caseSensitiveStr : "";
 
-          this._dispatchFindEvent("casesensitivitychange");
-        ]]></body>
-      </method>
+    // Show the checkbox on the full Find bar in non-auto mode.
+    // Show the label in all other cases.
+    let hideCheckbox = this._findMode != this.FIND_NORMAL ||
+      (this._typeAheadCaseSensitive != 0 &&
+        this._typeAheadCaseSensitive != 1);
+    checkbox.hidden = hideCheckbox;
+    statusLabel.hidden = !hideCheckbox;
 
-      <!--
-        - Updates the entire-word mode of the findbar and its UI.
-        -->
-      <method name="_setEntireWord">
-        <body><![CDATA[
-          let entireWord = this._entireWord;
-          let checkbox = this.getElement("find-entire-word");
-          let statusLabel = this.getElement("entire-word-status");
-          checkbox.checked = entireWord;
-
-          statusLabel.value = entireWord ? this._entireWordStr : "";
+    this.browser.finder.caseSensitive = caseSensitive;
+  }
 
-          // Show the checkbox on the full Find bar in non-auto mode.
-          // Show the label in all other cases.
-          let hideCheckbox = this._findMode != this.FIND_NORMAL;
-          checkbox.hidden = hideCheckbox;
-          statusLabel.hidden = !hideCheckbox;
+  /**
+   * - Sets the findbar case-sensitivity mode
+   * - @param aCaseSensitivity (int)
+   * -   0 - case insensitive
+   * -   1 - case sensitive
+   * -   2 - auto = case sensitive iff match string contains upper case letters
+   * -   @see _shouldBeCaseSensitive
+   */
+  _setCaseSensitivity(aCaseSensitivity) {
+    this._typeAheadCaseSensitive = aCaseSensitivity;
+    this._updateCaseSensitivity();
+    this._findFailedString = null;
+    this._find();
 
-          this.browser.finder.entireWord = entireWord;
-        ]]></body>
-      </method>
+    this._dispatchFindEvent("casesensitivitychange");
+  }
 
-      <!--
-        - Sets the findbar entire-word mode
-        - @param aEntireWord (boolean)
-        - Whether or not entire-word mode should be turned on.
-        -->
-      <method name="toggleEntireWord">
-        <parameter name="aEntireWord"/>
-        <parameter name="aFromPrefObserver"/>
-        <body><![CDATA[
-          if (!aFromPrefObserver) {
-            // Just set the pref; our observer will change the find bar behavior.
-            this._prefsvc.setBoolPref("findbar.entireword", aEntireWord);
-            return;
-          }
+  /**
+   * - Updates the entire-word mode of the findbar and its UI.
+   */
+  _setEntireWord() {
+    let entireWord = this._entireWord;
+    let checkbox = this.getElement("find-entire-word");
+    let statusLabel = this.getElement("entire-word-status");
+    checkbox.checked = entireWord;
 
-          this._findFailedString = null;
-          this._find();
-        ]]></body>
-      </method>
+    statusLabel.value = entireWord ? this._entireWordStr : "";
 
-      <field name="_strBundle">null</field>
-      <property name="strBundle">
-        <getter><![CDATA[
-          if (!this._strBundle) {
-            this._strBundle =
-              Cc["@mozilla.org/intl/stringbundle;1"]
-                .getService(Ci.nsIStringBundleService)
-                .createBundle("chrome://global/locale/findbar.properties");
-          }
-          return this._strBundle;
-        ]]></getter>
-      </property>
+    // Show the checkbox on the full Find bar in non-auto mode.
+    // Show the label in all other cases.
+    let hideCheckbox = this._findMode != this.FIND_NORMAL;
+    checkbox.hidden = hideCheckbox;
+    statusLabel.hidden = !hideCheckbox;
+
+    this.browser.finder.entireWord = entireWord;
+  }
 
-      <!--
-        - Opens and displays the find bar.
-        -
-        - @param aMode
-        -        the find mode to be used, which is either FIND_NORMAL,
-        -        FIND_TYPEAHEAD or FIND_LINKS. If not passed, the last
-        -        find mode if any or FIND_NORMAL.
-        - @returns true if the find bar wasn't previously open, false otherwise.
-        -->
-      <method name="open">
-        <parameter name="aMode"/>
-        <body><![CDATA[
-          if (aMode != undefined)
-            this._findMode = aMode;
+  /**
+   * - Sets the findbar entire-word mode
+   * - @param aEntireWord (boolean)
+   * - Whether or not entire-word mode should be turned on.
+   */
+  toggleEntireWord(aEntireWord, aFromPrefObserver) {
+    if (!aFromPrefObserver) {
+      // Just set the pref; our observer will change the find bar behavior.
+      this._prefsvc.setBoolPref("findbar.entireword", aEntireWord);
+      return;
+    }
 
-          if (!this._notFoundStr) {
-            var stringsBundle = this.strBundle;
-            this._notFoundStr = stringsBundle.GetStringFromName("NotFound");
-            this._wrappedToTopStr =
-              stringsBundle.GetStringFromName("WrappedToTop");
-            this._wrappedToBottomStr =
-              stringsBundle.GetStringFromName("WrappedToBottom");
-            this._normalFindStr =
-              stringsBundle.GetStringFromName("NormalFind");
-            this._fastFindStr =
-              stringsBundle.GetStringFromName("FastFind");
-            this._fastFindLinksStr =
-              stringsBundle.GetStringFromName("FastFindLinks");
-            this._caseSensitiveStr =
-              stringsBundle.GetStringFromName("CaseSensitive");
-            this._entireWordStr =
-              stringsBundle.GetStringFromName("EntireWord");
-          }
+    this._findFailedString = null;
+    this._find();
+  }
 
-          this._findFailedString = null;
+  /**
+   * - Opens and displays the find bar.
+   * -
+   * - @param aMode
+   * -        the find mode to be used, which is either FIND_NORMAL,
+   * -        FIND_TYPEAHEAD or FIND_LINKS. If not passed, the last
+   * -        find mode if any or FIND_NORMAL.
+   * - @returns true if the find bar wasn't previously open, false otherwise.
+   */
+  open(aMode) {
+    if (aMode != undefined)
+      this._findMode = aMode;
 
-          this._updateFindUI();
-          if (this.hidden) {
-            this.removeAttribute("noanim");
-            this.hidden = false;
-
-            this._updateStatusUI(this.nsITypeAheadFind.FIND_FOUND);
+    if (!this._notFoundStr) {
+      var stringsBundle = this.strBundle;
+      this._notFoundStr = stringsBundle.GetStringFromName("NotFound");
+      this._wrappedToTopStr =
+        stringsBundle.GetStringFromName("WrappedToTop");
+      this._wrappedToBottomStr =
+        stringsBundle.GetStringFromName("WrappedToBottom");
+      this._normalFindStr =
+        stringsBundle.GetStringFromName("NormalFind");
+      this._fastFindStr =
+        stringsBundle.GetStringFromName("FastFind");
+      this._fastFindLinksStr =
+        stringsBundle.GetStringFromName("FastFindLinks");
+      this._caseSensitiveStr =
+        stringsBundle.GetStringFromName("CaseSensitive");
+      this._entireWordStr =
+        stringsBundle.GetStringFromName("EntireWord");
+    }
 
-            let event = document.createEvent("Events");
-            event.initEvent("findbaropen", true, false);
-            this.dispatchEvent(event);
-
-            this.browser.finder.onFindbarOpen();
-
-            return true;
-          }
-          return false;
-        ]]></body>
-      </method>
+    this._findFailedString = null;
 
-      <!--
-        - Closes the findbar.
-        -->
-      <method name="close">
-        <parameter name="aNoAnim"/>
-        <body><![CDATA[
-          if (this.hidden)
-            return;
+    this._updateFindUI();
+    if (this.hidden) {
+      this.removeAttribute("noanim");
+      this.hidden = false;
+
+      this._updateStatusUI(this.nsITypeAheadFind.FIND_FOUND);
+
+      let event = document.createEvent("Events");
+      event.initEvent("findbaropen", true, false);
+      this.dispatchEvent(event);
+
+      this.browser.finder.onFindbarOpen();
 
-          if (aNoAnim)
-            this.setAttribute("noanim", true);
-          this.hidden = true;
+      return true;
+    }
+    return false;
+  }
 
-          // 'focusContent()' iterates over all listeners in the chrome
-          // process, so we need to call it from here.
-          this.browser.finder.focusContent();
-          this.browser.finder.onFindbarClose();
+  /**
+   * - Closes the findbar.
+   */
+  close(aNoAnim) {
+    if (this.hidden)
+      return;
 
-          this._cancelTimers();
-          this._updateBrowserWithState();
-
-          this._findFailedString = null;
-        ]]></body>
-      </method>
+    if (aNoAnim)
+      this.setAttribute("noanim", true);
+    this.hidden = true;
 
-      <method name="clear">
-        <body><![CDATA[
-          this.browser.finder.removeSelection();
-          this._findField.reset();
-          this.toggleHighlight(false);
-          this._updateStatusUI();
-          this._enableFindButtons(false);
-        ]]></body>
-      </method>
+    // 'focusContent()' iterates over all listeners in the chrome
+    // process, so we need to call it from here.
+    this.browser.finder.focusContent();
+    this.browser.finder.onFindbarClose();
+
+    this._cancelTimers();
+    this._updateBrowserWithState();
+
+    this._findFailedString = null;
+  }
 
-      <method name="_dispatchKeypressEvent">
-        <parameter name="aTarget"/>
-        <parameter name="fakeEvent"/>
-        <body><![CDATA[
-          if (!aTarget)
-            return;
+  clear() {
+    this.browser.finder.removeSelection();
+    this._findField.reset();
+    this.toggleHighlight(false);
+    this._updateStatusUI();
+    this._enableFindButtons(false);
+  }
 
-          // The event information comes from the child process. If we need more
-          // properties/information here, change the list of sent properties in
-          // browser-content.js
-          let event = new aTarget.ownerGlobal.KeyboardEvent(fakeEvent.type, fakeEvent);
-          aTarget.dispatchEvent(event);
-        ]]></body>
-      </method>
+  _dispatchKeypressEvent(aTarget, fakeEvent) {
+    if (!aTarget)
+      return;
 
-      <field name="_xulBrowserWindow">null</field>
-      <method name="_updateStatusUIBar">
-        <parameter name="aFoundURL"/>
-        <body><![CDATA[
-          if (!this._xulBrowserWindow) {
-            try {
-              this._xulBrowserWindow =
-                window.QueryInterface(Ci.nsIInterfaceRequestor)
-                      .getInterface(Ci.nsIWebNavigation)
-                      .QueryInterface(Ci.nsIDocShellTreeItem)
-                      .treeOwner
-                      .QueryInterface(Ci.nsIInterfaceRequestor)
-                      .getInterface(Ci.nsIXULWindow)
-                      .XULBrowserWindow;
-            } catch (ex) { }
-            if (!this._xulBrowserWindow)
-              return false;
-          }
+    // The event information comes from the child process. If we need more
+    // properties/information here, change the list of sent properties in
+    // browser-content.js
+    let event = new aTarget.ownerGlobal.KeyboardEvent(fakeEvent.type, fakeEvent);
+    aTarget.dispatchEvent(event);
+  }
 
-          // Call this has the same effect like hovering over link,
-          // the browser shows the URL as a tooltip.
-          this._xulBrowserWindow.setOverLink(aFoundURL || "", null);
-          return true;
-        ]]></body>
-      </method>
+  _updateStatusUIBar(aFoundURL) {
+    if (!this._xulBrowserWindow) {
+      try {
+        this._xulBrowserWindow =
+          window.QueryInterface(Ci.nsIInterfaceRequestor)
+          .getInterface(Ci.nsIWebNavigation)
+          .QueryInterface(Ci.nsIDocShellTreeItem)
+          .treeOwner
+          .QueryInterface(Ci.nsIInterfaceRequestor)
+          .getInterface(Ci.nsIXULWindow)
+          .XULBrowserWindow;
+      } catch (ex) {}
+      if (!this._xulBrowserWindow)
+        return false;
+    }
 
-      <method name="_finishFAYT">
-        <parameter name="aKeypressEvent"/>
-        <body><![CDATA[
-          this.browser.finder.focusContent();
+    // Call this has the same effect like hovering over link,
+    // the browser shows the URL as a tooltip.
+    this._xulBrowserWindow.setOverLink(aFoundURL || "", null);
+    return true;
+  }
 
-          if (aKeypressEvent)
-            aKeypressEvent.preventDefault();
+  _finishFAYT(aKeypressEvent) {
+    this.browser.finder.focusContent();
 
-          this.browser.finder.keyPress(aKeypressEvent);
+    if (aKeypressEvent)
+      aKeypressEvent.preventDefault();
 
-          this.close();
-          return true;
-        ]]></body>
-      </method>
+    this.browser.finder.keyPress(aKeypressEvent);
+
+    this.close();
+    return true;
+  }
 
-      <method name="_shouldBeCaseSensitive">
-        <parameter name="aString"/>
-        <body><![CDATA[
-          if (this._typeAheadCaseSensitive == 0)
-            return false;
-          if (this._typeAheadCaseSensitive == 1)
-            return true;
+  _shouldBeCaseSensitive(aString) {
+    if (this._typeAheadCaseSensitive == 0)
+      return false;
+    if (this._typeAheadCaseSensitive == 1)
+      return true;
 
-          return aString != aString.toLowerCase();
-        ]]></body>
-      </method>
+    return aString != aString.toLowerCase();
+  }
 
-      <!-- We get a fake event object through an IPC message when FAYT is being used
-           from within the browser. We then stuff that input in the find bar here. -->
-      <method name="_onBrowserKeypress">
-        <parameter name="aFakeEvent"/>
-        <body><![CDATA[
-          const FAYT_LINKS_KEY = "'";
-          const FAYT_TEXT_KEY = "/";
+  /**
+   * We get a fake event object through an IPC message when FAYT is being used
+   * from within the browser. We then stuff that input in the find bar here.
+   */
+  _onBrowserKeypress(aFakeEvent) {
+    const FAYT_LINKS_KEY = "'";
+    const FAYT_TEXT_KEY = "/";
 
-          if (!this.hidden && this._findField.inputField == document.activeElement) {
-            this._dispatchKeypressEvent(this._findField.inputField, aFakeEvent);
-            return;
-          }
+    if (!this.hidden && this._findField.inputField == document.activeElement) {
+      this._dispatchKeypressEvent(this._findField.inputField, aFakeEvent);
+      return;
+    }
 
-          if (this._findMode != this.FIND_NORMAL && this._quickFindTimeout) {
-            this._findField.select();
-            this._findField.focus();
-            this._dispatchKeypressEvent(this._findField.inputField, aFakeEvent);
-            return;
-          }
+    if (this._findMode != this.FIND_NORMAL && this._quickFindTimeout) {
+      this._findField.select();
+      this._findField.focus();
+      this._dispatchKeypressEvent(this._findField.inputField, aFakeEvent);
+      return;
+    }
 
-          let key = aFakeEvent.charCode ? String.fromCharCode(aFakeEvent.charCode) : null;
-          let manualstartFAYT = (key == FAYT_LINKS_KEY || key == FAYT_TEXT_KEY);
-          let autostartFAYT = !manualstartFAYT && this._findAsYouType &&
-                              key && key != " ";
-          if (manualstartFAYT || autostartFAYT) {
-            let mode = (key == FAYT_LINKS_KEY ||
-                        (autostartFAYT && this._typeAheadLinksOnly)) ?
-              this.FIND_LINKS : this.FIND_TYPEAHEAD;
+    let key = aFakeEvent.charCode ? String.fromCharCode(aFakeEvent.charCode) : null;
+    let manualstartFAYT = (key == FAYT_LINKS_KEY || key == FAYT_TEXT_KEY);
+    let autostartFAYT = !manualstartFAYT && this._findAsYouType &&
+      key && key != " ";
+    if (manualstartFAYT || autostartFAYT) {
+      let mode = (key == FAYT_LINKS_KEY ||
+          (autostartFAYT && this._typeAheadLinksOnly)) ?
+        this.FIND_LINKS : this.FIND_TYPEAHEAD;
 
-            // Clear bar first, so that when openFindBar() calls setCaseSensitivity()
-            // it doesn't get confused by a lingering value
-            this._findField.value = "";
+      // Clear bar first, so that when openFindBar() calls setCaseSensitivity()
+      // it doesn't get confused by a lingering value
+      this._findField.value = "";
 
-            this.open(mode);
-            this._setFindCloseTimeout();
-            this._findField.select();
-            this._findField.focus();
+      this.open(mode);
+      this._setFindCloseTimeout();
+      this._findField.select();
+      this._findField.focus();
 
-            if (autostartFAYT)
-              this._dispatchKeypressEvent(this._findField.inputField, aFakeEvent);
-            else
-              this._updateStatusUI(this.nsITypeAheadFind.FIND_FOUND);
-          }
-        ]]></body>
-      </method>
+      if (autostartFAYT)
+        this._dispatchKeypressEvent(this._findField.inputField, aFakeEvent);
+      else
+        this._updateStatusUI(this.nsITypeAheadFind.FIND_FOUND);
+    }
+  }
 
-      <!-- See MessageListener -->
-      <method name="receiveMessage">
-        <parameter name="aMessage"/>
-        <body><![CDATA[
-          if (aMessage.target != this._browser) {
-            return undefined;
-          }
-          switch (aMessage.name) {
-            case "Findbar:Mouseup":
-              if (!this.hidden && this._findMode != this.FIND_NORMAL)
-                this.close();
-              break;
-            case "Findbar:Keypress":
-              this._onBrowserKeypress(aMessage.data);
-              break;
-          }
-          return undefined;
-        ]]></body>
-      </method>
+  /**
+   * See MessageListener
+   */
+  receiveMessage(aMessage) {
+    if (aMessage.target != this._browser) {
+      return undefined;
+    }
+    switch (aMessage.name) {
+      case "Findbar:Mouseup":
+        if (!this.hidden && this._findMode != this.FIND_NORMAL)
+          this.close();
+        break;
+      case "Findbar:Keypress":
+        this._onBrowserKeypress(aMessage.data);
+        break;
+    }
+    return undefined;
+  }
 
-      <method name="_updateBrowserWithState">
-        <body><![CDATA[
-          if (this._browser && this._browser.messageManager) {
-            this._browser.messageManager.sendAsyncMessage("Findbar:UpdateState", {
-              findMode: this._findMode,
-              isOpenAndFocused: !this.hidden && document.activeElement == this._findField.inputField,
-              hasQuickFindTimeout: !!this._quickFindTimeout,
-            });
-          }
-        ]]></body>
-      </method>
+  _updateBrowserWithState() {
+    if (this._browser && this._browser.messageManager) {
+      this._browser.messageManager.sendAsyncMessage("Findbar:UpdateState", {
+        findMode: this._findMode,
+        isOpenAndFocused: !this.hidden && document.activeElement == this._findField.inputField,
+        hasQuickFindTimeout: !!this._quickFindTimeout,
+      });
+    }
+  }
+
+  _enableFindButtons(aEnable) {
+    this.getElement("find-next").disabled =
+      this.getElement("find-previous").disabled = !aEnable;
+  }
 
-      <method name="_enableFindButtons">
-        <parameter name="aEnable"/>
-        <body><![CDATA[
-          this.getElement("find-next").disabled =
-            this.getElement("find-previous").disabled = !aEnable;
-        ]]></body>
-      </method>
-
-      <!--
-        - Determines whether minimalist or general-purpose search UI is to be
-        - displayed when the find bar is activated.
-        -->
-      <method name="_updateFindUI">
-        <body><![CDATA[
-          let showMinimalUI = this._findMode != this.FIND_NORMAL;
+  /**
+   * - Determines whether minimalist or general-purpose search UI is to be
+   * - displayed when the find bar is activated.
+   */
+  _updateFindUI() {
+    let showMinimalUI = this._findMode != this.FIND_NORMAL;
 
-          let nodes = this.getElement("findbar-container").childNodes;
-          let wrapper = this.getElement("findbar-textbox-wrapper");
-          let foundMatches = this._foundMatches;
-          for (let node of nodes) {
-            if (node == wrapper || node == foundMatches)
-               continue;
-            node.hidden = showMinimalUI;
-          }
-          this.getElement("find-next").hidden =
-            this.getElement("find-previous").hidden = showMinimalUI;
-          foundMatches.hidden = showMinimalUI || !foundMatches.value;
-          this._updateCaseSensitivity();
-          this._setEntireWord();
-          this._setHighlightAll();
+    let nodes = this.getElement("findbar-container").childNodes;
+    let wrapper = this.getElement("findbar-textbox-wrapper");
+    let foundMatches = this._foundMatches;
+    for (let node of nodes) {
+      if (node == wrapper || node == foundMatches)
+        continue;
+      node.hidden = showMinimalUI;
+    }
+    this.getElement("find-next").hidden =
+      this.getElement("find-previous").hidden = showMinimalUI;
+    foundMatches.hidden = showMinimalUI || !foundMatches.value;
+    this._updateCaseSensitivity();
+    this._setEntireWord();
+    this._setHighlightAll();
 
-          if (showMinimalUI)
-            this._findField.classList.add("minimal");
-          else
-            this._findField.classList.remove("minimal");
+    if (showMinimalUI)
+      this._findField.classList.add("minimal");
+    else
+      this._findField.classList.remove("minimal");
 
-          if (this._findMode == this.FIND_TYPEAHEAD)
-            this._findField.placeholder = this._fastFindStr;
-          else if (this._findMode == this.FIND_LINKS)
-            this._findField.placeholder = this._fastFindLinksStr;
-          else
-            this._findField.placeholder = this._normalFindStr;
-        ]]></body>
-      </method>
+    if (this._findMode == this.FIND_TYPEAHEAD)
+      this._findField.placeholder = this._fastFindStr;
+    else if (this._findMode == this.FIND_LINKS)
+      this._findField.placeholder = this._fastFindLinksStr;
+    else
+      this._findField.placeholder = this._normalFindStr;
+  }
 
-      <method name="_find">
-        <parameter name="aValue"/>
-        <body><![CDATA[
-          if (!this._dispatchFindEvent(""))
-            return;
+  _find(aValue) {
+    if (!this._dispatchFindEvent(""))
+      return;
 
-          let val = aValue || this._findField.value;
+    let val = aValue || this._findField.value;
 
-          // We have to carry around an explicit version of this,
-          // because finder.searchString doesn't update on failed
-          // searches.
-          this.browser._lastSearchString = val;
+    // We have to carry around an explicit version of this,
+    // because finder.searchString doesn't update on failed
+    // searches.
+    this.browser._lastSearchString = val;
 
-          // Only search on input if we don't have a last-failed string,
-          // or if the current search string doesn't start with it.
-          // In entire-word mode we always attemp a find; since sequential matching
-          // is not guaranteed, the first character typed may not be a word (no
-          // match), but the with the second character it may well be a word,
-          // thus a match.
-          if (!this._findFailedString ||
-              !val.startsWith(this._findFailedString) ||
-              this._entireWord) {
-            // Getting here means the user commanded a find op. Make sure any
-            // initial prefilling is ignored if it hasn't happened yet.
-            if (this._startFindDeferred) {
-              this._startFindDeferred.resolve();
-              this._startFindDeferred = null;
-            }
+    // Only search on input if we don't have a last-failed string,
+    // or if the current search string doesn't start with it.
+    // In entire-word mode we always attemp a find; since sequential matching
+    // is not guaranteed, the first character typed may not be a word (no
+    // match), but the with the second character it may well be a word,
+    // thus a match.
+    if (!this._findFailedString ||
+      !val.startsWith(this._findFailedString) ||
+      this._entireWord) {
+      // Getting here means the user commanded a find op. Make sure any
+      // initial prefilling is ignored if it hasn't happened yet.
+      if (this._startFindDeferred) {
+        this._startFindDeferred.resolve();
+        this._startFindDeferred = null;
+      }
 
-            this._enableFindButtons(val);
-            this._updateCaseSensitivity(val);
-            this._setEntireWord();
+      this._enableFindButtons(val);
+      this._updateCaseSensitivity(val);
+      this._setEntireWord();
 
-            this.browser.finder.fastFind(val, this._findMode == this.FIND_LINKS,
-                                         this._findMode != this.FIND_NORMAL);
-          }
-
-          if (this._findMode != this.FIND_NORMAL)
-            this._setFindCloseTimeout();
+      this.browser.finder.fastFind(val, this._findMode == this.FIND_LINKS,
+        this._findMode != this.FIND_NORMAL);
+    }
 
-          if (this._findResetTimeout != -1)
-            clearTimeout(this._findResetTimeout);
+    if (this._findMode != this.FIND_NORMAL)
+      this._setFindCloseTimeout();
+
+    if (this._findResetTimeout != -1)
+      clearTimeout(this._findResetTimeout);
 
-          // allow a search to happen on input again after a second has
-          // expired since the previous input, to allow for dynamic
-          // content and/or page loading
-          this._findResetTimeout = setTimeout(() => {
-            this._findFailedString = null;
-            this._findResetTimeout = -1;
-          }, 1000);
-        ]]></body>
-      </method>
-
-      <method name="_flash">
-        <body><![CDATA[
-          if (this._flashFindBarCount === undefined)
-            this._flashFindBarCount = this._initialFlashFindBarCount;
+    // allow a search to happen on input again after a second has
+    // expired since the previous input, to allow for dynamic
+    // content and/or page loading
+    this._findResetTimeout = setTimeout(() => {
+      this._findFailedString = null;
+      this._findResetTimeout = -1;
+    }, 1000);
+  }
 
-          if (this._flashFindBarCount-- == 0) {
-            clearInterval(this._flashFindBarTimeout);
-            this.removeAttribute("flash");
-            this._flashFindBarCount = 6;
-            return;
-          }
+  _flash() {
+    if (this._flashFindBarCount === undefined)
+      this._flashFindBarCount = this._initialFlashFindBarCount;
+
+    if (this._flashFindBarCount-- == 0) {
+      clearInterval(this._flashFindBarTimeout);
+      this._findField.removeAttribute("flash");
+      this._flashFindBarCount = 6;
+      return;
+    }
 
-          this.setAttribute("flash",
-                            (this._flashFindBarCount % 2 == 0) ?
-                            "false" : "true");
-        ]]></body>
-      </method>
+    this._findField.setAttribute("flash",
+      (this._flashFindBarCount % 2 == 0) ?
+      "false" : "true");
+  }
 
-      <method name="_findAgain">
-        <parameter name="aFindPrevious"/>
-        <body><![CDATA[
-          this.browser.finder.findAgain(aFindPrevious,
-                                        this._findMode == this.FIND_LINKS,
-                                        this._findMode != this.FIND_NORMAL);
-        ]]></body>
-      </method>
+  _findAgain(aFindPrevious) {
+    this.browser.finder.findAgain(aFindPrevious,
+      this._findMode == this.FIND_LINKS,
+      this._findMode != this.FIND_NORMAL);
+  }
 
-      <method name="_updateStatusUI">
-        <parameter name="res"/>
-        <parameter name="aFindPrevious"/>
-        <body><![CDATA[
-          switch (res) {
-            case this.nsITypeAheadFind.FIND_WRAPPED:
-              this._findStatusIcon.setAttribute("status", "wrapped");
-              this._findStatusDesc.textContent =
-                aFindPrevious ? this._wrappedToBottomStr : this._wrappedToTopStr;
-              this._findField.removeAttribute("status");
-              break;
-            case this.nsITypeAheadFind.FIND_NOTFOUND:
-              this._findStatusIcon.setAttribute("status", "notfound");
-              this._findStatusDesc.textContent = this._notFoundStr;
-              this._findField.setAttribute("status", "notfound");
-              break;
-            case this.nsITypeAheadFind.FIND_PENDING:
-              this._findStatusIcon.setAttribute("status", "pending");
-              this._findStatusDesc.textContent = "";
-              this._findField.removeAttribute("status");
-              break;
-            case this.nsITypeAheadFind.FIND_FOUND:
-            default:
-              this._findStatusIcon.removeAttribute("status");
-              this._findStatusDesc.textContent = "";
-              this._findField.removeAttribute("status");
-              break;
-          }
-        ]]></body>
-      </method>
+  _updateStatusUI(res, aFindPrevious) {
+    switch (res) {
+      case this.nsITypeAheadFind.FIND_WRAPPED:
+        this._findStatusIcon.setAttribute("status", "wrapped");
+        this._findStatusDesc.textContent =
+          aFindPrevious ? this._wrappedToBottomStr : this._wrappedToTopStr;
+        this._findField.removeAttribute("status");
+        break;
+      case this.nsITypeAheadFind.FIND_NOTFOUND:
+        this._findStatusIcon.setAttribute("status", "notfound");
+        this._findStatusDesc.textContent = this._notFoundStr;
+        this._findField.setAttribute("status", "notfound");
+        break;
+      case this.nsITypeAheadFind.FIND_PENDING:
+        this._findStatusIcon.setAttribute("status", "pending");
+        this._findStatusDesc.textContent = "";
+        this._findField.removeAttribute("status");
+        break;
+      case this.nsITypeAheadFind.FIND_FOUND:
+      default:
+        this._findStatusIcon.removeAttribute("status");
+        this._findStatusDesc.textContent = "";
+        this._findField.removeAttribute("status");
+        break;
+    }
+  }
+
+  updateControlState(aResult, aFindPrevious) {
+    this._updateStatusUI(aResult, aFindPrevious);
+    this._enableFindButtons(aResult !== this.nsITypeAheadFind.FIND_NOTFOUND &&
+      !!this._findField.value);
+  }
 
-      <method name="updateControlState">
-        <parameter name="aResult"/>
-        <parameter name="aFindPrevious"/>
-        <body><![CDATA[
-          this._updateStatusUI(aResult, aFindPrevious);
-          this._enableFindButtons(aResult !== this.nsITypeAheadFind.FIND_NOTFOUND &&
-            !!this._findField.value);
-        ]]></body>
-      </method>
+  _dispatchFindEvent(aType, aFindPrevious) {
+    let event = document.createEvent("CustomEvent");
+    event.initCustomEvent("find" + aType, true, true, {
+      query: this._findField.value,
+      caseSensitive: !!this._typeAheadCaseSensitive,
+      entireWord: this._entireWord,
+      highlightAll: this._highlightAll,
+      findPrevious: aFindPrevious
+    });
+    return this.dispatchEvent(event);
+  }
 
-      <method name="_dispatchFindEvent">
-        <parameter name="aType"/>
-        <parameter name="aFindPrevious"/>
-        <body><![CDATA[
-          let event = document.createEvent("CustomEvent");
-          event.initCustomEvent("find" + aType, true, true, {
-            query: this._findField.value,
-            caseSensitive: !!this._typeAheadCaseSensitive,
-            entireWord: this._entireWord,
-            highlightAll: this._highlightAll,
-            findPrevious: aFindPrevious
-          });
-          return this.dispatchEvent(event);
-        ]]></body>
-      </method>
-
+  /**
+   * - Opens the findbar, focuses the findfield and selects its contents.
+   * - Also flashes the findbar the first time it's used.
+   * - @param aMode
+   * -        the find mode to be used, which is either FIND_NORMAL,
+   * -        FIND_TYPEAHEAD or FIND_LINKS. If not passed, the last
+   * -        find mode if any or FIND_NORMAL.
+   */
+  startFind(aMode) {
+    let prefsvc = this._prefsvc;
+    let userWantsPrefill = true;
+    this.open(aMode);
 
-      <!--
-        - Opens the findbar, focuses the findfield and selects its contents.
-        - Also flashes the findbar the first time it's used.
-        - @param aMode
-        -        the find mode to be used, which is either FIND_NORMAL,
-        -        FIND_TYPEAHEAD or FIND_LINKS. If not passed, the last
-        -        find mode if any or FIND_NORMAL.
-        -->
-      <method name="startFind">
-        <parameter name="aMode"/>
-        <body><![CDATA[
-          let prefsvc = this._prefsvc;
-          let userWantsPrefill = true;
-          this.open(aMode);
+    if (this._flashFindBar) {
+      this._flashFindBarTimeout = setInterval(() => this._flash(), 500);
+      prefsvc.setIntPref("accessibility.typeaheadfind.flashBar",
+        --this._flashFindBar);
+    }
 
-          if (this._flashFindBar) {
-            this._flashFindBarTimeout = setInterval(() => this._flash(), 500);
-            prefsvc.setIntPref("accessibility.typeaheadfind.flashBar",
-                               --this._flashFindBar);
-          }
+    let { PromiseUtils } =
+    ChromeUtils.import("resource://gre/modules/PromiseUtils.jsm", {});
+    this._startFindDeferred = PromiseUtils.defer();
+    let startFindPromise = this._startFindDeferred.promise;
 
-          let {PromiseUtils} =
-            ChromeUtils.import("resource://gre/modules/PromiseUtils.jsm", {});
-          this._startFindDeferred = PromiseUtils.defer();
-          let startFindPromise = this._startFindDeferred.promise;
+    if (this.prefillWithSelection)
+      userWantsPrefill =
+      prefsvc.getBoolPref("accessibility.typeaheadfind.prefillwithselection");
 
-          if (this.prefillWithSelection)
-            userWantsPrefill =
-              prefsvc.getBoolPref("accessibility.typeaheadfind.prefillwithselection");
-
-          if (this.prefillWithSelection && userWantsPrefill) {
-            // NB: We have to focus this._findField here so tests that send
-            // key events can open and close the find bar synchronously.
-            this._findField.focus();
+    if (this.prefillWithSelection && userWantsPrefill) {
+      // NB: We have to focus this._findField here so tests that send
+      // key events can open and close the find bar synchronously.
+      this._findField.focus();
 
-            // (e10s) since we focus lets also select it, otherwise that would
-            // only happen in this.onCurrentSelection and, because it is async,
-            // there's a chance keypresses could come inbetween, leading to
-            // jumbled up queries.
-            this._findField.select();
+      // (e10s) since we focus lets also select it, otherwise that would
+      // only happen in this.onCurrentSelection and, because it is async,
+      // there's a chance keypresses could come inbetween, leading to
+      // jumbled up queries.
+      this._findField.select();
 
-            this.browser.finder.getInitialSelection();
-            return startFindPromise;
-          }
+      this.browser.finder.getInitialSelection();
+      return startFindPromise;
+    }
 
-          // If userWantsPrefill is false but prefillWithSelection is true,
-          // then we might need to check the selection clipboard. Call
-          // onCurrentSelection to do so.
-          // Note: this.onCurrentSelection clears this._startFindDeferred.
-          this.onCurrentSelection("", true);
-          return startFindPromise;
-        ]]></body>
-      </method>
+    // If userWantsPrefill is false but prefillWithSelection is true,
+    // then we might need to check the selection clipboard. Call
+    // onCurrentSelection to do so.
+    // Note: this.onCurrentSelection clears this._startFindDeferred.
+    this.onCurrentSelection("", true);
+    return startFindPromise;
+  }
 
-      <!--
-        - Convenient alias to startFind(gFindBar.FIND_NORMAL);
-        -
-        - You should generally map the window's find command to this method.
-        -   e.g. <command name="cmd_find" oncommand="gFindBar.onFindCommand();"/>
-        -->
-      <method name="onFindCommand">
-        <body><![CDATA[
-          return this.startFind(this.FIND_NORMAL);
-        ]]></body>
-      </method>
+  /**
+   * - Convenient alias to startFind(gFindBar.FIND_NORMAL);
+   * -
+   * - You should generally map the window's find command to this method.
+   * -   e.g. <command name="cmd_find" oncommand="gFindBar.onFindCommand();"/>
+   */
+  onFindCommand() {
+    return this.startFind(this.FIND_NORMAL);
+  }
 
-      <!--
-        - Stub for find-next and find-previous commands
-        - @param aFindPrevious
-        -        true for find-previous, false otherwise.
-        -->
-      <method name="onFindAgainCommand">
-        <parameter name="aFindPrevious"/>
-        <body><![CDATA[
-          let findString = this._browser.finder.searchString || this._findField.value;
-          if (!findString)
-            return this.startFind();
+  /**
+   * - Stub for find-next and find-previous commands
+   * - @param aFindPrevious
+   * -        true for find-previous, false otherwise.
+   */
+  onFindAgainCommand(aFindPrevious) {
+    let findString = this._browser.finder.searchString || this._findField.value;
+    if (!findString)
+      return this.startFind();
 
-          // We dispatch the findAgain event here instead of in _findAgain since
-          // if there is a find event handler that prevents the default then
-          // finder.searchString will never get updated which in turn means
-          // there would never be findAgain events because of the logic below.
-          if (!this._dispatchFindEvent("again", aFindPrevious))
-            return undefined;
+    // We dispatch the findAgain event here instead of in _findAgain since
+    // if there is a find event handler that prevents the default then
+    // finder.searchString will never get updated which in turn means
+    // there would never be findAgain events because of the logic below.
+    if (!this._dispatchFindEvent("again", aFindPrevious))
+      return undefined;
 
-          // user explicitly requested another search, so do it even if we think it'll fail
-          this._findFailedString = null;
+    // user explicitly requested another search, so do it even if we think it'll fail
+    this._findFailedString = null;
 
-          // Ensure the stored SearchString is in sync with what we want to find
-          if (this._findField.value != this._browser.finder.searchString) {
-            this._find(this._findField.value);
-          } else {
-            this._findAgain(aFindPrevious);
-            if (this._useModalHighlight) {
-              this.open();
-              this._findField.focus();
-            }
-          }
+    // Ensure the stored SearchString is in sync with what we want to find
+    if (this._findField.value != this._browser.finder.searchString) {
+      this._find(this._findField.value);
+    } else {
+      this._findAgain(aFindPrevious);
+      if (this._useModalHighlight) {
+        this.open();
+        this._findField.focus();
+      }
+    }
 
-          return undefined;
-        ]]></body>
-      </method>
+    return undefined;
+  }
 
-#ifdef XP_MACOSX
-      <!--
-        - Fetches the currently selected text and sets that as the text to search
-        - next. This is a MacOS specific feature.
-      -->
-      <method name="onFindSelectionCommand">
-        <body><![CDATA[
-          let searchString = this.browser.finder.setSearchStringToSelection();
-          if (searchString)
-            this._findField.value = searchString;
-        ]]></body>
-      </method>
+  /* Fetches the currently selected text and sets that as the text to search
+     next. This is a MacOS specific feature. */
+  onFindSelectionCommand() {
+    let searchString = this.browser.finder.setSearchStringToSelection();
+    if (searchString)
+      this._findField.value = searchString;
+
+  }
 
-      <method name="_onFindFieldFocus">
-        <body><![CDATA[
-          let prefsvc = this._prefsvc;
-          const kPref = "accessibility.typeaheadfind.prefillwithselection";
-          if (this.prefillWithSelection && prefsvc.getBoolPref(kPref))
-            return;
+  _onFindFieldFocus() {
+    let prefsvc = this._prefsvc;
+    const kPref = "accessibility.typeaheadfind.prefillwithselection";
+    if (this.prefillWithSelection && prefsvc.getBoolPref(kPref))
+      return;
 
-          let clipboardSearchString = this._browser.finder.clipboardSearchString;
-          if (clipboardSearchString && this._findField.value != clipboardSearchString &&
-              !this._findField._willfullyDeleted) {
-            this._findField.value = clipboardSearchString;
-            this._findField._hadValue = true;
-            // Changing the search string makes the previous status invalid, so
-            // we better clear it here.
-            this._updateStatusUI();
-          }
-        ]]></body>
-      </method>
-#endif
+    let clipboardSearchString = this._browser.finder.clipboardSearchString;
+    if (clipboardSearchString && this._findField.value != clipboardSearchString &&
+        !this._findField._willfullyDeleted) {
+      this._findField.value = clipboardSearchString;
+      this._findField._hadValue = true;
+      // Changing the search string makes the previous status invalid, so
+      // we better clear it here.
+      this._updateStatusUI();
+    }
+  }
 
-      <!--
-        - This handles all the result changes for both
-        - type-ahead-find and highlighting.
-        - @param aResult
-        -   One of the nsITypeAheadFind.FIND_* constants
-        -   indicating the result of a search operation.
-        - @param aFindBackwards
-        -   If the search was done from the bottom to
-        -   the top. This is used for right error messages
-        -   when reaching "the end of the page".
-        - @param aLinkURL
-        -   When a link matched then its URK. Always null
-        -   when not in FIND_LINKS mode.
-        -->
-      <method name="onFindResult">
-        <parameter name="aData"/>
-        <body><![CDATA[
-          if (aData.result == this.nsITypeAheadFind.FIND_NOTFOUND) {
-            // If an explicit Find Again command fails, re-open the toolbar.
-            if (aData.storeResult && this.open()) {
-              this._findField.select();
-              this._findField.focus();
-            }
-            this._findFailedString = aData.searchString;
-          } else {
-            this._findFailedString = null;
-          }
+  /**
+   * - This handles all the result changes for both
+   * - type-ahead-find and highlighting.
+   * - @param aResult
+   * -   One of the nsITypeAheadFind.FIND_* constants
+   * -   indicating the result of a search operation.
+   * - @param aFindBackwards
+   * -   If the search was done from the bottom to
+   * -   the top. This is used for right error messages
+   * -   when reaching "the end of the page".
+   * - @param aLinkURL
+   * -   When a link matched then its URK. Always null
+   * -   when not in FIND_LINKS mode.
+   */
+  onFindResult(aData) {
+    if (aData.result == this.nsITypeAheadFind.FIND_NOTFOUND) {
+      // If an explicit Find Again command fails, re-open the toolbar.
+      if (aData.storeResult && this.open()) {
+        this._findField.select();
+        this._findField.focus();
+      }
+      this._findFailedString = aData.searchString;
+    } else {
+      this._findFailedString = null;
+    }
 
-          this._updateStatusUI(aData.result, aData.findBackwards);
-          this._updateStatusUIBar(aData.linkURL);
+    this._updateStatusUI(aData.result, aData.findBackwards);
+    this._updateStatusUIBar(aData.linkURL);
 
-          if (this._findMode != this.FIND_NORMAL)
-            this._setFindCloseTimeout();
-        ]]></body>
-      </method>
+    if (this._findMode != this.FIND_NORMAL)
+      this._setFindCloseTimeout();
+  }
 
-      <!--
-        - This handles all the result changes for matches counts.
-        - @param aResult
-        -   Result Object, containing the total amount of matches and a vector
-        -   of the current result.
-        -->
-      <method name="onMatchesCountResult">
-        <parameter name="aResult"/>
-        <body><![CDATA[
-          if (aResult.total !== 0) {
-            if (aResult.total == -1) {
-              this._foundMatches.value = this.pluralForm.get(
-                aResult.limit,
-                this.strBundle.GetStringFromName("FoundMatchesCountLimit")
-              ).replace("#1", aResult.limit);
-            } else {
-              this._foundMatches.value = this.pluralForm.get(
-                aResult.total,
-                this.strBundle.GetStringFromName("FoundMatches")
-              ).replace("#1", aResult.current)
-               .replace("#2", aResult.total);
-            }
-            this._foundMatches.hidden = false;
-          } else {
-            this._foundMatches.hidden = true;
-            this._foundMatches.value = "";
-          }
-        ]]></body>
-      </method>
+  /**
+   * - This handles all the result changes for matches counts.
+   * - @param aResult
+   * -   Result Object, containing the total amount of matches and a vector
+   * -   of the current result.
+   */
+  onMatchesCountResult(aResult) {
+    if (aResult.total !== 0) {
+      if (aResult.total == -1) {
+        this._foundMatches.value = this.pluralForm.get(
+          aResult.limit,
+          this.strBundle.GetStringFromName("FoundMatchesCountLimit")
+        ).replace("#1", aResult.limit);
+      } else {
+        this._foundMatches.value = this.pluralForm.get(
+            aResult.total,
+            this.strBundle.GetStringFromName("FoundMatches")
+          ).replace("#1", aResult.current)
+          .replace("#2", aResult.total);
+      }
+      this._foundMatches.hidden = false;
+    } else {
+      this._foundMatches.hidden = true;
+      this._foundMatches.value = "";
+    }
+  }
 
-      <method name="onHighlightFinished">
-        <parameter name="result"/>
-        <body><![CDATA[
-          // Noop.
-        ]]></body>
-      </method>
+  onHighlightFinished(result) {
+    // Noop.
+  }
 
-      <method name="onCurrentSelection">
-        <parameter name="aSelectionString" />
-        <parameter name="aIsInitialSelection" />
-        <body><![CDATA[
-          // Ignore the prefill if the user has already typed in the findbar,
-          // it would have been overwritten anyway. See bug 1198465.
-          if (aIsInitialSelection && !this._startFindDeferred)
-            return;
+  onCurrentSelection(aSelectionString, aIsInitialSelection) {
+    // Ignore the prefill if the user has already typed in the findbar,
+    // it would have been overwritten anyway. See bug 1198465.
+    if (aIsInitialSelection && !this._startFindDeferred)
+      return;
+
+    if (/Mac/.test(window.navigator.platform) && aIsInitialSelection && !aSelectionString) {
+      let clipboardSearchString = this.browser.finder.clipboardSearchString;
+      if (clipboardSearchString)
+        aSelectionString = clipboardSearchString;
+    }
 
-          if (/Mac/.test(navigator.platform) && aIsInitialSelection && !aSelectionString) {
-            let clipboardSearchString = this.browser.finder.clipboardSearchString;
-            if (clipboardSearchString)
-              aSelectionString = clipboardSearchString;
-          }
+    if (aSelectionString)
+      this._findField.value = aSelectionString;
 
-          if (aSelectionString)
-            this._findField.value = aSelectionString;
+    if (aIsInitialSelection) {
+      this._enableFindButtons(!!this._findField.value);
+      this._findField.select();
+      this._findField.focus();
 
-          if (aIsInitialSelection) {
-            this._enableFindButtons(!!this._findField.value);
-            this._findField.select();
-            this._findField.focus();
+      this._startFindDeferred.resolve();
+      this._startFindDeferred = null;
+    }
+  }
 
-            this._startFindDeferred.resolve();
-            this._startFindDeferred = null;
-          }
-        ]]></body>
-      </method>
+  /**
+   * - This handler may cancel a request to focus content by returning |false|
+   * - explicitly.
+   */
+  shouldFocusContent() {
+    const fm = Services.focus;
+    if (fm.focusedWindow != window)
+      return false;
 
-      <!--
-        - This handler may cancel a request to focus content by returning |false|
-        - explicitly.
-        -->
-      <method name="shouldFocusContent">
-        <body><![CDATA[
-          const fm = Cc["@mozilla.org/focus-manager;1"]
-                       .getService(Ci.nsIFocusManager);
-          if (fm.focusedWindow != window)
-            return false;
+    let focusedElement = fm.focusedElement;
+    if (!focusedElement)
+      return false;
 
-          let focusedElement = fm.focusedElement;
-          if (!focusedElement)
-            return false;
+    let bindingParent = document.getBindingParent(focusedElement);
+    if (bindingParent != this && bindingParent != this._findField)
+      return false;
+
+    return true;
+  }
 
-          let bindingParent = document.getBindingParent(focusedElement);
-          if (bindingParent != this && bindingParent != this._findField)
-            return false;
-
-          return true;
-        ]]></body>
-      </method>
-
-    </implementation>
+  disconnectedCallback() {
+    // Empty the DOM. We will rebuild if reconnected.
+    while (this.lastChild) {
+      this.removeChild(this.lastChild);
+    }
+    this.destroy();
+  }
+}
 
-    <handlers>
-      <!--
-        - We have to guard against `this.close` being |null| due to an unknown
-        - issue, which is tracked in bug 957999.
-        -->
-      <handler event="keypress" keycode="VK_ESCAPE" phase="capturing"
-               action="if (this.close) this.close();" preventdefault="true"/>
-    </handlers>
-  </binding>
-</bindings>
+customElements.define("findbar", MozFindbar);
+
+}
--- a/toolkit/content/widgets/findbar.xml
+++ b/toolkit/content/widgets/findbar.xml
@@ -1,34 +1,29 @@
 <?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 % findBarDTD SYSTEM "chrome://global/locale/findbar.dtd" >
-%findBarDTD;
-]>
-
 <bindings id="findbarBindings"
    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">
 
   <!-- Private binding -->
   <binding id="findbar-textbox"
            extends="chrome://global/content/bindings/textbox.xml#textbox">
     <implementation>
 
       <field name="_findbar">null</field>
       <property name="findbar" readonly="true">
         <getter>
           return this._findbar ?
-                 this._findbar : this._findbar = document.getBindingParent(this);
+                 this._findbar : this._findbar = this.closest("findbar");
         </getter>
       </property>
 
       <method name="_handleEnter">
         <parameter name="aEvent"/>
         <body><![CDATA[
           if (this.findbar._findMode == this.findbar.FIND_NORMAL) {
             let findString = this.findbar._findField;
@@ -149,1216 +144,9 @@
         let value = event.dataTransfer.getData("text/plain");
         this.value = value;
         this.findbar._find(value);
         event.stopPropagation();
         event.preventDefault();
       ]]></handler>
     </handlers>
   </binding>
-
-  <binding id="findbar">
-    <resources>
-      <stylesheet src="chrome://global/skin/findBar.css"/>
-    </resources>
-
-    <content hidden="true">
-    <xul:hbox anonid="findbar-container" class="findbar-container" flex="1" align="center">
-      <xul:hbox anonid="findbar-textbox-wrapper" align="stretch">
-        <xul:textbox anonid="findbar-textbox"
-                     class="findbar-textbox findbar-find-fast"
-                     xbl:inherits="flash"/>
-        <xul:toolbarbutton anonid="find-previous"
-                           class="findbar-find-previous tabbable"
-                           tooltiptext="&previous.tooltip;"
-                           oncommand="onFindAgainCommand(true);"
-                           disabled="true"
-                           xbl:inherits="accesskey=findpreviousaccesskey"/>
-        <xul:toolbarbutton anonid="find-next"
-                           class="findbar-find-next tabbable"
-                           tooltiptext="&next.tooltip;"
-                           oncommand="onFindAgainCommand(false);"
-                           disabled="true"
-                           xbl:inherits="accesskey=findnextaccesskey"/>
-      </xul:hbox>
-      <xul:toolbarbutton anonid="highlight"
-                         class="findbar-highlight findbar-button tabbable"
-                         label="&highlightAll.label;"
-                         accesskey="&highlightAll.accesskey;"
-                         tooltiptext="&highlightAll.tooltiptext;"
-                         oncommand="toggleHighlight(this.checked);"
-                         type="checkbox"
-                         xbl:inherits="accesskey=highlightaccesskey"/>
-      <xul:toolbarbutton anonid="find-case-sensitive"
-                         class="findbar-case-sensitive findbar-button tabbable"
-                         label="&caseSensitive.label;"
-                         accesskey="&caseSensitive.accesskey;"
-                         tooltiptext="&caseSensitive.tooltiptext;"
-                         oncommand="_setCaseSensitivity(this.checked ? 1 : 0);"
-                         type="checkbox"
-                         xbl:inherits="accesskey=matchcaseaccesskey"/>
-      <xul:toolbarbutton anonid="find-entire-word"
-                         class="findbar-entire-word findbar-button tabbable"
-                         label="&entireWord.label;"
-                         accesskey="&entireWord.accesskey;"
-                         tooltiptext="&entireWord.tooltiptext;"
-                         oncommand="toggleEntireWord(this.checked);"
-                         type="checkbox"
-                         xbl:inherits="accesskey=entirewordaccesskey"/>
-      <xul:label anonid="match-case-status" class="findbar-find-fast"/>
-      <xul:label anonid="entire-word-status" class="findbar-find-fast"/>
-      <xul:label anonid="found-matches" class="findbar-find-fast found-matches" hidden="true"/>
-      <xul:image anonid="find-status-icon" class="findbar-find-fast find-status-icon"/>
-      <xul:description anonid="find-status"
-                       control="findbar-textbox"
-                       class="findbar-find-fast findbar-find-status">
-      <!-- Do not use value, first child is used because it provides a11y with text change events -->
-      </xul:description>
-    </xul:hbox>
-    <xul:toolbarbutton anonid="find-closebutton"
-                       class="findbar-closebutton close-icon"
-                       tooltiptext="&findCloseButton.tooltip;"
-                       oncommand="close();"/>
-    </content>
-
-    <implementation>
-      <!-- Please keep in sync with toolkit/content/browser-content.js -->
-      <field name="FIND_NORMAL">0</field>
-      <field name="FIND_TYPEAHEAD">1</field>
-      <field name="FIND_LINKS">2</field>
-
-      <field name="__findMode">0</field>
-      <property name="_findMode" onget="return this.__findMode;"
-                onset="this.__findMode = val; this._updateBrowserWithState(); return val;"/>
-
-      <field name="_flashFindBar">0</field>
-      <field name="_initialFlashFindBarCount">6</field>
-
-      <!--
-        - For tests that need to know when the find bar is finished
-        - initializing, we store a promise to notify on.
-        -->
-      <field name="_startFindDeferred">null</field>
-
-      <property name="prefillWithSelection"
-                onget="return this.getAttribute('prefillwithselection') != 'false'"
-                onset="this.setAttribute('prefillwithselection', val); return val;"/>
-
-      <method name="getElement">
-        <parameter name="aAnonymousID"/>
-        <body><![CDATA[
-          return document.getAnonymousElementByAttribute(this,
-                                                         "anonid",
-                                                         aAnonymousID);
-        ]]></body>
-      </method>
-
-      <property name="findMode"
-                readonly="true"
-                onget="return this._findMode;"/>
-
-      <property name="hasTransactions" readonly="true">
-        <getter><![CDATA[
-          if (this._findField.value)
-            return true;
-
-          // Watch out for lazy editor init
-          if (this._findField.editor) {
-            let tm = this._findField.editor.transactionManager;
-            return !!(tm.numberOfUndoItems || tm.numberOfRedoItems);
-          }
-          return false;
-        ]]></getter>
-      </property>
-
-      <field name="_browser">null</field>
-      <property name="browser">
-        <getter><![CDATA[
-          if (!this._browser) {
-            this._browser =
-              document.getElementById(this.getAttribute("browserid"));
-          }
-          return this._browser;
-        ]]></getter>
-        <setter><![CDATA[
-          if (this._browser) {
-            if (this._browser.messageManager) {
-              this._browser.messageManager.removeMessageListener("Findbar:Keypress", this);
-              this._browser.messageManager.removeMessageListener("Findbar:Mouseup", this);
-            }
-            let finder = this._browser.finder;
-            if (finder)
-              finder.removeResultListener(this);
-          }
-
-          this._browser = val;
-          if (this._browser) {
-            // Need to do this to ensure the correct initial state.
-            this._updateBrowserWithState();
-            this._browser.messageManager.addMessageListener("Findbar:Keypress", this);
-            this._browser.messageManager.addMessageListener("Findbar:Mouseup", this);
-            this._browser.finder.addResultListener(this);
-
-            this._findField.value = this._browser._lastSearchString;
-          }
-          return val;
-        ]]></setter>
-      </property>
-
-      <field name="__prefsvc">null</field>
-      <property name="_prefsvc">
-        <getter><![CDATA[
-          if (!this.__prefsvc) {
-            this.__prefsvc = Cc["@mozilla.org/preferences-service;1"]
-              .getService(Ci.nsIPrefBranch);
-          }
-          return this.__prefsvc;
-        ]]></getter>
-      </property>
-
-      <field name="_observer"><![CDATA[({
-        _self: this,
-
-        QueryInterface: ChromeUtils.generateQI(["nsIObserver",
-                                                "nsISupportsWeakReference"]),
-
-        observe(aSubject, aTopic, aPrefName) {
-          if (aTopic != "nsPref:changed")
-            return;
-
-          let prefsvc = this._self._prefsvc;
-
-          switch (aPrefName) {
-            case "accessibility.typeaheadfind":
-              this._self._findAsYouType = prefsvc.getBoolPref(aPrefName);
-              break;
-            case "accessibility.typeaheadfind.linksonly":
-              this._self._typeAheadLinksOnly = prefsvc.getBoolPref(aPrefName);
-              break;
-            case "accessibility.typeaheadfind.casesensitive":
-              this._self._setCaseSensitivity(prefsvc.getIntPref(aPrefName));
-              break;
-            case "findbar.entireword":
-              this._self._entireWord = prefsvc.getBoolPref(aPrefName);
-              this._self.toggleEntireWord(this._self._entireWord, true);
-              break;
-            case "findbar.highlightAll":
-              this._self.toggleHighlight(prefsvc.getBoolPref(aPrefName), true);
-              break;
-            case "findbar.modalHighlight":
-              this._self._useModalHighlight = prefsvc.getBoolPref(aPrefName);
-              if (this._self.browser.finder)
-                this._self.browser.finder.onModalHighlightChange(this._self._useModalHighlight);
-              break;
-          }
-        }
-      })]]></field>
-
-      <field name="_destroyed">false</field>
-
-      <constructor><![CDATA[
-        // These elements are accessed frequently and are therefore cached
-        this._findField = this.getElement("findbar-textbox");
-        this._foundMatches = this.getElement("found-matches");
-        this._findStatusIcon = this.getElement("find-status-icon");
-        this._findStatusDesc = this.getElement("find-status");
-
-        this._foundURL = null;
-
-        let prefsvc = this._prefsvc;
-
-        this._quickFindTimeoutLength =
-          prefsvc.getIntPref("accessibility.typeaheadfind.timeout");
-        this._flashFindBar =
-          prefsvc.getIntPref("accessibility.typeaheadfind.flashBar");
-        this._useModalHighlight = prefsvc.getBoolPref("findbar.modalHighlight");
-
-        prefsvc.addObserver("accessibility.typeaheadfind",
-                            this._observer);
-        prefsvc.addObserver("accessibility.typeaheadfind.linksonly",
-                            this._observer);
-        prefsvc.addObserver("accessibility.typeaheadfind.casesensitive",
-                            this._observer);
-        prefsvc.addObserver("findbar.entireword", this._observer);
-        prefsvc.addObserver("findbar.highlightAll", this._observer);
-        prefsvc.addObserver("findbar.modalHighlight", this._observer);
-
-        this._findAsYouType =
-          prefsvc.getBoolPref("accessibility.typeaheadfind");
-        this._typeAheadLinksOnly =
-          prefsvc.getBoolPref("accessibility.typeaheadfind.linksonly");
-        this._typeAheadCaseSensitive =
-          prefsvc.getIntPref("accessibility.typeaheadfind.casesensitive");
-        this._entireWord = prefsvc.getBoolPref("findbar.entireword");
-        this._highlightAll = prefsvc.getBoolPref("findbar.highlightAll");
-
-        // Convenience
-        this.nsITypeAheadFind = Ci.nsITypeAheadFind;
-        this.nsISelectionController = Ci.nsISelectionController;
-        this._findSelection = this.nsISelectionController.SELECTION_FIND;
-
-        this._findResetTimeout = -1;
-
-        // Make sure the FAYT keypress listener is attached by initializing the
-        // browser property
-        if (this.getAttribute("browserid"))
-          setTimeout(function(aSelf) { aSelf.browser = aSelf.browser; }, 0, this);
-      ]]></constructor>
-
-      <destructor><![CDATA[
-        this.destroy();
-      ]]></destructor>
-
-      <!-- This is necessary because the destructor isn't called when
-           we are removed from a document that is not destroyed. This
-           needs to be explicitly called in this case -->
-      <method name="destroy">
-        <body><![CDATA[
-          if (this._destroyed)
-            return;
-          this._destroyed = true;
-
-          if (this.browser && this.browser.finder)
-            this.browser.finder.destroy();
-
-          this.browser = null;
-
-          let prefsvc = this._prefsvc;
-          prefsvc.removeObserver("accessibility.typeaheadfind",
-                                 this._observer);
-          prefsvc.removeObserver("accessibility.typeaheadfind.linksonly",
-                                 this._observer);
-          prefsvc.removeObserver("accessibility.typeaheadfind.casesensitive",
-                                 this._observer);
-          prefsvc.removeObserver("findbar.entireword", this._observer);
-          prefsvc.removeObserver("findbar.highlightAll", this._observer);
-          prefsvc.removeObserver("findbar.modalHighlight", this._observer);
-
-          // Clear all timers that might still be running.
-          this._cancelTimers();
-        ]]></body>
-      </method>
-
-      <method name="_cancelTimers">
-        <body><![CDATA[
-          if (this._flashFindBarTimeout) {
-            clearInterval(this._flashFindBarTimeout);
-            this._flashFindBarTimeout = null;
-          }
-          if (this._quickFindTimeout) {
-            clearTimeout(this._quickFindTimeout);
-            this._quickFindTimeout = null;
-          }
-          if (this._findResetTimeout) {
-            clearTimeout(this._findResetTimeout);
-            this._findResetTimeout = null;
-          }
-        ]]></body>
-      </method>
-
-      <method name="_setFindCloseTimeout">
-        <body><![CDATA[
-          if (this._quickFindTimeout)
-            clearTimeout(this._quickFindTimeout);
-
-          // Don't close the find toolbar while IME is composing OR when the
-          // findbar is already hidden.
-          if (this._isIMEComposing || this.hidden) {
-            this._quickFindTimeout = null;
-            this._updateBrowserWithState();
-            return;
-          }
-
-          this._quickFindTimeout = setTimeout(() => {
-             if (this._findMode != this.FIND_NORMAL)
-               this.close();
-             this._quickFindTimeout = null;
-           }, this._quickFindTimeoutLength);
-          this._updateBrowserWithState();
-        ]]></body>
-      </method>
-
-      <field name="_pluralForm">null</field>
-      <property name="pluralForm">
-        <getter><![CDATA[
-          if (!this._pluralForm) {
-            this._pluralForm = ChromeUtils.import(
-                               "resource://gre/modules/PluralForm.jsm", {}).PluralForm;
-          }
-          return this._pluralForm;
-        ]]></getter>
-      </property>
-
-      <!--
-        - Updates the search match count after each find operation on a new string.
-        - @param aRes
-        -        the result of the find operation
-        -->
-      <method name="_updateMatchesCount">
-        <body><![CDATA[
-          if (!this._dispatchFindEvent("matchescount"))
-            return;
-
-          this.browser.finder.requestMatchesCount(this._findField.value,
-            this._findMode == this.FIND_LINKS);
-        ]]></body>
-      </method>
-
-      <!--
-        - Turns highlight on or off.
-        - @param aHighlight (boolean)
-        -        Whether to turn the highlight on or off
-        - @param aFromPrefObserver (boolean)
-        -        Whether the callee is the pref observer, which means we should
-        -        not set the same pref again.
-        -->
-      <method name="toggleHighlight">
-        <parameter name="aHighlight"/>
-        <parameter name="aFromPrefObserver"/>
-        <body><![CDATA[
-          if (aHighlight === this._highlightAll) {
-            return;
-          }
-
-          this.browser.finder.onHighlightAllChange(aHighlight);
-
-          this._setHighlightAll(aHighlight, aFromPrefObserver);
-
-          if (!this._dispatchFindEvent("highlightallchange")) {
-            return;
-          }
-
-          let word = this._findField.value;
-          // Bug 429723. Don't attempt to highlight ""
-          if (aHighlight && !word)
-            return;
-
-          this.browser.finder.highlight(aHighlight, word,
-            this._findMode == this.FIND_LINKS);
-
-          // Update the matches count
-          this._updateMatchesCount(this.nsITypeAheadFind.FIND_FOUND);
-        ]]></body>
-      </method>
-
-      <!--
-        - Updates the highlight-all mode of the findbar and its UI.
-        - @param aHighlight (boolean)
-        -        Whether to turn the highlight on or off.
-        - @param aFromPrefObserver (boolean)
-        -        Whether the callee is the pref observer, which means we should
-        -        not set the same pref again.
-        -->
-      <method name="_setHighlightAll">
-        <parameter name="aHighlight"/>
-        <parameter name="aFromPrefObserver"/>
-        <body><![CDATA[
-          if (typeof aHighlight != "boolean") {
-            aHighlight = this._highlightAll;
-          }
-          if (aHighlight !== this._highlightAll && !aFromPrefObserver) {
-            this._prefsvc.setBoolPref("findbar.highlightAll", aHighlight);
-          }
-          this._highlightAll = aHighlight;
-          let checkbox = this.getElement("highlight");
-          checkbox.checked = this._highlightAll;
-        ]]></body>
-      </method>
-
-      <!--
-        - Updates the case-sensitivity mode of the findbar and its UI.
-        - @param [optional] aString
-        -        The string for which case sensitivity might be turned on.
-        -        This only used when case-sensitivity is in auto mode,
-        -        @see _shouldBeCaseSensitive. The default value for this
-        -        parameter is the find-field value.
-        -->
-      <method name="_updateCaseSensitivity">
-        <parameter name="aString"/>
-        <body><![CDATA[
-          let val = aString || this._findField.value;
-
-          let caseSensitive = this._shouldBeCaseSensitive(val);
-          let checkbox = this.getElement("find-case-sensitive");
-          let statusLabel = this.getElement("match-case-status");
-          checkbox.checked = caseSensitive;
-
-          statusLabel.value = caseSensitive ? this._caseSensitiveStr : "";
-
-          // Show the checkbox on the full Find bar in non-auto mode.
-          // Show the label in all other cases.
-          let hideCheckbox = this._findMode != this.FIND_NORMAL ||
-            (this._typeAheadCaseSensitive != 0 &&
-             this._typeAheadCaseSensitive != 1);
-          checkbox.hidden = hideCheckbox;
-          statusLabel.hidden = !hideCheckbox;
-
-          this.browser.finder.caseSensitive = caseSensitive;
-        ]]></body>
-      </method>
-
-      <!--
-        - Sets the findbar case-sensitivity mode
-        - @param aCaseSensitivity (int)
-        -   0 - case insensitive
-        -   1 - case sensitive
-        -   2 - auto = case sensitive iff match string contains upper case letters
-        -   @see _shouldBeCaseSensitive
-        -->
-      <method name="_setCaseSensitivity">
-        <parameter name="aCaseSensitivity"/>
-        <body><![CDATA[
-          this._typeAheadCaseSensitive = aCaseSensitivity;
-          this._updateCaseSensitivity();
-          this._findFailedString = null;
-          this._find();
-
-          this._dispatchFindEvent("casesensitivitychange");
-        ]]></body>
-      </method>
-
-      <!--
-        - Updates the entire-word mode of the findbar and its UI.
-        -->
-      <method name="_setEntireWord">
-        <body><![CDATA[
-          let entireWord = this._entireWord;
-          let checkbox = this.getElement("find-entire-word");
-          let statusLabel = this.getElement("entire-word-status");
-          checkbox.checked = entireWord;
-
-          statusLabel.value = entireWord ? this._entireWordStr : "";
-
-          // Show the checkbox on the full Find bar in non-auto mode.
-          // Show the label in all other cases.
-          let hideCheckbox = this._findMode != this.FIND_NORMAL;
-          checkbox.hidden = hideCheckbox;
-          statusLabel.hidden = !hideCheckbox;
-
-          this.browser.finder.entireWord = entireWord;
-        ]]></body>
-      </method>
-
-      <!--
-        - Sets the findbar entire-word mode
-        - @param aEntireWord (boolean)
-        - Whether or not entire-word mode should be turned on.
-        -->
-      <method name="toggleEntireWord">
-        <parameter name="aEntireWord"/>
-        <parameter name="aFromPrefObserver"/>
-        <body><![CDATA[
-          if (!aFromPrefObserver) {
-            // Just set the pref; our observer will change the find bar behavior.
-            this._prefsvc.setBoolPref("findbar.entireword", aEntireWord);
-            return;
-          }
-
-          this._findFailedString = null;
-          this._find();
-        ]]></body>
-      </method>
-
-      <field name="_strBundle">null</field>
-      <property name="strBundle">
-        <getter><![CDATA[
-          if (!this._strBundle) {
-            this._strBundle =
-              Cc["@mozilla.org/intl/stringbundle;1"]
-                .getService(Ci.nsIStringBundleService)
-                .createBundle("chrome://global/locale/findbar.properties");
-          }
-          return this._strBundle;
-        ]]></getter>
-      </property>
-
-      <!--
-        - Opens and displays the find bar.
-        -
-        - @param aMode
-        -        the find mode to be used, which is either FIND_NORMAL,
-        -        FIND_TYPEAHEAD or FIND_LINKS. If not passed, the last
-        -        find mode if any or FIND_NORMAL.
-        - @returns true if the find bar wasn't previously open, false otherwise.
-        -->
-      <method name="open">
-        <parameter name="aMode"/>
-        <body><![CDATA[
-          if (aMode != undefined)
-            this._findMode = aMode;
-
-          if (!this._notFoundStr) {
-            var stringsBundle = this.strBundle;
-            this._notFoundStr = stringsBundle.GetStringFromName("NotFound");
-            this._wrappedToTopStr =
-              stringsBundle.GetStringFromName("WrappedToTop");
-            this._wrappedToBottomStr =
-              stringsBundle.GetStringFromName("WrappedToBottom");
-            this._normalFindStr =
-              stringsBundle.GetStringFromName("NormalFind");
-            this._fastFindStr =
-              stringsBundle.GetStringFromName("FastFind");
-            this._fastFindLinksStr =
-              stringsBundle.GetStringFromName("FastFindLinks");
-            this._caseSensitiveStr =
-              stringsBundle.GetStringFromName("CaseSensitive");
-            this._entireWordStr =
-              stringsBundle.GetStringFromName("EntireWord");
-          }
-
-          this._findFailedString = null;
-
-          this._updateFindUI();
-          if (this.hidden) {
-            this.removeAttribute("noanim");
-            this.hidden = false;
-
-            this._updateStatusUI(this.nsITypeAheadFind.FIND_FOUND);
-
-            let event = document.createEvent("Events");
-            event.initEvent("findbaropen", true, false);
-            this.dispatchEvent(event);
-
-            this.browser.finder.onFindbarOpen();
-
-            return true;
-          }
-          return false;
-        ]]></body>
-      </method>
-
-      <!--
-        - Closes the findbar.
-        -->
-      <method name="close">
-        <parameter name="aNoAnim"/>
-        <body><![CDATA[
-          if (this.hidden)
-            return;
-
-          if (aNoAnim)
-            this.setAttribute("noanim", true);
-          this.hidden = true;
-
-          // 'focusContent()' iterates over all listeners in the chrome
-          // process, so we need to call it from here.
-          this.browser.finder.focusContent();
-          this.browser.finder.onFindbarClose();
-
-          this._cancelTimers();
-          this._updateBrowserWithState();
-
-          this._findFailedString = null;
-        ]]></body>
-      </method>
-
-      <method name="clear">
-        <body><![CDATA[
-          this.browser.finder.removeSelection();
-          this._findField.reset();
-          this.toggleHighlight(false);
-          this._updateStatusUI();
-          this._enableFindButtons(false);
-        ]]></body>
-      </method>
-
-      <method name="_dispatchKeypressEvent">
-        <parameter name="aTarget"/>
-        <parameter name="fakeEvent"/>
-        <body><![CDATA[
-          if (!aTarget)
-            return;
-
-          // The event information comes from the child process. If we need more
-          // properties/information here, change the list of sent properties in
-          // browser-content.js
-          let event = new aTarget.ownerGlobal.KeyboardEvent(fakeEvent.type, fakeEvent);
-          aTarget.dispatchEvent(event);
-        ]]></body>
-      </method>
-
-      <field name="_xulBrowserWindow">null</field>
-      <method name="_updateStatusUIBar">
-        <parameter name="aFoundURL"/>
-        <body><![CDATA[
-          if (!this._xulBrowserWindow) {
-            try {
-              this._xulBrowserWindow =
-                window.QueryInterface(Ci.nsIInterfaceRequestor)
-                      .getInterface(Ci.nsIWebNavigation)
-                      .QueryInterface(Ci.nsIDocShellTreeItem)
-                      .treeOwner
-                      .QueryInterface(Ci.nsIInterfaceRequestor)
-                      .getInterface(Ci.nsIXULWindow)
-                      .XULBrowserWindow;
-            } catch (ex) { }
-            if (!this._xulBrowserWindow)
-              return false;
-          }
-
-          // Call this has the same effect like hovering over link,
-          // the browser shows the URL as a tooltip.
-          this._xulBrowserWindow.setOverLink(aFoundURL || "", null);
-          return true;
-        ]]></body>
-      </method>
-
-      <method name="_finishFAYT">
-        <parameter name="aKeypressEvent"/>
-        <body><![CDATA[
-          this.browser.finder.focusContent();
-
-          if (aKeypressEvent)
-            aKeypressEvent.preventDefault();
-
-          this.browser.finder.keyPress(aKeypressEvent);
-
-          this.close();
-          return true;
-        ]]></body>
-      </method>
-
-      <method name="_shouldBeCaseSensitive">
-        <parameter name="aString"/>
-        <body><![CDATA[
-          if (this._typeAheadCaseSensitive == 0)
-            return false;
-          if (this._typeAheadCaseSensitive == 1)
-            return true;
-
-          return aString != aString.toLowerCase();
-        ]]></body>
-      </method>
-
-      <!-- We get a fake event object through an IPC message when FAYT is being used
-           from within the browser. We then stuff that input in the find bar here. -->
-      <method name="_onBrowserKeypress">
-        <parameter name="aFakeEvent"/>
-        <body><![CDATA[
-          const FAYT_LINKS_KEY = "'";
-          const FAYT_TEXT_KEY = "/";
-
-          if (!this.hidden && this._findField.inputField == document.activeElement) {
-            this._dispatchKeypressEvent(this._findField.inputField, aFakeEvent);
-            return;
-          }
-
-          if (this._findMode != this.FIND_NORMAL && this._quickFindTimeout) {
-            this._findField.select();
-            this._findField.focus();
-            this._dispatchKeypressEvent(this._findField.inputField, aFakeEvent);
-            return;
-          }
-
-          let key = aFakeEvent.charCode ? String.fromCharCode(aFakeEvent.charCode) : null;
-          let manualstartFAYT = (key == FAYT_LINKS_KEY || key == FAYT_TEXT_KEY);
-          let autostartFAYT = !manualstartFAYT && this._findAsYouType &&
-                              key && key != " ";
-          if (manualstartFAYT || autostartFAYT) {
-            let mode = (key == FAYT_LINKS_KEY ||
-                        (autostartFAYT && this._typeAheadLinksOnly)) ?
-              this.FIND_LINKS : this.FIND_TYPEAHEAD;
-
-            // Clear bar first, so that when openFindBar() calls setCaseSensitivity()
-            // it doesn't get confused by a lingering value
-            this._findField.value = "";
-
-            this.open(mode);
-            this._setFindCloseTimeout();
-            this._findField.select();
-            this._findField.focus();
-
-            if (autostartFAYT)
-              this._dispatchKeypressEvent(this._findField.inputField, aFakeEvent);
-            else
-              this._updateStatusUI(this.nsITypeAheadFind.FIND_FOUND);
-          }
-        ]]></body>
-      </method>
-
-      <!-- See MessageListener -->
-      <method name="receiveMessage">
-        <parameter name="aMessage"/>
-        <body><![CDATA[
-          if (aMessage.target != this._browser) {
-            return undefined;
-          }
-          switch (aMessage.name) {
-            case "Findbar:Mouseup":
-              if (!this.hidden && this._findMode != this.FIND_NORMAL)
-                this.close();
-              break;
-            case "Findbar:Keypress":
-              this._onBrowserKeypress(aMessage.data);
-              break;
-          }
-          return undefined;
-        ]]></body>
-      </method>
-
-      <method name="_updateBrowserWithState">
-        <body><![CDATA[
-          if (this._browser && this._browser.messageManager) {
-            this._browser.messageManager.sendAsyncMessage("Findbar:UpdateState", {
-              findMode: this._findMode,
-              isOpenAndFocused: !this.hidden && document.activeElement == this._findField.inputField,
-              hasQuickFindTimeout: !!this._quickFindTimeout,
-            });
-          }
-        ]]></body>
-      </method>
-
-      <method name="_enableFindButtons">
-        <parameter name="aEnable"/>
-        <body><![CDATA[
-          this.getElement("find-next").disabled =
-            this.getElement("find-previous").disabled = !aEnable;
-        ]]></body>
-      </method>
-
-      <!--
-        - Determines whether minimalist or general-purpose search UI is to be
-        - displayed when the find bar is activated.
-        -->
-      <method name="_updateFindUI">
-        <body><![CDATA[
-          let showMinimalUI = this._findMode != this.FIND_NORMAL;
-
-          let nodes = this.getElement("findbar-container").childNodes;
-          let wrapper = this.getElement("findbar-textbox-wrapper");
-          let foundMatches = this._foundMatches;
-          for (let node of nodes) {
-            if (node == wrapper || node == foundMatches)
-               continue;
-            node.hidden = showMinimalUI;
-          }
-          this.getElement("find-next").hidden =
-            this.getElement("find-previous").hidden = showMinimalUI;
-          foundMatches.hidden = showMinimalUI || !foundMatches.value;
-          this._updateCaseSensitivity();
-          this._setEntireWord();
-          this._setHighlightAll();
-
-          if (showMinimalUI)
-            this._findField.classList.add("minimal");
-          else
-            this._findField.classList.remove("minimal");
-
-          if (this._findMode == this.FIND_TYPEAHEAD)
-            this._findField.placeholder = this._fastFindStr;
-          else if (this._findMode == this.FIND_LINKS)
-            this._findField.placeholder = this._fastFindLinksStr;
-          else
-            this._findField.placeholder = this._normalFindStr;
-        ]]></body>
-      </method>
-
-      <method name="_find">
-        <parameter name="aValue"/>
-        <body><![CDATA[
-          if (!this._dispatchFindEvent(""))
-            return;
-
-          let val = aValue || this._findField.value;
-
-          // We have to carry around an explicit version of this,
-          // because finder.searchString doesn't update on failed
-          // searches.
-          this.browser._lastSearchString = val;
-
-          // Only search on input if we don't have a last-failed string,
-          // or if the current search string doesn't start with it.
-          // In entire-word mode we always attemp a find; since sequential matching
-          // is not guaranteed, the first character typed may not be a word (no
-          // match), but the with the second character it may well be a word,
-          // thus a match.
-          if (!this._findFailedString ||
-              !val.startsWith(this._findFailedString) ||
-              this._entireWord) {
-            // Getting here means the user commanded a find op. Make sure any
-            // initial prefilling is ignored if it hasn't happened yet.
-            if (this._startFindDeferred) {
-              this._startFindDeferred.resolve();
-              this._startFindDeferred = null;
-            }
-
-            this._enableFindButtons(val);
-            this._updateCaseSensitivity(val);
-            this._setEntireWord();
-
-            this.browser.finder.fastFind(val, this._findMode == this.FIND_LINKS,
-                                         this._findMode != this.FIND_NORMAL);
-          }
-
-          if (this._findMode != this.FIND_NORMAL)
-            this._setFindCloseTimeout();
-
-          if (this._findResetTimeout != -1)
-            clearTimeout(this._findResetTimeout);
-
-          // allow a search to happen on input again after a second has
-          // expired since the previous input, to allow for dynamic
-          // content and/or page loading
-          this._findResetTimeout = setTimeout(() => {
-            this._findFailedString = null;
-            this._findResetTimeout = -1;
-          }, 1000);
-        ]]></body>
-      </method>
-
-      <method name="_flash">
-        <body><![CDATA[
-          if (this._flashFindBarCount === undefined)
-            this._flashFindBarCount = this._initialFlashFindBarCount;
-
-          if (this._flashFindBarCount-- == 0) {
-            clearInterval(this._flashFindBarTimeout);
-            this.removeAttribute("flash");
-            this._flashFindBarCount = 6;
-            return;
-          }
-
-          this.setAttribute("flash",
-                            (this._flashFindBarCount % 2 == 0) ?
-                            "false" : "true");
-        ]]></body>
-      </method>
-
-      <method name="_findAgain">
-        <parameter name="aFindPrevious"/>
-        <body><![CDATA[
-          this.browser.finder.findAgain(aFindPrevious,
-                                        this._findMode == this.FIND_LINKS,
-                                        this._findMode != this.FIND_NORMAL);
-        ]]></body>
-      </method>
-
-      <method name="_updateStatusUI">
-        <parameter name="res"/>
-        <parameter name="aFindPrevious"/>
-        <body><![CDATA[
-          switch (res) {
-            case this.nsITypeAheadFind.FIND_WRAPPED:
-              this._findStatusIcon.setAttribute("status", "wrapped");
-              this._findStatusDesc.textContent =
-                aFindPrevious ? this._wrappedToBottomStr : this._wrappedToTopStr;
-              this._findField.removeAttribute("status");
-              break;
-            case this.nsITypeAheadFind.FIND_NOTFOUND:
-              this._findStatusIcon.setAttribute("status", "notfound");
-              this._findStatusDesc.textContent = this._notFoundStr;
-              this._findField.setAttribute("status", "notfound");
-              break;
-            case this.nsITypeAheadFind.FIND_PENDING:
-              this._findStatusIcon.setAttribute("status", "pending");
-              this._findStatusDesc.textContent = "";
-              this._findField.removeAttribute("status");
-              break;
-            case this.nsITypeAheadFind.FIND_FOUND:
-            default:
-              this._findStatusIcon.removeAttribute("status");
-              this._findStatusDesc.textContent = "";
-              this._findField.removeAttribute("status");
-              break;
-          }
-        ]]></body>
-      </method>
-
-      <method name="updateControlState">
-        <parameter name="aResult"/>
-        <parameter name="aFindPrevious"/>
-        <body><![CDATA[
-          this._updateStatusUI(aResult, aFindPrevious);
-          this._enableFindButtons(aResult !== this.nsITypeAheadFind.FIND_NOTFOUND &&
-            !!this._findField.value);
-        ]]></body>
-      </method>
-
-      <method name="_dispatchFindEvent">
-        <parameter name="aType"/>
-        <parameter name="aFindPrevious"/>
-        <body><![CDATA[
-          let event = document.createEvent("CustomEvent");
-          event.initCustomEvent("find" + aType, true, true, {
-            query: this._findField.value,
-            caseSensitive: !!this._typeAheadCaseSensitive,
-            entireWord: this._entireWord,
-            highlightAll: this._highlightAll,
-            findPrevious: aFindPrevious
-          });
-          return this.dispatchEvent(event);
-        ]]></body>
-      </method>
-
-
-      <!--
-        - Opens the findbar, focuses the findfield and selects its contents.
-        - Also flashes the findbar the first time it's used.
-        - @param aMode
-        -        the find mode to be used, which is either FIND_NORMAL,
-        -        FIND_TYPEAHEAD or FIND_LINKS. If not passed, the last
-        -        find mode if any or FIND_NORMAL.
-        -->
-      <method name="startFind">
-        <parameter name="aMode"/>
-        <body><![CDATA[
-          let prefsvc = this._prefsvc;
-          let userWantsPrefill = true;
-          this.open(aMode);
-
-          if (this._flashFindBar) {
-            this._flashFindBarTimeout = setInterval(() => this._flash(), 500);
-            prefsvc.setIntPref("accessibility.typeaheadfind.flashBar",
-                               --this._flashFindBar);
-          }
-
-          let {PromiseUtils} =
-            ChromeUtils.import("resource://gre/modules/PromiseUtils.jsm", {});
-          this._startFindDeferred = PromiseUtils.defer();
-          let startFindPromise = this._startFindDeferred.promise;
-
-          if (this.prefillWithSelection)
-            userWantsPrefill =
-              prefsvc.getBoolPref("accessibility.typeaheadfind.prefillwithselection");
-
-          if (this.prefillWithSelection && userWantsPrefill) {
-            // NB: We have to focus this._findField here so tests that send
-            // key events can open and close the find bar synchronously.
-            this._findField.focus();
-
-            // (e10s) since we focus lets also select it, otherwise that would
-            // only happen in this.onCurrentSelection and, because it is async,
-            // there's a chance keypresses could come inbetween, leading to
-            // jumbled up queries.
-            this._findField.select();
-
-            this.browser.finder.getInitialSelection();
-            return startFindPromise;
-          }
-
-          // If userWantsPrefill is false but prefillWithSelection is true,
-          // then we might need to check the selection clipboard. Call
-          // onCurrentSelection to do so.
-          // Note: this.onCurrentSelection clears this._startFindDeferred.
-          this.onCurrentSelection("", true);
-          return startFindPromise;
-        ]]></body>
-      </method>
-
-      <!--
-        - Convenient alias to startFind(gFindBar.FIND_NORMAL);
-        -
-        - You should generally map the window's find command to this method.
-        -   e.g. <command name="cmd_find" oncommand="gFindBar.onFindCommand();"/>
-        -->
-      <method name="onFindCommand">
-        <body><![CDATA[
-          return this.startFind(this.FIND_NORMAL);
-        ]]></body>
-      </method>
-
-      <!--
-        - Stub for find-next and find-previous commands
-        - @param aFindPrevious
-        -        true for find-previous, false otherwise.
-        -->
-      <method name="onFindAgainCommand">
-        <parameter name="aFindPrevious"/>
-        <body><![CDATA[
-          let findString = this._browser.finder.searchString || this._findField.value;
-          if (!findString)
-            return this.startFind();
-
-          // We dispatch the findAgain event here instead of in _findAgain since
-          // if there is a find event handler that prevents the default then
-          // finder.searchString will never get updated which in turn means
-          // there would never be findAgain events because of the logic below.
-          if (!this._dispatchFindEvent("again", aFindPrevious))
-            return undefined;
-
-          // user explicitly requested another search, so do it even if we think it'll fail
-          this._findFailedString = null;
-
-          // Ensure the stored SearchString is in sync with what we want to find
-          if (this._findField.value != this._browser.finder.searchString) {
-            this._find(this._findField.value);
-          } else {
-            this._findAgain(aFindPrevious);
-            if (this._useModalHighlight) {
-              this.open();
-              this._findField.focus();
-            }
-          }
-
-          return undefined;
-        ]]></body>
-      </method>
-
-#ifdef XP_MACOSX
-      <!--
-        - Fetches the currently selected text and sets that as the text to search
-        - next. This is a MacOS specific feature.
-      -->
-      <method name="onFindSelectionCommand">
-        <body><![CDATA[
-          let searchString = this.browser.finder.setSearchStringToSelection();
-          if (searchString)
-            this._findField.value = searchString;
-        ]]></body>
-      </method>
-
-      <method name="_onFindFieldFocus">
-        <body><![CDATA[
-          let prefsvc = this._prefsvc;
-          const kPref = "accessibility.typeaheadfind.prefillwithselection";
-          if (this.prefillWithSelection && prefsvc.getBoolPref(kPref))
-            return;
-
-          let clipboardSearchString = this._browser.finder.clipboardSearchString;
-          if (clipboardSearchString && this._findField.value != clipboardSearchString &&
-              !this._findField._willfullyDeleted) {
-            this._findField.value = clipboardSearchString;
-            this._findField._hadValue = true;
-            // Changing the search string makes the previous status invalid, so
-            // we better clear it here.
-            this._updateStatusUI();
-          }
-        ]]></body>
-      </method>
-#endif
-
-      <!--
-        - This handles all the result changes for both
-        - type-ahead-find and highlighting.
-        - @param aResult
-        -   One of the nsITypeAheadFind.FIND_* constants
-        -   indicating the result of a search operation.
-        - @param aFindBackwards
-        -   If the search was done from the bottom to
-        -   the top. This is used for right error messages
-        -   when reaching "the end of the page".
-        - @param aLinkURL
-        -   When a link matched then its URK. Always null
-        -   when not in FIND_LINKS mode.
-        -->
-      <method name="onFindResult">
-        <parameter name="aData"/>
-        <body><![CDATA[
-          if (aData.result == this.nsITypeAheadFind.FIND_NOTFOUND) {
-            // If an explicit Find Again command fails, re-open the toolbar.
-            if (aData.storeResult && this.open()) {
-              this._findField.select();
-              this._findField.focus();
-            }
-            this._findFailedString = aData.searchString;
-          } else {
-            this._findFailedString = null;
-          }
-
-          this._updateStatusUI(aData.result, aData.findBackwards);
-          this._updateStatusUIBar(aData.linkURL);
-
-          if (this._findMode != this.FIND_NORMAL)
-            this._setFindCloseTimeout();
-        ]]></body>
-      </method>
-
-      <!--
-        - This handles all the result changes for matches counts.
-        - @param aResult
-        -   Result Object, containing the total amount of matches and a vector
-        -   of the current result.
-        -->
-      <method name="onMatchesCountResult">
-        <parameter name="aResult"/>
-        <body><![CDATA[
-          if (aResult.total !== 0) {
-            if (aResult.total == -1) {
-              this._foundMatches.value = this.pluralForm.get(
-                aResult.limit,
-                this.strBundle.GetStringFromName("FoundMatchesCountLimit")
-              ).replace("#1", aResult.limit);
-            } else {
-              this._foundMatches.value = this.pluralForm.get(
-                aResult.total,
-                this.strBundle.GetStringFromName("FoundMatches")
-              ).replace("#1", aResult.current)
-               .replace("#2", aResult.total);
-            }
-            this._foundMatches.hidden = false;
-          } else {
-            this._foundMatches.hidden = true;
-            this._foundMatches.value = "";
-          }
-        ]]></body>
-      </method>
-
-      <method name="onHighlightFinished">
-        <parameter name="result"/>
-        <body><![CDATA[
-          // Noop.
-        ]]></body>
-      </method>
-
-      <method name="onCurrentSelection">
-        <parameter name="aSelectionString" />
-        <parameter name="aIsInitialSelection" />
-        <body><![CDATA[
-          // Ignore the prefill if the user has already typed in the findbar,
-          // it would have been overwritten anyway. See bug 1198465.
-          if (aIsInitialSelection && !this._startFindDeferred)
-            return;
-
-          if (/Mac/.test(navigator.platform) && aIsInitialSelection && !aSelectionString) {
-            let clipboardSearchString = this.browser.finder.clipboardSearchString;
-            if (clipboardSearchString)
-              aSelectionString = clipboardSearchString;
-          }
-
-          if (aSelectionString)
-            this._findField.value = aSelectionString;
-
-          if (aIsInitialSelection) {
-            this._enableFindButtons(!!this._findField.value);
-            this._findField.select();
-            this._findField.focus();
-
-            this._startFindDeferred.resolve();
-            this._startFindDeferred = null;
-          }
-        ]]></body>
-      </method>
-
-      <!--
-        - This handler may cancel a request to focus content by returning |false|
-        - explicitly.
-        -->
-      <method name="shouldFocusContent">
-        <body><![CDATA[
-          const fm = Cc["@mozilla.org/focus-manager;1"]
-                       .getService(Ci.nsIFocusManager);
-          if (fm.focusedWindow != window)
-            return false;
-
-          let focusedElement = fm.focusedElement;
-          if (!focusedElement)
-            return false;
-
-          let bindingParent = document.getBindingParent(focusedElement);
-          if (bindingParent != this && bindingParent != this._findField)
-            return false;
-
-          return true;
-        ]]></body>
-      </method>
-
-    </implementation>
-
-    <handlers>
-      <!--
-        - We have to guard against `this.close` being |null| due to an unknown
-        - issue, which is tracked in bug 957999.
-        -->
-      <handler event="keypress" keycode="VK_ESCAPE" phase="capturing"
-               action="if (this.close) this.close();" preventdefault="true"/>
-    </handlers>
-  </binding>
 </bindings>
--- a/toolkit/content/xul.css
+++ b/toolkit/content/xul.css
@@ -944,17 +944,16 @@ richlistitem {
 
 richlistbox > listheader {
   -moz-box-ordinal-group: 1;
 }
 
 
 /*********** findbar ************/
 findbar {
-  -moz-binding: url('chrome://global/content/bindings/findbar.xml#findbar');
   overflow-x: hidden;
 }
 
 .findbar-textbox {
   -moz-binding: url("chrome://global/content/bindings/findbar.xml#findbar-textbox");
 }
 
 /*********** tabmodalprompt ************/
deleted file mode 100644
--- a/toolkit/locales/en-US/chrome/global/findbar.dtd
+++ /dev/null
@@ -1,19 +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/. -->
-
-<!-- LOCALIZATION NOTE : FILE This file contains the entities needed to -->
-<!-- LOCALIZATION NOTE : FILE use the Find Bar. --> 
-
-<!ENTITY next.tooltip "Find the next occurrence of the phrase">
-<!ENTITY previous.tooltip "Find the previous occurrence of the phrase">
-<!ENTITY findCloseButton.tooltip "Close find bar">
-<!ENTITY highlightAll.label "Highlight All">
-<!ENTITY highlightAll.accesskey "l">
-<!ENTITY highlightAll.tooltiptext "Highlight all occurrences of the phrase">
-<!ENTITY caseSensitive.label "Match Case">
-<!ENTITY caseSensitive.accesskey "c">
-<!ENTITY caseSensitive.tooltiptext "Search with case sensitivity">
-<!ENTITY entireWord.label "Whole Words">
-<!ENTITY entireWord.accesskey "w">
-<!ENTITY entireWord.tooltiptext "Search whole words only">
--- a/toolkit/locales/jar.mn
+++ b/toolkit/locales/jar.mn
@@ -40,17 +40,16 @@
   locale/@AB_CD@/global/dialogOverlay.dtd               (%chrome/global/dialogOverlay.dtd)
 #ifndef MOZ_FENNEC
   locale/@AB_CD@/global/editMenuOverlay.dtd             (%chrome/global/editMenuOverlay.dtd)
 #endif
   locale/@AB_CD@/global/extensions.properties           (%chrome/global/extensions.properties)
   locale/@AB_CD@/global/fallbackMenubar.properties      (%chrome/global/fallbackMenubar.properties)
   locale/@AB_CD@/global/filepicker.properties           (%chrome/global/filepicker.properties)
 #ifndef MOZ_FENNEC
-  locale/@AB_CD@/global/findbar.dtd                     (%chrome/global/findbar.dtd)
   locale/@AB_CD@/global/findbar.properties              (%chrome/global/findbar.properties)
 #endif
   locale/@AB_CD@/global/globalKeys.dtd                  (%chrome/global/globalKeys.dtd)
   locale/@AB_CD@/global/intl.css                        (%chrome/global/intl.css)
   locale/@AB_CD@/global/intl.properties                 (%chrome/global/intl.properties)
   locale/@AB_CD@/global/keys.properties                 (%chrome/global/keys.properties)
   locale/@AB_CD@/global/languageNames.properties        (%chrome/global/languageNames.properties)
   locale/@AB_CD@/global/mozilla.dtd                     (%chrome/global/mozilla.dtd)
--- a/toolkit/themes/linux/global/global.css
+++ b/toolkit/themes/linux/global/global.css
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* ===== global.css =====================================================
   == Styles that apply everywhere.
   ======================================================================= */
 
 /* all localizable skin settings shall live here */
 @import url("chrome://global/locale/intl.css");
+@import url("chrome://global/skin/findBar.css");
 
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
 
 /* ::::: XBL bindings ::::: */
 
 menulist > menupopup {
   -moz-binding: url("chrome://global/content/bindings/popup.xml#popup-scrollbars");
 }
--- a/toolkit/themes/osx/global/global.css
+++ b/toolkit/themes/osx/global/global.css
@@ -1,14 +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/. */
 
 /* all localizable skin settings shall live here */
 @import url("chrome://global/locale/intl.css");
+@import url("chrome://global/skin/findBar.css");
 
 %include shared.inc
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
 
 /* ::::: XBL bindings ::::: */
 
 menulist > menupopup {
   -moz-binding: url("chrome://global/content/bindings/popup.xml#popup-scrollbars");
--- a/toolkit/themes/windows/global/global.css
+++ b/toolkit/themes/windows/global/global.css
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* ===== global.css =====================================================
   == Styles that apply everywhere.
   ======================================================================= */
 
 /* all localizable skin settings shall live here */
 @import url("chrome://global/locale/intl.css");
+@import url("chrome://global/skin/findBar.css");
 
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
 
 /* ::::: XBL bindings ::::: */
 
 menulist > menupopup {
   -moz-binding: url("chrome://global/content/bindings/popup.xml#popup-scrollbars");
 }