Bug 851519 - Keyboard commands may executed on the wrong download in the panel
authorMarco Bonardo <mbonardo@mozilla.com>
Wed, 17 Apr 2013 16:16:09 +0200
changeset 129077 63c0033754166f16bc204041fa47911d99528a87
parent 129076 78ccd7f5313ffe5ac56678d587950b948985cdb4
child 129078 4909e586d460899465144f5c8cb001ffd6e8e870
push id24556
push userryanvm@gmail.com
push dateWed, 17 Apr 2013 20:02:07 +0000
treeherdermozilla-central@25c2aaee8acc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs851519
milestone23.0a1
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 851519 - Keyboard commands may executed on the wrong download in the panel r=Mano
browser/components/downloads/content/downloads.js
browser/components/downloads/content/downloadsOverlay.xul
--- a/browser/components/downloads/content/downloads.js
+++ b/browser/components/downloads/content/downloads.js
@@ -317,19 +317,19 @@ const DownloadsPanel = {
     }
 
     DownloadsCommon.log("Downloads panel has shown.");
     this._state = this.kStateShown;
 
     // Since at most one popup is open at any given time, we can set globally.
     DownloadsCommon.getIndicatorData(window).attentionSuppressed = true;
 
-    // Ensure that an item is selected when the panel is focused.
+    // Ensure that the first item is selected when the panel is focused.
     if (DownloadsView.richListBox.itemCount > 0 &&
-        !DownloadsView.richListBox.selectedItem) {
+        DownloadsView.richListBox.selectedIndex == -1) {
       DownloadsView.richListBox.selectedIndex = 0;
     }
 
     this._focusPanel();
   },
 
   onPopupHidden: function DP_onPopupHidden(aEvent)
   {
@@ -412,16 +412,20 @@ const DownloadsPanel = {
     // navigation, thus enabling focusrings in the panel.  Keyboard navigation
     // is automatically disabled if the user moves the mouse on the panel, or
     // if the panel is closed.
     if ((aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_TAB ||
         aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_UP ||
         aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_DOWN) &&
         !this.keyFocusing) {
       this.keyFocusing = true;
+      // Ensure there's a selection, we will show the focus ring around it and
+      // prevent the richlistbox from changing the selection.
+      if (DownloadsView.richListBox.selectedIndex == -1)
+        DownloadsView.richListBox.selectedIndex = 0;
       aEvent.preventDefault();
       return;
     }
 
     if (aEvent.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_DOWN) {
       // If the last element in the list is selected, or the footer is already
       // focused, focus the footer.
       if (richListBox.selectedItem === richListBox.lastChild ||
@@ -899,18 +903,20 @@ const DownloadsView = {
    * Removes the view item associated with the specified data item.
    */
   _removeViewItem: function DV_removeViewItem(aDataItem)
   {
     DownloadsCommon.log("Removing a DownloadsViewItem from the downloads list.");
     let element = this.getViewItem(aDataItem)._element;
     let previousSelectedIndex = this.richListBox.selectedIndex;
     this.richListBox.removeChild(element);
-    this.richListBox.selectedIndex = Math.min(previousSelectedIndex,
-                                              this.richListBox.itemCount - 1);
+    if (previousSelectedIndex != -1) {
+      this.richListBox.selectedIndex = Math.min(previousSelectedIndex,
+                                                this.richListBox.itemCount - 1);
+    }
     delete this._viewItems[aDataItem.downloadGuid];
   },
 
   //////////////////////////////////////////////////////////////////////////////
   //// User interface event functions
 
   /**
    * Helper function to do commands on a specific download item.
@@ -958,16 +964,39 @@ const DownloadsView = {
     }
 
     if (aEvent.keyCode == KeyEvent.DOM_VK_ENTER ||
         aEvent.keyCode == KeyEvent.DOM_VK_RETURN) {
       goDoCommand("downloadsCmd_doDefault");
     }
   },
 
+
+  /**
+   * Mouse listeners to handle selection on hover.
+   */
+  onDownloadMouseOver: function DV_onDownloadMouseOver(aEvent)
+  {
+    if (aEvent.originalTarget.parentNode == this.richListBox)
+      this.richListBox.selectedItem = aEvent.originalTarget;
+  },
+  onDownloadMouseOut: function DV_onDownloadMouseOut(aEvent)
+  {
+    if (aEvent.originalTarget.parentNode == this.richListBox) {
+      // If the destination element is outside of the richlistitem, clear the
+      // selection.
+      let element = aEvent.relatedTarget;
+      while (element && element != aEvent.originalTarget) {
+        element = element.parentNode;
+      }
+      if (!element)
+        this.richListBox.selectedIndex = -1;
+    }
+  },
+
   onDownloadContextMenu: function DV_onDownloadContextMenu(aEvent)
   {
     let element = this.richListBox.selectedItem;
     if (!element) {
       return;
     }
 
     DownloadsViewController.updateCommands();
--- a/browser/components/downloads/content/downloadsOverlay.xul
+++ b/browser/components/downloads/content/downloadsOverlay.xul
@@ -96,16 +96,18 @@
                   label="&cmd.clearList.label;"
                   accesskey="&cmd.clearList.accesskey;"/>
       </menupopup>
 
       <richlistbox id="downloadsListBox"
                    class="plain"
                    flex="1"
                    context="downloadsContextMenu"
+                   onmouseover="DownloadsView.onDownloadMouseOver(event);"
+                   onmouseout="DownloadsView.onDownloadMouseOut(event);"
                    oncontextmenu="DownloadsView.onDownloadContextMenu(event);"
                    ondragstart="DownloadsView.onDownloadDragStart(event);"/>
 
       <vbox id="downloadsFooter">
         <hbox id="downloadsSummary"
               align="center"
               orient="horizontal"
               onkeydown="DownloadsSummary.onKeyDown(event);"