Bug 547224 - Remove the custom emptyText implementation, implement textbox.placeholder using the input field's native placeholder facility. r=enn
authorDão Gottwald <dao@mozilla.com>
Thu, 04 Mar 2010 08:13:27 +0100
changeset 38929 9ee18dec071b7d4e41d6cd67310bffb7588b6b5a
parent 38928 cf1240a63d4e294fd45f3d6147191c16d82dcb74
child 38930 580c63190d26cb889b1c8a75eba9021e406b04d8
push id11940
push userdgottwald@mozilla.com
push dateThu, 04 Mar 2010 07:15:01 +0000
treeherderautoland@9ee18dec071b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersenn
bugs547224
milestone1.9.3a3pre
Bug 547224 - Remove the custom emptyText implementation, implement textbox.placeholder using the input field's native placeholder facility. r=enn
accessible/tests/mochitest/test_textboxes.xul
browser/base/content/browser-tabPreviews.js
browser/base/content/browser.css
browser/base/content/browser.xul
browser/base/content/test/browser_bug495058.js
browser/base/content/urlbarBindings.xml
browser/components/places/content/editBookmarkOverlay.xul
browser/components/places/content/places.js
browser/components/preferences/applications.xul
browser/components/preferences/tests/browser_privacypane_1.js
browser/components/preferences/tests/privacypane_tests.js
browser/components/search/content/search.xml
browser/themes/pinstripe/browser/browser.css
browser/themes/winstripe/browser/browser.css
layout/reftests/editor/xul/empty-1.xul
layout/reftests/editor/xul/empty-2.xul
toolkit/components/help/content/help.xul
toolkit/content/tests/chrome/test_bug418874.xul
toolkit/content/tests/chrome/test_bug471776.xul
toolkit/content/tests/widgets/test_textbox_emptytext.xul
toolkit/content/tests/widgets/test_textbox_search.xul
toolkit/content/textbox.css
toolkit/content/widgets/autocomplete.xml
toolkit/content/widgets/numberbox.xml
toolkit/content/widgets/textbox.xml
toolkit/mozapps/downloads/content/downloads.xul
toolkit/mozapps/extensions/content/extensions.xul
toolkit/themes/faststripe/global/textbox.css
toolkit/themes/gnomestripe/global/textbox.css
toolkit/themes/pinstripe/global/textbox.css
toolkit/themes/winstripe/global/textbox-aero.css
toolkit/themes/winstripe/global/textbox.css
--- a/accessible/tests/mochitest/test_textboxes.xul
+++ b/accessible/tests/mochitest/test_textboxes.xul
@@ -241,12 +241,12 @@
                rows="5" value="You cannot change me, either."/>
     </vbox>
     <hbox>
       <label value="Search History:" accesskey="S" 
              control="search-box"/>
 	  <textbox id="search-box" flex="1" type="search"
 	           results="historyTree"/>
     </hbox>
-    <textbox id="searchfield" emptytext="Search all add-ons"
+    <textbox id="searchfield" placeholder="Search all add-ons"
              type="search" searchbutton="true"/>
   </vbox>
 </window>
--- a/browser/base/content/browser-tabPreviews.js
+++ b/browser/base/content/browser-tabPreviews.js
@@ -684,25 +684,25 @@ var allTabs = {
   },
 
   close: function allTabs_close() {
     this.panel.hidePopup();
   },
 
   setupGUI: function allTabs_setupGUI() {
     this.filterField.focus();
-    this.filterField.setAttribute("emptytext", this.filterField.tooltipText);
+    this.filterField.placeholder = this.filterField.tooltipText;
 
     this.panel.addEventListener("keypress", this, false);
     this.panel.addEventListener("keypress", this, true);
     this._browserCommandSet.addEventListener("command", this, false);
   },
 
   suspendGUI: function allTabs_suspendGUI() {
-    this.filterField.removeAttribute("emptytext");
+    this.filterField.placeholder = "";
     this.filterField.value = "";
     this._currentFilter = null;
 
     this._updateTabCloseButton();
 
     this.panel.removeEventListener("keypress", this, false);
     this.panel.removeEventListener("keypress", this, true);
     this._browserCommandSet.removeEventListener("command", this, false);
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -66,18 +66,17 @@ toolbar[mode="icons"] > #reload-button[d
   display: none;
 }
 
 #feed-menu > .feed-menuitem:-moz-locale-dir(rtl) {
   direction: rtl;
 }
 
 #urlbar[pageproxystate="invalid"] > #urlbar-icons > .urlbar-icon:not(#go-button),
-#urlbar[pageproxystate="valid"] > #urlbar-icons > #go-button ,
-#urlbar[isempty="true"] > #urlbar-icons > #go-button {
+#urlbar[pageproxystate="valid"] > #urlbar-icons > #go-button {
   visibility: collapse;
 }
 
 #identity-icon-labels {
   max-width: 18em;
 }
 
 #identity-icon-country-label {
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -394,20 +394,20 @@
                      ondragenter="homeButtonObserver.onDragOver(event)"
                      ondrop="homeButtonObserver.onDrop(event)"
                      ondragleave="homeButtonObserver.onDragLeave(event)"
                      onclick="BrowserGoHome(event);"/>
 
       <toolbaritem id="urlbar-container" align="center" flex="400" persist="width"
                    title="&locationItem.title;" class="chromeclass-location" removable="true">
         <textbox id="urlbar" flex="1"
-                 bookmarkhistoryemptytext="&urlbar.bookmarkhistory.emptyText;"
-                 bookmarkemptytext="&urlbar.bookmark.emptyText;"
-                 historyemptytext="&urlbar.history.emptyText;"
-                 noneemptytext="&urlbar.none.emptyText;"
+                 bookmarkhistoryplaceholder="&urlbar.bookmarkhistory.emptyText;"
+                 bookmarkplaceholder="&urlbar.bookmark.emptyText;"
+                 historyplaceholder="&urlbar.history.emptyText;"
+                 noneplaceholder="&urlbar.none.emptyText;"
                  type="autocomplete"
                  autocompletesearch="history"
                  autocompletepopup="PopupAutoCompleteRichResult"
                  completeselectedindex="true"
                  tabscrolling="true"
                  showcommentcolumn="true"
                  showimagecolumn="true"
                  enablehistory="true"
