зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1117139 - Move code controlling the "download.xml" binding to a common place. r=mak
This commit is contained in:
Родитель
1f1b323a7d
Коммит
91501caee2
|
@ -7,6 +7,7 @@
|
|||
<script type="application/javascript" src="chrome://global/content/viewZoomOverlay.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/places/browserPlacesViews.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/browser.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/downloads/downloadsViewCommon.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/downloads/downloads.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/downloads/indicator.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/customizableui/panelUI.js"/>
|
||||
|
|
|
@ -2,31 +2,10 @@
|
|||
* 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/. */
|
||||
|
||||
/**
|
||||
* THE PLACES VIEW IMPLEMENTED IN THIS FILE HAS A VERY PARTICULAR USE CASE.
|
||||
* IT IS HIGHLY RECOMMENDED NOT TO EXTEND IT FOR ANY OTHER USE CASES OR RELY
|
||||
* ON IT AS AN API.
|
||||
*/
|
||||
|
||||
let Cu = Components.utils;
|
||||
let Ci = Components.interfaces;
|
||||
let Cc = Components.classes;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/DownloadUtils.jsm");
|
||||
Cu.import("resource:///modules/DownloadsCommon.jsm");
|
||||
Cu.import("resource://gre/modules/PlacesUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsDataItem",
|
||||
"resource:///modules/DownloadsCommon.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
|
||||
"resource:///modules/RecentWindow.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
|
||||
const nsIDM = Ci.nsIDownloadManager;
|
||||
|
||||
|
@ -153,12 +132,12 @@ DownloadsHistoryDataItem.prototype = {
|
|||
* @param [optional] aHistoryDataItem
|
||||
* The history download, required if aSessionDataItem is not set.
|
||||
*/
|
||||
function DownloadElementShell(aSessionDataItem, aHistoryDataItem) {
|
||||
this._element = document.createElement("richlistitem");
|
||||
this._element._shell = this;
|
||||
function HistoryDownloadElementShell(aSessionDataItem, aHistoryDataItem) {
|
||||
this.element = document.createElement("richlistitem");
|
||||
this.element._shell = this;
|
||||
|
||||
this._element.classList.add("download");
|
||||
this._element.classList.add("download-state");
|
||||
this.element.classList.add("download");
|
||||
this.element.classList.add("download-state");
|
||||
|
||||
if (aSessionDataItem) {
|
||||
this.sessionDataItem = aSessionDataItem;
|
||||
|
@ -168,11 +147,8 @@ function DownloadElementShell(aSessionDataItem, aHistoryDataItem) {
|
|||
}
|
||||
}
|
||||
|
||||
DownloadElementShell.prototype = {
|
||||
/**
|
||||
* The richlistitem for the download.
|
||||
*/
|
||||
get element() this._element,
|
||||
HistoryDownloadElementShell.prototype = {
|
||||
__proto__: DownloadElementShell.prototype,
|
||||
|
||||
/**
|
||||
* Manages the "active" state of the shell. By default all the shells without
|
||||
|
@ -183,18 +159,12 @@ DownloadElementShell.prototype = {
|
|||
ensureActive() {
|
||||
if (!this._active) {
|
||||
this._active = true;
|
||||
this._element.setAttribute("active", true);
|
||||
this.element.setAttribute("active", true);
|
||||
this._updateUI();
|
||||
}
|
||||
},
|
||||
get active() !!this._active,
|
||||
|
||||
/**
|
||||
* Download or HistoryDownload object to use for displaying information and
|
||||
* for executing commands in the user interface.
|
||||
*/
|
||||
get download() this.dataItem.download,
|
||||
|
||||
/**
|
||||
* DownloadsDataItem or DownloadsHistoryDataItem object to use for displaying
|
||||
* information and for executing commands in the user interface.
|
||||
|
@ -236,16 +206,6 @@ DownloadElementShell.prototype = {
|
|||
return aValue;
|
||||
},
|
||||
|
||||
// The progressmeter element for the download
|
||||
get _progressElement() {
|
||||
if (!("__progressElement" in this)) {
|
||||
this.__progressElement =
|
||||
document.getAnonymousElementByAttribute(this._element, "anonid",
|
||||
"progressmeter");
|
||||
}
|
||||
return this.__progressElement;
|
||||
},
|
||||
|
||||
_updateUI() {
|
||||
// There is nothing to do if the item has always been invisible.
|
||||
if (!this.active) {
|
||||
|
@ -255,150 +215,20 @@ DownloadElementShell.prototype = {
|
|||
// Since the state changed, we may need to check the target file again.
|
||||
this._targetFileChecked = false;
|
||||
|
||||
this._element.setAttribute("displayName", this.displayName);
|
||||
this._element.setAttribute("image", this.image);
|
||||
|
||||
this._updateActiveStatusUI();
|
||||
this._updateState();
|
||||
},
|
||||
|
||||
// Updates the download state attribute (and by that hide/unhide the
|
||||
// appropriate buttons and context menu items), the status text label,
|
||||
// and the progress meter.
|
||||
_updateActiveStatusUI() {
|
||||
if (!this.active) {
|
||||
throw new Error("_updateActiveStatusUI called for an inactive item.");
|
||||
get statusTextAndTip() {
|
||||
let status = this.rawStatusTextAndTip;
|
||||
|
||||
// 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) {
|
||||
status.text = status.tip;
|
||||
}
|
||||
status.tip = "";
|
||||
|
||||
this._element.setAttribute("state", this.dataItem.state);
|
||||
this._element.setAttribute("status", this.statusText);
|
||||
|
||||
// We have update the progress meter only for session downloads.
|
||||
if (!this._sessionDataItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Copied from updateProgress in downloads.js.
|
||||
if (this.dataItem.starting) {
|
||||
// Before the download starts, the progress meter has its initial value.
|
||||
this._element.setAttribute("progressmode", "normal");
|
||||
this._element.setAttribute("progress", "0");
|
||||
} else if (this.dataItem.state == nsIDM.DOWNLOAD_SCANNING ||
|
||||
this.dataItem.percentComplete == -1) {
|
||||
// We might not know the progress of a running download, and we don't know
|
||||
// the remaining time during the malware scanning phase.
|
||||
this._element.setAttribute("progressmode", "undetermined");
|
||||
} else {
|
||||
// This is a running download of which we know the progress.
|
||||
this._element.setAttribute("progressmode", "normal");
|
||||
this._element.setAttribute("progress", this.dataItem.percentComplete);
|
||||
}
|
||||
|
||||
// Dispatch the ValueChange event for accessibility, if possible.
|
||||
if (this._progressElement) {
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("ValueChange", true, true);
|
||||
this._progressElement.dispatchEvent(event);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* URI string for the file type icon displayed in the download element.
|
||||
*/
|
||||
get image() {
|
||||
if (this.download.target.path) {
|
||||
return "moz-icon://" + this.download.target.path + "?size=32";
|
||||
}
|
||||
|
||||
// Old history downloads may not have a target path.
|
||||
return "moz-icon://.unknown?size=32";
|
||||
},
|
||||
|
||||
/**
|
||||
* The user-facing label for the download. This is normally the leaf name of
|
||||
* download target file. In case this is a very old history download for
|
||||
* which the target file is unknown, the download source URI is displayed.
|
||||
*/
|
||||
get displayName() {
|
||||
if (!this.download.target.path) {
|
||||
return this.download.source.url;
|
||||
}
|
||||
return OS.Path.basename(this.download.target.path);
|
||||
},
|
||||
|
||||
get statusText() {
|
||||
let s = DownloadsCommon.strings;
|
||||
if (this.dataItem.inProgress) {
|
||||
if (this.dataItem.paused) {
|
||||
let transfer =
|
||||
DownloadUtils.getTransferTotal(this.download.currentBytes,
|
||||
this.dataItem.maxBytes);
|
||||
|
||||
// We use the same XUL label to display both the state and the amount
|
||||
// transferred, for example "Paused - 1.1 MB".
|
||||
return s.statusSeparatorBeforeNumber(s.statePaused, transfer);
|
||||
}
|
||||
if (this.dataItem.state == nsIDM.DOWNLOAD_DOWNLOADING) {
|
||||
let [status, newEstimatedSecondsLeft] =
|
||||
DownloadUtils.getDownloadStatus(this.download.currentBytes,
|
||||
this.dataItem.maxBytes,
|
||||
this.download.speed,
|
||||
this._lastEstimatedSecondsLeft || Infinity);
|
||||
this._lastEstimatedSecondsLeft = newEstimatedSecondsLeft;
|
||||
return status;
|
||||
}
|
||||
if (this.dataItem.starting) {
|
||||
return s.stateStarting;
|
||||
}
|
||||
if (this.dataItem.state == nsIDM.DOWNLOAD_SCANNING) {
|
||||
return s.stateScanning;
|
||||
}
|
||||
|
||||
throw new Error("_getStatusText called with a bogus download state");
|
||||
}
|
||||
|
||||
// This is a not-in-progress or history download.
|
||||
let stateLabel = "";
|
||||
switch (this.dataItem.state) {
|
||||
case nsIDM.DOWNLOAD_FAILED:
|
||||
stateLabel = s.stateFailed;
|
||||
break;
|
||||
case nsIDM.DOWNLOAD_CANCELED:
|
||||
stateLabel = s.stateCanceled;
|
||||
break;
|
||||
case nsIDM.DOWNLOAD_BLOCKED_PARENTAL:
|
||||
stateLabel = s.stateBlockedParentalControls;
|
||||
break;
|
||||
case nsIDM.DOWNLOAD_BLOCKED_POLICY:
|
||||
stateLabel = s.stateBlockedPolicy;
|
||||
break;
|
||||
case nsIDM.DOWNLOAD_DIRTY:
|
||||
stateLabel = s.stateDirty;
|
||||
break;
|
||||
case nsIDM.DOWNLOAD_FINISHED:
|
||||
// For completed downloads, show the file size (e.g. "1.5 MB")
|
||||
if (this.dataItem.maxBytes !== undefined) {
|
||||
let [size, unit] =
|
||||
DownloadUtils.convertByteUnits(this.dataItem.maxBytes);
|
||||
stateLabel = s.sizeWithUnits(size, unit);
|
||||
break;
|
||||
}
|
||||
// Fallback to default unknown state.
|
||||
default:
|
||||
stateLabel = s.sizeUnknown;
|
||||
break;
|
||||
}
|
||||
|
||||
let referrer = this.download.source.referrer ||
|
||||
this.download.source.url;
|
||||
let [displayHost, fullHost] = DownloadUtils.getURIHost(referrer);
|
||||
|
||||
let date = new Date(this.dataItem.endTime);
|
||||
let [displayDate, fullDate] = DownloadUtils.getReadableDates(date);
|
||||
|
||||
// We use the same XUL label to display the state, the host name, and the
|
||||
// end time.
|
||||
let firstPart = s.statusSeparator(stateLabel, displayHost);
|
||||
return s.statusSeparator(firstPart, displayDate);
|
||||
return status;
|
||||
},
|
||||
|
||||
onStateChanged() {
|
||||
|
@ -409,10 +239,13 @@ DownloadElementShell.prototype = {
|
|||
// 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");
|
||||
this.element.setAttribute("image", this.image + "&state=normal");
|
||||
}
|
||||
|
||||
if (this._element.selected) {
|
||||
// Update the user interface after switching states.
|
||||
this.element.setAttribute("state", this.dataItem.state);
|
||||
|
||||
if (this.element.selected) {
|
||||
goUpdateDownloadCommands();
|
||||
} else {
|
||||
goUpdateCommand("downloadsCmd_clearDownloads");
|
||||
|
@ -420,7 +253,7 @@ DownloadElementShell.prototype = {
|
|||
},
|
||||
|
||||
onChanged() {
|
||||
this._updateActiveStatusUI();
|
||||
this._updateProgress();
|
||||
},
|
||||
|
||||
/* nsIController */
|
||||
|
@ -602,7 +435,7 @@ DownloadElementShell.prototype = {
|
|||
}
|
||||
|
||||
// Update the commands only if the element is still selected.
|
||||
if (this._element.selected) {
|
||||
if (this.element.selected) {
|
||||
goUpdateDownloadCommands();
|
||||
}
|
||||
}),
|
||||
|
@ -847,7 +680,7 @@ DownloadsPlacesView.prototype = {
|
|||
historyDataItem = new DownloadsHistoryDataItem(aPlacesNode);
|
||||
historyDataItem.updateFromMetaData(metaData);
|
||||
}
|
||||
let shell = new DownloadElementShell(aDataItem, historyDataItem);
|
||||
let shell = new HistoryDownloadElementShell(aDataItem, historyDataItem);
|
||||
shell.element._placesNode = aPlacesNode;
|
||||
newOrUpdatedShell = shell;
|
||||
shellsForURI.add(shell);
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/downloads/downloadsViewCommon.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/downloads/allDownloadsViewOverlay.js"/>
|
||||
<script type="application/javascript"
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
<xul:description class="downloadTarget"
|
||||
crop="center"
|
||||
style="min-width: &downloadsSummary.minWidth2;"
|
||||
xbl:inherits="value=target,tooltiptext=target"/>
|
||||
xbl:inherits="value=displayName,tooltiptext=displayName"/>
|
||||
<xul:progressmeter anonid="progressmeter"
|
||||
class="downloadProgress"
|
||||
min="0"
|
||||
|
|
|
@ -64,22 +64,6 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Globals
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadUtils",
|
||||
"resource://gre/modules/DownloadUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
|
||||
"resource:///modules/DownloadsCommon.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// DownloadsPanel
|
||||
|
||||
|
@ -866,7 +850,7 @@ const DownloadsView = {
|
|||
*/
|
||||
_removeViewItem(aDataItem) {
|
||||
DownloadsCommon.log("Removing a DownloadsViewItem from the downloads list.");
|
||||
let element = this._visibleViewItems.get(aDataItem)._element;
|
||||
let element = this._visibleViewItems.get(aDataItem).element;
|
||||
let previousSelectedIndex = this.richListBox.selectedIndex;
|
||||
this.richListBox.removeChild(element);
|
||||
if (previousSelectedIndex != -1) {
|
||||
|
@ -1000,37 +984,20 @@ const DownloadsView = {
|
|||
* XUL element corresponding to the single download item in the view.
|
||||
*/
|
||||
function DownloadsViewItem(aDataItem, aElement) {
|
||||
this._element = aElement;
|
||||
this.dataItem = aDataItem;
|
||||
this.element = aElement;
|
||||
this.element._shell = this;
|
||||
|
||||
this.lastEstimatedSecondsLeft = Infinity;
|
||||
this.element.setAttribute("type", "download");
|
||||
this.element.classList.add("download-state");
|
||||
|
||||
// Set the URI that represents the correct icon for the target file. As soon
|
||||
// as bug 239948 comment 12 is handled, the "file" property will be always a
|
||||
// file URL rather than a file name. At that point we should remove the "//"
|
||||
// (double slash) from the icon URI specification (see test_moz_icon_uri.js).
|
||||
this.image = "moz-icon://" + this.dataItem.download.target.path + "?size=32";
|
||||
|
||||
let attributes = {
|
||||
"type": "download",
|
||||
"class": "download-state",
|
||||
"state": this.dataItem.state,
|
||||
"progress": this.dataItem.inProgress ? this.dataItem.percentComplete : 100,
|
||||
"target": OS.Path.basename(this.dataItem.download.target.path),
|
||||
"image": this.image
|
||||
};
|
||||
|
||||
for (let attributeName in attributes) {
|
||||
this._element.setAttribute(attributeName, attributes[attributeName]);
|
||||
}
|
||||
|
||||
// Initialize more complex attributes.
|
||||
this._updateProgress();
|
||||
this._updateStatusLine();
|
||||
this._updateState();
|
||||
this.verifyTargetExists();
|
||||
}
|
||||
|
||||
DownloadsViewItem.prototype = {
|
||||
__proto__: DownloadElementShell.prototype,
|
||||
|
||||
/**
|
||||
* The DownloadDataItem associated with this view item.
|
||||
*/
|
||||
|
@ -1041,19 +1008,6 @@ DownloadsViewItem.prototype = {
|
|||
*/
|
||||
_element: null,
|
||||
|
||||
/**
|
||||
* The inner XUL element for the progress bar, or null if not available.
|
||||
*/
|
||||
_progressElement: null,
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// Callback functions from DownloadsData
|
||||
|
||||
/**
|
||||
* Called when the download state might have changed. Sometimes the state of
|
||||
* the download might be the same as before, if the data layer received
|
||||
* multiple events for the same download.
|
||||
*/
|
||||
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
|
||||
|
@ -1062,157 +1016,23 @@ DownloadsViewItem.prototype = {
|
|||
// scheme, this only works if we add one of the parameters explicitly
|
||||
// supported by the nsIMozIconURI interface.
|
||||
if (this.dataItem.state == Ci.nsIDownloadManager.DOWNLOAD_FINISHED) {
|
||||
this._element.setAttribute("image", this.image + "&state=normal");
|
||||
this.element.setAttribute("image", this.image + "&state=normal");
|
||||
|
||||
// We assume the existence of the target of a download that just completed
|
||||
// successfully, without checking the condition in the background. If the
|
||||
// panel is already open, this will take effect immediately. If the panel
|
||||
// is opened later, a new background existence check will be performed.
|
||||
this._element.setAttribute("exists", "true");
|
||||
this.element.setAttribute("exists", "true");
|
||||
}
|
||||
|
||||
// Update the user interface after switching states.
|
||||
this._element.setAttribute("state", this.dataItem.state);
|
||||
this.element.setAttribute("state", this.dataItem.state);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the download progress has changed.
|
||||
*/
|
||||
onChanged() {
|
||||
this._updateProgress();
|
||||
this._updateStatusLine();
|
||||
},
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// Functions for updating the user interface
|
||||
|
||||
/**
|
||||
* Updates the progress bar.
|
||||
*/
|
||||
_updateProgress() {
|
||||
if (this.dataItem.starting) {
|
||||
// Before the download starts, the progress meter has its initial value.
|
||||
this._element.setAttribute("progressmode", "normal");
|
||||
this._element.setAttribute("progress", "0");
|
||||
} else if (this.dataItem.state == Ci.nsIDownloadManager.DOWNLOAD_SCANNING ||
|
||||
this.dataItem.percentComplete == -1) {
|
||||
// We might not know the progress of a running download, and we don't know
|
||||
// the remaining time during the malware scanning phase.
|
||||
this._element.setAttribute("progressmode", "undetermined");
|
||||
} else {
|
||||
// This is a running download of which we know the progress.
|
||||
this._element.setAttribute("progressmode", "normal");
|
||||
this._element.setAttribute("progress", this.dataItem.percentComplete);
|
||||
}
|
||||
|
||||
// Find the progress element as soon as the download binding is accessible.
|
||||
if (!this._progressElement) {
|
||||
this._progressElement =
|
||||
document.getAnonymousElementByAttribute(this._element, "anonid",
|
||||
"progressmeter");
|
||||
}
|
||||
|
||||
// Dispatch the ValueChange event for accessibility, if possible.
|
||||
if (this._progressElement) {
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("ValueChange", true, true);
|
||||
this._progressElement.dispatchEvent(event);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the main status line, including bytes transferred, bytes total,
|
||||
* download rate, and time remaining.
|
||||
*/
|
||||
_updateStatusLine() {
|
||||
const nsIDM = Ci.nsIDownloadManager;
|
||||
|
||||
let status = "";
|
||||
let statusTip = "";
|
||||
|
||||
if (this.dataItem.paused) {
|
||||
let transfer = DownloadUtils.getTransferTotal(this.dataItem.download.currentBytes,
|
||||
this.dataItem.maxBytes);
|
||||
|
||||
// We use the same XUL label to display both the state and the amount
|
||||
// transferred, for example "Paused - 1.1 MB".
|
||||
status = DownloadsCommon.strings.statusSeparatorBeforeNumber(
|
||||
DownloadsCommon.strings.statePaused,
|
||||
transfer);
|
||||
} else if (this.dataItem.state == nsIDM.DOWNLOAD_DOWNLOADING) {
|
||||
// We don't show the rate for each download in order to reduce clutter.
|
||||
// The remaining time per download is likely enough information for the
|
||||
// panel.
|
||||
[status] =
|
||||
DownloadUtils.getDownloadStatusNoRate(this.dataItem.download.currentBytes,
|
||||
this.dataItem.maxBytes,
|
||||
this.dataItem.download.speed,
|
||||
this.lastEstimatedSecondsLeft);
|
||||
|
||||
// We are, however, OK with displaying the rate in the tooltip.
|
||||
let newEstimatedSecondsLeft;
|
||||
[statusTip, newEstimatedSecondsLeft] =
|
||||
DownloadUtils.getDownloadStatus(this.dataItem.download.currentBytes,
|
||||
this.dataItem.maxBytes,
|
||||
this.dataItem.download.speed,
|
||||
this.lastEstimatedSecondsLeft);
|
||||
this.lastEstimatedSecondsLeft = newEstimatedSecondsLeft;
|
||||
} else if (this.dataItem.starting) {
|
||||
status = DownloadsCommon.strings.stateStarting;
|
||||
} else if (this.dataItem.state == nsIDM.DOWNLOAD_SCANNING) {
|
||||
status = DownloadsCommon.strings.stateScanning;
|
||||
} else if (!this.dataItem.inProgress) {
|
||||
let stateLabel = function () {
|
||||
let s = DownloadsCommon.strings;
|
||||
switch (this.dataItem.state) {
|
||||
case nsIDM.DOWNLOAD_FAILED: return s.stateFailed;
|
||||
case nsIDM.DOWNLOAD_CANCELED: return s.stateCanceled;
|
||||
case nsIDM.DOWNLOAD_BLOCKED_PARENTAL: return s.stateBlockedParentalControls;
|
||||
case nsIDM.DOWNLOAD_BLOCKED_POLICY: return s.stateBlockedPolicy;
|
||||
case nsIDM.DOWNLOAD_DIRTY: return s.stateDirty;
|
||||
case nsIDM.DOWNLOAD_FINISHED: return this._fileSizeText;
|
||||
}
|
||||
return null;
|
||||
}.apply(this);
|
||||
|
||||
let [displayHost, fullHost] =
|
||||
DownloadUtils.getURIHost(this.dataItem.download.source.referrer ||
|
||||
this.dataItem.download.source.url);
|
||||
|
||||
let end = new Date(this.dataItem.endTime);
|
||||
let [displayDate, fullDate] = DownloadUtils.getReadableDates(end);
|
||||
|
||||
// We use the same XUL label to display the state, the host name, and the
|
||||
// end time, for example "Canceled - 222.net - 11:15" or "1.1 MB -
|
||||
// website2.com - Yesterday". We show the full host and the complete date
|
||||
// in the tooltip.
|
||||
let firstPart = DownloadsCommon.strings.statusSeparator(stateLabel,
|
||||
displayHost);
|
||||
status = DownloadsCommon.strings.statusSeparator(firstPart, displayDate);
|
||||
statusTip = DownloadsCommon.strings.statusSeparator(fullHost, fullDate);
|
||||
}
|
||||
|
||||
this._element.setAttribute("status", status);
|
||||
this._element.setAttribute("statusTip", statusTip || status);
|
||||
},
|
||||
|
||||
/**
|
||||
* Localized string representing the total size of completed downloads, for
|
||||
* example "1.5 MB" or "Unknown size".
|
||||
*/
|
||||
get _fileSizeText() {
|
||||
// Display the file size, but show "Unknown" for negative sizes.
|
||||
let fileSize = this.dataItem.maxBytes;
|
||||
if (fileSize < 0) {
|
||||
return DownloadsCommon.strings.sizeUnknown;
|
||||
}
|
||||
let [size, unit] = DownloadUtils.convertByteUnits(fileSize);
|
||||
return DownloadsCommon.strings.sizeWithUnits(size, unit);
|
||||
},
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// Functions called by the panel
|
||||
|
||||
/**
|
||||
* Starts checking whether the target file of a finished download is still
|
||||
* available on disk, and sets an attribute that controls how the item is
|
||||
|
@ -1222,15 +1042,15 @@ DownloadsViewItem.prototype = {
|
|||
*/
|
||||
verifyTargetExists() {
|
||||
// We don't need to check if the download is not finished successfully.
|
||||
if (!this.dataItem.download.succeeded) {
|
||||
if (!this.download.succeeded) {
|
||||
return;
|
||||
}
|
||||
|
||||
OS.File.exists(this.dataItem.download.target.path).then(aExists => {
|
||||
OS.File.exists(this.download.target.path).then(aExists => {
|
||||
if (aExists) {
|
||||
this._element.setAttribute("exists", "true");
|
||||
this.element.setAttribute("exists", "true");
|
||||
} else {
|
||||
this._element.removeAttribute("exists");
|
||||
this.element.removeAttribute("exists");
|
||||
}
|
||||
}).catch(Cu.reportError);
|
||||
},
|
||||
|
|
|
@ -0,0 +1,249 @@
|
|||
/* 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/. */
|
||||
|
||||
/*
|
||||
* This file is loaded in every window that uses the "download.xml" binding, and
|
||||
* provides prototypes for objects that handle input and display information.
|
||||
*
|
||||
* This file lazily imports common JavaScript modules in the window scope. Most
|
||||
* of these modules are generally already declared before this file is included.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
let { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadUtils",
|
||||
"resource://gre/modules/DownloadUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
|
||||
"resource:///modules/DownloadsCommon.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
/**
|
||||
* A download element shell is responsible for handling the commands and the
|
||||
* displayed data for a single element that uses the "download.xml" binding.
|
||||
*
|
||||
* The information to display is obtained through the associated Download object
|
||||
* from the JavaScript API for downloads, and commands are executed using a
|
||||
* combination of Download methods and DownloadsCommon.jsm helper functions.
|
||||
*
|
||||
* Specialized versions of this shell must be defined, currently they are the
|
||||
* HistoryDownloadElementShell and the DownloadsViewItem for the panel. The
|
||||
* history view may use a HistoryDownload object in place of a Download object.
|
||||
*/
|
||||
function DownloadElementShell() {}
|
||||
|
||||
DownloadElementShell.prototype = {
|
||||
/**
|
||||
* The richlistitem for the download, initialized by the derived object.
|
||||
*/
|
||||
element: null,
|
||||
|
||||
/**
|
||||
* The DownloadsDataItem for the download, overridden by the derived object.
|
||||
*/
|
||||
dataItem: null,
|
||||
|
||||
/**
|
||||
* Download or HistoryDownload object to use for displaying information and
|
||||
* for executing commands in the user interface.
|
||||
*/
|
||||
get download() this.dataItem.download,
|
||||
|
||||
/**
|
||||
* URI string for the file type icon displayed in the download element.
|
||||
*/
|
||||
get image() {
|
||||
if (this.download.target.path) {
|
||||
return "moz-icon://" + this.download.target.path + "?size=32";
|
||||
}
|
||||
|
||||
// Old history downloads may not have a target path.
|
||||
return "moz-icon://.unknown?size=32";
|
||||
},
|
||||
|
||||
/**
|
||||
* The user-facing label for the download. This is normally the leaf name of
|
||||
* the download target file. In case this is a very old history download for
|
||||
* which the target file is unknown, the download source URI is displayed.
|
||||
*/
|
||||
get displayName() {
|
||||
if (!this.download.target.path) {
|
||||
return this.download.source.url;
|
||||
}
|
||||
return OS.Path.basename(this.download.target.path);
|
||||
},
|
||||
|
||||
/**
|
||||
* The progress element for the download, or undefined in case the XBL binding
|
||||
* has not been applied yet.
|
||||
*/
|
||||
get _progressElement() {
|
||||
if (!this.__progressElement) {
|
||||
// If the element is not available now, we will try again the next time.
|
||||
this.__progressElement = document.getAnonymousElementByAttribute(
|
||||
this.element, "anonid", "progressmeter");
|
||||
}
|
||||
return this.__progressElement;
|
||||
},
|
||||
|
||||
/**
|
||||
* Processes a major state change in the user interface, then proceeds with
|
||||
* the normal progress update. This function is not called for every progress
|
||||
* update in order to improve performance.
|
||||
*/
|
||||
_updateState() {
|
||||
this.element.setAttribute("state", this.dataItem.state);
|
||||
this.element.setAttribute("displayName", this.displayName);
|
||||
this.element.setAttribute("image", this.image);
|
||||
|
||||
// Since state changed, reset the time left estimation.
|
||||
this.lastEstimatedSecondsLeft = Infinity;
|
||||
|
||||
this._updateProgress();
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the elements that change regularly for in-progress downloads,
|
||||
* namely the progress bar and the status line.
|
||||
*/
|
||||
_updateProgress() {
|
||||
if (this.dataItem.starting) {
|
||||
// Before the download starts, the progress meter has its initial value.
|
||||
this.element.setAttribute("progressmode", "normal");
|
||||
this.element.setAttribute("progress", "0");
|
||||
} else if (this.dataItem.state == Ci.nsIDownloadManager.DOWNLOAD_SCANNING ||
|
||||
this.dataItem.percentComplete == -1) {
|
||||
// We might not know the progress of a running download, and we don't know
|
||||
// the remaining time during the malware scanning phase.
|
||||
this.element.setAttribute("progressmode", "undetermined");
|
||||
} else {
|
||||
// This is a running download of which we know the progress.
|
||||
this.element.setAttribute("progressmode", "normal");
|
||||
this.element.setAttribute("progress", this.dataItem.percentComplete);
|
||||
}
|
||||
|
||||
// Dispatch the ValueChange event for accessibility, if possible.
|
||||
if (this._progressElement) {
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("ValueChange", true, true);
|
||||
this._progressElement.dispatchEvent(event);
|
||||
}
|
||||
|
||||
let status = this.statusTextAndTip;
|
||||
this.element.setAttribute("status", status.text);
|
||||
this.element.setAttribute("statusTip", status.tip);
|
||||
},
|
||||
|
||||
lastEstimatedSecondsLeft: Infinity,
|
||||
|
||||
/**
|
||||
* Returns the text for the status line and the associated tooltip. These are
|
||||
* returned by a single property because they are computed together. The
|
||||
* result may be overridden by derived objects.
|
||||
*/
|
||||
get statusTextAndTip() this.rawStatusTextAndTip,
|
||||
|
||||
/**
|
||||
* Derived objects may call this to get the status text.
|
||||
*/
|
||||
get rawStatusTextAndTip() {
|
||||
const nsIDM = Ci.nsIDownloadManager;
|
||||
let s = DownloadsCommon.strings;
|
||||
|
||||
let text = "";
|
||||
let tip = "";
|
||||
|
||||
if (this.dataItem.paused) {
|
||||
let transfer = DownloadUtils.getTransferTotal(this.download.currentBytes,
|
||||
this.dataItem.maxBytes);
|
||||
|
||||
// We use the same XUL label to display both the state and the amount
|
||||
// transferred, for example "Paused - 1.1 MB".
|
||||
text = s.statusSeparatorBeforeNumber(s.statePaused, transfer);
|
||||
} else if (this.dataItem.state == nsIDM.DOWNLOAD_DOWNLOADING) {
|
||||
// By default, extended status information including the individual
|
||||
// download rate is displayed in the tooltip. The history view overrides
|
||||
// the getter and displays the detials in the main area instead.
|
||||
[text] = DownloadUtils.getDownloadStatusNoRate(
|
||||
this.download.currentBytes,
|
||||
this.dataItem.maxBytes,
|
||||
this.download.speed,
|
||||
this.lastEstimatedSecondsLeft);
|
||||
let newEstimatedSecondsLeft;
|
||||
[tip, newEstimatedSecondsLeft] = DownloadUtils.getDownloadStatus(
|
||||
this.download.currentBytes,
|
||||
this.dataItem.maxBytes,
|
||||
this.download.speed,
|
||||
this.lastEstimatedSecondsLeft);
|
||||
this.lastEstimatedSecondsLeft = newEstimatedSecondsLeft;
|
||||
} else if (this.dataItem.starting) {
|
||||
text = s.stateStarting;
|
||||
} else if (this.dataItem.state == nsIDM.DOWNLOAD_SCANNING) {
|
||||
text = s.stateScanning;
|
||||
} else {
|
||||
let stateLabel;
|
||||
switch (this.dataItem.state) {
|
||||
case nsIDM.DOWNLOAD_FAILED:
|
||||
stateLabel = s.stateFailed;
|
||||
break;
|
||||
case nsIDM.DOWNLOAD_CANCELED:
|
||||
stateLabel = s.stateCanceled;
|
||||
break;
|
||||
case nsIDM.DOWNLOAD_BLOCKED_PARENTAL:
|
||||
stateLabel = s.stateBlockedParentalControls;
|
||||
break;
|
||||
case nsIDM.DOWNLOAD_BLOCKED_POLICY:
|
||||
stateLabel = s.stateBlockedPolicy;
|
||||
break;
|
||||
case nsIDM.DOWNLOAD_DIRTY:
|
||||
stateLabel = s.stateDirty;
|
||||
break;
|
||||
case nsIDM.DOWNLOAD_FINISHED:
|
||||
// For completed downloads, show the file size (e.g. "1.5 MB")
|
||||
if (this.dataItem.maxBytes !== undefined &&
|
||||
this.dataItem.maxBytes >= 0) {
|
||||
let [size, unit] =
|
||||
DownloadUtils.convertByteUnits(this.dataItem.maxBytes);
|
||||
stateLabel = s.sizeWithUnits(size, unit);
|
||||
break;
|
||||
}
|
||||
// Fallback to default unknown state.
|
||||
default:
|
||||
stateLabel = s.sizeUnknown;
|
||||
break;
|
||||
}
|
||||
|
||||
let referrer = this.download.source.referrer ||
|
||||
this.download.source.url;
|
||||
let [displayHost, fullHost] = DownloadUtils.getURIHost(referrer);
|
||||
|
||||
let date = new Date(this.dataItem.endTime);
|
||||
let [displayDate, fullDate] = DownloadUtils.getReadableDates(date);
|
||||
|
||||
let firstPart = s.statusSeparator(stateLabel, displayHost);
|
||||
text = s.statusSeparator(firstPart, displayDate);
|
||||
tip = s.statusSeparator(fullHost, fullDate);
|
||||
}
|
||||
|
||||
return { text, tip: tip || text };
|
||||
},
|
||||
};
|
|
@ -7,6 +7,7 @@ browser.jar:
|
|||
content/browser/downloads/download.css (content/download.css)
|
||||
content/browser/downloads/downloads.css (content/downloads.css)
|
||||
* content/browser/downloads/downloads.js (content/downloads.js)
|
||||
content/browser/downloads/downloadsViewCommon.js (content/downloadsViewCommon.js)
|
||||
* content/browser/downloads/downloadsOverlay.xul (content/downloadsOverlay.xul)
|
||||
content/browser/downloads/indicator.js (content/indicator.js)
|
||||
content/browser/downloads/indicatorOverlay.xul (content/indicatorOverlay.xul)
|
||||
|
|
Загрузка…
Ссылка в новой задаче