Bug 596485 - Provide visual indication of Switch to Tab override. r=gavin, a=blocking-betaN
authorDrew Willcoxon <adw@mozilla.com>
Fri, 10 Dec 2010 18:32:14 -0800
changeset 59104 5113288ca83e
parent 59103 1bad85a23cc5
child 59105 0020a1042b3f
push id17531
push userdwillcoxon@mozilla.com
push dateSat, 11 Dec 2010 02:33:16 +0000
treeherdermozilla-central@5113288ca83e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgavin, blocking-betaN
bugs596485
milestone2.0b8pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 596485 - Provide visual indication of Switch to Tab override. r=gavin, a=blocking-betaN
browser/base/content/browser.css
browser/base/content/urlbarBindings.xml
browser/themes/gnomestripe/browser/browser.css
browser/themes/pinstripe/browser/browser.css
browser/themes/winstripe/browser/browser.css
toolkit/content/widgets/autocomplete.xml
toolkit/content/xul.css
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -250,20 +250,29 @@ html|*.urlbar-input {
 }
 
 .urlbar-over-link-box:not([overlinkstate]) {
   opacity: 0;
 }
 
 /* For results that are actions, their description text is shown instead of
    the URL - this needs to follow the locale's direction, unlike URLs. */
-richlistitem[type~="action"]:-moz-locale-dir(rtl) > .ac-url-box {
+panel:not([noactions]) > richlistbox > richlistitem[type~="action"]:-moz-locale-dir(rtl) > .ac-url-box {
   direction: rtl;
 }
 
+panel[noactions] > richlistbox > richlistitem[type~="action"] > .ac-url-box > .ac-url > .ac-action-text,
+panel[noactions] > richlistbox > richlistitem[type~="action"] > .ac-url-box > .ac-action-icon {
+  visibility: collapse;
+}
+
+panel[noactions] > richlistbox > richlistitem[type~="action"] > .ac-url-box > .ac-url > .ac-url-text {
+  visibility: visible;
+}
+
 #urlbar:not([actiontype]) > #urlbar-display {
   display: none;
 }
 
 #wrapper-urlbar-container > #urlbar-container > #urlbar {
   -moz-user-input: disabled;
   cursor: -moz-grab;
 }
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -230,17 +230,17 @@
             return; // Do nothing for right clicks
 
           var url = this.value;
           var postData = null;
 
           var action = this._parseActionUrl(url);
           if (action) {
             url = action.param;
-            if (!(aTriggeringEvent && aTriggeringEvent.altKey)) {
+            if (this.hasAttribute("actiontype")) {
               if (action.type == "switchtab") {
                 this.handleRevert();
                 let prevTab = gBrowser.selectedTab;
                 if (switchToTabHavingURI(url) &&
                     isTabEmpty(prevTab))
                   gBrowser.removeTab(prevTab);
               }
               return;
@@ -272,16 +272,19 @@
             }
             openUILinkIn(url, where,
                         { allowThirdPartyFixup: true, postData: postData });
             return;
           }
 
           if (aTriggeringEvent && aTriggeringEvent.altKey) {
             this.handleRevert();
+            let prevTab = gBrowser.selectedTab;
+            if (isTabEmpty(prevTab))
+              gBrowser.removeTab(prevTab);
             content.focus();
             gBrowser.loadOneTab(url, {
                                 postData: postData,
                                 inBackground: false,
                                 allowThirdPartyFixup: true});
             aTriggeringEvent.preventDefault();
             aTriggeringEvent.stopPropagation();
           }
@@ -774,19 +777,58 @@
             overLinkPath.crop = host ? "start" : "end";
             overLink.style.minWidth = maxWidth + "px";
             overLink.style.maxWidth = maxWidth + "px";
           }
 
           this._originLabel.value = this.value;
         ]]></body>
       </method>
+
+      <field name="_numNoActionsKeys"><![CDATA[
+        0
+      ]]></field>
+
+      <method name="_clearNoActions">
+        <parameter name="aURL"/>
+        <body><![CDATA[
+          this._numNoActionsKeys = 0;
+          this.popup.removeAttribute("noactions");
+          let action = this._parseActionUrl(this._value);
+          if (action)
+            this.setAttribute("actiontype", action.type);
+        ]]></body>
+      </method>
     </implementation>
 
     <handlers>