--- a/browser/base/content/test/browser_bug495058.js
+++ b/browser/base/content/test/browser_bug495058.js
@@ -32,18 +32,17 @@ function next() {
       var _delayedStartup = win.delayedStartup;
       win.delayedStartup = function delayedStartup() {
         _delayedStartup.apply(win, arguments);
         win.delayedStartup = _delayedStartup;
 
         is(win.gBrowser.currentURI.spec, uri, uri + ": uri loaded in detached tab");
         is(win.document.activeElement, win.gBrowser.selectedBrowser, uri + ": browser is focused");
         is(win.gURLBar.value, "", uri + ": urlbar is empty");
-        ok(win.gURLBar.emptyText, uri + ": emptytext is present");
-        ok(win.gURLBar.hasAttribute("isempty"), uri + ": emptytext is displayed");
+        ok(win.gURLBar.placeholder, uri + ": placeholder text is present");
 
         win.close();
         if (uris.length)
           next();
         else
           executeSoon(finish);
       };
     }, false);
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -48,20 +48,17 @@
                                 .getBranch("browser.urlbar.")
                                 .QueryInterface(Components.interfaces.nsIPrefBranch2);
 
         this._prefs.addObserver("", this, false);
         this.clickSelectsAll = this._prefs.getBoolPref("clickSelectsAll");
         this.doubleClickSelectsAll = this._prefs.getBoolPref("doubleClickSelectsAll");
         this.completeDefaultIndex = this._prefs.getBoolPref("autoFill");
         this.timeout = this._prefs.getIntPref("delay");
-        setTimeout(function (self) {
-          if (self._setEmptyText)
-            self._setEmptyText();
-        }, 0, this);
+        this._setPlaceholder();
 
         this._urlTooltip = document.getElementById("urlTooltip");
 
         this.inputField.controllers.insertControllerAt(0, this._copyCutController);
         this.inputField.addEventListener("mousedown", this, false);
         this.inputField.addEventListener("mousemove", this, false);
         this.inputField.addEventListener("mouseout", this, false);
         this.inputField.addEventListener("overflow", this, false);
@@ -363,17 +360,17 @@
               case "autoFill":
                 this.completeDefaultIndex = this._prefs.getBoolPref(aData);
                 break;
               case "delay":
                 this.timeout = this._prefs.getIntPref(aData);
                 break;
               case "autocomplete.enabled":
               case "default.behavior":
-                this._setEmptyText();
+                this._setPlaceholder();
                 break;
             }
           }
         ]]></body>
       </method>
 
       <method name="handleEvent">
         <parameter name="aEvent"/>
@@ -420,34 +417,34 @@
           this.dispatchEvent(evt);
           this.mIgnoreInput = false;
 
           return this.value;
           ]]>
         </setter>
       </property>
 
