Bug 1417119 - Remove xpfe autocomplete binding;r=paolo,r=frg draft
authorBrian Grinstead <bgrinstead@mozilla.com>
Mon, 27 Nov 2017 11:21:09 -0800
changeset 703785 c7fdf29766fe836af3e6517f148813d92ccadafe
parent 703363 4ce67352b2a9744ac51f0333cea0455e3d59bbf3
child 703789 6183342b3b0a6adf1568106d7534a7e8c046125f
push id90971
push userbgrinstead@mozilla.com
push dateMon, 27 Nov 2017 19:21:21 +0000
reviewerspaolo, frg
bugs1417119
milestone59.0a1
Bug 1417119 - Remove xpfe autocomplete binding;r=paolo,r=frg MozReview-Commit-ID: 6oDDVFetEBT
accessible/tests/mochitest/tree/test_combobox.xul
accessible/tests/mochitest/tree/test_txtctrl.xul
toolkit/content/tests/chrome/test_autocomplete_delayOnPaste.xul
toolkit/content/tests/chrome/test_autocomplete_placehold_last_complete.xul
toolkit/content/xul.css
xpfe/components/autocomplete/jar.mn
xpfe/components/autocomplete/moz.build
xpfe/components/autocomplete/resources/content/autocomplete.css
xpfe/components/autocomplete/resources/content/autocomplete.xml
--- a/accessible/tests/mochitest/tree/test_combobox.xul
+++ b/accessible/tests/mochitest/tree/test_combobox.xul
@@ -118,52 +118,19 @@
           {
             // xul:menupopup
             role: ROLE_COMBOBOX_LIST, // context menu popup
             children: []
           }
         ]
       };
 
-      // XPFE and Toolkit autocomplete widgets differ.
+      // Popup is lazily created, so not present in for toolkit autocomplete
       var ac1h = document.getElementById("autocomplete");
-      if ("clearResults" in ac1h) {
-        SimpleTest.ok(true, "Testing (Old) XPFE autocomplete widget. (ac1h)");
-
-        // Popup is always created.
-        accTree.children.push(
-          {
-            // xul:panel
-            role: ROLE_COMBOBOX_LIST,
-            children: [
-              {
-                // xul:tree
-                role: ROLE_TABLE,
-                children: [
-                  {
-                    // xul:treecols
-                    role: ROLE_LIST,
-                    children: [
-                      {
-                        // xul:treecol
-                        role: ROLE_COLUMNHEADER,
-                        children: []
-                      }
-                    ]
-                  }
-                ]
-              }
-            ]
-          }
-          );
-      } else {
-        SimpleTest.ok(true, "Testing (New) Toolkit autocomplete widget. (ac1h)");
-
-        // Popup is lazily created, so not present in this case.
-      }
+      SimpleTest.ok(ac1h, "Testing (New) Toolkit autocomplete widget. (ac1h)");
 
       testAccessibleTree("autocomplete", accTree);
 
       //////////////////////////////////////////////////////////////////////////
       // textbox@type=autocomplete #2 (child menupoup)
 
       accTree = {
         // textbox
@@ -190,52 +157,20 @@
           {
             // xul:menupopup
             role: ROLE_COMBOBOX_LIST, // context menu popup
             children: []
           }
         ]
       };
 
-      // XPFE and Toolkit autocomplete widgets differ.
+
+      // Popup is lazily created, so not present in for toolkit autocomplete
       var ac2cmp = document.getElementById("autocomplete2");
-      if ("clearResults" in ac2cmp) {
-        SimpleTest.ok(true, "Testing (Old) XPFE autocomplete widget. (ac2mp)");
-
-        // Popup is always created.
-        accTree.children.push(
-          {
-            // xul:panel
-            role: ROLE_COMBOBOX_LIST,
-            children: [
-              {
-                // xul:tree
-                role: ROLE_TABLE,
-                children: [
-                  {
-                    // xul:treecols
-                    role: ROLE_LIST,
-                    children: [
-                      {
-                        // xul:treecol
-                        role: ROLE_COLUMNHEADER,
-                        children: []
-                      }
-                    ]
-                  }
-                ]
-              }
-            ]
-          }
-          );
-      } else {
-        SimpleTest.ok(true, "Testing (New) Toolkit autocomplete widget. (ac2mp)");
-
-        // Popup is lazily created, so not present in this case.
-      }
+      SimpleTest.ok(ac2cmp, "Testing (New) Toolkit autocomplete widget. (ac2mp)");
 
       testAccessibleTree("autocomplete2", accTree);
 
       SimpleTest.finish()
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
--- a/accessible/tests/mochitest/tree/test_txtctrl.xul
+++ b/accessible/tests/mochitest/tree/test_txtctrl.xul
@@ -120,75 +120,40 @@
         ]
       };
 
       function test_AutocompleteControl() {
         testAccessibleTree("txc_autocomplete", accTree);
         SimpleTest.finish();
       }
 
-      // XPFE and Toolkit autocomplete widgets differ.
       var txc = document.getElementById("txc_autocomplete");
-      if ("clearResults" in txc) {
-        SimpleTest.ok(true, "Testing (Old) XPFE autocomplete widget.");
+      SimpleTest.ok(txc, "Testing (New) Toolkit autocomplete widget.");
 
-        // Popup is always created. (See code below.)
+      // Dumb access to trigger popup lazy creation.
+      dump("Trigget popup lazy creation");
+      waitForEvent(EVENT_REORDER, txc, test_AutocompleteControl);
+      txc.popup;
 
-        accTree.children.push(
-          {
-            // xul:panel
-            role: ROLE_COMBOBOX_LIST,
-            children: [
-              {
-                // xul:tree
-                role: ROLE_TABLE,
-                children: [
-                  {
-                    // xul:treecols
-                    role: ROLE_LIST,
-                    children: [
-                      {
-                        // xul:treecol
-                        role: ROLE_COLUMNHEADER,
-                        children: []
-                      }
-                    ]
-                  }
-                ]
-              }
-            ]
-          }
-        );
-        test_AutocompleteControl();
-
-      } else {
-        SimpleTest.ok(true, "Testing (New) Toolkit autocomplete widget.");
-
-        // Dumb access to trigger popup lazy creation.
-        dump("Trigget popup lazy creation");
-        waitForEvent(EVENT_REORDER, txc, test_AutocompleteControl);
-        txc.popup;
-
-        accTree.children.push(
-          {
-            role: ROLE_LIST,
-            children: [
-              {
-                role: ROLE_LIST,
-                children: [
-                  {
-                    role: ROLE_COLUMNHEADER,
-                    children: []
-                  }
-                ]
-              }
-            ]
-          }
-        );
-      }
+      accTree.children.push(
+        {
+          role: ROLE_LIST,
+          children: [
+            {
+              role: ROLE_LIST,
+              children: [
+                {
+                  role: ROLE_COLUMNHEADER,
+                  children: []
+                }
+              ]
+            }
+          ]
+        }
+      );
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   ]]>
   </script>
 
   <hbox flex="1" style="overflow: auto;">
--- a/toolkit/content/tests/chrome/test_autocomplete_delayOnPaste.xul
+++ b/toolkit/content/tests/chrome/test_autocomplete_delayOnPaste.xul
@@ -75,32 +75,31 @@ let autoCompleteSimple = {
     let result = new autoCompleteSimpleResult(aString);
     aListener.onSearchResult(this, result);
   },
   stopSearch: function () {}
 };
 
 SimpleTest.waitForExplicitFinish();
 