+      <handler event="keydown"><![CDATA[
+        if ((event.keyCode === KeyEvent.DOM_VK_ALT ||
+             event.keyCode === KeyEvent.DOM_VK_SHIFT) &&
+            this.popup.selectedIndex >= 0) {
+          this._numNoActionsKeys++;
+          this.popup.setAttribute("noactions", "true");
+          this.removeAttribute("actiontype");
+        }
+      ]]></handler>
+
+      <handler event="keyup"><![CDATA[
+        if ((event.keyCode === KeyEvent.DOM_VK_ALT ||
+             event.keyCode === KeyEvent.DOM_VK_SHIFT) &&
+            this._numNoActionsKeys > 0) {
+          this._numNoActionsKeys--;
+          if (this._numNoActionsKeys == 0)
+            this._clearNoActions();
+        }
+      ]]></handler>
+
+      <handler event="blur"><![CDATA[
+        this._clearNoActions();
+      ]]></handler>
+
       <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.
         //       This can be changed once editor code is updated to the new API.
         //       See bug 499008 for details.
 
         // Drag only if the gesture starts from the input field.
         if (event.originalTarget != this.inputField)
--- a/browser/themes/gnomestripe/browser/browser.css
+++ b/browser/themes/gnomestripe/browser/browser.css
@@ -1218,29 +1218,32 @@ toolbar[iconsize="small"] #feed-button {
 .ac-comment {
   font-size: 1.15em;
 }
 
 .ac-extra > .ac-comment {
   font-size: inherit;
 }
 
-.ac-url-text {
+.ac-url-text,
+.ac-action-text {
   color: -moz-nativehyperlinktext;
 }
 
 richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
   list-style-image: url("chrome://browser/skin/actionicon-tab.png");
 }
 
 .autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
   color: GrayText;
 }
 