-      <method name="_setEmptyText">
+      <method name="_setPlaceholder">
         <body><![CDATA[
           var type = "none";
           if (this._prefs.getBoolPref("autocomplete.enabled")) {
             // Bottom 2 bits of default.behavior specify history/bookmark
             switch (this._prefs.getIntPref("default.behavior") & 3) {
               case 0:
                 type = "bookmarkhistory";
                 break;
               case 1:
                 type = "history";
                 break;
               case 2:
                 type = "bookmark";
                 break;
             }
           }
-          this.emptyText = this.getAttribute(type + "emptytext");
+          this.placeholder = this.getAttribute(type + "placeholder");
         ]]></body>
       </method>
     </implementation>
 
     <handlers>
       <handler event="draggesture" phase="capturing"><![CDATA[
         // TODO: This should use dragstart but editor code is still using
         //       the old drag & drop APIs, so we have to handle draggesture.
--- a/browser/components/places/content/editBookmarkOverlay.xul
+++ b/browser/components/places/content/editBookmarkOverlay.xul
@@ -193,17 +193,17 @@
                      class="padded"
                      flex="1"
                      autocompletesearch="places-tag-autocomplete" 
                      completedefaultindex="true"
                      tabscrolling="true"
                      showcommentcolumn="true"
                      onblur="gEditItemOverlay.onTagsFieldBlur();"
                      observes="paneElementsBroadcaster"
-                     emptytext="&editBookmarkOverlay.tagsEmptyDesc.label;"/>
+                     placeholder="&editBookmarkOverlay.tagsEmptyDesc.label;"/>
             <button id="editBMPanel_tagsSelectorExpander"
                     class="expander-down"
                     tooltiptext="&editBookmarkOverlay.tagsExpanderDown.tooltip;"
                     tooltiptextdown="&editBookmarkOverlay.tagsExpanderDown.tooltip;"
                     tooltiptextup="&editBookmarkOverlay.expanderUp.tooltip;"
                     oncommand="gEditItemOverlay.toggleTagsSelector();"
                     observes="paneElementsBroadcaster"/>
           </hbox>
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -924,22 +924,22 @@ var PlacesSearchBox = {
 
   /**
    * Updates the display with the title of the current collection.
    * @param   title
    *          The title of the current collection.
    */
   updateCollectionTitle: function PSB_updateCollectionTitle(title) {
     if (title)
-      this.searchFilter.emptyText =
+      this.searchFilter.placeholder =
         PlacesUIUtils.getFormattedString("searchCurrentDefault", [title]);
     else
-      this.searchFilter.emptyText = this.filterCollection == "history" ?
-                                    PlacesUIUtils.getString("searchHistory") :
-                                    PlacesUIUtils.getString("searchBookmarks");
+      this.searchFilter.placeholder = this.filterCollection == "history" ?
+                                      PlacesUIUtils.getString("searchHistory") :
+                                      PlacesUIUtils.getString("searchBookmarks");
   },
 
   /**
    * Gets/sets the active collection from the dropdown menu.
    */
   get filterCollection() {
     return this.searchFilter.getAttribute("collection");
   },
--- a/browser/components/preferences/applications.xul
+++ b/browser/components/preferences/applications.xul
@@ -108,17 +108,17 @@
     <keyset>
       <key key="&focusSearch1.key;" modifiers="accel" oncommand="gApplicationsPane.focusFilterBox();"/>
       <key key="&focusSearch2.key;" modifiers="accel" oncommand="gApplicationsPane.focusFilterBox();"/>
     </keyset>
 
     <hbox>
       <textbox id="filter" flex="1"
                type="search"
-               emptytext="&filter.emptytext;"
+               placeholder="&filter.emptytext;"
                aria-controls="handlersView"
                oncommand="gApplicationsPane.filter();"/>
     </hbox>
 
     <separator class="thin"/>
 
     <richlistbox id="handlersView" orient="vertical" persist="lastSelectedType"
                  preference="pref.downloads.disable_button.edit_actions"
--- a/browser/components/preferences/tests/browser_privacypane_1.js
+++ b/browser/components/preferences/tests/browser_privacypane_1.js
@@ -36,17 +36,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 function test() {
   let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
                getService(Ci.mozIJSSubScriptLoader);
   loader.loadSubScript("chrome://mochikit/content/browser/browser/components/preferences/tests/privacypane_tests.js", this);
 
   run_test_subset([
-    test_locbar_emptyText,
+    test_locbar_placeholder,
     test_pane_visibility,
     test_dependent_elements,
     test_dependent_cookie_elements,
     test_dependent_clearonclose_elements,
     test_dependent_prefs,
 
     // reset all preferences to their default values once we're done
     reset_preferences
--- a/browser/components/preferences/tests/privacypane_tests.js
+++ b/browser/components/preferences/tests/privacypane_tests.js
@@ -62,27 +62,27 @@ function runTestOnPrivacyPrefPane(testFu
   let dialog = openDialog("chrome://browser/content/preferences/preferences.xul", "Preferences",
                           "chrome,titlebar,toolbar,centerscreen,dialog=no", "panePrivacy");
 }
 
 function controlChanged(element) {
   element.doCommand();
 }
 
-function test_locbar_emptyText(win) {
+function test_locbar_placeholder(win) {
   let texts = ["none", "bookmarkhistory", "history", "bookmark"];
 
   let locbarlist = win.document.getElementById("locationBarSuggestion");
   ok(locbarlist, "location bar suggestion menulist should exist");
 
   for (let level = -1; level <= 2; ++level) {
     locbarlist.value = level;
     controlChanged(locbarlist);
-    is(gURLBar.emptyText, gURLBar.getAttribute(texts[level + 1] + "emptytext"),
-      "location bar empty text for for level " + level + " is correctly set");
+    is(gURLBar.placeholder, gURLBar.getAttribute(texts[level + 1] + "placeholder"),
+       "location bar placeholder for for level " + level + " is correctly set");
   }
 }
 
 function test_pane_visibility(win) {
   let modes = {
     "remember": "historyRememberPane",
     "dontremember": "historyDontRememberPane",
     "custom": "historyCustomPane"
--- a/browser/components/search/content/search.xml
+++ b/browser/components/search/content/search.xml
@@ -309,17 +309,17 @@
 
       <method name="updateDisplay">
         <body><![CDATA[
           var uri = this.currentEngine.iconURI;
           this.setAttribute("src", uri ? uri.spec : "");
 
           var name = this.currentEngine.name;
           var text = this._stringBundle.getFormattedString("searchtip", [name]);
-          this._textbox.emptyText = name;
+          this._textbox.placeholder = name;
           this._textbox.label = text;
           this._textbox.tooltipText = text;
         ]]></body>
       </method>
 
       <!-- Rebuilds the dynamic portion of the popup menu (i.e., the menu items
            for new search engines that can be added to the available list).  This
            is called each time the popup is shown.
--- a/browser/themes/pinstripe/browser/browser.css
+++ b/browser/themes/pinstripe/browser/browser.css
@@ -1334,17 +1334,17 @@ richlistitem[selected="true"][current="t
   background-color: #666 !important;
   color: #fff !important;
 }
 
 #editBMPanel_namePicker[droppable="false"] > .menulist-editable-box > html|*.menulist-editable-input {
   color: inherit;
 }
 
-#editBMPanel_tagsField[isempty="true"] {
+#editBMPanel_tagsField > .autocomplete-textbox-container > .textbox-input-box > html|*.textbox-input:-moz-placeholder {
   color: #bbb !important;
 }
 
 #editBMPanel_tagsField[focused="true"],
 #editBMPanel_namePicker[droppable="false"][focused="true"] > .menulist-editable-box {
   outline: 2px solid -moz-mac-focusring;
   outline-offset: -1px;
   -moz-outline-radius: 1px;
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -549,18 +549,18 @@ toolbar:not([iconsize="small"])[mode="ic
 }
 
 #urlbar:-moz-lwtheme,
 .searchbar-textbox:-moz-lwtheme {
   background-color: rgba(255,255,255,.8);
   color: black;
 }
 
-#urlbar:-moz-lwtheme[isempty="true"],
-.searchbar-textbox:-moz-lwtheme[isempty="true"] {
+#urlbar:-moz-lwtheme > .autocomplete-textbox-container > .textbox-input-box > html|*.textbox-input:-moz-placeholder,
+.searchbar-textbox:-moz-lwtheme > .autocomplete-textbox-container > .textbox-input-box > html|*.textbox-input:-moz-placeholder {
   color: #777;
 }
 
 #urlbar:-moz-lwtheme[focused="true"],
 .searchbar-textbox:-moz-lwtheme[focused="true"] {
   background-color: white;
 }
 
--- a/layout/reftests/editor/xul/empty-1.xul
+++ b/layout/reftests/editor/xul/empty-1.xul
@@ -1,22 +1,12 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml"
-        title="Textbox tests"
-        class="reftest-wait">
+        title="Textbox tests">
 
   <script type="text/javascript" src="platform.js"/>
 
-  <script type="text/javascript">
-  <![CDATA[
-    // Wait for one second so that the emptytext attribute kicks in
-    window.setTimeout(function() {
-      document.documentElement.removeAttribute("class");
-    }, 1000);
-  ]]>
-  </script>
-
-  <textbox emptytext="test"/>
+  <textbox placeholder="test"/>
       
 </window>
--- a/layout/reftests/editor/xul/empty-2.xul
+++ b/layout/reftests/editor/xul/empty-2.xul
@@ -1,22 +1,12 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml"
-        title="Textbox tests"
-        class="reftest-wait">
+        title="Textbox tests">
 
   <script type="text/javascript" src="platform.js"/>
 
-  <script type="text/javascript">
-  <![CDATA[
-    // Wait for one second so that the emptytext attribute kicks in
-    window.setTimeout(function() {
-      document.documentElement.removeAttribute("class");
-    }, 1000);
-  ]]>
-  </script>
-
-  <textbox emptytext="test" value="value"/>
+  <textbox placeholder="test" value="value"/>
       
 </window>
--- a/toolkit/components/help/content/help.xul
+++ b/toolkit/components/help/content/help.xul
@@ -171,17 +171,17 @@
         <toolbarseparator/>
         <toolbarbutton id="help-print-button"
                        label="&printButton.label;"
                        oncommand="print();"
                        tooltiptext="&printButton.tooltip;"/>
         <toolbarspring flex="1"/>
         <toolbaritem id="search-box"
                      align="center" pack="center">
-          <textbox id="findText" type="search" emptytext="&search.emptytext;"
+          <textbox id="findText" type="search" placeholder="&search.emptytext;"
                    aria-controls="help-toc-panel"
                    oncommand="doFind();"/>
         </toolbaritem>
       </toolbar>
     </toolbox>
 
     <hbox flex="1">
       <vbox id="help-sidebar" persist="width">
--- a/toolkit/content/tests/chrome/test_bug418874.xul
+++ b/toolkit/content/tests/chrome/test_bug418874.xul
@@ -36,28 +36,28 @@
    - the terms of any one of the MPL, the GPL or the LGPL.
    -
    - ***** END LICENSE BLOCK ***** -->
 
 
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 
-<window title="Textbox with emptyText test" width="500" height="600"
+<window title="Textbox with placeholder test" width="500" height="600"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
 
   <hbox>
-    <textbox id="t1" emptytext="empty"/>
+    <textbox id="t1" placeholder="empty"/>
   </hbox>
 
   <hbox>
-    <textbox id="t2" emptytext="empty"/>
+    <textbox id="t2" placeholder="empty"/>
   </hbox>
 
   <!-- test results are displayed in the html:body -->
   <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;">
     <p id="display">
     </p>
     <div id="content" style="display: none">
     </div>
@@ -72,26 +72,25 @@
     function doTest() {
       var t1 = $("t1");
       var t2 = $("t2");
       t1.value = "1";
       var t1Enabled = {};
       var t1CanUndo = {};
       t1.editor.canUndo(t1Enabled, t1CanUndo);
       is(t1CanUndo.value, true,
-         "undo correctly enabled when emptyText was not changed through property");
+         "undo correctly enabled when placeholder was not changed through property");
 
-      t2.emptyText = "reallyempty";
-      is(t2.inputField.value, "reallyempty", "updated emptyText displayed");
+      t2.placeholder = "reallyempty";
       t2.value = "2";
       var t2Enabled = {};
       var t2CanUndo = {};
       t2.editor.canUndo(t2Enabled, t2CanUndo);
       is(t2CanUndo.value, true,
-         "undo correctly enabled when emptyText explicitly changed through property");
+         "undo correctly enabled when placeholder explicitly changed through property");
 
       SimpleTest.finish();
    }
 
    SimpleTest.waitForFocus(doTest);
 
   ]]></script>
 
--- a/toolkit/content/tests/chrome/test_bug471776.xul
+++ b/toolkit/content/tests/chrome/test_bug471776.xul
@@ -36,25 +36,25 @@
    - the terms of any one of the MPL, the GPL or the LGPL.
    -
    - ***** END LICENSE BLOCK ***** -->
 
 
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 
-<window title="Textbox with emptyText undo test" width="500" height="600"
+<window title="Textbox with placeholder undo test" width="500" height="600"
         onload="doTest();"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
 
   <hbox>
-    <textbox id="t1" emptytext="empty"/>
+    <textbox id="t1" placeholder="empty"/>
   </hbox>
 
   <!-- test results are displayed in the html:body -->
   <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;">
     <p id="display">
     </p>
     <div id="content" style="display: none">
     </div>
@@ -63,24 +63,19 @@
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
     SimpleTest.waitForExplicitFinish();
 
     function doTest() {
       var t1 = $("t1");
-
-      // Need to perform test on a timeout, otherwise textbox gets focus
-      // too quickly ie before constructor calls _updateVisibleText
-      setTimeout(function() {
-        t1.focus();
-        var t1Enabled = {};
-        var t1CanUndo = {};
-        t1.editor.canUndo(t1Enabled, t1CanUndo);
-        ok(!t1CanUndo.value, "undo correctly disabled when no user edits");
-        SimpleTest.finish();
-     }, 100);
-   }
+      t1.focus();
+      var t1Enabled = {};
+      var t1CanUndo = {};
+      t1.editor.canUndo(t1Enabled, t1CanUndo);
+      ok(!t1CanUndo.value, "undo correctly disabled when no user edits");
+      SimpleTest.finish();
+    }
 
   ]]></script>
 
 </window>
--- a/toolkit/content/tests/widgets/test_textbox_emptytext.xul
+++ b/toolkit/content/tests/widgets/test_textbox_emptytext.xul
@@ -1,15 +1,15 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
 <!--
-  XUL Widget Test for textbox with emptyText
+  XUL Widget Test for textbox with placeholder
   -->
-<window title="Textbox with emptyText test" width="500" height="600"
+<window title="Textbox with placeholder test" width="500" height="600"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <script type="application/javascript" src="/MochiKit/packed.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
 
   <hbox>
     <textbox id="t1"/>
   </hbox>
 
@@ -19,36 +19,30 @@
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
 
 SimpleTest.waitForExplicitFinish();
 
 function doTests() {
   var t1 = $("t1");
 
-  t1.emptyText = 1;
-  ok(t1.hasAttribute("isempty"), "emptyText but no value => 'isempty' attribute is present");
-  ok("1" === t1.label,          "emptyText exposed as label");
-  ok(""  === t1.value,          "emptyText not exposed as value");
+  t1.placeholder = 1;
+  ok("1" === t1.label,          "placeholder exposed as label");
+  ok(""  === t1.value,          "placeholder not exposed as value");
 
   t1.label = 2;
   ok("2" === t1.label,          "label can be set explicitly");
-  ok("1" === t1.emptyText,      "emptyText persists after setting label");
+  ok("1" === t1.placeholder,    "placeholder persists after setting label");
 
   t1.value = 3;
-  ok(!t1.hasAttribute("isempty"), "value present => 'isempty' attribute not present");
-  ok("3" === t1.value,          "value setter/getter works while emptyText is present");
-  ok("1" === t1.emptyText,      "emptyText persists after setting value");
+  ok("3" === t1.value,          "value setter/getter works while placeholder is present");
+  ok("1" === t1.placeholder,    "placeholder persists after setting value");
 
   t1.value = "";
-  is(t1.inputField.value, 1,    "emptyText is displayed");
-  is(t1.textLength, 0,          "textLength while emptyText is displayed");
-
-  t1.focus();
-  is(t1.inputField.value, "",   "emptyText is not displayed as the textbox has focus");
+  is(t1.textLength, 0,          "textLength while placeholder is displayed");
 
   SimpleTest.finish();
 }
 
 SimpleTest.waitForFocus(doTests);
 
   ]]></script>
 
