diff options
-rw-r--r-- | application/palemoon/components/downloads/content/downloadsViewCommon.js | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/application/palemoon/components/downloads/content/downloadsViewCommon.js b/application/palemoon/components/downloads/content/downloadsViewCommon.js new file mode 100644 index 000000000..7b763ed07 --- /dev/null +++ b/application/palemoon/components/downloads/content/downloadsViewCommon.js @@ -0,0 +1,267 @@ +/* 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); + }, + + get extendedDisplayName() { + let s = DownloadsCommon.strings; + let referrer = this.dataItem.download.source.referrer || + this.dataItem.download.source.url; + let [displayHost, fullHost] = DownloadUtils.getURIHost(referrer); + return s.statusSeparator(this.displayName, displayHost); + }, + + get extendedDisplayNameTip() { + let s = DownloadsCommon.strings; + let referrer = this.dataItem.download.source.referrer || + this.dataItem.download.source.url; + let [displayHost, fullHost] = DownloadUtils.getURIHost(referrer); + return s.statusSeparator(this.displayName, fullHost); + }, + + /** + * 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("extendedDisplayName", this.extendedDisplayName); + this.element.setAttribute("extendedDisplayNameTip", this.extendedDisplayNameTip); + 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 }; + }, +}; |