Bug 1152743 - Re-implement "Search" field and "Clear List" button in Saved Files tab (version only for TB38). ui-r=ThomasD r=mkmelin, r=rkent, ui-r=Paenglab, a=rkent
authoraceman <acelists@atlas.sk>
Mon, 07 Sep 2015 23:56:33 +0200
changeset 22894 3db4218c150aa0882a95c66b63ab3c1221d5bc6c
parent 22893 1d6740a71280b3e045fa5d42ecc6b1982b050083
child 22895 31f969d986fd81889f7d49a253e344c4c99dc0f1
push id1467
push userkent@caspia.com
push dateTue, 15 Sep 2015 01:43:32 +0000
treeherdercomm-beta@3db4218c150a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersThomasD, mkmelin, rkent, Paenglab, rkent
bugs1152743
Bug 1152743 - Re-implement "Search" field and "Clear List" button in Saved Files tab (version only for TB38). ui-r=ThomasD r=mkmelin, r=rkent, ui-r=Paenglab, a=rkent
mail/components/downloads/content/aboutDownloads.js
mail/components/downloads/content/aboutDownloads.xul
mail/locales/en-US/chrome/messenger/aboutDownloads.dtd
mail/themes/linux/mail/downloads/aboutDownloads.css
mail/themes/osx/mail/downloads/aboutDownloads.css
mail/themes/windows/mail/downloads/aboutDownloads.css
--- a/mail/components/downloads/content/aboutDownloads.js
+++ b/mail/components/downloads/content/aboutDownloads.js
@@ -5,17 +5,17 @@
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
-Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Downloads", "resource://gre/modules/Downloads.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DownloadUtils", "resource://gre/modules/DownloadUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
 
 const DownloadsView = {
   init() {
     window.controllers.insertControllerAt(0, this);
@@ -53,17 +53,17 @@ const DownloadsView = {
   },
 
   onDownloadAdded(aDownload) {
     let isPurgedFromDisk = download => {
       if (!download.succeeded) {
         return false;
       }
       let targetFile = Cc["@mozilla.org/file/local;1"]
-                        .createInstance(Ci.nsIFile);
+                         .createInstance(Ci.nsIFile);
       targetFile.initWithPath(download.target.path);
       return !targetFile.exists();
     }
     if (isPurgedFromDisk(aDownload)) {
       Downloads.getList(Downloads.ALL)
                .then(list => list.remove(aDownload))
       return;
     }
@@ -93,76 +93,86 @@ const DownloadsView = {
       Cu.reportError("No DownloadItem found for download");
       return;
     }
 
     this.items.delete(aDownload);
     this.listElement.removeChild(item.element);
   },
 
-  onDownloadContextMenu(aEvent) {
-    let element = this.listElement.selectedItem;
-    if (!element) {
-      return;
-    }
-
+  onDownloadContextMenu() {
     this.updateCommands();
   },
 
   clearDownloads() {
     Downloads.getList(Downloads.ALL)
              .then(list => list.removeFinished())
              .then(null, Cu.reportError);
   },
 
+  searchDownloads() {
+    let searchString = document.getElementById("searchBox").value;
+    for (let i = 0; i < this.listElement.itemCount; i++) {
+      let downloadElem = this.listElement.getItemAtIndex(i);
+      downloadElem.collapsed =
+        !downloadElem.downloadItem.fileName.contains(searchString);
+    }
+    this.listElement.clearSelection();
+  },
+
   supportsCommand(aCommand) {
-    if (!(this.commands.some(command => command == aCommand)) &&
-        !(DownloadItem.prototype.supportsCommand(aCommand))) {
-      return false;
-    }
-    return true;
+    return this.commands.indexOf(aCommand) >= 0;
   },
 
   isCommandEnabled(aCommand) {
-    if (aCommand == "msgDownloadsCmd_clearDownloads") {
+    switch (aCommand) {
+      case "msgDownloadsCmd_clearDownloads":
+      case "msgDownloadsCmd_searchDownloads":
+        // We could disable these if there are no downloads in the list, but
+        // updating the commands when new items become available is tricky.
         return true;
     }
 
     let element = this.listElement.selectedItem;
     if (element) {
       return element.downloadItem.isCommandEnabled(aCommand);
     }
 
     return false;
   },
 
   doCommand(aCommand) {
-    if (aCommand == "msgDownloadsCmd_clearDownloads") {
+    switch (aCommand) {
+      case "msgDownloadsCmd_clearDownloads":
         this.clearDownloads();
         return;
+      case "msgDownloadsCmd_searchDownloads":
+        this.searchDownloads();
+        return;
     }
 
-    if (this.listElement.selectedItems.length == 0) {
+    if (this.listElement.selectedCount == 0) {
       return;
     }
 
-    for (let [, element] in Iterator(this.listElement.selectedItems)) {
+    for (let element of this.listElement.selectedItems) {
       element.downloadItem.doCommand(aCommand);
     }
   },
 
   onEvent() { },
 
   updateCommands() {
     this.commands.forEach(goUpdateCommand);
     DownloadItem.prototype.commands.forEach(goUpdateCommand);
   },
 
   commands: [
     "msgDownloadsCmd_clearDownloads",
+    "msgDownloadsCmd_searchDownloads"
   ]
 };
 
 function DownloadItem(aDownload) {
   this._download = aDownload;
   this._updateFromDownload();
 
   if (aDownload._unknownProperties && aDownload._unknownProperties.sender) {
@@ -254,17 +264,17 @@ DownloadItem.prototype = {
     Downloads.getList(Downloads.ALL)
              .then(list => list.remove(this.download))
              .then(() => this.download.finalize(true))
              .then(null, Cu.reportError);
   },
 
   show() {
     if (this.download.succeeded) {
-      let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
+      let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
       file.initWithPath(this._filePath);
       file.reveal();
     }
   },
 
   onDownloadChanged() {
     this._updateFromDownload();
     this.updateElement(this.element);
@@ -315,11 +325,11 @@ DownloadItem.prototype = {
         this.remove();
         break;
     }
   },
 
   commands: [
     "msgDownloadsCmd_remove",
     "msgDownloadsCmd_open",
-    "msgDownloadsCmd_show",
+    "msgDownloadsCmd_show"
   ]
 };
--- a/mail/components/downloads/content/aboutDownloads.xul
+++ b/mail/components/downloads/content/aboutDownloads.xul
@@ -4,54 +4,80 @@
 <?xml-stylesheet href="chrome://messenger/skin/downloads/aboutDownloads.css" type="text/css"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
   - License, v. 2.0. If a copy of the MPL was not distributed with this
   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <!DOCTYPE window [
 <!ENTITY % aboutDownloadsDTD SYSTEM "chrome://messenger/locale/aboutDownloads.dtd">
 %aboutDownloadsDTD;
+<!ENTITY % activityDTD SYSTEM "chrome://messenger/locale/activity.dtd">
+%activityDTD;
 ]>
 
 <window id="aboutDownloads"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:xhtml="http://www.w3.org/1999/xhtml"
         title="&aboutDownloads.title;"
         onload="DownloadsView.init();">
   <xhtml:link rel="shortcut icon"
               href="chrome://messenger/skin/downloads/download.svg"/>
   <script type="application/javascript"
           src="chrome://global/content/globalOverlay.js"/>
   <script type="application/javascript"
           src="chrome://messenger/content/downloads/aboutDownloads.js"/>
 
-  <stack flex="1">
-    <richlistbox id="msgDownloadsRichListBox"
-                 flex="1"
-                 seltype="multiple"
-                 context="msgDownloadsContextMenu"
-                 oncontextmenu="DownloadsView.onDownloadContextMenu(event);"/>
-    <description id="msgDownloadsListEmptyDescription"
-                 value="&aboutDownloads.empty;"
-                 mousethrough="always"/>
-  </stack>
-
   <commandset id="msgDownloadCommands"
               commandupdater="true"
               events="focus,select,contextmenu">
     <command id="msgDownloadsCmd_open"
              oncommand="goDoCommand('msgDownloadsCmd_open')"/>
     <command id="msgDownloadsCmd_show"
              oncommand="goDoCommand('msgDownloadsCmd_show')"/>
     <command id="msgDownloadsCmd_remove"
              oncommand="goDoCommand('msgDownloadsCmd_remove')"/>
     <command id="msgDownloadsCmd_clearDownloads"
              oncommand="goDoCommand('msgDownloadsCmd_clearDownloads')"/>
+    <command id="msgDownloadsCmd_searchDownloads"
+             oncommand="goDoCommand('msgDownloadsCmd_searchDownloads')"/>
   </commandset>
 
+  <keyset id="downloadKeys">
+    <key keycode="&cmd.find.commandkey;" modifiers="accel"
+         oncommand="document.getElementById('searchBox').focus();"/>
+  </keyset>
+
+  <hbox align="center">
+    <button id="clearDownloads"
+            command="msgDownloadsCmd_clearDownloads"
+            label="&cmd.clearList.label;"
+            accesskey="&cmd.clearList.accesskey;"
+            tooltiptext="&cmd.clearList.tooltip;"/>
+
+    <spacer flex="1"/>
+    <textbox id="searchBox"
+             type="search"
+             command="msgDownloadsCmd_searchDownloads"
+             placeholder="&searchBox.label;"/>
+  </hbox>
+
+  <separator class="thin"/>
+
+  <stack flex="1">
+    <richlistbox id="msgDownloadsRichListBox"
+                 flex="1"
+                 seltype="multiple"
+                 context="msgDownloadsContextMenu"
+                 oncontextmenu="DownloadsView.onDownloadContextMenu();"/>
+    <description id="msgDownloadsListEmptyDescription"
+                 value="&aboutDownloads.empty;"
+                 mousethrough="always"/>
+  </stack>
+
+
   <menupopup id="msgDownloadsContextMenu">
     <menuitem command="msgDownloadsCmd_remove"
               class="msgDownloadRemoveFromHistoryMenuItem"
               label="&cmd.removeFromHistory.label;"
               accesskey="&cmd.removeFromHistory.accesskey;"/>
     <menuitem command="msgDownloadsCmd_open"
               label="&cmd.open.label;"
               accesskey="&cmd.open.accesskey;"/>
@@ -61,12 +87,13 @@
               label="&cmd.showMac.label;"
               accesskey="&cmd.showMac.accesskey;"
 #else
               label="&cmd.show.label;"
               accesskey="&cmd.show.accesskey;"
 #endif
               />
     <menuitem command="msgDownloadsCmd_clearDownloads"
-              label="&cmd.clearDownloads.label;"
-              accesskey="&cmd.clearDownloads.accesskey;"/>
+              label="&cmd.clearList.label;"
+              accesskey="&cmd.clearList.accesskey;"
+              tooltiptext="&cmd.clearList.tooltip;"/>
   </menupopup>
 </window>
--- a/mail/locales/en-US/chrome/messenger/aboutDownloads.dtd
+++ b/mail/locales/en-US/chrome/messenger/aboutDownloads.dtd
@@ -12,10 +12,8 @@
 <!ENTITY cmd.show.label                            "Open Containing Folder">
 <!ENTITY cmd.show.accesskey                        "F">
 <!ENTITY cmd.showMac.label                         "Show In Finder">
 <!ENTITY cmd.showMac.accesskey                     "F">
 <!ENTITY cmd.open.label                            "Open">
 <!ENTITY cmd.open.accesskey                        "O">
 <!ENTITY cmd.removeFromHistory.label               "Remove From History">
 <!ENTITY cmd.removeFromHistory.accesskey           "e">
-<!ENTITY cmd.clearDownloads.label                  "Clear Downloads">
-<!ENTITY cmd.clearDownloads.accesskey              "D">
--- a/mail/themes/linux/mail/downloads/aboutDownloads.css
+++ b/mail/themes/linux/mail/downloads/aboutDownloads.css
@@ -20,16 +20,25 @@
   /** The default listbox appearance comes with an unwanted margin. **/
   -moz-appearance: none;
   margin: 0;
 }
 
 #msgDownloadsRichListBox > richlistitem.download {
   height: 5em;
   padding: 5px 8px;
+  border-bottom: 1px solid #f1f1f1;
+}
+
+#clearDownloads {
+  margin-inline-start: 0;
+}
+
+#searchBox {
+  margin-inline-end: 0;
 }
 
 .fileTypeIcon {
   -moz-margin-end: 8px;
   /* Prevent flickering when changing states. */
   min-height: 32px;
   min-width: 32px;
 }
--- a/mail/themes/osx/mail/downloads/aboutDownloads.css
+++ b/mail/themes/osx/mail/downloads/aboutDownloads.css
@@ -20,16 +20,25 @@
   /** The default listbox appearance comes with an unwanted margin. **/
   -moz-appearance: none;
   margin: 0;
 }
 
 #msgDownloadsRichListBox > richlistitem.download {
   height: 6em;
   padding: 5px 8px;
+  border-bottom: 1px solid #f1f1f1;
+}
+
+#clearDownloads {
+  margin-inline-start: 0;
+}
+
+#searchBox {
+  margin-inline-end: 0;
 }
 
 .fileTypeIcon {
   -moz-margin-end: 8px;
   /* Ensure icons are displayed at 32px size even on Retina display */
   height: 32px;
   width: 32px;
 }
--- a/mail/themes/windows/mail/downloads/aboutDownloads.css
+++ b/mail/themes/windows/mail/downloads/aboutDownloads.css
@@ -19,21 +19,30 @@
 #msgDownloadsRichListBox {
   /** The default listbox appearance comes with an unwanted margin. **/
   -moz-appearance: none;
   margin: 0;
 }
 
 #msgDownloadsRichListBox > richlistitem.download {
   height: 6em;
+  border-bottom: 1px solid #f1f1f1;
 %ifndef WINDOWS_AERO
   padding: 5px 8px;
 %endif
 }
 
+#clearDownloads {
+  margin-inline-start: 0;
+}
+
+#searchBox {
+  margin-inline-end: 0;
+}
+
 .fileTypeIcon {
   -moz-margin-end: 8px;
 %ifdef WINDOWS_AERO
   -moz-margin-start: 8px;
 %endif
   /* explicitly size the icon, so size doesn't vary on hidpi systems */
   height: 32px;
   width: 32px;