X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=common%2Fmodules%2Fdownloads.jsm;h=faee6e22a7a1ce5a28bcda6019c2e99dc9c05a68;hb=70740024f9c028c1fd63e1a1850ab062ff956054;hp=403c1e418a4642ec6867d1a6b47babb0b8557549;hpb=eeed0be1a8abf7e3c97f43b63c1d595e940fef21;p=dactyl.git
diff --git a/common/modules/downloads.jsm b/common/modules/downloads.jsm
index 403c1e4..faee6e2 100644
--- a/common/modules/downloads.jsm
+++ b/common/modules/downloads.jsm
@@ -7,7 +7,7 @@
Components.utils.import("resource://dactyl/bootstrap.jsm");
defineModule("downloads", {
exports: ["Download", "Downloads", "downloads"],
- use: ["io", "prefs", "services", "util"]
+ use: ["io", "messages", "prefs", "services", "util"]
}, this);
Cu.import("resource://gre/modules/DownloadUtils.jsm", this);
@@ -32,30 +32,38 @@ var Download = Class("Download", {
- {self.displayName}
{self.targetFile.path}
|
|
- Pause
- Remove
- Resume
- Retry
- Cancel
- Delete
+ {_("download.action.Pause")}
+ {_("download.action.Remove")}
+ {_("download.action.Resume")}
+ {_("download.action.Retry")}
+ {_("download.action.Cancel")}
+ {_("download.action.Delete")}
|
/
|
|
+ |
|
{self.source.spec} |
,
this.list.document, this.nodes);
+ this.nodes.launch.addEventListener("click", function (event) {
+ if (event.button == 0) {
+ event.preventDefault();
+ self.command("launch");
+ }
+ }, false);
+
self.updateStatus();
return self;
},
@@ -78,10 +86,13 @@ var Download = Class("Download", {
})),
command: function command(name) {
- util.assert(set.has(this.allowedCommands, name), "Unknown command");
- util.assert(this.allowedCommands[name], "Command not allowed");
+ util.assert(Set.has(this.allowedCommands, name), _("download.unknownCommand"));
+ util.assert(this.allowedCommands[name], _("download.commandNotAllowed"));
- services.downloadManager[name + "Download"](this.id);
+ if (Set.has(this.commands, name))
+ this.commands[name].call(this);
+ else
+ services.downloadManager[name + "Download"](this.id);
},
commands: {
@@ -95,7 +106,7 @@ var Download = Class("Download", {
function action() {
try {
if (this.MIMEInfo && this.MIMEInfo.preferredAction == this.MIMEInfo.useHelperApp)
- this.MIMEInfo.launchWithFile(file)
+ this.MIMEInfo.launchWithFile(file);
else
file.launch();
}
@@ -106,7 +117,7 @@ var Download = Class("Download", {
let file = io.File(this.targetFile);
if (file.isExecutable() && prefs.get("browser.download.manager.alertOnEXEOpen", true))
- this.list.modules.commandline.input("This will launch an executable download. Continue? (yes/[no]/always) ",
+ this.list.modules.commandline.input(_("download.prompt.launchExecutable") + " ",
function (resp) {
if (/^a(lways)$/i.test(resp)) {
prefs.set("browser.download.manager.alertOnEXEOpen", false);
@@ -120,26 +131,48 @@ var Download = Class("Download", {
}
},
- compare: function compare(other) String.localeCompare(this.displayName, other.displayName),
+ _compare: {
+ active: function (a, b) a.alive - b.alive,
+ complete: function (a, b) a.percentComplete - b.percentComplete,
+ date: function (a, b) a.startTime - b.startTime,
+ filename: function (a, b) String.localeCompare(a.targetFile.leafName, b.targetFile.leafName),
+ size: function (a, b) a.size - b.size,
+ speed: function (a, b) a.speed - b.speed,
+ time: function (a, b) a.timeRemaining - b.timeRemaining,
+ url: function (a, b) String.localeCompare(a.source.spec, b.source.spec)
+ },
+
+ compare: function compare(other) values(this.list.sortOrder).map(function (order) {
+ let val = this._compare[order.substr(1)](this, other);
+
+ return (order[0] == "-") ? -val : val;
+ }, this).nth(util.identity, 0) || 0,
timeRemaining: Infinity,
updateProgress: function updateProgress() {
let self = this.__proto__;
- if (this.amountTransferred === this.size)
+ if (this.amountTransferred === this.size) {
+ this.nodes.speed.textContent = "";
this.nodes.time.textContent = "";
- else if (this.speed == 0 || this.size == 0)
- this.nodes.time.textContent = "Unknown";
+ }
else {
- let seconds = (this.size - this.amountTransferred) / this.speed;
- [, self.timeRemaining] = DownloadUtils.getTimeLeft(seconds, this.timeRemaining);
- if (this.timeRemaining)
- this.nodes.time.textContent = util.formatSeconds(this.timeRemaining);
- else
- this.nodes.time.textContent = "~1 second";
+ this.nodes.speed.textContent = util.formatBytes(this.speed, 1, true) + "/s";
+
+ if (this.speed == 0 || this.size == 0)
+ this.nodes.time.textContent = _("download.unknown");
+ else {
+ let seconds = (this.size - this.amountTransferred) / this.speed;
+ [, self.timeRemaining] = DownloadUtils.getTimeLeft(seconds, this.timeRemaining);
+ if (this.timeRemaining)
+ this.nodes.time.textContent = util.formatSeconds(this.timeRemaining);
+ else
+ this.nodes.time.textContent = _("download.almostDone");
+ }
}
- let total = this.nodes.progressTotal.textContent = this.size ? util.formatBytes(this.size, 1, true) : "Unknown";
+
+ let total = this.nodes.progressTotal.textContent = this.size ? util.formatBytes(this.size, 1, true) : _("download.unknown");
let suffix = RegExp(/( [a-z]+)?$/i.exec(total)[0] + "$");
this.nodes.progressHave.textContent = util.formatBytes(this.amountTransferred, 1, true).replace(suffix, "");
@@ -165,7 +198,8 @@ var DownloadList = Class("DownloadList",
XPCOM([Ci.nsIDownloadProgressListener,
Ci.nsIObserver,
Ci.nsISupportsWeakReference]), {
- init: function init(modules, filter) {
+ init: function init(modules, filter, sort) {
+ this.sortOrder = sort;
this.modules = modules;
this.filter = filter && filter.toLowerCase();
this.nodes = {
@@ -173,6 +207,7 @@ var DownloadList = Class("DownloadList",
};
this.downloads = {};
},
+
cleanup: function cleanup() {
this.observe.unregister();
services.downloadManager.removeListener(this);
@@ -182,26 +217,28 @@ var DownloadList = Class("DownloadList",
util.xmlToDom(
- Title
- Status
+ {_("title.Title")}
+ {_("title.Status")}
- Progress
+ {_("title.Progress")}
- Time remaining
- Source
+ {_("title.Speed")}
+ {_("title.Time remaining")}
+ {_("title.Source")}
- Totals: |
+ {_("title.Totals")}: |
|
- Clear
+ {_("download.action.Clear")}
|
/
|
|
+ |
|
|
@@ -253,6 +290,17 @@ var DownloadList = Class("DownloadList",
}
},
+ sort: function sort() {
+ let list = values(this.downloads).sort(function (a, b) a.compare(b));
+
+ for (let [i, download] in iter(list))
+ if (this.nodes.list.childNodes[i + 1] != download.nodes.row)
+ this.nodes.list.insertBefore(download.nodes.row,
+ this.nodes.list.childNodes[i + 1]);
+ },
+
+ shouldSort: function shouldSort() Array.some(arguments, function (val) this.sortOrder.some(function (v) v.substr(1) == val), this),
+
update: function update() {
for (let node in values(this.nodes))
if (node.update && node.update != update)
@@ -277,9 +325,12 @@ var DownloadList = Class("DownloadList",
let active = downloads.filter(function (dl) dl.alive).length;
if (active)
- this.nodes.total.textContent = active + " active";
- else for (let key in values(["total", "percent", "time"]))
+ this.nodes.total.textContent = _("download.nActive", active);
+ else for (let key in values(["total", "percent", "speed", "time"]))
this.nodes[key].textContent = "";
+
+ if (this.shouldSort("complete", "size", "speed", "time"))
+ this.sort();
},
observers: {
@@ -305,11 +356,15 @@ var DownloadList = Class("DownloadList",
this.nodes.list.scrollIntoView(false);
}
this.update();
+
+ if (this.shouldSort("active"))
+ this.sort();
}
catch (e) {
util.reportError(e);
}
},
+
onProgressChange: function (webProgress, request,
curProgress, maxProgress,
curTotalProgress, maxTotalProgress,
@@ -328,17 +383,85 @@ var DownloadList = Class("DownloadList",
var Downloads = Module("downloads", {
}, {
}, {
- commands: function (dactyl, modules, window) {
- const { commands } = modules;
+ commands: function initCommands(dactyl, modules, window) {
+ const { commands, CommandOption } = modules;
commands.add(["downl[oads]", "dl"],
"Display the downloads list",
function (args) {
- let downloads = DownloadList(modules, args[0]);
+ let downloads = DownloadList(modules, args[0], args["-sort"]);
modules.commandline.echo(downloads);
},
{
- argCount: "?"
+ argCount: "?",
+ options: [
+ {
+ names: ["-sort", "-s"],
+ description: "Sort order (see 'downloadsort')",
+ type: CommandOption.LIST,
+ get default() modules.options["downloadsort"],
+ completer: function (context, args) modules.options.get("downloadsort").completer(context, { values: args["-sort"] }),
+ validator: function (value) modules.options.get("downloadsort").validator(value)
+ }
+ ]
+ });
+
+ commands.add(["dlc[lear]"],
+ "Clear completed downloads",
+ function (args) { services.downloadManager.cleanUp(); });
+ },
+ options: function initOptions(dactyl, modules, window) {
+ const { options } = modules;
+
+ if (false)
+ options.add(["downloadcolumns", "dlc"],
+ "The columns to show in the download manager",
+ "stringlist", "filename,state,buttons,progress,percent,time,url",
+ {
+ values: {
+ buttons: "Control buttons",
+ filename: "Target filename",
+ percent: "Percent complete",
+ size: "File size",
+ speed: "Download speed",
+ state: "The download's state",
+ time: "Time remaining",
+ url: "Source URL"
+ }
+ });
+
+ options.add(["downloadsort", "dlsort", "dls"],
+ ":downloads sort order",
+ "stringlist", "-active,+filename",
+ {
+ values: {
+ active: "Whether download is active",
+ complete: "Percent complete",
+ date: "Date and time the download began",
+ filename: "Target filename",
+ size: "File size",
+ speed: "Download speed",
+ time: "Time remaining",
+ url: "Source URL"
+ },
+
+ completer: function (context, extra) {
+ let seen = Set.has(Set(extra.values.map(function (val) val.substr(1))));
+
+ context.completions = iter(this.values).filter(function ([k, v]) !seen(k))
+ .map(function ([k, v]) [["+" + k, [v, " (", _("sort.ascending"), ")"].join("")],
+ ["-" + k, [v, " (", _("sort.descending"), ")"].join("")]])
+ .flatten().array;
+ },
+
+ has: function () Array.some(arguments, function (val) this.value.some(function (v) v.substr(1) == val)),
+
+ validator: function (value) {
+ let seen = {};
+ return value.every(function (val) /^[+-]/.test(val) && Set.has(this.values, val.substr(1))
+ && !Set.add(seen, val.substr(1)),
+ this) && value.length;
+ }
});
}
});