1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-20 22:47:59 +01:00

Update downloads.jsm to use Downloads.jsm rather than defunct downloads service.

This commit is contained in:
Kris Maglione
2014-02-15 15:04:09 -08:00
parent 789b44209c
commit e4aa798f6d
10 changed files with 323 additions and 172 deletions

View File

@@ -2136,7 +2136,8 @@ var ItemList = Class("ItemList", {
// We need to collect all of the rescrolling functions in // We need to collect all of the rescrolling functions in
// one go, as the height calculation that they need to do // one go, as the height calculation that they need to do
// would force a reflow after each DOM modification. // would force an expensive reflow after each call due to
// DOM modifications, otherwise.
this.activeGroups.filter(g => !g.collapsed) this.activeGroups.filter(g => !g.collapsed)
.map(g => g.rescrollFunc) .map(g => g.rescrollFunc)
.forEach(call); .forEach(call);
@@ -2270,7 +2271,7 @@ var ItemList = Class("ItemList", {
getGroup: function getGroup(context) getGroup: function getGroup(context)
context instanceof ItemList.Group ? context context instanceof ItemList.Group ? context
: context && context.getCache("itemlist-group", : context && context.getCache("itemlist-group",
bind("Group", ItemList, this, context)), () => ItemList.Group(this, context)),
getOffset: function getOffset(tuple) tuple && this.getGroup(tuple[0]).getOffset(tuple[1]) getOffset: function getOffset(tuple) tuple && this.getGroup(tuple[0]).getOffset(tuple[1])
}, { }, {

View File

@@ -332,7 +332,7 @@ var HintSession = Class("HintSession", CommandMode, {
__proto__: this.Hint __proto__: this.Hint
}); });
for (let hint in values(_hints)) { for (let hint of _hints) {
let { elem, rect } = hint; let { elem, rect } = hint;
if (elem.hasAttributeNS(NS, "hint")) if (elem.hasAttributeNS(NS, "hint"))

View File

@@ -162,13 +162,11 @@ download.nActive-1 = %S active
download.almostDone = ~1 second download.almostDone = ~1 second
download.unknown = Unknown download.unknown = Unknown
download.action.Cancel = Cancel
download.action.Clear = Clear download.action.Clear = Clear
download.action.Delete = Delete download.action.Delete = Delete
download.action.Pause = Pause download.action.Stop = Stop
download.action.Remove = Remove download.action.Remove = Remove
download.action.Resume = Resume download.action.Resume = Resume
download.action.Retry = Retry
editor.prompt.editPassword = Editing a password field externally will reveal the password. Would you like to continue? (yes/[no]): editor.prompt.editPassword = Editing a password field externally will reveal the password. Would you like to continue? (yes/[no]):

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2009-2013 Kris Maglione <maglione.k@gmail.com> // Copyright (c) 2009-2014 Kris Maglione <maglione.k@gmail.com>
// //
// This work is licensed for reuse under an MIT license. Details are // This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file. // given in the LICENSE.txt file included with this file.
@@ -6,10 +6,15 @@
var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components; var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); function module(url) {
let obj = {};
Cu.import(url, obj);
return obj;
}
var { XPCOMUtils } = module("resource://gre/modules/XPCOMUtils.jsm");
try { try {
var ctypes; var ctypes = module("resource://gre/modules/ctypes.jsm");
Cu.import("resource://gre/modules/ctypes.jsm");
} }
catch (e) {} catch (e) {}
@@ -22,7 +27,11 @@ if (typeof XPCSafeJSObjectWrapper === "undefined")
let getGlobalForObject = Cu.getGlobalForObject || (obj => obj.__parent__); let getGlobalForObject = Cu.getGlobalForObject || (obj => obj.__parent__);
function require(module, target) JSMLoader.load(module, target); function require(module_, target) {
if (/^[A-Za-z0-9]+:/.test(module_))
return module(module_);
return JSMLoader.load(module_, target);
}
function lazyRequire(module, names, target) { function lazyRequire(module, names, target) {
for each (let name in names) for each (let name in names)
@@ -133,13 +142,16 @@ function require_(obj, name, from, targetName) {
defineModule("base", { defineModule("base", {
// sed -n 's/^(const|var|function) ([a-zA-Z0-9_]+).*/ "\2",/p' base.jsm | sort | fmt // sed -n 's/^(const|var|function) ([a-zA-Z0-9_]+).*/ "\2",/p' base.jsm | sort | fmt
exports: [ exports: [
"ErrorBase", "Cc", "Ci", "Class", "Cr", "Cu", "Finished", "Module", "JSMLoader", "ErrorBase", "Cc", "Ci", "Class", "Cr", "Cu", "Finished",
"Set", "Struct", "StructBase", "Timer", "UTF8", "XPCOM", "XPCOMShim", "XPCOMUtils", "Module", "JSMLoader", "RealSet", "Set", "Struct", "StructBase",
"XPCSafeJSObjectWrapper", "array", "bind", "call", "callable", "ctypes", "curry", "Timer", "UTF8", "XPCOM", "XPCOMShim", "XPCOMUtils",
"debuggerProperties", "defineModule", "deprecated", "endModule", "forEach", "isArray", "XPCSafeJSObjectWrapper", "array", "bind", "call", "callable",
"isGenerator", "isinstance", "isObject", "isString", "isSubclass", "isXML", "iter", "ctypes", "curry", "debuggerProperties", "defineModule",
"iterAll", "iterOwnProperties", "keys", "literal", "memoize", "octal", "properties", "deprecated", "endModule", "forEach", "isArray", "isGenerator",
"require", "set", "update", "values", "update_" "isinstance", "isObject", "isString", "isSubclass", "isXML",
"iter", "iterAll", "iterOwnProperties", "keys", "literal",
"memoize", "modujle", "octal", "properties", "require", "set",
"update", "values", "update_"
] ]
}); });
@@ -318,6 +330,10 @@ deprecated.warn = function warn(func, name, alternative, frame) {
* @returns {Generator} * @returns {Generator}
*/ */
function keys(obj) iter(function keys() { function keys(obj) iter(function keys() {
if (isinstance(obj, ["Map"]))
for (let [k, v] of obj)
yield k;
else
for (var k in obj) for (var k in obj)
if (hasOwnProperty.call(obj, k)) if (hasOwnProperty.call(obj, k))
yield k; yield k;
@@ -331,7 +347,10 @@ function keys(obj) iter(function keys() {
* @returns {Generator} * @returns {Generator}
*/ */
function values(obj) iter(function values() { function values(obj) iter(function values() {
if (isinstance(obj, ["Generator", "Iterator", Iter])) if (isinstance(obj, ["Map"]))
for (let [k, v] of obj)
yield v;
else if (isinstance(obj, ["Generator", "Iterator", Iter]))
for (let k in obj) for (let k in obj)
yield k; yield k;
else else
@@ -343,6 +362,8 @@ function values(obj) iter(function values() {
var forEach = deprecated("iter.forEach", function forEach() iter.forEach.apply(iter, arguments)); var forEach = deprecated("iter.forEach", function forEach() iter.forEach.apply(iter, arguments));
var iterAll = deprecated("iter", function iterAll() iter.apply(null, arguments)); var iterAll = deprecated("iter", function iterAll() iter.apply(null, arguments));
var RealSet = Set;
/** /**
* Utility for managing sets of strings. Given an array, returns an * Utility for managing sets of strings. Given an array, returns an
* object with one key for each value thereof. * object with one key for each value thereof.
@@ -350,7 +371,7 @@ var iterAll = deprecated("iter", function iterAll() iter.apply(null, arguments))
* @param {[string]} ary @optional * @param {[string]} ary @optional
* @returns {object} * @returns {object}
*/ */
function Set(ary) { this.Set = function Set(ary) {
let obj = {}; let obj = {};
if (ary) if (ary)
for (let val in values(ary)) for (let val in values(ary))
@@ -1377,6 +1398,10 @@ function iter(obj, iface) {
if (arguments.length == 2 && iface instanceof Ci.nsIJSIID) if (arguments.length == 2 && iface instanceof Ci.nsIJSIID)
return iter(obj).map(item => item.QueryInterface(iface)); return iter(obj).map(item => item.QueryInterface(iface));
if (isinstance(obj, ["Map Iterator"]))
// This is stupid.
obj = { __iterator__: (function () this).bind(obj) };
let args = arguments; let args = arguments;
let res = Iterator(obj); let res = Iterator(obj);
@@ -1388,6 +1413,9 @@ function iter(obj, iface) {
})(); })();
else if (isinstance(obj, ["Iterator", "Generator"])) else if (isinstance(obj, ["Iterator", "Generator"]))
; ;
else if (isinstance(obj, ["Map"]))
// This is stupid.
res = (r for (r of obj));
else if (ctypes && ctypes.CData && obj instanceof ctypes.CData) { else if (ctypes && ctypes.CData && obj instanceof ctypes.CData) {
while (obj.constructor instanceof ctypes.PointerType) while (obj.constructor instanceof ctypes.PointerType)
obj = obj.contents; obj = obj.contents;

View File

@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org> // Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com> // Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
// Copyright (c) 2008-2013 Kris Maglione <maglione.k at Gmail> // Copyright (c) 2008-2014 Kris Maglione <maglione.k at Gmail>
// //
// This work is licensed for reuse under an MIT license. Details are // This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file. // given in the LICENSE.txt file included with this file.
@@ -16,6 +16,7 @@ lazyRequire("contexts", ["Group"]);
lazyRequire("io", ["io"]); lazyRequire("io", ["io"]);
lazyRequire("finder", ["RangeFind"]); lazyRequire("finder", ["RangeFind"]);
lazyRequire("overlay", ["overlay"]); lazyRequire("overlay", ["overlay"]);
lazyRequire("promises", ["Promise", "promises"]);
lazyRequire("sanitizer", ["sanitizer"]); lazyRequire("sanitizer", ["sanitizer"]);
lazyRequire("storage", ["File", "storage"]); lazyRequire("storage", ["File", "storage"]);
lazyRequire("template", ["template"]); lazyRequire("template", ["template"]);
@@ -68,6 +69,50 @@ var Buffer = Module("Buffer", {
); );
}, },
/**
* The load context of the window bound to this buffer.
*/
get loadContext() sanitizer.getContext(this.win),
/**
* Content preference methods.
*/
prefs: Class.Memoize(() => ({
/**
* Returns a promise for the given preference name.
*
* @param {string} pref The name of the preference to return.
* @returns {Promise<string>}
*/
get: promises.withCallback(function get(callback, pref) {
services.contentPrefs.getByDomainAndName(
this.uri.host, pref, this.loadContext,
callback);
}),
/**
* Sets a content preference for the given buffer.
*
* @param {string} pref The preference to set.
* @param {string} value The value to store.
*/
set: promises.withCallback(function set(callback, pref, value) {
services.contentPrefs.set(
this.uri.host, pref, value, this.loadContext,
callback);
}),
/**
* Clear a content preference for the given buffer.
*
* @param {string} pref The preference to clear.
*/
clear: promises.withCallback(function clear(callback, pref) {
services.contentPrefs.removeByDomainAndName(
this.uri.domain, pref, this.loadContext, callback);
}),
})),
/** /**
* Gets a content preference for the given buffer. * Gets a content preference for the given buffer.
* *
@@ -77,10 +122,10 @@ var Buffer = Module("Buffer", {
* @returns {string|number|boolean} The value of the preference, if * @returns {string|number|boolean} The value of the preference, if
* callback is not provided. * callback is not provided.
*/ */
getPref: function getPref(pref, callback) { getPref: deprecated("prefs.get", function getPref(pref, callback) {
services.contentPrefs.getPref(this.uri, pref, services.contentPrefs.getPref(this.uri, pref,
sanitizer.getContext(this.win), callback); this.loadContext, callback);
}, }),
/** /**
* Sets a content preference for the given buffer. * Sets a content preference for the given buffer.
@@ -88,20 +133,20 @@ var Buffer = Module("Buffer", {
* @param {string} pref The preference to set. * @param {string} pref The preference to set.
* @param {string} value The value to store. * @param {string} value The value to store.
*/ */
setPref: function setPref(pref, value) { setPref: deprecated("prefs.set", function setPref(pref, value) {
services.contentPrefs.setPref( services.contentPrefs.setPref(
this.uri, pref, value, sanitizer.getContext(this.win)); this.uri, pref, value, this.loadContext);
}, }),
/** /**
* Clear a content preference for the given buffer. * Clear a content preference for the given buffer.
* *
* @param {string} pref The preference to clear. * @param {string} pref The preference to clear.
*/ */
clearPref: function clearPref(pref) { clearPref: deprecated("prefs.clear", function clearPref(pref) {
services.contentPrefs.removePref( services.contentPrefs.removePref(
this.uri, pref, sanitizer.getContext(this.win)); this.uri, pref, this.loadContext);
}, }),
climbUrlPath: function climbUrlPath(count) { climbUrlPath: function climbUrlPath(count) {
let { dactyl } = this.modules; let { dactyl } = this.modules;
@@ -1244,12 +1289,12 @@ var Buffer = Module("Buffer", {
if (prefs.get("browser.zoom.siteSpecific")) { if (prefs.get("browser.zoom.siteSpecific")) {
var privacy = sanitizer.getContext(this.win); var privacy = sanitizer.getContext(this.win);
if (value == 1) { if (value == 1) {
this.clearPref("browser.content.full-zoom"); this.prefs.clear("browser.content.full-zoom");
this.clearPref("dactyl.content.full-zoom"); this.prefs.clear("dactyl.content.full-zoom");
} }
else { else {
this.setPref("browser.content.full-zoom", value); this.prefs.set("browser.content.full-zoom", value);
this.setPref("dactyl.content.full-zoom", fullZoom); this.prefs.set("dactyl.content.full-zoom", fullZoom);
} }
} }
@@ -1259,15 +1304,15 @@ var Buffer = Module("Buffer", {
/** /**
* Updates the zoom level of this buffer from a content preference. * Updates the zoom level of this buffer from a content preference.
*/ */
updateZoom: util.wrapCallback(function updateZoom() { updateZoom: promises.task(function updateZoom() {
let uri = this.uri; let uri = this.uri;
if (prefs.get("browser.zoom.siteSpecific")) { if (prefs.get("browser.zoom.siteSpecific")) {
this.getPref("dactyl.content.full-zoom", (val) => { let val = this.prefs.get("dactyl.content.full-zoom");
if (val != null && uri.equals(this.uri) && val != prefs.get("browser.zoom.full")) if (val != null && uri.equals(this.uri) && val != prefs.get("browser.zoom.full"))
[this.contentViewer.textZoom, this.contentViewer.fullZoom] = [this.contentViewer.textZoom, this.contentViewer.fullZoom] =
[this.contentViewer.fullZoom, this.contentViewer.textZoom]; [this.contentViewer.fullZoom, this.contentViewer.textZoom];
});
} }
}), }),

View File

@@ -733,7 +733,7 @@ var CompletionContext = Class("CompletionContext", {
let alias = (prop) => { let alias = (prop) => {
context.__defineGetter__(prop, () => this[prop]); context.__defineGetter__(prop, () => this[prop]);
context.__defineSetter__(prop, (val) => this[prop] = val); context.__defineSetter__(prop, (val) => this[prop] = val);
} };
alias("_cache"); alias("_cache");
alias("_completions"); alias("_completions");
alias("_generate"); alias("_generate");

View File

@@ -45,7 +45,7 @@ var ConfigBase = Class("ConfigBase", {
* initialization code. Must call superclass's init function. * initialization code. Must call superclass's init function.
*/ */
init: function init() { init: function init() {
if (config.haveGecko("26")) if (!config.haveGecko("26"))
this.modules.global = this.modules.global.filter(m => m != "downloads"); // FIXME this.modules.global = this.modules.global.filter(m => m != "downloads"); // FIXME
this.loadConfig(); this.loadConfig();

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2011-2013 Kris Maglione <maglione.k@gmail.com> // Copyright (c) 2011-2014 Kris Maglione <maglione.k@gmail.com>
// //
// This work is licensed for reuse under an MIT license. Details are // This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file. // given in the LICENSE.txt file included with this file.
@@ -10,8 +10,10 @@ defineModule("downloads", {
}); });
lazyRequire("overlay", ["overlay"]); lazyRequire("overlay", ["overlay"]);
lazyRequire("promises", ["Task", "promises"]);
Cu.import("resource://gre/modules/DownloadUtils.jsm", this); lazyRequire("resource://gre/modules/Downloads.jsm", ["Downloads"]);
lazyRequire("resource://gre/modules/DownloadUtils.jsm", ["DownloadUtils"]);
var MAX_LOAD_TIME = 10 * 1000; var MAX_LOAD_TIME = 10 * 1000;
@@ -22,8 +24,8 @@ var states = iter([v, k.slice(prefix.length).toLowerCase()]
.toObject(); .toObject();
var Download = Class("Download", { var Download = Class("Download", {
init: function init(id, list) { init: function init(download, list) {
this.download = services.downloadManager.getDownload(id); this.download = download;
this.list = list; this.list = list;
this.nodes = { this.nodes = {
@@ -39,11 +41,9 @@ var Download = Class("Download", {
this.targetFile.path]]], this.targetFile.path]]],
["td", { highlight: "DownloadState", key: "state" }], ["td", { highlight: "DownloadState", key: "state" }],
["td", { highlight: "DownloadButtons Buttons" }, ["td", { highlight: "DownloadButtons Buttons" },
["a", { highlight: "Button", href: "javascript:0", key: "pause" }, _("download.action.Pause")], ["a", { highlight: "Button", href: "javascript:0", key: "stop" }, _("download.action.Stop")],
["a", { highlight: "Button", href: "javascript:0", key: "remove" }, _("download.action.Remove")], ["a", { highlight: "Button", href: "javascript:0", key: "remove" }, _("download.action.Remove")],
["a", { highlight: "Button", href: "javascript:0", key: "resume" }, _("download.action.Resume")], ["a", { highlight: "Button", href: "javascript:0", key: "resume" }, _("download.action.Resume")],
["a", { highlight: "Button", href: "javascript:0", key: "retry" }, _("download.action.Retry")],
["a", { highlight: "Button", href: "javascript:0", key: "cancel" }, _("download.action.Cancel")],
["a", { highlight: "Button", href: "javascript:0", key: "delete" }, _("download.action.Delete")]], ["a", { highlight: "Button", href: "javascript:0", key: "delete" }, _("download.action.Delete")]],
["td", { highlight: "DownloadProgress", key: "progress" }, ["td", { highlight: "DownloadProgress", key: "progress" },
["span", { highlight: "DownloadProgressHave", key: "progressHave" }], ["span", { highlight: "DownloadProgressHave", key: "progressHave" }],
@@ -53,8 +53,8 @@ var Download = Class("Download", {
["td", { highlight: "DownloadSpeed", key: "speed" }], ["td", { highlight: "DownloadSpeed", key: "speed" }],
["td", { highlight: "DownloadTime", key: "time" }], ["td", { highlight: "DownloadTime", key: "time" }],
["td", {}, ["td", {},
["a", { highlight: "DownloadSource", key: "source", href: this.source.spec }, ["a", { highlight: "DownloadSource", key: "source", href: this.source.url },
this.source.spec]]], this.source.url]]],
this.list.document, this.nodes); this.list.document, this.nodes);
this.nodes.launch.addEventListener("click", (event) => { this.nodes.launch.addEventListener("click", (event) => {
@@ -68,21 +68,22 @@ var Download = Class("Download", {
return this; return this;
}, },
get active() !this.stopped,
get targetFile() File(this.download.target.path),
get displayName() this.targetFile.leafName,
get status() states[this.state], get status() states[this.state],
inState: function inState(states) states.indexOf(this.status) >= 0, inState: function inState(states) states.indexOf(this.status) >= 0,
get alive() this.inState(["downloading", "notstarted", "paused", "queued", "scanning"]),
allowedCommands: Class.Memoize(function () let (self = this) ({ allowedCommands: Class.Memoize(function () let (self = this) ({
get cancel() self.cancelable && self.inState(["downloading", "paused", "starting"]), get delete() !self.active && (self.targetFile.exists() || self.hasPartialData),
get delete() !this.cancel && self.targetFile.exists(), get launch() self.targetFile.exists() && self.succeeded,
get launch() self.targetFile.exists() && self.inState(["finished"]), get stop() self.active,
get pause() self.inState(["downloading"]), get remove() !self.active,
get remove() self.inState(["blocked_parental", "blocked_policy", get resume() self.canceled
"canceled", "dirty", "failed", "finished"]),
get resume() self.resumable && self.inState(["paused"]),
get retry() self.inState(["canceled", "failed"])
})), })),
command: function command(name) { command: function command(name) {
@@ -91,15 +92,16 @@ var Download = Class("Download", {
if (Set.has(this.commands, name)) if (Set.has(this.commands, name))
this.commands[name].call(this); this.commands[name].call(this);
else
services.downloadManager[name + "Download"](this.id);
}, },
commands: { commands: {
delete: function delete_() { delete: promises.task(function delete_() {
if (this.hasPartialData)
yield this.removePartialData();
else if (self.targetFile.exists())
this.targetFile.remove(false); this.targetFile.remove(false);
this.updateStatus(); this.updateStatus();
}, }),
launch: function launch() { launch: function launch() {
// Behavior mimics that of the builtin Download Manager. // Behavior mimics that of the builtin Download Manager.
function action() { function action() {
@@ -127,18 +129,28 @@ var Download = Class("Download", {
}); });
else else
action.call(this); action.call(this);
} },
resume: function resume() {
this.download.start();
},
remove: promises.task(function remove() {
yield this.list.list.remove(this.download);
yield this.download.finalize(true);
}),
stop: function stop() {
this.download.cancel();
},
}, },
_compare: { _compare: {
active: (a, b) => a.alive - b.alive, active: (a, b) => a.active - b.active,
complete: (a, b) => a.percentComplete - b.percentComplete, complete: (a, b) => a.percentComplete - b.percentComplete,
date: (a, b) => a.startTime - b.startTime, date: (a, b) => a.startTime - b.startTime,
filename: (a, b) => String.localeCompare(a.targetFile.leafName, b.targetFile.leafName), filename: (a, b) => String.localeCompare(a.targetFile.leafName, b.targetFile.leafName),
size: (a, b) => a.size - b.size, size: (a, b) => a.totalBytes - b.totalBytes,
speed: (a, b) => a.speed - b.speed, speed: (a, b) => a.speed - b.speed,
time: (a, b) => a.timeRemaining - b.timeRemaining, time: (a, b) => a.timeRemaining - b.timeRemaining,
url: (a, b) => String.localeCompare(a.source.spec, b.source.spec) url: (a, b) => String.localeCompare(a.source.url, b.source.url)
}, },
compare: function compare(other) values(this.list.sortOrder).map(function (order) { compare: function compare(other) values(this.list.sortOrder).map(function (order) {
@@ -152,17 +164,17 @@ var Download = Class("Download", {
updateProgress: function updateProgress() { updateProgress: function updateProgress() {
let self = this.__proto__; let self = this.__proto__;
if (this.amountTransferred === this.size) { if (!this.active) {
this.nodes.speed.textContent = ""; this.nodes.speed.textContent = "";
this.nodes.time.textContent = ""; this.nodes.time.textContent = "";
} }
else { else {
this.nodes.speed.textContent = util.formatBytes(this.speed, 1, true) + "/s"; this.nodes.speed.textContent = util.formatBytes(this.speed, 1, true) + "/s";
if (this.speed == 0 || this.size == 0) if (this.speed == 0 || !this.hasProgress)
this.nodes.time.textContent = _("download.unknown"); this.nodes.time.textContent = _("download.unknown");
else { else {
let seconds = (this.size - this.amountTransferred) / this.speed; let seconds = (this.totalBytes - this.currentBytes) / this.speed;
[, self.timeRemaining] = DownloadUtils.getTimeLeft(seconds, this.timeRemaining); [, self.timeRemaining] = DownloadUtils.getTimeLeft(seconds, this.timeRemaining);
if (this.timeRemaining) if (this.timeRemaining)
this.nodes.time.textContent = util.formatSeconds(this.timeRemaining); this.nodes.time.textContent = util.formatSeconds(this.timeRemaining);
@@ -171,17 +183,20 @@ var Download = Class("Download", {
} }
} }
let total = this.nodes.progressTotal.textContent = this.size || !this.nActive ? util.formatBytes(this.size, 1, true) let total = this.nodes.progressTotal.textContent =
this.hasProgress && (this.totalBytes || !this.nActive)
? util.formatBytes(this.totalBytes, 1, true)
: _("download.unknown"); : _("download.unknown");
let suffix = RegExp(/( [a-z]+)?$/i.exec(total)[0] + "$");
this.nodes.progressHave.textContent = util.formatBytes(this.amountTransferred, 1, true).replace(suffix, "");
this.nodes.percent.textContent = this.size ? Math.round(this.amountTransferred * 100 / this.size) + "%" : ""; let suffix = RegExp(/( [a-z]+)?$/i.exec(total)[0] + "$");
this.nodes.progressHave.textContent = util.formatBytes(this.currentBytes, 1, true).replace(suffix, "");
this.nodes.percent.textContent = this.hasProgress ? this.progress + "%" : "";
}, },
updateStatus: function updateStatus() { updateStatus: function updateStatus() {
this.nodes.row[this.alive ? "setAttribute" : "removeAttribute"]("active", "true"); this.nodes.row[this.active ? "setAttribute" : "removeAttribute"]("active", "true");
this.nodes.row.setAttribute("status", this.status); this.nodes.row.setAttribute("status", this.status);
this.nodes.state.textContent = util.capitalize(this.status); this.nodes.state.textContent = util.capitalize(this.status);
@@ -193,14 +208,6 @@ var Download = Class("Download", {
this.updateProgress(); this.updateProgress();
} }
}); });
Object.keys(XPCOMShim([Ci.nsIDownload])).forEach(function (key) {
if (!(key in Download.prototype))
Object.defineProperty(Download.prototype, key, {
get: function get() this.download[key],
set: function set(val) this.download[key] = val,
configurable: true
});
});
var DownloadList = Class("DownloadList", var DownloadList = Class("DownloadList",
XPCOM([Ci.nsIDownloadProgressListener, XPCOM([Ci.nsIDownloadProgressListener,
@@ -213,12 +220,13 @@ var DownloadList = Class("DownloadList",
this.nodes = { this.nodes = {
commandTarget: this commandTarget: this
}; };
this.downloads = {}; this.downloads = Map();
}, },
cleanup: function cleanup() { cleanup: function cleanup() {
this.observe.unregister(); if (this.list)
services.downloadManager.removeListener(this); this.list.removeView(this);
this.dead = true;
}, },
message: Class.Memoize(function () { message: Class.Memoize(function () {
@@ -258,40 +266,44 @@ var DownloadList = Class("DownloadList",
this.index = Array.indexOf(this.nodes.list.childNodes, this.index = Array.indexOf(this.nodes.list.childNodes,
this.nodes.head); this.nodes.head);
Task.spawn(function () {
this.list = yield Downloads.getList(Downloads.ALL);
let start = Date.now(); let start = Date.now();
for (let row in iter(services.downloadManager.DBConnection for (let download of yield this.list.getAll()) {
.createStatement("SELECT id FROM moz_downloads"))) {
if (Date.now() - start > MAX_LOAD_TIME) { if (Date.now() - start > MAX_LOAD_TIME) {
util.dactyl.warn(_("download.givingUpAfter", (Date.now() - start) / 1000)); util.dactyl.warn(_("download.givingUpAfter", (Date.now() - start) / 1000));
break; break;
} }
this.addDownload(row.id); this.addDownload(download);
} }
this.update(); this.update();
util.addObserver(this); if (!this.dead)
services.downloadManager.addListener(this); this.list.addView(this);
}.bind(this));
return this.nodes.list; return this.nodes.list;
}), }),
addDownload: function addDownload(id) { addDownload: function addDownload(download) {
if (!(id in this.downloads)) { if (!this.downloads.has(download)) {
let download = Download(id, this); download = Download(download, this);
if (this.filter && download.displayName.indexOf(this.filter) === -1) if (this.filter && download.displayName.indexOf(this.filter) === -1)
return; return;
this.downloads[id] = download; this.downloads.set(download.download, download);
let index = values(this.downloads).sort((a, b) => a.compare(b)) let index = values(this.downloads).toArray()
.sort((a, b) => a.compare(b))
.indexOf(download); .indexOf(download);
this.nodes.list.insertBefore(download.nodes.row, this.nodes.list.insertBefore(download.nodes.row,
this.nodes.list.childNodes[index + this.index + 1]); this.nodes.list.childNodes[index + this.index + 1]);
} }
}, },
removeDownload: function removeDownload(id) { removeDownload: function removeDownload(download) {
if (id in this.downloads) { if (this.downloads.has(download)) {
this.nodes.list.removeChild(this.downloads[id].nodes.row); this.nodes.list.removeChild(this.downloads.get(download).nodes.row);
delete this.downloads[id]; delete this.downloads.delete(download);
} }
}, },
@@ -301,17 +313,17 @@ var DownloadList = Class("DownloadList",
}, },
allowedCommands: Class.Memoize(function () let (self = this) ({ allowedCommands: Class.Memoize(function () let (self = this) ({
get clear() values(self.downloads).some(dl => dl.allowedCommands.remove) get clear() iter(self.downloads.values()).some(dl => dl.allowedCommands.remove)
})), })),
commands: { commands: {
clear: function () { clear: function () {
services.downloadManager.cleanUp(); this.list.removeFinished();
} }
}, },
sort: function sort() { sort: function sort() {
let list = values(this.downloads).sort((a, b) => a.compare(b)); let list = iter(this.downloads.values()).sort((a, b) => a.compare(b));
for (let [i, download] in iter(list)) for (let [i, download] in iter(list))
if (this.nodes.list.childNodes[i + 1] != download.nodes.row) if (this.nodes.list.childNodes[i + 1] != download.nodes.row)
@@ -335,16 +347,19 @@ var DownloadList = Class("DownloadList",
timeRemaining: Infinity, timeRemaining: Infinity,
updateProgress: function updateProgress() { updateProgress: function updateProgress() {
let downloads = values(this.downloads).toArray(); let downloads = iter(this.downloads.values()).toArray();
let active = downloads.filter(d => d.alive); let active = downloads.filter(d => d.active);
let self = Object.create(this); let self = Object.create(this);
for (let prop in values(["amountTransferred", "size", "speed", "timeRemaining"])) for (let prop in values(["currentBytes", "totalBytes", "speed", "timeRemaining"]))
this[prop] = active.reduce((acc, dl) => dl[prop] + acc, 0); this[prop] = active.reduce((acc, dl) => dl[prop] + acc, 0);
this.hasProgress = active.every(d => d.hasProgress);
this.progress = Math.round((this.currentBytes / this.totalBytes) * 100);
this.nActive = active.length;
Download.prototype.updateProgress.call(self); Download.prototype.updateProgress.call(self);
this.nActive = active.length;
if (active.length) if (active.length)
this.nodes.total.textContent = _("download.nActive", active.length); this.nodes.total.textContent = _("download.nActive", active.length);
else for (let key in values(["total", "percent", "speed", "time"])) else for (let key in values(["total", "percent", "speed", "time"]))
@@ -354,68 +369,87 @@ var DownloadList = Class("DownloadList",
this.sort(); this.sort();
}, },
observers: { onDownloadAdded: function onDownloadAdded(download) {
"download-manager-remove-download": function (id) { this.addDownload(download);
if (id == null)
id = [k for ([k, dl] in iter(this.downloads)) if (dl.allowedCommands.remove)];
else
id = [id.QueryInterface(Ci.nsISupportsPRUint32).data];
Array.concat(id).map(this.closure.removeDownload);
this.update();
}
},
onDownloadStateChange: function (state, download) {
try {
if (download.id in this.downloads)
this.downloads[download.id].updateStatus();
else {
this.addDownload(download.id);
this.modules.mow.resize(false); this.modules.mow.resize(false);
this.nodes.list.scrollIntoView(false); this.nodes.list.scrollIntoView(false);
} },
onDownloadRemoved: function onDownloadRemoved(download) {
this.removeDownload(download);
},
onDownloadChanged: function onDownloadChanged(download) {
if (this.downloads.has(download)) {
download = this.downloads.get(download)
download.updateStatus();
download.updateProgress();
this.update(); this.update();
if (this.shouldSort("active")) if (this.shouldSort("active"))
this.sort(); this.sort();
} }
catch (e) {
util.reportError(e);
}
},
onProgressChange: function (webProgress, request,
curProgress, maxProgress,
curTotalProgress, maxTotalProgress,
download) {
try {
if (download.id in this.downloads)
this.downloads[download.id].updateProgress();
this.updateProgress();
}
catch (e) {
util.reportError(e);
}
} }
}); });
["canceled",
"contentType",
"currentBytes",
"error",
"hasPartialData",
"hasProgress",
"launchWhenSucceeded",
"launcherPath",
"progress",
"saver",
"source",
"speed",
"startTime",
"stopped",
"succeeded",
"target",
"totalBytes",
"tryToKeepPartialData"].forEach(key => {
if (!(key in Download.prototype))
Object.defineProperty(Download.prototype, key, {
get: function get() this.download[key],
set: function set(val) this.download[key] = val,
configurable: true
});
});
var Downloads = Module("downloads", XPCOM(Ci.nsIDownloadProgressListener), {
var Downloads_ = Module("downloads", XPCOM(Ci.nsIDownloadProgressListener), {
init: function () { init: function () {
services.downloadManager.addListener(this); Downloads.getList(Downloads.ALL).then(list => {
this.list = list;
if (!this.dead)
this.list.addView(this);
});
}, },
cleanup: function destroy() { cleanup: function destroy() {
services.downloadManager.removeListener(this); if (this.list)
this.list.removeView(this);
this.dead = true;
}, },
onDownloadStateChange: function (state, download) { onDownloadAdded: function onDownloadAdded(download) {
if (download.state == services.downloadManager.DOWNLOAD_FINISHED) { },
let url = download.source.spec;
let title = download.displayName; onDownloadRemoved: function onDownloadRemoved(download) {
let file = download.targetFile.path; },
let size = download.size;
onDownloadChanged: function onDownloadChanged(download) {
if (download.succeeded) {
let target = File(download.target.path);
let url = download.source.url;
let title = target.leafName;
let file = target.path;
let size = download.totalBytes;
overlay.modules.forEach(function (modules) { overlay.modules.forEach(function (modules) {
modules.dactyl.echomsg({ domains: [util.getHost(url)], message: _("io.downloadFinished", title, file) }, modules.dactyl.echomsg({ domains: [util.getHost(url)], message: _("io.downloadFinished", title, file) },
@@ -451,7 +485,7 @@ var Downloads = Module("downloads", XPCOM(Ci.nsIDownloadProgressListener), {
commands.add(["dlc[lear]"], commands.add(["dlc[lear]"],
"Clear completed downloads", "Clear completed downloads",
function (args) { services.downloadManager.cleanUp(); }); function (args) { downloads.list.removeFinished(); });
}, },
options: function initOptions(dactyl, modules, window) { options: function initOptions(dactyl, modules, window) {
const { options } = modules; const { options } = modules;

View File

@@ -336,9 +336,6 @@ var JavaScript = Module("javascript", {
_complete: function (objects, key, compl, string, last) { _complete: function (objects, key, compl, string, last) {
const self = this; const self = this;
if (!getOwnPropertyNames && !services.debugger.isOn && !this.context.message)
this.context.message = /*L*/"For better completion data, please enable the JavaScript debugger (:set jsdebugger)";
let base = this.context.fork("js", this._top.offset); let base = this.context.fork("js", this._top.offset);
base.forceAnchored = true; base.forceAnchored = true;
base.filter = last == null ? key : string; base.filter = last == null ? key : string;

View File

@@ -0,0 +1,48 @@
// Copyright (c) 2014 Kris Maglione <maglione.k at Gmail>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
"use strict";
defineModule("promises", {
exports: ["Promise", "Task", "promises"],
require: []
});
lazyRequire("resource://gre/modules/Promise.jsm", ["Promise"]);
lazyRequire("resource://gre/modules/Task.jsm", ["Task"]);
var Promises = Module("Promises", {
/**
* Wraps the given function so that each call spawns a Task.
*
* @param {function} fn The function to wrap.
* @returns {function}
*/
task: function task(fn) {
return function task_(...args) {
return Task.spawn(fn.bind.apply(fn, [this].concat(args)));
}
},
/**
* Wraps the given function so that its first argument is a
* callback which, when called, resolves the returned promise.
*
* @param {function} fn The function to wrap.
* @returns {Promise}
*/
withCallback: function withCallback(fn) {
return function wrapper(...args) {
let deferred = Promise.defer();
function callback(arg) {
deferred.resolve(arg);
}
return fn.apply(this, [callback].concat(args));
}
},
});
endModule();
// vim: set fdm=marker sw=4 sts=4 ts=8 et ft=javascript: