summaryrefslogtreecommitdiffstats
path: root/application/palemoon/components/downloads/content/allDownloadsViewOverlay.js
diff options
context:
space:
mode:
Diffstat (limited to 'application/palemoon/components/downloads/content/allDownloadsViewOverlay.js')
-rw-r--r--application/palemoon/components/downloads/content/allDownloadsViewOverlay.js196
1 files changed, 112 insertions, 84 deletions
diff --git a/application/palemoon/components/downloads/content/allDownloadsViewOverlay.js b/application/palemoon/components/downloads/content/allDownloadsViewOverlay.js
index b85b64c1c..59da61c91 100644
--- a/application/palemoon/components/downloads/content/allDownloadsViewOverlay.js
+++ b/application/palemoon/components/downloads/content/allDownloadsViewOverlay.js
@@ -24,69 +24,48 @@ const DOWNLOAD_VIEW_SUPPORTED_COMMANDS =
*
* @param url
* URI string for the download source.
+ * @param endTime
+ * Timestamp with the end time for the download, used if there is no
+ * additional metadata available.
*/
-function HistoryDownload(url) {
+function HistoryDownload(aPlacesNode) {
// TODO (bug 829201): history downloads should get the referrer from Places.
- this.source = { url };
+ this.source = { url: aPlacesNode.uri };
this.target = { path: undefined, size: undefined };
-}
-
-HistoryDownload.prototype = {
- /**
- * This method mimicks the "start" method of session downloads, and is called
- * when the user retries a history download.
- */
- start() {
- // In future we may try to download into the same original target uri, when
- // we have it. Though that requires verifying the path is still valid and
- // may surprise the user if he wants to be requested every time.
- let browserWin = RecentWindow.getMostRecentBrowserWindow();
- let initiatingDoc = browserWin ? browserWin.document : document;
-
- // Do not suggest a file name if we don't know the original target.
- let leafName = this.target.path ? OS.Path.basename(this.target.path) : null;
- DownloadURL(this.source.url, leafName, initiatingDoc);
-
- return Promise.resolve();
- },
-};
-
-/**
- * Represents a download from the browser history. It uses the same interface as
- * the DownloadsDataItem object.
- *
- * @param aPlacesNode
- * The Places node for the history download.
- */
-function DownloadsHistoryDataItem(aPlacesNode) {
- this.download = new HistoryDownload(aPlacesNode.uri);
// In case this download cannot obtain its end time from the Places metadata,
// use the time from the Places node, that is the start time of the download.
this.endTime = aPlacesNode.time / 1000;
}
-DownloadsHistoryDataItem.prototype = {
- __proto__: DownloadsDataItem.prototype,
-
+HistoryDownload.prototype = {
/**
* Pushes information from Places metadata into this object.
*/
updateFromMetaData(aPlacesMetaData) {
try {
- let targetFile = Cc["@mozilla.org/network/protocol;1?name=file"]
- .getService(Ci.nsIFileProtocolHandler)
- .getFileFromURLSpec(aPlacesMetaData.targetFileURISpec);
- this.download.target.path = targetFile.path;
+ this.target.path = Cc["@mozilla.org/network/protocol;1?name=file"]
+ .getService(Ci.nsIFileProtocolHandler)
+ .getFileFromURLSpec(aPlacesMetaData.
+ targetFileURISpec).path;
} catch (ex) {
- this.download.target.path = undefined;
+ this.target.path = undefined;
}
try {
let metaData = JSON.parse(aPlacesMetaData.jsonDetails);
- this.state = metaData.state;
+ this.succeeded = metaData.state == nsIDM.DOWNLOAD_FINISHED;
+ this.error = metaData.state == nsIDM.DOWNLOAD_FAILED
+ ? { message: "History download failed." }
+ : metaData.state == nsIDM.DOWNLOAD_BLOCKED_PARENTAL
+ ? { becauseBlockedByParentalControls: true }
+ : metaData.state == nsIDM.DOWNLOAD_DIRTY
+ ? { becauseBlockedByReputationCheck: true }
+ : null;
+ this.canceled = metaData.state == nsIDM.DOWNLOAD_CANCELED ||
+ metaData.state == nsIDM.DOWNLOAD_PAUSED;
this.endTime = metaData.endTime;
- this.download.target.size = metaData.fileSize;
+ this.target.size = metaData.fileSize;
} catch (ex) {
// Metadata might be missing from a download that has started but hasn't
// stopped already. Normally, this state is overridden with the one from
@@ -98,21 +77,72 @@ DownloadsHistoryDataItem.prototype = {
// On the other hand, if the download is missing the target file
// annotation as well, it is just a very old one, and we can assume it
// succeeded.
- this.state = this.download.target.path ? nsIDM.DOWNLOAD_FAILED
- : nsIDM.DOWNLOAD_FINISHED;
- this.download.target.size = undefined;
+ this.succeeded = !this.target.path;
+ this.error = this.target.path ? { message: "Unstarted download." } : null;
+ this.canceled = false;
+ this.target.size = -1;
}
// This property is currently used to get the size of downloads, but will be
// replaced by download.target.size when available for session downloads.
- this.maxBytes = this.download.target.size;
+ this.totalBytes = this.target.size;
+ this.currentBytes = this.target.size;
+ },
+
+ /**
+ * History downloads are never in progress.
+ */
+ stopped: true,
- // This is not displayed for history downloads, that are never in progress.
- this.percentComplete = 100;
+ /**
+ * No percentage indication is shown for history downloads.
+ */
+ hasProgress: false,
+
+ /**
+ * History downloads cannot be restarted using their partial data, even if
+ * they are indicated as paused in their Places metadata. The only way is to
+ * use the information from a persisted session download, that will be shown
+ * instead of the history download. In case this session download is not
+ * available, we show the history download as canceled, not paused.
+ */
+ hasPartialData: false,
+
+ /**
+ * This method mimicks the "start" method of session downloads, and is called
+ * when the user retries a history download.
+ */
+ start() {
+ // In future we may try to download into the same original target uri, when
+ // we have it. Though that requires verifying the path is still valid and
+ // may surprise the user if he wants to be requested every time.
+ let browserWin = RecentWindow.getMostRecentBrowserWindow();
+ let initiatingDoc = browserWin ? browserWin.document : document;
+
+ // Do not suggest a file name if we don't know the original target.
+ let leafName = this.target.path ? OS.Path.basename(this.target.path) : null;
+ DownloadURL(this.source.url, leafName, initiatingDoc);
+
+ return Promise.resolve();
},
};
/**
+ * Represents a download from the browser history. It uses the same interface as
+ * the DownloadsDataItem object.
+ *
+ * @param aPlacesNode
+ * The Places node for the history download.
+ */
+function DownloadsHistoryDataItem(aPlacesNode) {
+ this.download = new HistoryDownload(aPlacesNode);
+}
+
+DownloadsHistoryDataItem.prototype = {
+ __proto__: DownloadsDataItem.prototype,
+};
+
+/**
* A download element shell is responsible for handling the commands and the
* displayed data for a single download view element.
*
@@ -223,7 +253,7 @@ HistoryDownloadElementShell.prototype = {
// The base object would show extended progress information in the tooltip,
// but we move this to the main view and never display a tooltip.
- if (this.dataItem.state == nsIDM.DOWNLOAD_DOWNLOADING) {
+ if (!this.download.stopped) {
status.text = status.tip;
}
status.tip = "";
@@ -232,18 +262,9 @@ HistoryDownloadElementShell.prototype = {
},
onStateChanged() {
- // If a download just finished successfully, it means that the target file
- // now exists and we can extract its specific icon. To ensure that the icon
- // is reloaded, we must change the URI used by the XUL image element, for
- // example by adding a query parameter. Since this URI has a "moz-icon"
- // scheme, this only works if we add one of the parameters explicitly
- // supported by the nsIMozIconURI interface.
- if (this.dataItem.state == nsIDM.DOWNLOAD_FINISHED) {
- this.element.setAttribute("image", this.image + "&state=normal");
- }
-
- // Update the user interface after switching states.
- this.element.setAttribute("state", this.dataItem.state);
+ this.element.setAttribute("image", this.image);
+ this.element.setAttribute("state",
+ DownloadsCommon.stateOfDownload(this.download));
if (this.element.selected) {
goUpdateDownloadCommands();
@@ -275,12 +296,14 @@ HistoryDownloadElementShell.prototype = {
// If the target file information is not yet fetched,
// temporarily assume that the file is in place.
- return this.dataItem.state == nsIDM.DOWNLOAD_FINISHED;
+ return this.download.succeeded;
case "downloadsCmd_show":
// TODO: Bug 827010 - Handle part-file asynchronously.
- if (this._sessionDataItem &&
- this.dataItem.partFile && this.dataItem.partFile.exists()) {
- return true;
+ if (this._sessionDataItem && this.download.target.partFilePath) {
+ let partFile = new FileUtils.File(this.download.target.partFilePath);
+ if (partFile.exists()) {
+ return true;
+ }
}
if (this._targetFileChecked) {
@@ -289,17 +312,16 @@ HistoryDownloadElementShell.prototype = {
// If the target file information is not yet fetched,
// temporarily assume that the file is in place.
- return this.dataItem.state == nsIDM.DOWNLOAD_FINISHED;
+ return this.download.succeeded;
case "downloadsCmd_pauseResume":
- return this._sessionDataItem && this.dataItem.inProgress &&
- this.dataItem.download.hasPartialData;
+ return this.download.hasPartialData && !this.download.error;
case "downloadsCmd_retry":
- return this.dataItem.canRetry;
+ return this.download.canceled || this.download.error;
case "downloadsCmd_openReferrer":
return !!this.download.source.referrer;
case "cmd_delete":
- // The behavior in this case is somewhat unexpected, so we disallow that.
- return !this.dataItem.inProgress;
+ // We don't want in-progress downloads to be removed accidentally.
+ return this.download.stopped;
case "downloadsCmd_cancel":
return !!this._sessionDataItem;
}
@@ -393,7 +415,8 @@ HistoryDownloadElementShell.prototype = {
}
return "";
}
- let command = getDefaultCommandForState(this.dataItem.state);
+ let command = getDefaultCommandForState(
+ DownloadsCommon.stateOfDownload(this.download));
if (command && this.isCommandEnabled(command))
this.doCommand(command);
},
@@ -621,8 +644,9 @@ DownloadsPlacesView.prototype = {
_addDownloadData:
function DPV_addDownloadData(aDataItem, aPlacesNode, aNewest = false,
aDocumentFragment = null) {
+ let sessionDownload = aDataItem && aDataItem.download;
let downloadURI = aPlacesNode ? aPlacesNode.uri
- : aDataItem.download.source.url;
+ : sessionDownload.source.url;
let shellsForURI = this._downloadElementsShellsForURI.get(downloadURI);
if (!shellsForURI) {
shellsForURI = new Set();
@@ -674,7 +698,7 @@ DownloadsPlacesView.prototype = {
if (aPlacesNode) {
let metaData = this._getCachedPlacesMetaDataFor(aPlacesNode.uri);
historyDataItem = new DownloadsHistoryDataItem(aPlacesNode);
- historyDataItem.updateFromMetaData(metaData);
+ historyDataItem.download.updateFromMetaData(metaData);
}
let shell = new HistoryDownloadElementShell(aDataItem, historyDataItem);
shell.element._placesNode = aPlacesNode;
@@ -782,8 +806,9 @@ DownloadsPlacesView.prototype = {
_removeSessionDownloadFromView:
function DPV__removeSessionDownloadFromView(aDataItem) {
+ let download = aDataItem.download;
let shells = this._downloadElementsShellsForURI
- .get(aDataItem.download.source.url);
+ .get(download.source.url);
if (shells.size == 0)
throw new Error("Should have had at leaat one shell for this uri");
@@ -799,7 +824,7 @@ DownloadsPlacesView.prototype = {
this._removeElement(shell.element);
shells.delete(shell);
if (shells.size == 0)
- this._downloadElementsShellsForURI.delete(aDataItem.download.source.url);
+ this._downloadElementsShellsForURI.delete(download.source.url);
}
else {
// We have one download element shell containing both a session download
@@ -809,7 +834,7 @@ DownloadsPlacesView.prototype = {
// read the latest metadata before removing the session download.
let url = shell.historyDataItem.download.source.url;
let metaData = this._getPlacesMetaDataFor(url);
- shell.historyDataItem.updateFromMetaData(metaData);
+ shell.historyDataItem.download.updateFromMetaData(metaData);
shell.sessionDataItem = null;
// Move it below the session-download items;
if (this._lastSessionDownloadElement == shell.element) {
@@ -1142,7 +1167,9 @@ DownloadsPlacesView.prototype = {
// Because history downloads are always removable and are listed after the
// session downloads, check from bottom to top.
for (let elt = this._richlistbox.lastChild; elt; elt = elt.previousSibling) {
- if (!elt._shell.dataItem.inProgress) {
+ // Stopped, paused, and failed downloads with partial data are removed.
+ let download = elt._shell.download;
+ if (download.stopped && !(download.canceled && download.hasPartialData)) {
return true;
}
}
@@ -1244,12 +1271,13 @@ DownloadsPlacesView.prototype = {
// Set the state attribute so that only the appropriate items are displayed.
let contextMenu = document.getElementById("downloadsContextMenu");
- let state = element._shell.dataItem.state;
- contextMenu.setAttribute("state", state);
+ let download = element._shell.download;
+ contextMenu.setAttribute("state",
+ DownloadsCommon.stateOfDownload(download));
- if (state == nsIDM.DOWNLOAD_DOWNLOADING) {
- // The resumable property of a download may change at any time, so
- // ensure we update the related command now.
+ if (!download.stopped) {
+ // The hasPartialData property of a download may change at any time after
+ // it has started, so ensure we update the related command now.
goUpdateCommand("downloadsCmd_pauseResume");
}
return true;