--- a/toolkit/content/tests/widgets/test_textbox_search.xul
+++ b/toolkit/content/tests/widgets/test_textbox_search.xul
@@ -9,17 +9,17 @@
   <script type="application/javascript" src="/MochiKit/packed.js"/>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"/>
   <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"/>
 
   <hbox>
     <textbox id="searchbox"
              type="search"
              oncommand="doSearch(this.value);"
-             emptytext="random emptytext"
+             placeholder="random placeholder"
              timeout="1"/>
   </hbox>
 
   <!-- test results are displayed in the html:body -->
   <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
 
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
@@ -35,18 +35,18 @@ function doTests() {
   var searchIcon = document.getAnonymousElementByAttribute(textbox, "class", "textbox-search-icon");
   var clearIcon = document.getAnonymousElementByAttribute(textbox, "class", "textbox-search-clear");
 
   ok(icons, "icon deck found");
   ok(searchIcon, "search icon found");
   ok(clearIcon, "clear icon found");
   is(icons.selectedPanel, searchIcon, "search icon is displayed");
 
-  is(textbox.emptyText, "random emptytext", "search textbox supports emptytext");
-  is(textbox.value, "", "emptytext doesn't interfere with the real value");
+  is(textbox.placeholder, "random placeholder", "search textbox supports placeholder");
+  is(textbox.value, "", "placeholder doesn't interfere with the real value");
 
   function iconClick(aIcon) {
     is(icons.selectedPanel, aIcon, aIcon.className + " icon must be displayed in order to be clickable");
 
     //XXX synthesizeMouse worked on Linux but failed on Windows an Mac
     //    for unknown reasons. Manually dispatch the event for now.
     //synthesizeMouse(aIcon, 0, 0, {});
 
--- a/toolkit/content/textbox.css
+++ b/toolkit/content/textbox.css
@@ -9,25 +9,20 @@ html|*.textbox-input {
 }
 
 html|*.textbox-textarea {
   -moz-appearance: none !important;
   text-shadow: inherit;
   -moz-box-sizing: border-box;
 }
 
-textbox[isempty="true"] html|*.textbox-input ,
-textbox[isempty="true"] html|*.textbox-textarea {
+html|*.textbox-input:-moz-placeholder,
+html|*.textbox-textarea:-moz-placeholder {
   text-align: left;
   direction: ltr;
 }
 
-textbox[isempty="true"]:-moz-locale-dir(rtl) html|*.textbox-input ,
-textbox[isempty="true"]:-moz-locale-dir(rtl) html|*.textbox-textarea {
+html|*.textbox-input:-moz-placeholder:-moz-locale-dir(rtl),
+html|*.textbox-textarea:-moz-placeholder:-moz-locale-dir(rtl) {
   text-align: right;
   direction: rtl;
 }
 
-textbox[isempty="true"] html|*.textbox-input[emptytextdelay="true"] ,
-textbox[isempty="true"] html|*.textbox-textarea[emptytextdelay="true"] {
-  color: transparent !important;
-}
-
--- a/toolkit/content/widgets/autocomplete.xml
+++ b/toolkit/content/widgets/autocomplete.xml
@@ -59,17 +59,17 @@
         <children includes="image|deck|stack|box">
           <xul:image class="autocomplete-icon" allowevents="true"/>
         </children>
 
         <xul:hbox anonid="textbox-input-box" class="textbox-input-box" flex="1" xbl:inherits="tooltiptext=inputtooltiptext">
           <children/>
           <html:input anonid="input" class="autocomplete-textbox textbox-input"
                       flex="1" allowevents="true"
-                      xbl:inherits="tooltiptext=inputtooltiptext,onfocus,onblur,value,type,maxlength,disabled,size,readonly,tabindex,accesskey"/>
+                      xbl:inherits="tooltiptext=inputtooltiptext,onfocus,onblur,value,type,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey"/>
         </xul:hbox>
         <children includes="hbox"/>
       </xul:hbox>
 
       <xul:dropmarker anonid="historydropmarker" class="autocomplete-history-dropmarker"
                       allowevents="true"
                       xbl:inherits="open,enablehistory,parentfocused=focused"/>
 
@@ -249,28 +249,20 @@
           else
             this.closePopup();
         ]]></setter>
       </property>
 
       <!-- =================== PUBLIC MEMBERS =================== -->
 
       <property name="value"
-                onget="return this.hasAttribute('isempty') ? '' : this.inputField.value;">
+                onget="return this.inputField.value;">
         <setter><![CDATA[
           this.mIgnoreInput = true;
-          if (val) {
-            // clear the emptyText _before_ setting a new non-empty value
-            this._clearEmptyText();
-            this.inputField.value = val;
-          } else {
-            // display the emptyText _after_ setting a value that's an empty string
-            this.inputField.value = val;
-            this._updateVisibleText();
-          }
+          this.inputField.value = val;
           this.mIgnoreInput = false;
           var event = document.createEvent('Events');
           event.initEvent('ValueChange', true, true);
           this.inputField.dispatchEvent(event);
           return val;
         ]]></setter>
       </property>
 
--- a/toolkit/content/widgets/numberbox.xml
+++ b/toolkit/content/widgets/numberbox.xml
@@ -11,17 +11,17 @@
 
     <resources>
       <stylesheet src="chrome://global/skin/numberbox.css"/>
     </resources>
 
     <content>
       <xul:hbox class="textbox-input-box numberbox-input-box" flex="1" xbl:inherits="context,disabled,focused">
         <html:input class="numberbox-input textbox-input" flex="1" anonid="input"
-                    xbl:inherits="onfocus,onblur,value,type,maxlength,disabled,size,readonly,tabindex,accesskey"/>
+                    xbl:inherits="onfocus,onblur,value,type,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey"/>
       </xul:hbox>
       <xul:spinbuttons anonid="buttons" xbl:inherits="disabled,hidden=hidespinbuttons"/>
     </content>
 
     <implementation>
       <field name="_valueEntered">false</field>
       <field name="_spinButtons">null</field>
       <field name="_value">0</field>
--- a/toolkit/content/widgets/textbox.xml
+++ b/toolkit/content/widgets/textbox.xml
@@ -16,17 +16,17 @@
       <stylesheet src="chrome://global/content/textbox.css"/>
       <stylesheet src="chrome://global/skin/textbox.css"/>
     </resources>
 
     <content>
       <children/>
       <xul:hbox class="textbox-input-box" flex="1" xbl:inherits="context,spellcheck">
         <html:input class="textbox-input" flex="1" anonid="input"
-                    xbl:inherits="onfocus,onblur,value,type,maxlength,disabled,size,readonly,tabindex,accesskey,noinitialfocus"/>
+                    xbl:inherits="onfocus,onblur,value,type,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey,noinitialfocus"/>
       </xul:hbox>
     </content>
 
     <implementation implements="nsIAccessibleProvider, nsIDOMXULTextBoxElement, nsIDOMXULLabeledControlElement">
       <property name="accessibleType" readonly="true">
         <getter>
           <![CDATA[
             return Components.interfaces.nsIAccessibleProvider.XULTextBox;
@@ -47,40 +47,28 @@
       <property name="inputField" readonly="true">
         <getter><![CDATA[
           if (!this.mInputField)
             this.mInputField = document.getAnonymousElementByAttribute(this, "anonid", "input");
           return this.mInputField;
         ]]></getter>
       </property>
 
-      <property name="value"
-                onget="return this.hasAttribute('isempty') ? '' : this.inputField.value;">
-        <setter><![CDATA[
-          if (val) {
-            // clear the emptyText _before_ setting a new non-empty value
-            this._clearEmptyText();
-            this.inputField.value = val;
-          } else {
-            // display the emptyText _after_ setting a value that's an empty string
-            this.inputField.value = val;
-            this._updateVisibleText();
-          }
-          return val;
-        ]]></setter>
-      </property>
+      <property name="value"      onset="this.inputField.value = val; return val;"
+                                  onget="return this.inputField.value;"/>
       <property name="defaultValue" onset="this.inputField.defaultValue = val; return val;"
                                   onget="return this.inputField.defaultValue;"/>
       <property name="label"      onset="this.setAttribute('label', val); return val;"
                                   onget="return this.getAttribute('label') ||
                                                 (this.labelElement ? this.labelElement.value :
-                                                 this.emptyText);"/>
-      <property name="emptyText"  onget="return this.getAttribute('emptytext') || '';"
-                                  onset="this.setAttribute('emptytext', val);
-                                         this._updateVisibleText(); return val;" />
+                                                 this.placeholder);"/>
+      <property name="placeholder" onset="this.inputField.placeholder = val; return val;"
+                                  onget="return this.inputField.placeholder;"/>
+      <property name="emptyText"  onset="this.placeholder = val; return val;"
+                                  onget="return this.placeholder;"/>
       <property name="type"       onset="if (val) this.setAttribute('type', val);
                                          else this.removeAttribute('type'); return val;"
                                   onget="return this.getAttribute('type');"/>
       <property name="maxLength"  onset="this.inputField.maxLength = val; return val;"
                                   onget="return this.inputField.maxLength;"/>
       <property name="disabled"   onset="this.inputField.disabled = val;
                                          if (val) this.setAttribute('disabled', 'true');
                                          else this.removeAttribute('disabled'); return val;"
@@ -122,18 +110,17 @@
       <method name="select">
         <body>
           this.inputField.select();
         </body>
       </method>
 
       <property name="controllers"    readonly="true" onget="return this.inputField.controllers"/>
       <property name="textLength"     readonly="true"
-                                      onget="return this.hasAttribute('isempty') ?
-                                                    0 : this.inputField.textLength;"/>
+                                      onget="return this.inputField.textLength;"/>
       <property name="selectionStart" onset="this.inputField.selectionStart = val; return val;"
                                       onget="return this.inputField.selectionStart;"/>
       <property name="selectionEnd"   onset="this.inputField.selectionEnd = val; return val;"
                                       onget="return this.inputField.selectionEnd;"/>
 
       <method name="setSelectionRange">
         <parameter name="aSelectionStart"/>
         <parameter name="aSelectionEnd"/>
@@ -155,68 +142,27 @@
                   break;
                 }
               }
             }
           }
         ]]></body>
       </method>
 
