1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-20 18:27: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
// 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)
.map(g => g.rescrollFunc)
.forEach(call);
@@ -2270,7 +2271,7 @@ var ItemList = Class("ItemList", {
getGroup: function getGroup(context)
context instanceof ItemList.Group ? context
: 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])
}, {

View File

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

View File

@@ -162,13 +162,11 @@ download.nActive-1 = %S active
download.almostDone = ~1 second
download.unknown = Unknown
download.action.Cancel = Cancel
download.action.Clear = Clear
download.action.Delete = Delete
download.action.Pause = Pause
download.action.Stop = Stop
download.action.Remove = Remove
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]):

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
// given in the LICENSE.txt file included with this file.
@@ -6,10 +6,15 @@
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 {
var ctypes;
Cu.import("resource://gre/modules/ctypes.jsm");
var ctypes = module("resource://gre/modules/ctypes.jsm");
}
catch (e) {}
@@ -22,7 +27,11 @@ if (typeof XPCSafeJSObjectWrapper === "undefined")
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) {
for each (let name in names)
@@ -133,13 +142,16 @@ function require_(obj, name, from, targetName) {
defineModule("base", {
// sed -n 's/^(const|var|function) ([a-zA-Z0-9_]+).*/ "\2",/p' base.jsm | sort | fmt
exports: [
"ErrorBase", "Cc", "Ci", "Class", "Cr", "Cu", "Finished", "Module", "JSMLoader",
"Set", "Struct", "StructBase", "Timer", "UTF8", "XPCOM", "XPCOMShim", "XPCOMUtils",
"XPCSafeJSObjectWrapper", "array", "bind", "call", "callable", "ctypes", "curry",
"debuggerProperties", "defineModule", "deprecated", "endModule", "forEach", "isArray",
"isGenerator", "isinstance", "isObject", "isString", "isSubclass", "isXML", "iter",
"iterAll", "iterOwnProperties", "keys", "literal", "memoize", "octal", "properties",
"require", "set", "update", "values", "update_"
"ErrorBase", "Cc", "Ci", "Class", "Cr", "Cu", "Finished",
"Module", "JSMLoader", "RealSet", "Set", "Struct", "StructBase",
"Timer", "UTF8", "XPCOM", "XPCOMShim", "XPCOMUtils",
"XPCSafeJSObjectWrapper", "array", "bind", "call", "callable",
"ctypes", "curry", "debuggerProperties", "defineModule",
"deprecated", "endModule", "forEach", "isArray", "isGenerator",
"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}
*/
function keys(obj) iter(function keys() {
if (isinstance(obj, ["Map"]))
for (let [k, v] of obj)
yield k;
else
for (var k in obj)
if (hasOwnProperty.call(obj, k))
yield k;
@@ -331,7 +347,10 @@ function keys(obj) iter(function keys() {
* @returns {Generator}
*/
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)
yield k;
else
@@ -343,6 +362,8 @@ function values(obj) iter(function values() {
var forEach = deprecated("iter.forEach", function forEach() iter.forEach.apply(iter, 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
* 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
* @returns {object}
*/
function Set(ary) {
this.Set = function Set(ary) {
let obj = {};
if (ary)
for (let val in values(ary))
@@ -1377,6 +1398,10 @@ function iter(obj, iface) {
if (arguments.length == 2 && iface instanceof Ci.nsIJSIID)
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 res = Iterator(obj);
@@ -1388,6 +1413,9 @@ function iter(obj, iface) {
})();
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) {
while (obj.constructor instanceof ctypes.PointerType)
obj = obj.contents;

View File

@@ -1,6 +1,6 @@
// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// 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
// given in the LICENSE.txt file included with this file.
@@ -16,6 +16,7 @@ lazyRequire("contexts", ["Group"]);
lazyRequire("io", ["io"]);
lazyRequire("finder", ["RangeFind"]);
lazyRequire("overlay", ["overlay"]);
lazyRequire("promises", ["Promise", "promises"]);
lazyRequire("sanitizer", ["sanitizer"]);
lazyRequire("storage", ["File", "storage"]);
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.
*
@@ -77,10 +122,10 @@ var Buffer = Module("Buffer", {
* @returns {string|number|boolean} The value of the preference, if
* callback is not provided.
*/
getPref: function getPref(pref, callback) {
getPref: deprecated("prefs.get", function getPref(pref, callback) {
services.contentPrefs.getPref(this.uri, pref,
sanitizer.getContext(this.win), callback);
},
this.loadContext, callback);
}),
/**
* 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} value The value to store.
*/
setPref: function setPref(pref, value) {
setPref: deprecated("prefs.set", function setPref(pref, value) {
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.
*
* @param {string} pref The preference to clear.
*/
clearPref: function clearPref(pref) {
clearPref: deprecated("prefs.clear", function clearPref(pref) {
services.contentPrefs.removePref(
this.uri, pref, sanitizer.getContext(this.win));
},
this.uri, pref, this.loadContext);
}),
climbUrlPath: function climbUrlPath(count) {
let { dactyl } = this.modules;
@@ -1244,12 +1289,12 @@ var Buffer = Module("Buffer", {
if (prefs.get("browser.zoom.siteSpecific")) {
var privacy = sanitizer.getContext(this.win);
if (value == 1) {
this.clearPref("browser.content.full-zoom");
this.clearPref("dactyl.content.full-zoom");
this.prefs.clear("browser.content.full-zoom");
this.prefs.clear("dactyl.content.full-zoom");
}
else {
this.setPref("browser.content.full-zoom", value);
this.setPref("dactyl.content.full-zoom", fullZoom);
this.prefs.set("browser.content.full-zoom", value);
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.
*/
updateZoom: util.wrapCallback(function updateZoom() {
updateZoom: promises.task(function updateZoom() {
let uri = this.uri;
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"))
[this.contentViewer.textZoom, this.contentViewer.fullZoom] =
[this.contentViewer.fullZoom, this.contentViewer.textZoom];
});
}
}),

View File

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

View File

@@ -45,7 +45,7 @@ var ConfigBase = Class("ConfigBase", {
* initialization code. Must call superclass's init function.
*/
init: function init() {
if (config.haveGecko("26"))
if (!config.haveGecko("26"))
this.modules.global = this.modules.global.filter(m => m != "downloads"); // FIXME
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
// given in the LICENSE.txt file included with this file.
@@ -10,8 +10,10 @@ defineModule("downloads", {
});
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;
@@ -22,8 +24,8 @@ var states = iter([v, k.slice(prefix.length).toLowerCase()]
.toObject();
var Download = Class("Download", {
init: function init(id, list) {
this.download = services.downloadManager.getDownload(id);
init: function init(download, list) {
this.download = download;
this.list = list;
this.nodes = {
@@ -39,11 +41,9 @@ var Download = Class("Download", {
this.targetFile.path]]],
["td", { highlight: "DownloadState", key: "state" }],
["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: "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")]],
["td", { highlight: "DownloadProgress", key: "progress" },
["span", { highlight: "DownloadProgressHave", key: "progressHave" }],
@@ -53,8 +53,8 @@ var Download = Class("Download", {
["td", { highlight: "DownloadSpeed", key: "speed" }],
["td", { highlight: "DownloadTime", key: "time" }],
["td", {},
["a", { highlight: "DownloadSource", key: "source", href: this.source.spec },
this.source.spec]]],
["a", { highlight: "DownloadSource", key: "source", href: this.source.url },
this.source.url]]],
this.list.document, this.nodes);
this.nodes.launch.addEventListener("click", (event) => {
@@ -68,21 +68,22 @@ var Download = Class("Download", {
return this;
},
get active() !this.stopped,
get targetFile() File(this.download.target.path),
get displayName() this.targetFile.leafName,
get status() states[this.state],
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) ({
get cancel() self.cancelable && self.inState(["downloading", "paused", "starting"]),
get delete() !this.cancel && self.targetFile.exists(),
get launch() self.targetFile.exists() && self.inState(["finished"]),
get pause() self.inState(["downloading"]),
get remove() self.inState(["blocked_parental", "blocked_policy",
"canceled", "dirty", "failed", "finished"]),
get resume() self.resumable && self.inState(["paused"]),
get retry() self.inState(["canceled", "failed"])
get delete() !self.active && (self.targetFile.exists() || self.hasPartialData),
get launch() self.targetFile.exists() && self.succeeded,
get stop() self.active,
get remove() !self.active,
get resume() self.canceled
})),
command: function command(name) {
@@ -91,15 +92,16 @@ var Download = Class("Download", {
if (Set.has(this.commands, name))
this.commands[name].call(this);
else
services.downloadManager[name + "Download"](this.id);
},
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.updateStatus();
},
}),
launch: function launch() {
// Behavior mimics that of the builtin Download Manager.
function action() {
@@ -127,18 +129,28 @@ var Download = Class("Download", {
});
else
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: {
active: (a, b) => a.alive - b.alive,
active: (a, b) => a.active - b.active,
complete: (a, b) => a.percentComplete - b.percentComplete,
date: (a, b) => a.startTime - b.startTime,
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,
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) {
@@ -152,17 +164,17 @@ var Download = Class("Download", {
updateProgress: function updateProgress() {
let self = this.__proto__;
if (this.amountTransferred === this.size) {
if (!this.active) {
this.nodes.speed.textContent = "";
this.nodes.time.textContent = "";
}
else {
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");
else {
let seconds = (this.size - this.amountTransferred) / this.speed;
let seconds = (this.totalBytes - this.currentBytes) / this.speed;
[, self.timeRemaining] = DownloadUtils.getTimeLeft(seconds, this.timeRemaining);
if (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");
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() {
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.state.textContent = util.capitalize(this.status);
@@ -193,14 +208,6 @@ var Download = Class("Download", {
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",
XPCOM([Ci.nsIDownloadProgressListener,
@@ -213,12 +220,13 @@ var DownloadList = Class("DownloadList",
this.nodes = {
commandTarget: this
};
this.downloads = {};
this.downloads = Map();
},
cleanup: function cleanup() {
this.observe.unregister();
services.downloadManager.removeListener(this);
if (this.list)
this.list.removeView(this);
this.dead = true;
},
message: Class.Memoize(function () {
@@ -258,40 +266,44 @@ var DownloadList = Class("DownloadList",
this.index = Array.indexOf(this.nodes.list.childNodes,
this.nodes.head);
Task.spawn(function () {
this.list = yield Downloads.getList(Downloads.ALL);
let start = Date.now();
for (let row in iter(services.downloadManager.DBConnection
.createStatement("SELECT id FROM moz_downloads"))) {
for (let download of yield this.list.getAll()) {
if (Date.now() - start > MAX_LOAD_TIME) {
util.dactyl.warn(_("download.givingUpAfter", (Date.now() - start) / 1000));
break;
}
this.addDownload(row.id);
this.addDownload(download);
}
this.update();
util.addObserver(this);
services.downloadManager.addListener(this);
if (!this.dead)
this.list.addView(this);
}.bind(this));
return this.nodes.list;
}),
addDownload: function addDownload(id) {
if (!(id in this.downloads)) {
let download = Download(id, this);
addDownload: function addDownload(download) {
if (!this.downloads.has(download)) {
download = Download(download, this);
if (this.filter && download.displayName.indexOf(this.filter) === -1)
return;
this.downloads[id] = download;
let index = values(this.downloads).sort((a, b) => a.compare(b))
this.downloads.set(download.download, download);
let index = values(this.downloads).toArray()
.sort((a, b) => a.compare(b))
.indexOf(download);
this.nodes.list.insertBefore(download.nodes.row,
this.nodes.list.childNodes[index + this.index + 1]);
}
},
removeDownload: function removeDownload(id) {
if (id in this.downloads) {
this.nodes.list.removeChild(this.downloads[id].nodes.row);
delete this.downloads[id];
removeDownload: function removeDownload(download) {
if (this.downloads.has(download)) {
this.nodes.list.removeChild(this.downloads.get(download).nodes.row);
delete this.downloads.delete(download);
}
},
@@ -301,17 +313,17 @@ var DownloadList = Class("DownloadList",
},
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: {
clear: function () {
services.downloadManager.cleanUp();
this.list.removeFinished();
}
},
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))
if (this.nodes.list.childNodes[i + 1] != download.nodes.row)
@@ -335,16 +347,19 @@ var DownloadList = Class("DownloadList",
timeRemaining: Infinity,
updateProgress: function updateProgress() {
let downloads = values(this.downloads).toArray();
let active = downloads.filter(d => d.alive);
let downloads = iter(this.downloads.values()).toArray();
let active = downloads.filter(d => d.active);
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.hasProgress = active.every(d => d.hasProgress);
this.progress = Math.round((this.currentBytes / this.totalBytes) * 100);
this.nActive = active.length;
Download.prototype.updateProgress.call(self);
this.nActive = active.length;
if (active.length)
this.nodes.total.textContent = _("download.nActive", active.length);
else for (let key in values(["total", "percent", "speed", "time"]))
@@ -354,68 +369,87 @@ var DownloadList = Class("DownloadList",
this.sort();
},
observers: {
"download-manager-remove-download": function (id) {
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);
onDownloadAdded: function onDownloadAdded(download) {
this.addDownload(download);
this.modules.mow.resize(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();
if (this.shouldSort("active"))
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 () {
services.downloadManager.addListener(this);
Downloads.getList(Downloads.ALL).then(list => {
this.list = list;
if (!this.dead)
this.list.addView(this);
});
},
cleanup: function destroy() {
services.downloadManager.removeListener(this);
if (this.list)
this.list.removeView(this);
this.dead = true;
},
onDownloadStateChange: function (state, download) {
if (download.state == services.downloadManager.DOWNLOAD_FINISHED) {
let url = download.source.spec;
let title = download.displayName;
let file = download.targetFile.path;
let size = download.size;
onDownloadAdded: function onDownloadAdded(download) {
},
onDownloadRemoved: function onDownloadRemoved(download) {
},
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) {
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]"],
"Clear completed downloads",
function (args) { services.downloadManager.cleanUp(); });
function (args) { downloads.list.removeFinished(); });
},
options: function initOptions(dactyl, modules, window) {
const { options } = modules;

View File

@@ -336,9 +336,6 @@ var JavaScript = Module("javascript", {
_complete: function (objects, key, compl, string, last) {
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);
base.forceAnchored = true;
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: