--- 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.
*/