-      <method name="_updateVisibleText">
-        <body><![CDATA[
-          if (!this.hasAttribute("focused") &&
-              !this.value &&
-              this.emptyText) {
-
-            if (!this.hasAttribute("isempty")) {
-              this.setAttribute("isempty", "true");
-
-              // Hide the emptytext for a bit, in case the textbox will be focused subsequently
-              this.inputField.setAttribute("emptytextdelay", "true");
-              setTimeout(function (input) {
-                input.removeAttribute("emptytextdelay");
-              }, 100, this.inputField);
-
-              try {
-                this.editor.transactionManager.beginBatch();
-              } catch (e) {}
-            }
-
-            this.inputField.value = this.emptyText;
-          }
-        ]]></body>
-      </method>
-
-      <method name="_clearEmptyText">
-        <body><![CDATA[
-          if (this.hasAttribute("isempty")) {
-            this.inputField.value = "";
-            try {
-              var transactionManager = this.editor.transactionManager;
-              transactionManager.endBatch();
-
-              // Clear undo stack if there have been no user edits
-              if (transactionManager.numberOfUndoItems == 1 &&
-                  transactionManager.numberOfRedoItems == 0)
-                transactionManager.clear();
-            } catch (e) {}
-            this.removeAttribute("isempty");
-          }
-        ]]></body>
-      </method>
-
       <constructor><![CDATA[
         var str = this.boxObject.getProperty("value");
         if (str) {
           this.inputField.value = str;
           this.boxObject.removeProperty("value");
         }
 
-        this._updateVisibleText();
         this._setNewlineHandling();
+
+        if (this.hasAttribute("emptytext"))
+          this.placeholder = this.setAttribute("emptytext");
       ]]></constructor>
 
       <destructor>
         <![CDATA[
           if (this.inputField.value)
             this.boxObject.setProperty('value', this.inputField.value);
           this.mInputField = null;
         ]]>
@@ -231,18 +177,16 @@
             return;
 
           switch (event.originalTarget) {
             case this:
               // Forward focus to actual HTML input
               this.inputField.focus();
               break;
             case this.inputField:
-              this._clearEmptyText();
-
               if (this.mIgnoreFocus) {
                 this.mIgnoreFocus = false;
               } else if (this.clickSelectsAll) {
                 try {
                   const nsIEditorIMESupport =
                           Components.interfaces.nsIEditorIMESupport;
                   let imeEditor = this.editor.QueryInterface(nsIEditorIMESupport);
                   if (!imeEditor || !imeEditor.composing)
@@ -256,34 +200,25 @@
           }
           this.setAttribute("focused", "true");
         ]]>
       </handler>
 
       <handler event="blur" phase="capturing">
         <![CDATA[
           this.removeAttribute('focused');
-          this._updateVisibleText();
 
           // don't trigger clickSelectsAll when switching application windows
           if (window == window.top &&
               window.constructor == ChromeWindow &&
               document.activeElement == this.inputField)
             this.mIgnoreFocus = true;
         ]]>
       </handler>
 
-      <handler event="dragover" phase="capturing">
-        this._clearEmptyText();
-      </handler>
-
-      <handler event="dragexit" phase="capturing">
-        this._updateVisibleText();
-      </handler>
-
       <handler event="mousedown">
         <![CDATA[
           this.mIgnoreClick = this.hasAttribute("focused");
 
           if (!this.mIgnoreClick) {
             this.mIgnoreFocus = true;
             this.inputField.setSelectionRange(0, 0);
             if (event.originalTarget == this ||
@@ -318,27 +253,19 @@
           consoleService.logMessage(scriptError);
         } catch (e) {}
       ]]></constructor>
       <field name="_timer">null</field>
       <property name="timeout"
                 onset="this.setAttribute('timeout', val); return val;"
                 onget="return parseInt(this.getAttribute('timeout')) || 0;"/>
       <property name="value"
-                onget="return this.hasAttribute('isempty') ? '' : this.inputField.value;">
+                onget="return this.inputField.value;">
         <setter><![CDATA[
-          if (val) {
-            // clear the emptyText _before_ setting a new non-empty value
-            this._clearEmptyText();
-            this.inputField.value = val;
-          } else {
-            // display the emptyText _after_ setting a value that's an empty string
-            this.inputField.value = val;
-            this._updateVisibleText();
-          }
+          this.inputField.value = val;
           if (this._timer)
             clearTimeout(this._timer);
           return val;
         ]]></setter>
       </property>
       <method name="_fireCommand">
         <parameter name="me"/>
         <body>
@@ -368,17 +295,17 @@
     </handlers>
   </binding>
 
   <binding id="search-textbox" extends="chrome://global/content/bindings/textbox.xml#textbox">
     <content>
       <children/>
       <xul:hbox class="textbox-input-box" flex="1" xbl:inherits="context,spellcheck" align="center">
         <html:input class="textbox-input" flex="1" anonid="input"
-                    xbl:inherits="onfocus,onblur,value,type,maxlength,disabled,size,readonly,tabindex,accesskey"/>
+                    xbl:inherits="onfocus,onblur,value,type,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey"/>
         <xul:deck class="textbox-search-icons" anonid="search-icons">
           <xul:image class="textbox-search-icon"
                      onclick="document.getBindingParent(this)._iconClick();"
                      xbl:inherits="src=image,searchbutton,disabled"/>
           <xul:image class="textbox-search-clear"
                      onclick="document.getBindingParent(this)._clearSearch();"
                      xbl:inherits="disabled"/>
         </xul:deck>
@@ -401,31 +328,28 @@
           } else {
             this.removeAttribute("searchbutton");
             this.setAttribute("aria-autocomplete", "list");
           }
           return val;
         ]]></setter>
       </property>
       <property name="value"
