Bug 1117145 - Part 2 - Unify DownloadsViewItem and DownloadsViewItemController. r=jaws
authorPaolo Amadini <paolo.mozmail@amadzone.org>
Wed, 10 Feb 2016 14:54:24 +0000
changeset 322347 5cec228f15f172b8f9e5095ba93e271871fe49ae
parent 322346 9e22d8f88099dbbfcb71afe7f09a08209fb505e4
child 322348 8cac6a90ec0cdd12e658f36a62fd72b8eba653b4
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws
bugs1117145
milestone47.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 1117145 - Part 2 - Unify DownloadsViewItem and DownloadsViewItemController. r=jaws MozReview-Commit-ID: 8qcV5Y7t1hM
browser/components/downloads/content/downloads.js
--- a/browser/components/downloads/content/downloads.js
+++ b/browser/components/downloads/content/downloads.js
@@ -18,26 +18,23 @@
  *
  * DownloadsView
  * Builds and updates the downloads list widget, responding to changes in the
  * download state and real-time data.  In addition, handles part of the user
  * interaction events raised by the downloads list widget.
  *
  * DownloadsViewItem
  * Builds and updates a single item in the downloads list widget, responding to
- * changes in the download state and real-time data.
+ * changes in the download state and real-time data, and handles the user
+ * interaction events related to a single item in the downloads list widgets.
  *
  * DownloadsViewController
  * Handles part of the user interaction events raised by the downloads list
  * widget, in particular the "commands" that apply to multiple items, and
  * dispatches the commands that apply to individual items.
- *
- * DownloadsViewItemController
- * Handles all the user interaction events, in particular the "commands",
- * related to a single item in the downloads list widgets.
  */
 
 /**
  * A few words on focus and focusrings
  *
  * We do quite a few hacks in the Downloads Panel for focusrings. In fact, we
  * basically suppress most if not all XUL-level focusrings, and style/draw
  * them ourselves (using :focus instead of -moz-focusring). There are a few
@@ -841,38 +838,37 @@ const DownloadsView = {
       }
     }
 
     this._itemCountChanged();
   },
 
   /**
    * Associates each richlistitem for a download with its corresponding
-   * DownloadsViewItemController object.
+   * DownloadsViewItem object.
    */
-  _controllersForElements: new Map(),
+  _itemsForElements: new Map(),
 
-  controllerForElement(element) {
-    return this._controllersForElements.get(element);
+  itemForElement(element) {
+    return this._itemsForElements.get(element);
   },
 
   /**
    * Creates a new view item associated with the specified data item, and adds
    * it to the top or the bottom of the list.
    */
   _addViewItem(download, aNewest)
   {
     DownloadsCommon.log("Adding a new DownloadsViewItem to the downloads list.",
                         "aNewest =", aNewest);
 
     let element = document.createElement("richlistitem");
     let viewItem = new DownloadsViewItem(download, element);
     this._visibleViewItems.set(download, viewItem);
-    let viewItemController = new DownloadsViewItemController(download);
-    this._controllersForElements.set(element, viewItemController);
+    this._itemsForElements.set(element, viewItem);
     if (aNewest) {
       this.richListBox.insertBefore(element, this.richListBox.firstChild);
     } else {
       this.richListBox.appendChild(element);
     }
   },
 
   /**
@@ -883,17 +879,17 @@ const DownloadsView = {
     let element = this._visibleViewItems.get(download).element;
     let previousSelectedIndex = this.richListBox.selectedIndex;
     this.richListBox.removeChild(element);
     if (previousSelectedIndex != -1) {
       this.richListBox.selectedIndex = Math.min(previousSelectedIndex,
                                                 this.richListBox.itemCount - 1);
     }
     this._visibleViewItems.delete(download);
-    this._controllersForElements.delete(element);
+    this._itemsForElements.delete(element);
   },
 
   //////////////////////////////////////////////////////////////////////////////
   //// User interface event functions
 
   /**
    * Helper function to do commands on a specific download item.
    *
@@ -904,17 +900,17 @@ const DownloadsView = {
    * @param aCommand
    *        The command to be performed.
    */
   onDownloadCommand(aEvent, aCommand) {
     let target = aEvent.target;
     while (target.nodeName != "richlistitem") {
       target = target.parentNode;
     }
-    DownloadsView.controllerForElement(target).doCommand(aCommand);
+    DownloadsView.itemForElement(target).doCommand(aCommand);
   },
 
   onDownloadClick(aEvent) {
     // Handle primary clicks only, and exclude the action button.
     if (aEvent.button == 0 &&
         !aEvent.originalTarget.hasAttribute("oncommand")) {
       goDoCommand("downloadsCmd_open");
     }
@@ -981,17 +977,17 @@ const DownloadsView = {
 
   onDownloadDragStart(aEvent) {
     let element = this.richListBox.selectedItem;
     if (!element) {
       return;
     }
 
     // We must check for existence synchronously because this is a DOM event.
-    let file = new FileUtils.File(DownloadsView.controllerForElement(element)
+    let file = new FileUtils.File(DownloadsView.itemForElement(element)
                                                .download.target.path);
     if (!file.exists()) {
       return;
     }
 
     let dataTransfer = aEvent.dataTransfer;
     dataTransfer.mozSetDataAt("application/x-moz-file", file, 0);
     dataTransfer.effectAllowed = "copyMove";
@@ -1006,17 +1002,18 @@ const DownloadsView = {
 
 XPCOMUtils.defineConstant(this, "DownloadsView", DownloadsView);
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadsViewItem
 
 /**
  * Builds and updates a single item in the downloads list widget, responding to
- * changes in the download state and real-time data.
+ * changes in the download state and real-time data, and handles the user
+ * interaction events related to a single item in the downloads list widgets.
  *
  * @param download
  *        Download object to be associated with the view item.
  * @param aElement
  *        XUL element corresponding to the single download item in the view.
  */
 function DownloadsViewItem(download, aElement) {
   this.download = download;
@@ -1046,123 +1043,17 @@ DownloadsViewItem.prototype = {
   onChanged() {
     // This cannot be placed within onStateChanged because
     // when a download goes from hasBlockedData to !hasBlockedData
     // it will still remain in the same state.
     this.element.classList.toggle("temporary-block",
                                   !!this.download.hasBlockedData);
     this._updateProgress();
   },
-};
 
-////////////////////////////////////////////////////////////////////////////////
-//// DownloadsViewController
-
-/**
- * Handles part of the user interaction events raised by the downloads list
- * widget, in particular the "commands" that apply to multiple items, and
- * dispatches the commands that apply to individual items.
- */
-const DownloadsViewController = {
-  //////////////////////////////////////////////////////////////////////////////
-  //// Initialization and termination
-
-  initialize() {
-    window.controllers.insertControllerAt(0, this);
-  },
-
-  terminate() {
-    window.controllers.removeController(this);
-  },
-
-  //////////////////////////////////////////////////////////////////////////////
-  //// nsIController
-
-  supportsCommand(aCommand) {
-    // Firstly, determine if this is a command that we can handle.
-    if (!(aCommand in this.commands) &&
-        !(aCommand in DownloadsViewItemController.prototype.commands)) {
-      return false;
-    }
-    // Secondly, determine if focus is on a control in the downloads list.
-    let element = document.commandDispatcher.focusedElement;
-    while (element && element != DownloadsView.richListBox) {
-      element = element.parentNode;
-    }
-    // We should handle the command only if the downloads list is among the
-    // ancestors of the focused element.
-    return !!element;
-  },
-
-  isCommandEnabled(aCommand) {
-    // Handle commands that are not selection-specific.
-    if (aCommand == "downloadsCmd_clearList") {
-      return DownloadsCommon.getData(window).canRemoveFinished;
-    }
-
-    // Other commands are selection-specific.
-    let element = DownloadsView.richListBox.selectedItem;
-    return element && DownloadsView.controllerForElement(element)
-                                   .isCommandEnabled(aCommand);
-  },
-
-  doCommand(aCommand) {
-    // If this command is not selection-specific, execute it.
-    if (aCommand in this.commands) {
-      this.commands[aCommand].apply(this);
-      return;
-    }
-
-    // Other commands are selection-specific.
-    let element = DownloadsView.richListBox.selectedItem;
-    if (element) {
-      // The doCommand function also checks if the command is enabled.
-      DownloadsView.controllerForElement(element).doCommand(aCommand);
-    }
-  },
-
-  onEvent() {},
-
-  //////////////////////////////////////////////////////////////////////////////
-  //// Other functions
-
-  updateCommands() {
-    Object.keys(this.commands).forEach(goUpdateCommand);
-    Object.keys(DownloadsViewItemController.prototype.commands)
-          .forEach(goUpdateCommand);
-  },
-
-  //////////////////////////////////////////////////////////////////////////////
-  //// Selection-independent commands
-
-  /**
-   * This object contains one key for each command that operates regardless of
-   * the currently selected item in the list.
-   */
-  commands: {
-    downloadsCmd_clearList() {
-      DownloadsCommon.getData(window).removeFinished();
-    }
-  }
-};
-
-XPCOMUtils.defineConstant(this, "DownloadsViewController", DownloadsViewController);
-
-////////////////////////////////////////////////////////////////////////////////
-//// DownloadsViewItemController
-
-/**
- * Handles all the user interaction events, in particular the "commands",
- * related to a single item in the downloads list widgets.
- */
-function DownloadsViewItemController(download) {
-  this.download = download;
-}
-
-DownloadsViewItemController.prototype = {
   isCommandEnabled(aCommand) {
     switch (aCommand) {
       case "downloadsCmd_open": {
         if (!this.download.succeeded) {
           return false;
         }
 
         let file = new FileUtils.File(this.download.target.path);
@@ -1206,17 +1097,17 @@ DownloadsViewItemController.prototype = 
   },
 
   //////////////////////////////////////////////////////////////////////////////
   //// Item commands
 
   /**
    * This object contains one key for each command that operates on this item.
    *
-   * In commands, the "this" identifier points to the controller item.
+   * In commands, the "this" identifier points to the DownloadsViewItem.
    */
   commands: {
     cmd_delete() {
       DownloadsCommon.removeAndFinalizeDownload(this.download);
       PlacesUtils.bhistory.removePage(
                              NetUtil.newURI(this.download.source.url));
     },
 
@@ -1305,16 +1196,108 @@ DownloadsViewItemController.prototype = 
       }.apply(this);
       if (defaultCommand && this.isCommandEnabled(defaultCommand)) {
         this.doCommand(defaultCommand);
       }
     },
   },
 };
 
+////////////////////////////////////////////////////////////////////////////////
+//// DownloadsViewController
+
+/**
+ * Handles part of the user interaction events raised by the downloads list
+ * widget, in particular the "commands" that apply to multiple items, and
+ * dispatches the commands that apply to individual items.
+ */
+const DownloadsViewController = {
+  //////////////////////////////////////////////////////////////////////////////
+  //// Initialization and termination
+
+  initialize() {
+    window.controllers.insertControllerAt(0, this);
+  },
+
+  terminate() {
+    window.controllers.removeController(this);
+  },
+
+  //////////////////////////////////////////////////////////////////////////////
+  //// nsIController
+
+  supportsCommand(aCommand) {
+    // Firstly, determine if this is a command that we can handle.
+    if (!(aCommand in this.commands) &&
+        !(aCommand in DownloadsViewItem.prototype.commands)) {
+      return false;
+    }
+    // Secondly, determine if focus is on a control in the downloads list.
+    let element = document.commandDispatcher.focusedElement;
+    while (element && element != DownloadsView.richListBox) {
+      element = element.parentNode;
+    }
+    // We should handle the command only if the downloads list is among the
+    // ancestors of the focused element.
+    return !!element;
+  },
+
+  isCommandEnabled(aCommand) {
+    // Handle commands that are not selection-specific.
+    if (aCommand == "downloadsCmd_clearList") {
+      return DownloadsCommon.getData(window).canRemoveFinished;
+    }
+
+    // Other commands are selection-specific.
+    let element = DownloadsView.richListBox.selectedItem;
+    return element && DownloadsView.itemForElement(element)
+                                   .isCommandEnabled(aCommand);
+  },
+
+  doCommand(aCommand) {
+    // If this command is not selection-specific, execute it.
+    if (aCommand in this.commands) {
+      this.commands[aCommand].apply(this);
+      return;
+    }
+
+    // Other commands are selection-specific.
+    let element = DownloadsView.richListBox.selectedItem;
+    if (element) {
+      // The doCommand function also checks if the command is enabled.
+      DownloadsView.itemForElement(element).doCommand(aCommand);
+    }
+  },
+
+  onEvent() {},
+
+  //////////////////////////////////////////////////////////////////////////////
+  //// Other functions
+
+  updateCommands() {
+    Object.keys(this.commands).forEach(goUpdateCommand);
+    Object.keys(DownloadsViewItem.prototype.commands)
+          .forEach(goUpdateCommand);
+  },
+
+  //////////////////////////////////////////////////////////////////////////////
+  //// Selection-independent commands
+
+  /**
+   * This object contains one key for each command that operates regardless of
+   * the currently selected item in the list.
+   */
+  commands: {
+    downloadsCmd_clearList() {
+      DownloadsCommon.getData(window).removeFinished();
+    }
+  }
+};
+
+XPCOMUtils.defineConstant(this, "DownloadsViewController", DownloadsViewController);
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadsSummary
 
 /**
  * Manages the summary at the bottom of the downloads panel list if the number
  * of items in the list exceeds the panels limit.
  */