-.ac-comment[selected="true"], .ac-url-text[selected="true"] {
+.ac-comment[selected="true"],
+.ac-url-text[selected="true"],
+.ac-action-text[selected="true"] {
   color: inherit !important;
 }
 
 .autocomplete-treebody::-moz-tree-cell-text(suggesthint, treecolAutoCompleteComment), 
 .autocomplete-treebody::-moz-tree-cell-text(suggestfirst, treecolAutoCompleteComment) {
   color: GrayText;
   font-size: smaller;
 }
--- a/browser/themes/pinstripe/browser/browser.css
+++ b/browser/themes/pinstripe/browser/browser.css
@@ -917,30 +917,33 @@ richlistitem[selected="true"][current="t
 .ac-comment {
   font-size: 1.1em;
 }
 
 .ac-extra > .ac-comment {
   font-size: inherit;
 }
 
-.ac-url-text {
+.ac-url-text,
+.ac-action-text {
   color: -moz-nativehyperlinktext;
   font-size: 0.95em;
 }
 
 richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
   list-style-image: url("chrome://browser/skin/actionicon-tab.png");
 }
 
 .autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
   color: GrayText;
 }
 
-.ac-comment[selected="true"], .ac-url-text[selected="true"] {
+.ac-comment[selected="true"],
+.ac-url-text[selected="true"],
+.ac-action-text[selected="true"] {
   color: inherit !important;
 }
 
 .autocomplete-treebody::-moz-tree-cell-text(suggesthint, treecolAutoCompleteComment), 
 .autocomplete-treebody::-moz-tree-cell-text(suggestfirst, treecolAutoCompleteComment) 
 {
   color: GrayText;
   font-size: smaller;
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -1245,35 +1245,39 @@ html|*.urlbar-input:-moz-lwtheme:-moz-pl
 .ac-comment {
   font-size: 1.15em;
 }
 
 .ac-extra > .ac-comment {
   font-size: inherit;
 }
 
-.ac-url-text {
+.ac-url-text,
+.ac-action-text {
   color: -moz-nativehyperlinktext;
 }
 
 %ifndef WINSTRIPE_AERO
-.ac-url-text:-moz-system-metric(windows-default-theme) {
+.ac-url-text:-moz-system-metric(windows-default-theme),
+.ac-action-text:-moz-system-metric(windows-default-theme) {
   color: #006600;
 }
 %endif
 
 richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
   list-style-image: url("chrome://browser/skin/actionicon-tab.png");
 }
 
 .autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
   color: GrayText;
 }
 
-.ac-comment[selected="true"], .ac-url-text[selected="true"] {
+.ac-comment[selected="true"],
+.ac-url-text[selected="true"],
+.ac-action-text[selected="true"] {
   color: inherit !important;
 }
 
 .autocomplete-treebody::-moz-tree-cell-text(suggesthint, treecolAutoCompleteComment), 
 .autocomplete-treebody::-moz-tree-cell-text(suggestfirst, treecolAutoCompleteComment) 
 {
   color: GrayText;
   font-size: smaller;
--- a/toolkit/content/widgets/autocomplete.xml
+++ b/toolkit/content/widgets/autocomplete.xml
@@ -22,16 +22,17 @@
 # the Initial Developer. All Rights Reserved.
 #
 # Contributor(s):
 #   Pierre Chanial (p_ch@verizon.net)
 #   Dean Tessman   (dean_tessman@hotmail.com)
 #   Masayuki Nakano (masayuki@d-toybox.com)
 #   Pamela Greene (pamg.bugs@gmail.com)
 #   Edward Lee (edward.lee@engineering.uiuc.edu)
+#   Drew Willcoxon (adw@mozilla.com)
 #
 # Alternatively, the contents of this file may be used under the terms of
 # either the GNU General Public License Version 2 or later (the "GPL"), or
 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 # in which case the provisions of the GPL or the LGPL are applicable instead
 # of those above. If you wish to allow use of your version of this file only
 # under the terms of either the GPL or the LGPL, and not to allow others to
 # use your version of this file under the terms of the MPL, indicate your
@@ -1159,37 +1160,42 @@
     </implementation>
   </binding>
 
   <binding id="autocomplete-richlistitem" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
     <content>
       <xul:hbox align="center" class="ac-title-box">
         <xul:image xbl:inherits="src=image" class="ac-site-icon"/>
         <xul:hbox anonid="title-box" class="ac-title" flex="1"
-                  onunderflow="_doUnderflow('_title');">
+                  onunderflow="_doUnderflow('_title');"
+                  onoverflow="_doOverflow('_title');">
           <xul:description anonid="title" class="ac-normal-text ac-comment" xbl:inherits="selected"/>
         </xul:hbox>
         <xul:label anonid="title-overflow-ellipsis" xbl:inherits="selected"
-                   class="ac-ellipsis-after ac-comment" hidden="true"/>
+                   class="ac-ellipsis-after ac-comment"/>
         <xul:hbox anonid="extra-box" class="ac-extra" align="center" hidden="true">
           <xul:image class="ac-result-type-tag"/>
           <xul:label class="ac-normal-text ac-comment" xbl:inherits="selected" value=":"/>
           <xul:description anonid="extra" class="ac-normal-text ac-comment" xbl:inherits="selected"/>
         </xul:hbox>
         <xul:image anonid="type-image" class="ac-type-icon"/>
       </xul:hbox>
       <xul:hbox align="center" class="ac-url-box">
         <xul:spacer class="ac-site-icon"/>
         <xul:image class="ac-action-icon"/>
         <xul:hbox anonid="url-box" class="ac-url" flex="1"
-                  onunderflow="_doUnderflow('_url');">
-          <xul:description anonid="url" class="ac-normal-text ac-url-text" xbl:inherits="selected"/>
+                  onunderflow="_doUnderflow('_url');"
+                  onoverflow="_doOverflow('_url');">
+          <xul:description anonid="url" class="ac-normal-text ac-url-text"
+                           xbl:inherits="selected type"/>
+          <xul:description anonid="action" class="ac-normal-text ac-action-text"
+                           xbl:inherits="selected type"/>
         </xul:hbox>
         <xul:label anonid="url-overflow-ellipsis" xbl:inherits="selected"
-                   class="ac-ellipsis-after ac-url-text" hidden="true"/>
+                   class="ac-ellipsis-after ac-url-text"/>
         <xul:spacer class="ac-type-icon"/>
       </xul:hbox>
     </content>
     <implementation implements="nsIDOMXULSelectControlItemElement">
       <constructor>
         <![CDATA[
             let ellipsis = "\u2026";
             try {
@@ -1206,16 +1212,17 @@
 
             this._urlOverflowEllipsis.value = ellipsis;
             this._titleOverflowEllipsis.value = ellipsis;
 
             this._typeImage = document.getAnonymousElementByAttribute(this, "anonid", "type-image");
 
             this._urlBox = document.getAnonymousElementByAttribute(this, "anonid", "url-box");
             this._url = document.getAnonymousElementByAttribute(this, "anonid", "url");
+            this._action = document.getAnonymousElementByAttribute(this, "anonid", "action");
 
             this._titleBox = document.getAnonymousElementByAttribute(this, "anonid", "title-box");
             this._title = document.getAnonymousElementByAttribute(this, "anonid", "title");
 
             this._extraBox = document.getAnonymousElementByAttribute(this, "anonid", "extra-box");
             this._extra = document.getAnonymousElementByAttribute(this, "anonid", "extra");
 
             this._adjustAcItem();
@@ -1403,28 +1410,25 @@
         <body>
           <![CDATA[
           var url = this.getAttribute("url");
           var title = this.getAttribute("title");
           var type = this.getAttribute("type");
 
           this.removeAttribute("actiontype");
 
-          var setupUrl = true;
-
           // If the type includes an action, set up the item appropriately.
           var types = type.split(/\s+/);
           var actionIndex = types.indexOf("action");
           if (actionIndex >= 0) {
             let [,action, param] = url.match(/^moz-action:([^,]+),(.*)$/);
             this.setAttribute("actiontype", action);
             url = param;
             let desc = "]]>&action.switchToTab.label;<![CDATA[";
-            this._setUpDescription(this._url, desc, true);
-            setupUrl = false;
+            this._setUpDescription(this._action, desc, true);
 
             // Remove the "action" substring so that the correct style, if any,
             // is applied below.
             types.splice(actionIndex, 1);
             type = types.join(" ");
           }
 
           // If we have a tag match, show the tags and icon
@@ -1479,34 +1483,33 @@
             (type ? " ac-result-type-" + type : "");
 
           // Show the url as the title if we don't have a title
           if (title == "")
             title = url;
 
           // Emphasize the matching search terms for the description
           this._setUpDescription(this._title, title);
-          if (setupUrl)
-            this._setUpDescription(this._url, url);
+          this._setUpDescription(this._url, url);
 
           // Set up overflow on a timeout because the contents of the box
           // might not have a width yet even though we just changed them
           setTimeout(this._setUpOverflow, 0, this._titleBox, this._titleOverflowEllipsis);
           setTimeout(this._setUpOverflow, 0, this._urlBox, this._urlOverflowEllipsis);
           ]]>
         </body>
       </method>
 
       <method name="_setUpOverflow">
         <parameter name="aParentBox"/>
         <parameter name="aEllipsis"/>
         <body>
           <![CDATA[
           // Hide the ellipsis incase there's just enough to not underflow
-          aEllipsis.hidden = true;
+          aEllipsis.style.visibility = "hidden";
 
           // Start with the parent's width and subtract off its children
           let tooltip = [];
           let children = aParentBox.childNodes;
           let widthDiff = aParentBox.boxObject.width;
 
           for (let i = 0; i < children.length; i++) {
             // Only consider a child if it actually takes up space
@@ -1520,33 +1523,43 @@
               if (childText)
                 tooltip.push(childText);
             }
           }
 
           // If the children take up more space than the parent.. overflow!
           if (widthDiff < 0) {
             // Re-show the ellipsis now that we know it's needed
-            aEllipsis.hidden = false;
+            aEllipsis.style.visibility = "visible";
 
             // Separate text components with a ndash --
             aParentBox.tooltipText = tooltip.join(" \u2013 ");
           }
           ]]>
         </body>
       </method>
 
       <method name="_doUnderflow">
         <parameter name="aName"/>
         <body>
           <![CDATA[
           // Hide the ellipsis right when we know we're underflowing instead of
           // waiting for the timeout to trigger the _setUpOverflow calculations
           this[aName + "Box"].tooltipText = "";
-          this[aName + "OverflowEllipsis"].hidden = true;
+          this[aName + "OverflowEllipsis"].style.visibility = "hidden";
+          ]]>
+        </body>
+      </method>
+
+      <method name="_doOverflow">
+        <parameter name="aName"/>
+        <body>
+          <![CDATA[
+          this._setUpOverflow(this[aName + "Box"],
+                              this[aName + "OverflowEllipsis"]);
           ]]>
         </body>
       </method>
 
     </implementation>
   </binding>
 
   <binding id="autocomplete-tree" extends="chrome://global/content/bindings/tree.xml#tree">
--- a/toolkit/content/xul.css
+++ b/toolkit/content/xul.css
@@ -784,16 +784,18 @@ textbox[type="autocomplete"] {
 panel[type="autocomplete"] {
   -moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete-result-popup");
 }
 
 panel[type="autocomplete-richlistbox"] {
   -moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete-rich-result-popup");
 }
 
+/* FIXME: bug 616258 */
+
 .autocomplete-tree {
   -moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete-tree");
   -moz-user-focus: ignore;
 }
 
 .autocomplete-treebody {
   -moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete-treebody");
 }
@@ -821,16 +823,25 @@ panel[type="autocomplete-richlistbox"] {
   display: none;
 }
 
 .autocomplete-history-dropmarker[enablehistory="true"] {
   display: -moz-box;
   -moz-binding: url("chrome://global/content/bindings/autocomplete.xml#history-dropmarker");
 }
 
+.ac-ellipsis-after {
+  visibility: hidden;
+}
+
+.ac-url-text[type~="action"],
+.ac-action-text:not([type~="action"]) {
+  visibility: collapse;
+}
+
 %endif
 
 
 
 /* the C++ implementation of widgets is too eager to make popups visible.
    this causes problems (bug 120155 and others), thus this workaround: */
 popup[type="autocomplete"][hidden="true"] {
   visibility: hidden;