-                onget="return this.hasAttribute('isempty') ? '' : this.inputField.value;">
+                onget="return this.inputField.value;">
         <setter><![CDATA[
-          if (val) {
-            // clear the emptyText _before_ setting a new non-empty value
-            this._clearEmptyText();
-            this.inputField.value = val;
+          this.inputField.value = val;
+
+          if (val)
             this._searchIcons.selectedIndex = this.searchButton ? 0 : 1;
-          } else {
-            // display the emptyText _after_ setting a value that's an empty string
-            this.inputField.value = val;
-            this._updateVisibleText();
+          else
             this._searchIcons.selectedIndex = 0;
-          }
+
           if (this._timer)
             clearTimeout(this._timer);
+
           return val;
         ]]></setter>
       </property>
       <constructor><![CDATA[
         if (this.searchButton)
           this.removeAttribute("aria-autocomplete");
         else
           this.setAttribute("aria-autocomplete", "list");
@@ -498,17 +422,17 @@
       </handler>
     </handlers>
   </binding>
 
   <binding id="textarea" extends="chrome://global/content/bindings/textbox.xml#textbox">
     <content>
       <xul:hbox class="textbox-input-box" flex="1" xbl:inherits="context,spellcheck">
         <html:textarea class="textbox-textarea" flex="1" anonid="input"
-                       xbl:inherits="onfocus,onblur,xbl:text=value,disabled,tabindex,rows,cols,readonly,wrap"><children/></html:textarea>
+                       xbl:inherits="onfocus,onblur,xbl:text=value,disabled,tabindex,rows,cols,readonly,wrap,placeholder"><children/></html:textarea>
       </xul:hbox>
     </content>
   </binding>
 
   <binding id="input-box">
     <content context="_child">
       <children/>
       <xul:menupopup anonid="input-box-contextmenu"
--- a/toolkit/mozapps/downloads/content/downloads.xul
+++ b/toolkit/mozapps/downloads/content/downloads.xul
@@ -186,12 +186,12 @@
   <windowdragbox id="search" align="center">
     <button id="clearListButton" command="cmd_clearList"
             label="&cmd.clearList.label;"
             accesskey="&cmd.clearList.accesskey;"
             tooltiptext="&cmd.clearList.tooltip;"/>
     <spacer flex="1"/>
     <textbox type="search" id="searchbox" class="compact"
              aria-controls="downloadView"
-             oncommand="buildDownloadList();" emptytext="&searchBox.label;"/>
+             oncommand="buildDownloadList();" placeholder="&searchBox.label;"/>
   </windowdragbox>
 
 </window>
--- a/toolkit/mozapps/extensions/content/extensions.xul
+++ b/toolkit/mozapps/extensions/content/extensions.xul
@@ -181,17 +181,17 @@
         <progressmeter id="addonsProgress" class="extension-item-progress" flex="1"/>
         <spacer flex="1"/>
       </vbox>
     </deck>
   </windowdragbox>
   <notificationbox id="addonsMsg" flex="1">
     <vbox id="extensionsBox" flex="1">
       <hbox id="searchPanel" align="center">
-        <textbox id="searchfield" emptytext="&searchAddons.label;"
+        <textbox id="searchfield" placeholder="&searchAddons.label;"
                  type="search" searchbutton="true" class="compact"
                  oncommand="retrieveRepositoryAddons(this.value);"/>
         <spacer flex="1"/>
         <label id="browseAddons" class="text-link" value="&browseAddons.label;"
                onclick="if (event.button == 0) { openURL(this.getAttribute('homepageURL')); }"/>
       </hbox>
       
       <hbox flex="1">
--- a/toolkit/themes/faststripe/global/textbox.css
+++ b/toolkit/themes/faststripe/global/textbox.css
@@ -50,20 +50,16 @@ textbox {
   margin: 2px 4px;
   border: 1px solid #555555;
   padding: 2px 2px 3px;
   -moz-padding-start: 4px;
   background-color: white;
   color: black;
 }
 
-textbox[isempty="true"] {
-  color: #999999;
-}
-
 html|*.textbox-input, 
 html|*.textbox-textarea {
   margin: 0px !important;
   border: none !important;
   padding: 0px !important;
   background-color: inherit;
   color: inherit;
   font: inherit;
--- a/toolkit/themes/gnomestripe/global/textbox.css
+++ b/toolkit/themes/gnomestripe/global/textbox.css
@@ -55,20 +55,16 @@ textbox {
   -moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
   -moz-border-left-colors: ThreeDShadow ThreeDDarkShadow;
   padding: 2px 2px 3px;
   -moz-padding-start: 4px;
   background-color: -moz-Field;
   color: -moz-FieldText;
 }
 
-textbox[isempty="true"] {
-  color: GrayText;
-}
-
 html|*.textbox-input, 
 html|*.textbox-textarea {
   margin: 0px !important;
   border: none !important;
   padding: 0px !important;
   background-color: inherit;
   color: inherit;
   font: inherit;
--- a/toolkit/themes/pinstripe/global/textbox.css
+++ b/toolkit/themes/pinstripe/global/textbox.css
@@ -53,20 +53,16 @@ textbox {
   -moz-border-radius-topright: 2px;
   -moz-border-radius-bottomleft: 2px;
   /*padding: 1px 0px 1px 2px ;*/
   padding: 0px;
   background-color: -moz-Field;
   color: -moz-FieldText;
 }
 
-textbox[isempty="true"] {
-  color: GrayText;
-}
-
 html|*.textbox-input, 
 html|*.textbox-textarea {
   margin: 0px !important;
   border: none !important;
   padding: 0px !important;
   background-color: inherit;
   color: inherit;
   font: inherit;
--- a/toolkit/themes/winstripe/global/textbox-aero.css
+++ b/toolkit/themes/winstripe/global/textbox-aero.css
@@ -1,5 +1,5 @@
 %include textbox.css
 
-textbox[isempty="true"]:-moz-system-metric(windows-default-theme) {
+textbox html|*.textbox-input:-moz-placeholder:-moz-system-metric(windows-default-theme) {
   font-style: italic;
 }
--- a/toolkit/themes/winstripe/global/textbox.css
+++ b/toolkit/themes/winstripe/global/textbox.css
@@ -55,20 +55,16 @@ textbox {
   -moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
   -moz-border-left-colors: ThreeDShadow ThreeDDarkShadow;
   padding: 2px 2px 3px;
   -moz-padding-start: 4px;
   background-color: -moz-Field;
   color: -moz-FieldText;
 }
 
-textbox[isempty="true"] {
-  color: GrayText;
-}
-
 html|*.textbox-input, 
 html|*.textbox-textarea {
   margin: 0px !important;
   border: none !important;
   padding: 0px !important;
   background-color: inherit;
   color: inherit;
   font: inherit;