-// XPFE AutoComplete needs to register early.
-autoCompleteSimple.registerFactory();
-
 let gACTimer;
 let gAutoComplete;
 
 function searchComplete() {
   is(gAutoComplete.value, "result", "Value should be autocompleted now");
   ok(Date.now() - gACTimer  > 500, "There should be a delay before autocomplete");
 
   // Unregister the factory so that we don't get in the way of other tests
   autoCompleteSimple.unregisterFactory();
   SimpleTest.finish();
 }
 
 function runTest() {
+
+  autoCompleteSimple.registerFactory();
   gAutoComplete = $("autocomplete");
 
   const SEARCH_STRING = "res";
 
   function cbCallback() {
     gAutoComplete.focus();
     synthesizeKey("v", { accelKey: true });
     is(gAutoComplete.value, SEARCH_STRING, "Value should not be autocompleted immediately");
--- a/toolkit/content/tests/chrome/test_autocomplete_placehold_last_complete.xul
+++ b/toolkit/content/tests/chrome/test_autocomplete_placehold_last_complete.xul
@@ -101,32 +101,30 @@ let autoCompleteSimple = {
   },
   stopSearch: function () {
     clearTimeout(this.pendingSearch);
   }
 };
 
 SimpleTest.waitForExplicitFinish();
 
-// XPFE AutoComplete needs to register early.
-autoCompleteSimple.registerFactory();
-
 let gACTimer;
 let gAutoComplete;
 let asyncTest;
 
 let searchCompleteTimeoutId = null;
 
 function finishTest() {
   // Unregister the factory so that we don't get in the way of other tests
   autoCompleteSimple.unregisterFactory();
   SimpleTest.finish();
 }
 
 function runTest() {
+  autoCompleteSimple.registerFactory();
   gAutoComplete = $("autocomplete");
   gAutoComplete.focus();
 
   // Return the search results synchronous, which also makes the completion
   // happen synchronous.
   autoCompleteSimple.searchAsync = false;
 
   synthesizeKey("r", {});
--- a/toolkit/content/xul.css
+++ b/toolkit/content/xul.css
@@ -802,55 +802,18 @@ textbox[type="number"] {
 }
 
 .textbox-contextmenu:-moz-locale-dir(rtl) {
   direction: rtl;
 }
 
 /********** autocomplete textbox **********/
 
-/* SeaMonkey does not use the new toolkit's autocomplete widget */
-%ifdef MOZ_SUITE
-
-textbox[type="autocomplete"] {
-  -moz-binding: url("chrome://global/content/autocomplete.xml#autocomplete");
-}
-
-panel[type="autocomplete"] {
-  -moz-binding: url("chrome://global/content/autocomplete.xml#autocomplete-result-popup");
-}
-
-.autocomplete-history-popup {
-  -moz-binding: url("chrome://global/content/autocomplete.xml#autocomplete-history-popup");
-}
-
-.autocomplete-treebody {
-  -moz-binding: url("chrome://global/content/autocomplete.xml#autocomplete-treebody");
-}
-
-panel[type="autocomplete-richlistbox"] {
-  -moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete-rich-result-popup");
-}
-
-.autocomplete-richlistbox {
-  -moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete-richlistbox");
-  -moz-user-focus: ignore;
-}
-
-.autocomplete-richlistbox > scrollbox {
-  overflow-x: hidden !important;
-}
-
-.autocomplete-richlistitem {
-  -moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete-richlistitem");
-  -moz-box-orient: vertical;
-  overflow: -moz-hidden-unscrollable;
-}
-
-%else
+/* SeaMonkey uses its own autocomplete and the toolkit's autocomplete widget */
+%ifndef MOZ_SUITE
 
 textbox[type="autocomplete"] {
   -moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete");
 }
 
 panel[type="autocomplete"] {
   -moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete-result-popup");
 }
deleted file mode 100644
--- a/xpfe/components/autocomplete/jar.mn
+++ /dev/null
@@ -1,9 +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/.
-
-toolkit.jar:
-    content/global/autocomplete.xml                             (resources/content/autocomplete.xml)
-
-comm.jar:
-    content/communicator/autocomplete.css                       (resources/content/autocomplete.css)
deleted file mode 100644
--- a/xpfe/components/autocomplete/moz.build
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
-
-with Files("**"):
-    BUG_COMPONENT = ("SeaMonkey", "Autocomplete")
-
-JAR_MANIFESTS += ['jar.mn']
\ No newline at end of file
deleted file mode 100644
--- a/xpfe/components/autocomplete/resources/content/autocomplete.css
+++ /dev/null
@@ -1,46 +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/. */
-
-
-.autocomplete-result-popupset {
-  width: 0 !important;
-}
-
-.autocomplete-result-popup {
-  display: -moz-popup !important;
-}
-
-/* the C++ implementation of widgets is too eager to make popups visible.
-   this causes problems (bug 120155 and others), thus this workaround: */
-.autocomplete-result-popup[hidden="true"] {
-  visibility: hidden;
-}
-
-.autocomplete-tree {
-  -moz-user-focus: ignore;
-}
-
-.autocomplete-history-dropmarker {
-  display: none;
-}
-
-.autocomplete-history-dropmarker[enablehistory="true"] {
-  display: -moz-box;
-}
-
-/* The following rule is here to fix bug 96899 (and now 117952).  
-   Somehow trees create a situation
-   in which a popupset flows itself as if its popup child is directly within it
-   instead of the placeholder child that should actually be inside the popupset.
-   This is a stopgap measure, and it does not address the real bug.  */
-popupset {
-  max-width: 0px;
-  width: 0px;
-  min-width: 0%;
-  min-height: 0%;
-}
-
-treecolpicker {
-  display: none;
-}
deleted file mode 100644
--- a/xpfe/components/autocomplete/resources/content/autocomplete.xml
+++ /dev/null
@@ -1,1644 +0,0 @@
-<?xml version="1.0"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-
-<bindings id="autocompleteBindings"
-          xmlns="http://www.mozilla.org/xbl"
-          xmlns:html="http://www.w3.org/1999/xhtml"
-          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-          xmlns:xbl="http://www.mozilla.org/xbl">
-
-  <binding id="autocomplete" role="xul:combobox"
-           extends="chrome://global/content/bindings/textbox.xml#textbox">
-    <resources>
-      <stylesheet src="chrome://communicator/content/autocomplete.css"/>
-      <stylesheet src="chrome://global/skin/autocomplete.css"/>
-    </resources>
-
-    <content>
-      <children includes="menupopup"/>
-
-      <xul:hbox class="autocomplete-textbox-container" flex="1" align="center">
-        <children includes="image|deck|stack|box">
-          <xul:image class="autocomplete-icon" allowevents="true"/>
-        </children>
-
-        <xul:hbox class="textbox-input-box" flex="1" xbl:inherits="context,tooltiptext=inputtooltiptext">
-          <children/>
-          <html:input anonid="input" class="autocomplete-textbox textbox-input"
-                      allowevents="true"
-                      xbl:inherits="tooltiptext=inputtooltiptext,value,type,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey,mozactionhint,userAction"/>
-        </xul:hbox>
-        <children includes="hbox"/>
-      </xul:hbox>
-
-      <xul:dropmarker class="autocomplete-history-dropmarker" allowevents="true"
-                      xbl:inherits="open,enablehistory" anonid="historydropmarker"/>
-
-      <xul:popupset>
-        <xul:panel type="autocomplete" anonid="popup"
-                   ignorekeys="true" noautofocus="true" level="top"
-                   xbl:inherits="for=id,nomatch"/>
-      </xul:popupset>
-    </content>
-
-    <implementation implements="nsIDOMXULMenuListElement">
-
-      <constructor><![CDATA[
-        // XXX bug 90337 band-aid until we figure out what's going on here
-        if (this.value != this.mInputElt.value)
-          this.mInputElt.value = this.value;
-        delete this.value;
-
-        // listen for pastes
-        this.mInputElt.controllers.insertControllerAt(0, this.mPasteController);
-
-        // listen for menubar activation
-        window.top.addEventListener("DOMMenuBarActive", this.mMenuBarListener, true);
-
-        // set default property values
-        this.ifSetAttribute("timeout", 50);
-        this.ifSetAttribute("pastetimeout", 1000);
-        this.ifSetAttribute("maxrows", 5);
-        this.ifSetAttribute("showpopup", true);
-        this.ifSetAttribute("disableKeyNavigation", true);
-
-        // initialize the search sessions
-        if (this.hasAttribute("autocompletesearch"))
-          this.initAutoCompleteSearch();
-
-        // hack to work around lack of bottom-up constructor calling
-        if ("initialize" in this.popup)
-          this.popup.initialize();
-      ]]></constructor>
-
-      <destructor><![CDATA[
-        this.clearResults(false);
-        window.top.removeEventListener("DOMMenuBarActive", this.mMenuBarListener, true);
-        this.mInputElt.controllers.removeController(this.mPasteController);
-      ]]></destructor>
-
-      <!-- =================== nsIAutoCompleteInput =================== -->
-      <!-- XXX: This implementation is currently incomplete. -->
-
-      <!-- reference to the results popup element -->
-      <field name="popup"><![CDATA[
-        document.getAnonymousElementByAttribute(this, "anonid", "popup");
-      ]]></field>
-
-      <property name="popupOpen"
-                onget="return this.mMenuOpen;"
-                onset="if (val) this.openPopup(); else this.closePopup(); return val;"/>
-
-      <!-- option to turn off autocomplete -->
-      <property name="disableAutoComplete"
-                onset="this.setAttribute('disableautocomplete', val); return val;"
-                onget="return this.getAttribute('disableautocomplete') == 'true';"/>
-
-      <!-- if the resulting match string is not at the beginning of the typed string,
-           this will optionally autofill like this "bar |>> foobar|" -->
-      <property name="completeDefaultIndex"
-                onset="this.setAttribute('completedefaultindex', val); return val;"
-                onget="return this.getAttribute('completedefaultindex') == 'true';"/>
-
-      <!-- option for completing to the default result whenever the user hits
-           enter or the textbox loses focus -->
-      <property name="forceComplete"
-                onset="this.setAttribute('forcecomplete', val); return val;"
-                onget="return this.getAttribute('forcecomplete') == 'true';"/>
-
-      <property name="minResultsForPopup"
-                onset="this.setAttribute('minresultsforpopup', val); return val;"
-                onget="var t = this.getAttribute('minresultsforpopup'); return t ? parseInt(t) : 1;"/>
-
-      <!-- maximum number of rows to display -->
-      <property name="maxRows"
-                onset="this.setAttribute('maxrows', val); return val;"
-                onget="return parseInt(this.getAttribute('maxrows')) || 0;"/>
-
-      <!-- toggles a second column in the results list which contains
-           the string in the comment field of each autocomplete result -->
-      <property name="showCommentColumn"
-                onget="return this.getAttribute('showcommentcolumn') == 'true';">
-        <setter><![CDATA[
-          this.popup.showCommentColumn = val;
-          this.setAttribute('showcommentcolumn', val);
-          return val;
-        ]]></setter>
-      </property>
-
-      <!-- number of milliseconds after a keystroke before a search begins -->
-      <property name="timeout"
-                onset="this.setAttribute('timeout', val); return val;"
-                onget="return parseInt(this.getAttribute('timeout')) || 0;"/>
-
-      <property name="searchParam"
-                onget="return this.getAttribute('autocompletesearchparam') || '';"
-                onset="this.setAttribute('autocompletesearchparam', val); return val;"/>
-
-      <property name="searchCount" readonly="true"
-                onget="return this.sessionCount;"/>
-
-      <method name="getSearchAt">
-        <parameter name="aIndex"/>
-        <body><![CDATA[
-          var idx = -1;
-          for (var name in this.mSessions)
-            if (++idx == aIndex)
-              return name;
-
-          return null;
-        ]]></body>
-      </method>
-
-      <property name="textValue"
-                onget="return this.value;"
-                onset="this.setTextValue(val); return val;"/>
-
-      <method name="onSearchBegin">
-        <body><![CDATA[
-          this._fireEvent("searchbegin");
-        ]]></body>
-      </method>
-
-      <method name="onSearchComplete">
-        <body><![CDATA[
-          if (this.noMatch)
-            this.setAttribute("nomatch", "true");
-          else
-            this.removeAttribute("nomatch");
-
-          this._fireEvent("searchcomplete");
-        ]]></body>
-      </method>
-
-      <method name="onTextReverted">
-        <body><![CDATA[
-          return this._fireEvent("textreverted");
-        ]]></body>
-      </method>
-
-      <!-- =================== nsIDOMXULMenuListElement =================== -->
-
-      <property name="editable" readonly="true"
-                onget="return true;" />
-
-      <property name="crop"
-                onset="this.setAttribute('crop', val); return val;"
-                onget="return this.getAttribute('crop');"/>
-
-      <property name="label" readonly="true"
-                onget="return this.mInputElt.value;"/>
-
-      <property name="open"
-                onget="return this.getAttribute('open') == 'true';">
-        <setter>
-          <![CDATA[
-            var historyPopup = document.getAnonymousElementByAttribute(this, "anonid", "historydropmarker");
-            if (val) {
-              this.setAttribute('open', true);
-              historyPopup.showPopup();
-            } else {
-              this.removeAttribute('open');
-              historyPopup.hidePopup();
-            }
-          ]]>
-        </setter>
-      </property>
-
-      <!-- =================== PUBLIC PROPERTIES =================== -->
-
-      <property name="value"
-                onget="return this.mInputElt.value;">
-        <setter><![CDATA[
-          this.ignoreInputEvent = true;
-          this.mInputElt.value = val;
-          this.ignoreInputEvent = false;
-          var event = document.createEvent('Events');
-          event.initEvent('ValueChange', true, true);
-          this.mInputElt.dispatchEvent(event);
-          return val;
-        ]]></setter>
-      </property>
-
-      <property name="focused"
-                onget="return this.getAttribute('focused') == 'true';"/>
-
-      <method name="initAutoCompleteSearch">
-        <body><![CDATA[
-          var list = this.getAttribute("autocompletesearch").split(" ");
-          for (var i = 0; i < list.length; i++) {
-            var name = list[i];
-            var contractid = "@mozilla.org/autocomplete/search;1?name=" + name;
-            if (contractid in Components.classes) {
-              try {
-                this.mSessions[name] =
-                  Components.classes[contractid].getService(Components.interfaces.nsIAutoCompleteSearch);
-                this.mLastResults[name] = null;
-                this.mLastRows[name] = 0;
-                ++this.sessionCount;
-              } catch (e) {
-                dump("### ERROR - unable to create search \"" + name + "\".\n");
-              }
-            } else {
-              dump("search \"" + name + "\" not found - skipping.\n");
-            }
-          }
-        ]]></body>
-      </method>
-
-      <!-- the number of sessions currently in use -->
-      <field name="sessionCount">0</field>
-
-      <!-- number of milliseconds after a paste before a search begins -->
-      <property name="pasteTimeout"
-                onset="this.setAttribute('pastetimeout', val); return val;"
-                onget="var t = parseInt(this.getAttribute('pastetimeout')); return t ? t : 0;"/>
-
-      <!-- option for filling the textbox with the best match while typing
-           and selecting the difference -->
-      <property name="autoFill"
-                onset="this.setAttribute('autofill', val); return val;"
-                onget="return this.getAttribute('autofill') == 'true';"/>
-
-      <!--  if this attribute is set, allow different style for
-            non auto-completed lines -->
-      <property name="highlightNonMatches"
-                onset="this.setAttribute('highlightnonmatches', val); return val;"
-                onget="return this.getAttribute('highlightnonmatches') == 'true';"/>
-
-      <!-- option to show the popup containing the results -->
-      <property name="showPopup"
-                onset="this.setAttribute('showpopup', val); return val;"
-                onget="return this.getAttribute('showpopup') == 'true';"/>
-
-      <!-- option to allow scrolling through the list via the tab key, rather than
-           tab moving focus out of the textbox -->
-      <property name="tabScrolling"
-                onset="this.setAttribute('tabscrolling', val); return val;"
-                onget="return this.getAttribute('tabscrolling') == 'true';"/>
-
-      <!-- option to completely ignore any blur events while
-           searches are still going on.  This is useful so that nothing
-           gets autopicked if the window is required to lose focus for
-           some reason (eg in LDAP autocomplete, another window may be
-           brought up so that the user can enter a password to authenticate
-           to an LDAP server).  -->
-      <property name="ignoreBlurWhileSearching"
-                onset="this.setAttribute('ignoreblurwhilesearching', val); return val;"
-                onget="return this.getAttribute('ignoreblurwhilesearching') == 'true';"/>
-
-      <!-- state which indicates the current action being performed by the user.
-           Possible values are : none, typing, scrolling -->
-      <property name="userAction"
-                onset="this.setAttribute('userAction', val); return val;"
-                onget="return this.getAttribute('userAction');"/>
-
-      <!-- state which indicates if the last search had no matches -->
-      <field name="noMatch">true</field>
-
-      <!-- state which indicates a search is currently happening -->
-      <field name="isSearching">false</field>
-
-      <!-- state which indicates a search timeout is current waiting -->
-      <property name="isWaiting" 
-                onget="return this.mAutoCompleteTimer != 0;"/>
-
-      <!-- =================== PRIVATE PROPERTIES =================== -->
-
-      <field name="mSessions">({})</field>
-      <field name="mLastResults">({})</field>
-      <field name="mLastRows">({})</field>
-      <field name="mLastKeyCode">null</field>
-      <field name="mAutoCompleteTimer">0</field>
-      <field name="mMenuOpen">false</field>
-      <field name="mFireAfterSearch">false</field>
-      <field name="mFinishAfterSearch">false</field>
-      <field name="mNeedToFinish">false</field>
-      <field name="mNeedToComplete">false</field>
-      <field name="mTransientValue">false</field>
-      <field name="mView">null</field>
-      <field name="currentSearchString">""</field>
-      <field name="ignoreInputEvent">false</field>
-      <field name="oninit">null</field>
-      <field name="mDefaultMatchFilled">false</field>
-      <field name="mFirstReturn">true</field>
-      <field name="mIsPasting">false</field>
-
-      <field name="mPasteController"><![CDATA[
-        ({
-          self: this,
-          kGlobalClipboard: Components.interfaces.nsIClipboard.kGlobalClipboard,
-          supportsCommand: function(aCommand) {
-            return aCommand == "cmd_paste";
-          },
-          isCommandEnabled: function(aCommand) {
-            return aCommand == "cmd_paste" &&
-                   this.self.editor.isSelectionEditable &&
-                   this.self.editor.canPaste(this.kGlobalClipboard);
-          },
-          doCommand: function(aCommand) {
-            if (aCommand == "cmd_paste") {
-              this.self.mIsPasting = true;
-              this.self.editor.paste(this.kGlobalClipboard);
-              this.self.mIsPasting = false;
-            }
-          },
-          onEvent: function() {}
-        })
-      ]]></field>
-
-      <field name="mMenuBarListener"><![CDATA[
-        ({
-          self: this,
-          handleEvent: function(aEvent) {
-            try {
-              this.self.finishAutoComplete(false, false, aEvent);
-              this.self.clearTimer();
-              this.self.closePopup();
-            } catch (e) {
-              window.top.removeEventListener("DOMMenuBarActive", this, true);
-            }
-          }
-        })
-      ]]></field>
-
-      <field name="mAutoCompleteObserver"><![CDATA[
-        ({
-          self: this,
-          onSearchResult: function(aSearch, aResult) {
-            for (var name in this.self.mSessions)
-              if (this.self.mSessions[name] == aSearch)
-                this.self.processResults(name, aResult);
-          }
-        })
-      ]]></field>
-
-      <field name="mInputElt"><![CDATA[
-        document.getAnonymousElementByAttribute(this, "anonid", "input");
-      ]]></field>
-
-      <field name="mMenuAccessKey"><![CDATA[
-        Components.classes["@mozilla.org/preferences-service;1"]
-                 .getService(Components.interfaces.nsIPrefBranch)
-                 .getIntPref("ui.key.menuAccessKey");
-      ]]></field>
-
-      <!-- =================== PUBLIC METHODS =================== -->
-
-      <method name="getErrorAt">
-        <parameter name="aIndex"/>
-        <body><![CDATA[
-          var obj = aIndex < 0 ? null : this.convertIndexToSession(aIndex);
-          return obj && this.mLastResults[obj.session] &&
-                        this.mLastResults[obj.session].errorDescription;
-        ]]></body>
-      </method>
-
-      <!-- get a value from the autocomplete results as a string via an absolute index-->
-      <method name="getResultValueAt">
-        <parameter name="aIndex"/>
-        <body><![CDATA[
-          var obj = this.convertIndexToSession(aIndex);
-          return obj ? this.getSessionValueAt(obj.session, obj.index) : null;
-        ]]></body>
-      </method>
-
-      <!-- get a value from the autocomplete results as a string from a specific session -->
-      <method name="getSessionValueAt">
-        <parameter name="aSession"/>
-        <parameter name="aIndex"/>
-        <body><![CDATA[
-          var result = this.mLastResults[aSession];
-          return result.errorDescription || result.getValueAt(aIndex);
-        ]]></body>
-      </method>
-
-      <!-- get the total number of results overall -->
-      <method name="getResultCount">
-        <body><![CDATA[
-          return this.view.rowCount;
-        ]]></body>
-      </method>
-
-      <!-- get the first session that has results -->
-      <method name="getDefaultSession">
-        <body><![CDATA[
-          for (var name in this.mLastResults) {
-            var results = this.mLastResults[name];
-            if (results && results.matchCount > 0 && !results.errorDescription)
-              return name;
-          }
-          return null;
-        ]]></body>
-      </method>
-
-      <!-- empty the cached result data and empty the results popup -->
-      <method name="clearResults">
-        <parameter name="aInvalidate"/>
-        <body><![CDATA[
-          this.clearResultData();
-          this.clearResultElements(aInvalidate);
-        ]]></body>
-      </method>
-
-      <!-- =================== PRIVATE METHODS =================== -->
-
-      <!-- ::::::::::::: session searching ::::::::::::: -->
-
-      <!--  -->
-      <method name="callListener">
-        <parameter name="me"/>
-        <parameter name="aAction"/>
-        <body><![CDATA[
-          // bail if the binding was detached or the element removed from
-          // document during the timeout
-          if (!("startLookup" in me) || !me.ownerDocument || !me.parentNode)
-            return;
-
-          me.clearTimer();
-
-          if (me.disableAutoComplete)
-            return;
-
-          switch (aAction) {
-            case "startLookup":
-              me.startLookup();
-              break;
-
-            case "stopLookup":
-              me.stopLookup();
-              break;
-          }
-        ]]></body>
-      </method>
-
-      <!--  -->
-      <method name="startLookup">
-        <body><![CDATA[
-          var str = this.currentSearchString;
-          if (!str) {
-            this.clearResults(false);
-            this.closePopup();
-            return;
-          }
-
-          this.isSearching = true;
-          this.mFirstReturn = true;
-          this.mSessionReturns = this.sessionCount;
-          this.mFailureItems = 0;
-          this.mDefaultMatchFilled = false; // clear out our prefill state.
-
-          // Notify the input that the search is beginning.
-          this.onSearchBegin();
-
-          // tell each session to start searching...
-          for (var name in this.mSessions)
-            try {
-              this.mSessions[name].startSearch(str, this.searchParam, this.mLastResults[name], this.mAutoCompleteObserver);
-            } catch (e) {
-              --this.mSessionReturns;
-              this.searchFailed();
-            }
-        ]]></body>
-      </method>
-
-      <!--  -->
-      <method name="stopLookup">
-        <body><![CDATA[
-          for (var name in this.mSessions)
-            this.mSessions[name].stopSearch();
-        ]]></body>
-      </method>
-
-      <!--  -->
-      <method name="processResults">
-        <parameter name="aSessionName"/>
-        <parameter name="aResults"/>
-        <body><![CDATA[
-          if (this.disableAutoComplete)
-            return;
-
-          const ACR = Components.interfaces.nsIAutoCompleteResult;
-          var status = aResults.searchResult;
-          if (status != ACR.RESULT_NOMATCH_ONGOING &&
-              status != ACR.RESULT_SUCCESS_ONGOING)
-            --this.mSessionReturns;
-
-          // check the many criteria for failure
-          if (aResults.errorDescription)
-            ++this.mFailureItems;
-          else if (status == ACR.RESULT_IGNORED ||
-                   status == ACR.RESULT_FAILURE ||
-                   status == ACR.RESULT_NOMATCH ||
-                   status == ACR.RESULT_NOMATCH_ONGOING ||
-                   aResults.matchCount == 0 ||
-                   aResults.searchString != this.currentSearchString)
-          {
-            this.mLastResults[aSessionName] = null;
-            if (this.mFirstReturn)
-              this.clearResultElements(false);
-            this.mFirstReturn = false;
-            this.searchFailed();
-            return;
-          }
-
-          if (this.mFirstReturn) {
-            if (this.view.mTree)
-              this.view.mTree.beginUpdateBatch();
-            this.clearResultElements(false); // clear results, but don't repaint yet
-          }
-
-          // always call openPopup...we may not have opened it
-          // if a previous search session didn't return enough search results.
-          // it's smart and doesn't try to open itself multiple times...
-          // be sure to add our result elements before calling openPopup as we need
-          // to know the total # of results found so far.
-          this.addResultElements(aSessionName, aResults);
-
-          this.autoFillInput(aSessionName, aResults, false);
-          if (this.mFirstReturn && this.view.mTree)
-            this.view.mTree.endUpdateBatch();
-          this.openPopup();
-          this.mFirstReturn = false;
-
-          // if this is the last session to return...
-          if (this.mSessionReturns == 0) 
-            this.postSearchCleanup();
-
-          if (this.mFinishAfterSearch)
-            this.finishAutoComplete(false, this.mFireAfterSearch, null);
-        ]]></body>
-      </method>
-
-      <!-- called each time a search fails, except when failure items need
-           to be displayed. If all searches have failed, clear the list
-           and close the popup -->
-      <method name="searchFailed">
-        <body><![CDATA[
-          // if all searches are done and they all failed...
-          if (this.mSessionReturns == 0 && this.getResultCount() == 0) {
-            if (this.minResultsForPopup == 0) {
-              this.clearResults(true); // clear data and repaint empty
-              this.openPopup();
-            } else {
-              this.closePopup(); 
-            }
-          }
-
-          // if it's the last session to return, time to clean up...
-          if (this.mSessionReturns == 0)
-            this.postSearchCleanup();
-        ]]></body>
-      </method>
-
-      <!-- does some stuff after a search is done (success or failure) -->
-      <method name="postSearchCleanup">
-        <body><![CDATA[
-          this.isSearching = false;
-
-          // figure out if there are no matches in all search sessions
-          var failed = true;
-          for (var name in this.mSessions) {
-            if (this.mLastResults[name])
-              failed = this.mLastResults[name].errorDescription ||
-                       this.mLastResults[name].matchCount == 0;
-            if (!failed)
-              break;
-          }
-          this.noMatch = failed;
-
-          // if we have processed all of our searches, and none of them gave us a default index,
-          // then we should try to auto fill the input field with the first match.
-          // note: autoFillInput is smart enough to kick out if we've already prefilled something...
-          if (!this.noMatch) {
-             var defaultSession = this.getDefaultSession();
-             if (defaultSession)
-                this.autoFillInput(defaultSession, this.mLastResults[defaultSession], true);         
-          }
-
-          // Notify the input that the search is complete.
-          this.onSearchComplete();
-        ]]></body>
-      </method>
-
-      <!-- when the focus exits the widget or user hits return,
-           determine what value to leave in the textbox -->
-      <method name="finishAutoComplete">
-        <parameter name="aForceComplete"/>
-        <parameter name="aFireTextCommand"/>
-        <parameter name="aTriggeringEvent"/>
-        <body><![CDATA[
-          this.mFinishAfterSearch = false;
-          this.mFireAfterSearch = false;
-          if (this.mNeedToFinish && !this.disableAutoComplete) {
-            // set textbox value to either override value, or default search result
-            var val = this.popup.overrideValue;
-            if (val) {
-              this.setTextValue(val);
-              this.mNeedToFinish = false;
-            } else if (this.mTransientValue || 
-                       !(this.forceComplete ||
-                        (aForceComplete &&
-                         this.mDefaultMatchFilled &&
-                         this.mNeedToComplete))) {
-              this.mNeedToFinish = false;
-            } else if (this.isWaiting) {
-              // if the user typed, the search results are out of date, so let
-              // the search finish, and tell it to come back here when it's done
-              this.mFinishAfterSearch = true;
-              this.mFireAfterSearch = aFireTextCommand;
-              return;
-            } else {
-              // we want to use the default item index for the first session which gave us a valid
-              // default item index...
-              for (var name in this.mLastResults) {
-                var results = this.mLastResults[name];
-                if (results && results.matchCount > 0 &&
-                    !results.errorDescription && results.defaultIndex != -1)
-                {
-                  val = results.getValueAt(results.defaultIndex);
-                  this.setTextValue(val);
-                  this.mDefaultMatchFilled = true;
-                  this.mNeedToFinish = false;
-                  break;
-                }
-              }
-
-              if (this.mNeedToFinish) {
-                // if a search is happening at this juncture, bail out of this function
-                // and let the search finish, and tell it to come back here when it's done
-                if (this.isSearching) {
-                  this.mFinishAfterSearch = true;
-                  this.mFireAfterSearch = aFireTextCommand;
-                  return;
-                }
-
-                this.mNeedToFinish = false;
-                var defaultSession = this.getDefaultSession();
-                if (defaultSession)
-                {
-                    // preselect the first one
-                    var first = this.getSessionValueAt(defaultSession, 0);
-                    this.setTextValue(first);
-                    this.mDefaultMatchFilled = true;
-                }
-              }
-            }
-
-            this.stopLookup();
-
-            this.closePopup();
-          }
-
-          this.mNeedToComplete = false;
-          this.clearTimer();
-
-          if (aFireTextCommand)
-            this._fireEvent("textentered", this.userAction, aTriggeringEvent);
-        ]]></body>
-      </method>
-
-      <!--  when the user clicks an entry in the autocomplete popup -->
-      <method name="onResultClick">
-        <body><![CDATA[
-         // set textbox value to either override value, or the clicked result
-          var errItem = this.getErrorAt(this.popup.selectedIndex);
-          var val = this.popup.overrideValue;
-            if (val)
-              this.setTextValue(val);
-          else if (this.popup.selectedIndex != -1) {
-            if (errItem) {
-              this.setTextValue(this.currentSearchString);
-              this.mTransientValue = true;
-            } else { 
-              this.setTextValue(this.getResultValueAt(
-                                             this.popup.selectedIndex));
-            }
-          }
-
-          this.mNeedToFinish = false;
-          this.mNeedToComplete = false;
-
-          this.closePopup();
-
-          this.currentSearchString = "";
-
-          if (errItem)
-            this._fireEvent("errorcommand", errItem);
-          this._fireEvent("textentered", "clicking");
-        ]]></body>
-      </method>
-
-      <!-- when the user hits escape, revert the previously typed value in the textbox -->
-      <method name="undoAutoComplete">
-        <body><![CDATA[
-          var val = this.currentSearchString;
-
-          var ok = this.onTextReverted();
-          if ((ok || ok == undefined) && val)
-            this.setTextValue(val);
-
-          this.userAction = "typing";
-
-          this.currentSearchString = this.value;
-          this.mNeedToComplete = false;
-        ]]></body>
-      </method>
-
-      <!-- convert an absolute result index into a session name/index pair -->
-      <method name="convertIndexToSession">
-        <parameter name="aIndex"/>
-        <body><![CDATA[
-          for (var name in this.mLastRows) {
-            if (aIndex < this.mLastRows[name])
-              return { session: name, index: aIndex };
-            aIndex -= this.mLastRows[name];
-          }
-          return null;
-        ]]></body>
-      </method>
-
-      <!-- ::::::::::::: user input handling ::::::::::::: -->
-
-      <!--  -->
-      <method name="processInput">
-        <body><![CDATA[
-          // stop current lookup in case it's async.
-          this.stopLookup();
-          // stop the queued up lookup on a timer
-          this.clearTimer();
-
-          if (this.disableAutoComplete)
-            return;
-
-          this.userAction = "typing";
-          this.mFinishAfterSearch = false;
-          this.mNeedToFinish = true;
-          this.mTransientValue = false;
-          this.mNeedToComplete = true;
-          var str = this.value;
-          this.currentSearchString = str;
-          this.popup.clearSelection();
-
-          var timeout = this.mIsPasting ? this.pasteTimeout : this.timeout;
-          this.mAutoCompleteTimer = setTimeout(this.callListener, timeout, this, "startLookup");
-        ]]></body>
-      </method>
-
-      <!--  -->
-      <method name="processKeyPress">
-        <parameter name="aEvent"/>
-        <body><![CDATA[
-          this.mLastKeyCode = aEvent.keyCode;
-
-          var killEvent = false;
-
-          switch (aEvent.keyCode) {
-            case KeyEvent.DOM_VK_TAB:
-              if (this.tabScrolling) {
-                // don't kill this event if alt-tab or ctrl-tab is hit
-                if (!aEvent.altKey && !aEvent.ctrlKey) {
-                  killEvent = this.mMenuOpen;
-                  if (killEvent)
-                    this.keyNavigation(aEvent);
-                }
-              } 
-              break;              
-
-            case KeyEvent.DOM_VK_RETURN:
-
-              // if this is a failure item, save it for fireErrorCommand
-              var errItem = this.getErrorAt(this.popup.selectedIndex);
-
-              killEvent = this.mMenuOpen;
-              this.finishAutoComplete(true, true, aEvent);
-              this.closePopup();
-              if (errItem) {
-                  this._fireEvent("errorcommand", errItem);
-              }
-              break;
-
-            case KeyEvent.DOM_VK_ESCAPE:
-              this.clearTimer();
-              killEvent = this.mMenuOpen;
-              this.undoAutoComplete();
-              this.closePopup();
-              break;
-
-            case KeyEvent.DOM_VK_LEFT:
-            case KeyEvent.DOM_VK_RIGHT:
-            case KeyEvent.DOM_VK_HOME:
-            case KeyEvent.DOM_VK_END:
-              this.finishAutoComplete(true, false, aEvent);
-              this.clearTimer();
-              this.closePopup();
-              break;
-
-            case KeyEvent.DOM_VK_DOWN:
-              if (!aEvent.altKey) {
-                this.clearTimer();
-                killEvent = this.keyNavigation(aEvent);
-                break;
-              }
-            // Alt+Down falls through to history popup toggling code
-
-            case KeyEvent.DOM_VK_F4:
-              if (!aEvent.ctrlKey && !aEvent.shiftKey && this.getAttribute("enablehistory") == "true") {
-                var historyPopup = document.getAnonymousElementByAttribute(this, "anonid", "historydropmarker");
-                if (historyPopup)
-                  historyPopup.showPopup();
-                else
-                  historyPopup.hidePopup();
-              }
-              break;
-            case KeyEvent.DOM_VK_PAGE_UP:
-            case KeyEvent.DOM_VK_PAGE_DOWN:
-            case KeyEvent.DOM_VK_UP:
-              if (!aEvent.ctrlKey && !aEvent.metaKey) {
-                this.clearTimer();
-                killEvent = this.keyNavigation(aEvent);
-              }
-              break;
-
-            case KeyEvent.DOM_VK_BACK_SPACE:
-              if (!aEvent.ctrlKey && !aEvent.altKey && !aEvent.shiftKey &&
-                  this.selectionStart == this.currentSearchString.length &&
-                  this.selectionEnd == this.value.length &&
-                  this.mDefaultMatchFilled) {
-                this.mDefaultMatchFilled = false;
-                this.value = this.currentSearchString;
-              }
-
-              if (!/Mac/.test(navigator.platform))
-                break;
-            case KeyEvent.DOM_VK_DELETE:
-              if (/Mac/.test(navigator.platform) && !aEvent.shiftKey)
-                break;
-
-              if (this.mMenuOpen && this.popup.selectedIndex != -1) {
-                var obj = this.convertIndexToSession(this.popup.selectedIndex);
-                if (obj) {
-                  var result = this.mLastResults[obj.session];
-                  if (!result.errorDescription) {
-                    var count = result.matchCount;
-                    result.removeValueAt(obj.index, true);
-                    this.view.updateResults(this.popup.selectedIndex, result.matchCount - count);
-                    killEvent = true;
-                  }
-                }
-              }
-              break;
-          }
-
-          if (killEvent) {
-            aEvent.preventDefault();
-            aEvent.stopPropagation();
-          }
-
-          return true;
-        ]]></body>
-      </method>
-
-      <!--  -->
-      <method name="processStartComposition">
-        <body><![CDATA[
-          this.finishAutoComplete(false, false, null);
-          this.clearTimer();
-          this.closePopup();
-        ]]></body>
-      </method>
-
-      <!--  -->
-      <method name="keyNavigation">
-        <parameter name="aEvent"/>
-        <body><![CDATA[
-          var k = aEvent.keyCode;
-          if (k == KeyEvent.DOM_VK_TAB ||
-              k == KeyEvent.DOM_VK_UP || k == KeyEvent.DOM_VK_DOWN ||
-              k == KeyEvent.DOM_VK_PAGE_UP || k == KeyEvent.DOM_VK_PAGE_DOWN)
-          {
-            if (!this.mMenuOpen) {
-              // Original xpfe style was to allow the up and down keys to have
-              // their default Mac action if the popup could not be opened.
-              // For compatibility for toolkit we now have to predict which
-              // keys have a default action that we can always allow to fire.
-              if (/Mac/.test(navigator.platform) &&
-                  ((k == KeyEvent.DOM_VK_UP &&
-                   (this.selectionStart != 0 ||
-                    this.selectionEnd != 0)) ||
-                  (k == KeyEvent.DOM_VK_DOWN &&
-                   (this.selectionStart != this.value.length ||
-                    this.selectionEnd != this.value.length))))
-                return false;
-              if (this.currentSearchString != this.value) {
-                 this.processInput();
-                 return true;
-              }
-              if (this.view.rowCount < this.minResultsForPopup)
-                return true; // used to be false, see above
-
-              this.mNeedToFinish = true;
-              this.openPopup();
-              return true;
-            }
-
-            this.userAction = "scrolling";
-            this.mNeedToComplete = false;
-
-            var reverse = k == KeyEvent.DOM_VK_TAB && aEvent.shiftKey ||
-                          k == KeyEvent.DOM_VK_UP ||
-                          k == KeyEvent.DOM_VK_PAGE_UP;
-            var page = k == KeyEvent.DOM_VK_PAGE_UP ||
-                       k == KeyEvent.DOM_VK_PAGE_DOWN;
-            var selected = this.popup.selectBy(reverse, page);
-
-            // determine which value to place in the textbox
-            this.ignoreInputEvent = true;
-            if (selected != -1) {
-              if (this.getErrorAt(selected)) {
-                if (this.currentSearchString)
-                  this.setTextValue(this.currentSearchString);
-              } else {
-                this.setTextValue(this.getResultValueAt(selected));
-              }
-              this.mTransientValue = true;
-            } else {
-              if (this.currentSearchString)
-                this.setTextValue(this.currentSearchString);
-              this.mTransientValue = false;
-            }
-
-            // move cursor to the end
-            this.mInputElt.setSelectionRange(this.value.length, this.value.length);
-            this.ignoreInputEvent = false;
-          }
-          return true;
-        ]]></body>
-      </method>
-
-      <!-- while the user is typing, fill the textbox with the "default" value
-           if one can be assumed, and select the end of the text -->
-      <method name="autoFillInput">
-        <parameter name="aSessionName"/>
-        <parameter name="aResults"/>
-        <parameter name="aUseFirstMatchIfNoDefault"/>
-        <body><![CDATA[
-          if (this.mInputElt.selectionEnd < this.currentSearchString.length ||
-              this.mDefaultMatchFilled)
-            return;
-
-          if (!this.mFinishAfterSearch &&
-              (this.autoFill || this.completeDefaultIndex) && 
-              this.mLastKeyCode != KeyEvent.DOM_VK_BACK_SPACE &&
-              this.mLastKeyCode != KeyEvent.DOM_VK_DELETE) {
-            var indexToUse = aResults.defaultIndex;
-            if (aUseFirstMatchIfNoDefault && indexToUse == -1)
-              indexToUse = 0; 
-
-            if (indexToUse != -1) {
-              var resultValue = this.getSessionValueAt(aSessionName, indexToUse);
-              var match = resultValue.toLowerCase();
-              var entry = this.currentSearchString.toLowerCase();
-              this.ignoreInputEvent = true;
-              if (match.indexOf(entry) == 0) {
-                var endPoint = this.value.length;
-                this.setTextValue(this.value + resultValue.substr(endPoint));
-                this.mInputElt.setSelectionRange(endPoint, this.value.length);
-              } else {
-                if (this.completeDefaultIndex) {
-                  this.setTextValue(this.value + " >> " + resultValue);
-                  this.mInputElt.setSelectionRange(entry.length, this.value.length);
-                } else {
-                  var postIndex = resultValue.indexOf(this.value);
-                  if (postIndex >= 0) {
-                    var startPt = this.value.length;
-                    this.setTextValue(this.value + 
-                                      resultValue.substr(startPt+postIndex));
-                    this.mInputElt.setSelectionRange(startPt, this.value.length);
-                  }
-                }
-              }
-              this.mNeedToComplete = true;
-              this.ignoreInputEvent = false;
-              this.mDefaultMatchFilled = true;
-            }
-          } 
-        ]]></body>
-      </method>
-
-      <!-- ::::::::::::: popup and tree ::::::::::::: -->
-
-      <!--  -->
-      <method name="openPopup">
-        <body><![CDATA[
-          if (!this.mMenuOpen && this.focused &&
-              (this.getResultCount() >= this.minResultsForPopup ||
-               this.mFailureItems)) {
-            var w = this.boxObject.width;
-            if (w != this.popup.boxObject.width)
-              this.popup.setAttribute("width", w);
-            this.popup.showPopup(this, -1, -1, "popup", "bottomleft", "topleft");
-            this.mMenuOpen = true;
-          }
-        ]]></body>
-      </method>
-
-      <!--  -->
-      <method name="closePopup">
-        <body><![CDATA[
-          if (this.popup && this.mMenuOpen) {
-            this.popup.hidePopup();
-            this.mMenuOpen = false;
-          }
-        ]]></body>
-      </method>
-
-      <!--  -->
-      <method name="addResultElements">
-        <parameter name="aSession"/>
-        <parameter name="aResults"/>
-        <body><![CDATA[
-          var count = aResults.errorDescription ? 1 : aResults.matchCount;
-          if (this.focused && this.showPopup) {
-            var row = 0;
-            for (var name in this.mSessions) {
-              row += this.mLastRows[name];
-              if (name == aSession)
-                break;
-            }
-            this.view.updateResults(row, count - this.mLastRows[name]);
-            this.popup.adjustHeight();
-          }
-          this.mLastResults[aSession] = aResults;
-          this.mLastRows[aSession] = count;
-        ]]></body>
-      </method>
-
-      <!--  -->
-      <method name="clearResultElements">
-        <parameter name="aInvalidate"/>
-        <body><![CDATA[
-          for (var name in this.mSessions)
-            this.mLastRows[name] = 0;
-          this.view.clearResults();
-          if (aInvalidate)
-            this.popup.adjustHeight();
-
-          this.noMatch = true;
-        ]]></body>
-      </method>
-
-      <!--  -->
-      <method name="setTextValue">
-        <parameter name="aValue"/>
-        <body><![CDATA[
-          this.value = aValue;
-
-          // Completing a result should simulate the user typing the result,
-          // so fire an input event.
-          var evt = document.createEvent("UIEvents");
-          evt.initUIEvent("input", true, false, window, 0);
-          var oldIgnoreInput = this.ignoreInputEvent;
-          this.ignoreInputEvent = true;
-          this.dispatchEvent(evt);
-          this.ignoreInputEvent = oldIgnoreInput;
-        ]]></body>
-      </method>
-
-      <!--  -->
-      <method name="clearResultData">
-        <body><![CDATA[
-          for (var name in this.mSessions)
-            this.mLastResults[name] = null;
-        ]]></body>
-      </method>
-
-      <!-- ::::::::::::: miscellaneous ::::::::::::: -->
-
-      <!--  -->
-      <method name="ifSetAttribute">
-        <parameter name="aAttr"/>
-        <parameter name="aVal"/>
-        <body><![CDATA[
-          if (!this.hasAttribute(aAttr))
-            this.setAttribute(aAttr, aVal);
-        ]]></body>
-      </method>
-
-      <!--  -->
-      <method name="clearTimer">
-        <body><![CDATA[
-          if (this.mAutoCompleteTimer) {
-            clearTimeout(this.mAutoCompleteTimer);
-            this.mAutoCompleteTimer = 0;
-          }
-        ]]></body>
-      </method>
-
-      <!-- ::::::::::::: event dispatching ::::::::::::: -->
-
-      <method name="_fireEvent">
-        <parameter name="aEventType"/>
-        <parameter name="aEventParam"/>
-        <parameter name="aTriggeringEvent"/>
-        <body>
-        <![CDATA[
-          var noCancel = true;
-          // handle any xml attribute event handlers
-          var handler = this.getAttribute("on"+aEventType);
-          if (handler) {
-            var fn = new Function("eventParam", "domEvent", handler);
-            var returned = fn.apply(this, [aEventParam, aTriggeringEvent]);
-            if (returned == false)
-              noCancel = false;
-          }
-
-          return noCancel;
-        ]]>
-        </body>
-      </method>
-
-      <!-- =================== TREE VIEW =================== -->
-
-      <field name="view"><![CDATA[
-        ({
-          mTextbox: this,
-          mTree: null,
-          mSelection: null,
-          mRowCount: 0,
-
-          clearResults: function()
-          {
-            var oldCount = this.mRowCount;
-            this.mRowCount = 0;  
-
-            if (this.mTree) {
-              this.mTree.rowCountChanged(0, -oldCount);
-              this.mTree.scrollToRow(0);
-            }
-          },
-
-          updateResults: function(aRow, aCount)
-          {
-            this.mRowCount += aCount;
-
-            if (this.mTree)
-              this.mTree.rowCountChanged(aRow, aCount);
-          },
-
-          //////////////////////////////////////////////////////////
-          // nsIAutoCompleteController interface
-
-          // this is the only method required by the treebody mouseup handler
-          handleEnter: function(aIsPopupSelection) {
-            this.mTextbox.onResultClick();
-          },
-
-          //////////////////////////////////////////////////////////
-          // nsITreeView interface
-
-          get rowCount() {
-            return this.mRowCount;
-          },
-
-          get selection() {
-            return this.mSelection;
-          },
-
-          set selection(aVal) {
-            return this.mSelection = aVal;
-          },
-
-          setTree: function(aTree)
-          {
-            this.mTree = aTree;
-          },
-
-          getCellText: function(aRow, aCol)
-          {
-            for (var name in this.mTextbox.mSessions) {
-              if (aRow < this.mTextbox.mLastRows[name]) {
-                var result = this.mTextbox.mLastResults[name];
-                switch (aCol.id) {
-                  case "treecolAutoCompleteValue":
-                    return result.errorDescription || result.getLabelAt(aRow);
-                  case "treecolAutoCompleteComment":
-                    if (!result.errorDescription)
-                      return result.getCommentAt(aRow);
-                  default:
-                    return "";
-                }
-              }
-              aRow -= this.mTextbox.mLastRows[name];
-            }
-            return "";
-          },
-
-          getRowProperties: function(aIndex)
-          {
-            return "";
-          },
-
-          getCellProperties: function(aIndex, aCol)
-          {
-            // for the value column, append nsIAutoCompleteItem::className
-            // to the property list so that we can style this column
-            // using that property
-            if (aCol.id == "treecolAutoCompleteValue") {
-              for (var name in this.mTextbox.mSessions) {
-                if (aIndex < this.mTextbox.mLastRows[name]) {
-                  var result = this.mTextbox.mLastResults[name];
-                  if (result.errorDescription)
-                    return "";
-                  return result.getStyleAt(aIndex);
-                }
-                aIndex -= this.mTextbox.mLastRows[name];
-              }
-            }
-            return "";
-          },
-
-          getColumnProperties: function(aCol)
-          {
-            return "";
-          },
-
-          getImageSrc: function(aRow, aCol)
-          {
-            if (aCol.id == "treecolAutoCompleteValue") {
-              for (var name in this.mTextbox.mSessions) {
-                if (aRow < this.mTextbox.mLastRows[name]) {
-                  var result = this.mTextbox.mLastResults[name];
-                  if (result.errorDescription)
-                    return "";
-                  return result.getImageAt(aRow);
-                }
-                aRow -= this.mTextbox.mLastRows[name];
-              }
-            }
-            return "";
-          },
-
-          getParentIndex: function(aRowIndex) { },
-          hasNextSibling: function(aRowIndex, aAfterIndex) { },
-          getLevel: function(aIndex) {},
-          getProgressMode: function(aRow, aCol) {},
-          getCellValue: function(aRow, aCol) {},
-          isContainer: function(aIndex) {},
-          isContainerOpen: function(aIndex) {},
-          isContainerEmpty: function(aIndex) {},
-          isSeparator: function(aIndex) {},
-          isSorted: function() {},
-          toggleOpenState: function(aIndex) {},
-          selectionChanged: function() {},
-          cycleHeader: function(aCol) {},
-          cycleCell: function(aRow, aCol) {},
-          isEditable: function(aRow, aCol) {},
-          isSelectable: function(aRow, aCol) {},
-          setCellValue: function(aRow, aCol, aValue) {},
-          setCellText: function(aRow, aCol, aValue) {},
-          performAction: function(aAction) {},
-          performActionOnRow: function(aAction, aRow) {},
-          performActionOnCell: function(aAction, aRow, aCol) {}
-        });
-      ]]></field>
-
-    </implementation>
-
-    <handlers>
-      <handler event="input"
-               action="if (!this.ignoreInputEvent) this.processInput();"/>
-
-      <handler event="keypress" phase="capturing"
-                action="return this.processKeyPress(event);"/>
-
-      <handler event="compositionstart" phase="capturing"
-                action="this.processStartComposition();"/>
-
-      <handler event="focus" phase="capturing"
-               action="this.userAction = 'typing';"/>
-
-      <handler event="blur" phase="capturing"
-               action="if ( !(this.ignoreBlurWhileSearching &amp;&amp; this.isSearching) ) {this.userAction = 'none'; this.finishAutoComplete(false, false, event);}"/>
-
-      <handler event="mousedown" phase="capturing"
-               action="if ( !this.mMenuOpen ) this.finishAutoComplete(false, false, event);"/>
-    </handlers>
-  </binding>
-
-  <binding id="autocomplete-result-popup" extends="chrome://global/content/bindings/popup.xml#popup">
-    <resources>
-      <stylesheet src="chrome://communicator/content/autocomplete.css"/>
-      <stylesheet src="chrome://global/skin/autocomplete.css"/>
-    </resources>
-
-    <content ignorekeys="true" level="top">
-      <xul:tree anonid="tree" class="autocomplete-tree plain" flex="1">
-        <xul:treecols anonid="treecols">
-          <xul:treecol class="autocomplete-treecol" id="treecolAutoCompleteValue" flex="2"/>
-          <xul:treecol class="autocomplete-treecol" id="treecolAutoCompleteComment" flex="1" hidden="true"/>
-        </xul:treecols>
-        <xul:treechildren anonid="treebody" class="autocomplete-treebody"/>
-      </xul:tree>
-    </content>
-
-    <implementation implements="nsIAutoCompletePopup">
-      <constructor><![CDATA[
-        if (this.textbox && this.textbox.view)
-          this.initialize();
-      ]]></constructor>
-
-      <destructor><![CDATA[
-        if (this.view)
-          this.tree.view = null;
-      ]]></destructor>
-
-      <field name="textbox">
-        document.getBindingParent(this);
-      </field>
-
-      <field name="tree">
-        document.getAnonymousElementByAttribute(this, "anonid", "tree");
-      </field>
-
-      <field name="treecols">
-        document.getAnonymousElementByAttribute(this, "anonid", "treecols");
-      </field>
-
-      <field name="treebody">
-        document.getAnonymousElementByAttribute(this, "anonid", "treebody");
-      </field>
-
-      <field name="view">
-        null
-      </field>
-
-      <!-- Setting tree.view doesn't always immediately create a selection,
-           so we ensure the selection by asking the tree for the view. Note:
-           this.view.selection is quicker if we know the selection exists. -->
-      <property name="selection" onget="return this.tree.view.selection;"/>
-
-     <property name="pageCount"
-               onget="return this.tree.treeBoxObject.getPageLength();"/>
-
-     <field name="maxRows">0</field>
-     <field name="mLastRows">0</field>
-
-      <method name="initialize">
-        <body><![CDATA[
-        this.showCommentColumn = this.textbox.showCommentColumn;
-        this.tree.view = this.textbox.view;
-        this.view = this.textbox.view;
-        this.maxRows = this.textbox.maxRows;
-        ]]></body>
-      </method>
-
-      <property name="showCommentColumn"
-                onget="return !this.treecols.lastChild.hidden;"
-                onset="this.treecols.lastChild.hidden = !val; return val;"/>
-
-      <method name="adjustHeight">
-        <body><![CDATA[
-          // detect the desired height of the tree
-          var bx = this.tree.treeBoxObject;
-          var view = this.view;
-          var rows = this.maxRows || 6;
-          if (!view.rowCount || (rows && view.rowCount < rows))
-            rows = view.rowCount;
-
-          var height = rows * bx.rowHeight;
-
-          if (height == 0)
-            this.tree.setAttribute("collapsed", "true");
-          else {
-            if (this.tree.hasAttribute("collapsed"))
-              this.tree.removeAttribute("collapsed");
-            this.tree.setAttribute("height", height);
-          }
-        ]]></body>
-      </method>
-
-      <method name="clearSelection">
-        <body>
-          this.selection.clearSelection();
-        </body>
-      </method>
-
-      <method name="getNextIndex">
-        <parameter name="aReverse"/>
-        <parameter name="aPage"/>
-        <parameter name="aIndex"/>
-        <parameter name="aMaxRow"/>
-        <body><![CDATA[
-          if (aMaxRow < 0)
-            return -1;
-
-          if (aIndex == -1)
-            return aReverse ? aMaxRow : 0;
-          if (aIndex == (aReverse ? 0 : aMaxRow))
-            return -1;
-
-          var amount = aPage ? this.pageCount - 1 : 1;
-          aIndex = aReverse ? aIndex - amount : aIndex + amount;
-          if (aIndex > aMaxRow)
-            return aMaxRow;
-          if (aIndex < 0)
-            return 0;
-          return aIndex;
-        ]]></body>
-      </method>
-
-      <!-- =================== nsIAutoCompletePopup =================== -->
-
-      <field name="input">
-        null
-      </field>
-
-      <!-- This property is meant to be overriden by bindings extending
-           this one.  When the user selects an item from the list by
-           hitting enter or clicking, this method can set the value
-           of the textbox to a different value if it wants to. -->
-      <property name="overrideValue" readonly="true" onget="return null;"/>
-
-      <property name="selectedIndex">
-        <getter>
-          if (!this.view || !this.selection.count)
-            return -1;
-          var start = {}, end = {};
-          this.view.selection.getRangeAt(0, start, end);
-          return start.value;
-        </getter>
-        <setter>
-          if (this.view) {
-            this.selection.select(val);
-            if (val >= 0) {
-              this.view.selection.currentIndex = -1;
-              this.tree.treeBoxObject.ensureRowIsVisible(val);
-            }
-          }
-          return val;
-        </setter>
-      </property>
-
-      <property name="popupOpen" onget="return !!this.input;" readonly="true"/>
-
-      <method name="openAutocompletePopup">
-        <parameter name="aInput"/>
-        <parameter name="aElement"/>
-        <body><![CDATA[
-          if (!this.input) {
-            this.tree.view = aInput.controller;
-            this.view = this.tree.view;
-            this.showCommentColumn = aInput.showCommentColumn;
-            this.maxRows = aInput.maxRows;
-            this.invalidate();
-
-            var viewer = aElement.ownerGlobal
-                .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                .getInterface(Components.interfaces.nsIWebNavigation)
-                .QueryInterface(Components.interfaces.nsIDocShell)
-                .contentViewer;
-            var rect = aElement.getBoundingClientRect();
-            var width = Math.round((rect.right - rect.left) * viewer.fullZoom);
-            this.setAttribute("width", width > 100 ? width : 100);
-            // Adjust the direction (which is not inherited) of the autocomplete
-            // popup list, based on the textbox direction. (Bug 707039)
-            this.style.direction = aElement.ownerGlobal
-                                           .getComputedStyle(aElement)
-                                           .direction;
-            this.popupBoxObject.setConsumeRollupEvent(aInput.consumeRollupEvent
-              ? PopupBoxObject.ROLLUP_CONSUME
-              : PopupBoxObject.ROLLUP_NO_CONSUME);
-            this.openPopup(aElement, "after_start", 0, 0, false, false);
-            if (this.state != "closed")
-              this.input = aInput;
-          }
-        ]]></body>
-      </method>
-
-      <method name="closePopup">
-        <body>
-          this.hidePopup();
-        </body>
-      </method>
-
-      <method name="invalidate">
-        <body>
-          if (this.view)
-            this.adjustHeight();
-          this.tree.treeBoxObject.invalidate();
-        </body>
-      </method>
-
-      <method name="selectBy">
-        <parameter name="aReverse"/>
-        <parameter name="aPage"/>
-        <body><![CDATA[
-          try {
-            return this.selectedIndex = this.getNextIndex(aReverse, aPage, this.selectedIndex, this.view.rowCount - 1);
-          } catch (ex) {
-            // do nothing - occasionally timer-related js errors happen here
-            // e.g. "this.selectedIndex has no properties", when you type fast and hit a
-            // navigation key before this popup has opened
-            return -1;
-          }
-        ]]></body>
-      </method>
-    </implementation>
-
-    <handlers>
-      <handler event="popupshowing">
-        if (this.textbox)
-          this.textbox.mMenuOpen = true;
-      </handler>
-
-      <handler event="popuphiding">
-        if (this.textbox)
-          this.textbox.mMenuOpen = false;
-        this.clearSelection();
-        this.input = null;
-      </handler>
-    </handlers>
-  </binding>
-
-  <binding id="autocomplete-treebody">
-    <implementation>
-      <field name="popup">document.getBindingParent(this);</field>
-
-      <field name="mLastMoveTime">Date.now()</field>
-    </implementation>
-
-    <handlers>
-      <handler event="mouseout" action="this.popup.selectedIndex = -1;"/>
-
-      <handler event="mouseup"><![CDATA[
-        var rc = this.parentNode.treeBoxObject.getRowAt(event.clientX, event.clientY);
-        if (rc != -1) {
-          this.popup.selectedIndex = rc;
-          this.popup.view.handleEnter(true);
-        }
-      ]]></handler>
-
-      <handler event="mousemove"><![CDATA[
-        if (Date.now() - this.mLastMoveTime > 30) {
-          var rc = this.parentNode.treeBoxObject.getRowAt(event.clientX, event.clientY);
-          if (rc != -1 && rc != this.popup.selectedIndex) 
-            this.popup.selectedIndex = rc;
-          this.mLastMoveTime = Date.now();
-        }
-      ]]></handler>
-    </handlers>
-  </binding>
-
-  <binding id="autocomplete-history-popup"
-           extends="chrome://global/content/bindings/popup.xml#popup-scrollbars">
-    <resources>
-      <stylesheet src="chrome://communicator/content/autocomplete.css"/>
-      <stylesheet src="chrome://global/skin/autocomplete.css"/>
-    </resources>
-
-    <implementation>
-      <method name="removeOpenAttribute">
-        <parameter name="parentNode"/>
-        <body><![CDATA[
-          parentNode.removeAttribute("open");
-        ]]></body>
-      </method>
-    </implementation>
-
-    <handlers>
-      <handler event="popuphiding"><![CDATA[
-        setTimeout(this.removeOpenAttribute, 0, this.parentNode);
-      ]]></handler>
-    </handlers>
-  </binding>
-
-  <binding id="history-dropmarker" extends="chrome://global/content/bindings/general.xml#dropmarker">
-
-    <implementation>
-      <method name="showPopup">
-        <body><![CDATA[
-          var textbox = document.getBindingParent(this);
-          var kids = textbox.getElementsByClassName("autocomplete-history-popup");
-          if (kids.item(0) && textbox.getAttribute("open") != "true") { // Open history popup
-            var w = textbox.boxObject.width;
-            if (w != kids[0].boxObject.width)
-              kids[0].width = w;
-            kids[0].showPopup(textbox, -1, -1, "popup", "bottomleft", "topleft");
-            textbox.setAttribute("open", "true");
-          }
-        ]]></body>
-      </method>
-    </implementation>
-
-    <handlers>
-      <handler event="mousedown"><![CDATA[
-        this.showPopup();
-      ]]></handler>
-    </handlers>
-  </binding>
-
-</bindings>