diff --git a/common/bootstrap.js b/common/bootstrap.js index 466ce387..636fa686 100755 --- a/common/bootstrap.js +++ b/common/bootstrap.js @@ -264,6 +264,7 @@ function init() { bootstrap = Cu.Sandbox(Cc["@mozilla.org/systemprincipal;1"].createInstance(), { sandboxName: BOOTSTRAP, addonId: addon.id, + wantGlobalProperties: ["TextDecoder", "TextEncoder"], metadata: { addonID: addon.id } }); Services.scriptloader.loadSubScript(BOOTSTRAP, bootstrap); } diff --git a/common/content/bookmarks.js b/common/content/bookmarks.js index c755a6bf..fbbe3172 100644 --- a/common/content/bookmarks.js +++ b/common/content/bookmarks.js @@ -1,6 +1,6 @@ // Copyright (c) 2006-2008 by Martin Stubenschrott // Copyright (c) 2007-2011 by Doug Kearns -// Copyright (c) 2008-2014 Kris Maglione +// Copyright (c) 2008-2015 Kris Maglione // // This work is licensed for reuse under an MIT license. Details are // given in the LICENSE.txt file included with this file. @@ -302,23 +302,22 @@ var Bookmarks = Module("bookmarks", { * @returns {Promise} */ makeSuggestions: function makeSuggestions(url, parser) { - let deferred = Promise.defer(); + return new CancelablePromise((resolve, reject, canceled) => { + let req = util.fetchUrl(url); + req.then(function process(req) { + let results = []; + try { + results = parser(req); + } + catch (e) { + reject(e); + return; + } + resolve(results); + }); - let req = util.fetchUrl(url); - req.then(function process(req) { - let results = []; - try { - results = parser(req); - } - catch (e) { - deferred.reject(e); - return; - } - deferred.resolve(results); + canceled.then(req.cancel); }); - - promises.oncancel(deferred, reason => promises.cancel(req, reason)); - return deferred.promise; }, suggestionProviders: {}, diff --git a/common/content/commandline.js b/common/content/commandline.js index 958d466f..1104a5db 100644 --- a/common/content/commandline.js +++ b/common/content/commandline.js @@ -855,13 +855,15 @@ var CommandLine = Module("commandline", { * @... {string} default - The initial value that will be returned * if the user presses straightaway. @default "" */ - input: promises.withCallbacks(function _input([callback, reject], prompt, extra={}, thing={}) { - if (callable(extra)) - // Deprecated. - [callback, extra] = [extra, thing]; + input: function _input(prompt, extra={}, thing={}) { + return new Promise((resolve, reject) => { + if (callable(extra)) + // Deprecated. + [resolve, extra] = [extra, thing]; - CommandPromptMode(prompt, update({ onSubmit: callback, onCancel: reject }, extra)).open(); - }), + CommandPromptMode(prompt, update({ onSubmit: resolve, onCancel: reject }, extra)).open(); + }); + }, readHeredoc: function readHeredoc(end) { return util.waitFor(commandline.inputMultiline(end)); @@ -876,33 +878,35 @@ var CommandLine = Module("commandline", { * @returns {Promise} */ // FIXME: Buggy, especially when pasting. - inputMultiline: promises.withCallbacks(function inputMultiline([callback], end) { - let cmd = this.command; - let self = { - end: "\n" + end + "\n", - callback: callback - }; + inputMultiline: function inputMultiline(end) { + return new Promise((resolve, reject) => { + let cmd = this.command; + let self = { + end: "\n" + end + "\n", + callback: resolve + }; - modes.push(modes.INPUT_MULTILINE, null, { - holdFocus: true, - leave: function leave() { - if (!self.done) - self.callback(null); - }, - mappingSelf: self + modes.push(modes.INPUT_MULTILINE, null, { + holdFocus: true, + leave: function leave() { + if (!self.done) + self.callback(null); + }, + mappingSelf: self + }); + + if (cmd != false) + this._echoLine(cmd, this.HL_NORMAL); + + // save the arguments, they are needed in the event handler onKeyPress + + this.multilineInputVisible = true; + this.widgets.multilineInput.value = ""; + this._autosizeMultilineInputWidget(); + + this.timeout(function () { dactyl.focus(this.widgets.multilineInput); }, 10); }); - - if (cmd != false) - this._echoLine(cmd, this.HL_NORMAL); - - // save the arguments, they are needed in the event handler onKeyPress - - this.multilineInputVisible = true; - this.widgets.multilineInput.value = ""; - this._autosizeMultilineInputWidget(); - - this.timeout(function () { dactyl.focus(this.widgets.multilineInput); }, 10); - }), + }, get commandMode() this.commandSession && isinstance(modes.main, modes.COMMAND_LINE), diff --git a/common/modules/base.jsm b/common/modules/base.jsm index f9a21fd0..6f710bc4 100644 --- a/common/modules/base.jsm +++ b/common/modules/base.jsm @@ -182,7 +182,6 @@ defineModule("base", { "Cr", "Cs", "Cu", - "DOMPromise", "ErrorBase", "Finished", "JSMLoader", @@ -762,12 +761,6 @@ function memoize(obj, key, getter) { } } -let sandbox = Cu.Sandbox(Cc["@mozilla.org/systemprincipal;1"].createInstance(), - { wantGlobalProperties: ["TextDecoder", "TextEncoder"], - sandboxPrototype: this }); - -var { TextEncoder, TextDecoder, Promise: DOMPromise } = sandbox; - /** * Updates an object with the properties of another object. Getters * and setters are copied as expected. Moreover, any function diff --git a/common/modules/bootstrap.jsm b/common/modules/bootstrap.jsm index 1325f294..36e91e6f 100644 --- a/common/modules/bootstrap.jsm +++ b/common/modules/bootstrap.jsm @@ -15,6 +15,9 @@ this["import"] = function import_(obj) { return res; } +if (typeof TextEncoder == "undefined") + Components.utils.importGlobalProperties(["TextEncoder", "TextDecoder"]); + // Deal with subScriptLoader prepending crap to loaded URLs Components.utils.import("resource://gre/modules/Services.jsm"); function loadSubScript() Services.scriptloader.loadSubScript.apply(null, arguments); diff --git a/common/modules/buffer.jsm b/common/modules/buffer.jsm index 74ac15aa..e1730f16 100644 --- a/common/modules/buffer.jsm +++ b/common/modules/buffer.jsm @@ -86,26 +86,28 @@ var Buffer = Module("Buffer", { * @param {string} pref The name of the preference to return. * @returns {Promise<*>} */ - get: promises.withCallbacks(function get([resolve, reject], pref) { - let val = services.contentPrefs.getCachedByDomainAndName( - self.uri.spec, pref, self.loadContext); + get: function get(pref) { + return new Promise((resolve, reject) => { + let val = services.contentPrefs.getCachedByDomainAndName( + self.uri.spec, pref, self.loadContext); - let found = false; - if (val) - resolve(val.value); - else - services.contentPrefs.getByDomainAndName( - self.uri.spec, pref, self.loadContext, - { handleCompletion: () => { - if (!found) - resolve(undefined); - }, - handleResult: (pref) => { - found = true; - resolve(pref.value); - }, - handleError: reject }); - }), + let found = false; + if (val) + resolve(val.value); + else + services.contentPrefs.getByDomainAndName( + self.uri.spec, pref, self.loadContext, + { handleCompletion: () => { + if (!found) + resolve(undefined); + }, + handleResult: (pref) => { + found = true; + resolve(pref.value); + }, + handleError: reject }); + }); + }, /** * Sets a content preference for the given buffer. @@ -113,26 +115,30 @@ var Buffer = Module("Buffer", { * @param {string} pref The preference to set. * @param {string} value The value to store. */ - set: promises.withCallbacks(function set([resolve, reject], pref, value) { - services.contentPrefs.set( - self.uri.spec, pref, value, self.loadContext, - { handleCompletion: () => {}, - handleResult: resolve, - handleError: reject }); - }), + set: function set(pref, value) { + return new Promise((resolve, reject) => { + services.contentPrefs.set( + self.uri.spec, pref, value, self.loadContext, + { handleCompletion: () => {}, + handleResult: resolve, + handleError: reject }); + }); + }, /** * Clear a content preference for the given buffer. * * @param {string} pref The preference to clear. */ - clear: promises.withCallbacks(function clear([resolve, reject], pref) { - services.contentPrefs.removeByDomainAndName( - self.uri.spec, pref, self.loadContext, - { handleCompletion: () => {}, - handleResult: resolve, - handleError: reject }); - }) + clear: function clear(pref) { + return new Promise((resolve, reject) => { + services.contentPrefs.removeByDomainAndName( + self.uri.spec, pref, self.loadContext, + { handleCompletion: () => {}, + handleResult: resolve, + handleError: reject }); + }); + } }; }), diff --git a/common/modules/config.jsm b/common/modules/config.jsm index 7ba778b3..6d2b9bd7 100644 --- a/common/modules/config.jsm +++ b/common/modules/config.jsm @@ -140,7 +140,7 @@ var ConfigBase = Class("ConfigBase", { "options", "overlay", "prefs", - ["promises", "Promise", "Task", "promises"], + ["promises", "CancelablePromise", "Promise", "Task", "promises"], "protocol", "sanitizer", "services", diff --git a/common/modules/main.jsm b/common/modules/main.jsm index e5dade2b..9af7db74 100644 --- a/common/modules/main.jsm +++ b/common/modules/main.jsm @@ -95,9 +95,9 @@ var Modules = function Modules(window) { if (normal) return create(proto); - sandbox = Components.utils.Sandbox(window, { sandboxPrototype: proto || modules, - sandboxName: name || ("Dactyl Sandbox " + ++_id), - wantXrays: true }); + let sandbox = Components.utils.Sandbox(window, { sandboxPrototype: proto || modules, + sandboxName: name || ("Dactyl Sandbox " + ++_id), + wantXrays: true }); // Hack: // sandbox.Object = jsmodules.Object; diff --git a/common/modules/promises.jsm b/common/modules/promises.jsm index cb0b8d70..6ef8f426 100644 --- a/common/modules/promises.jsm +++ b/common/modules/promises.jsm @@ -5,7 +5,7 @@ "use strict"; defineModule("promises", { - exports: ["Promise", "Task", "promises"], + exports: ["CancelablePromise", "Promise", "Task", "promises"], require: [] }); @@ -24,6 +24,26 @@ function withCallbacks(fn) { } } +function CancelablePromise(executor, oncancel) { + let deferred = Promise.defer(); + let canceled = new Promise((accept, reject) => { + promises.oncancel(deferred, accept); + }); + + try { + executor(deferred.resolve, deferred.reject, canceled); + } + catch (e) { + deferred.reject(e); + } + + return Object.freeze(Object.create(deferred.promise, { + cancel: { + value: thing => promises.cancel(deferred.promise, thing) + } + })); +} + var Promises = Module("Promises", { _cancel: new WeakMap, @@ -38,7 +58,7 @@ var Promises = Module("Promises", { let cleanup = this._cancel.get(promise); if (cleanup) { cleanup[0](promise); - cleanup[1].reject(reason); + cleanup[1](reason); } this._cancel.delete(promise); }, @@ -50,16 +70,18 @@ var Promises = Module("Promises", { * @param {function} fn The cleanup function. */ oncancel: function oncancel(deferred, fn) { - this._cancel.set(deferred.promise, [fn, deferred]); + this._cancel.set(deferred.promise, [fn, deferred.reject]); }, /** * Returns a promise which resolves after a brief delay. */ - delay: withCallbacks(function delay([accept]) { - let { mainThread } = services.threading; - mainThread.dispatch(accept, mainThread.DISPATCH_NORMAL); - }), + delay: function delay([accept]) { + return new Promise(resolve => { + let { mainThread } = services.threading; + mainThread.dispatch(resolve, mainThread.DISPATCH_NORMAL); + }); + }, /** * Returns a promise which resolves after the given number of @@ -67,9 +89,11 @@ var Promises = Module("Promises", { * * @param {number} delay The number of milliseconds to wait. */ - sleep: withCallbacks(function sleep([callback], delay) { - this.timeout(callback, delay); - }), + sleep: function sleep(delay) { + return new Promise(resolve => { + this.timeout(resolve, delay); + }); + }, /** * Wraps the given function so that each call spawns a Task. @@ -94,25 +118,27 @@ var Promises = Module("Promises", { * @param {number} pollInterval The poll interval, in milliseconds. * @default 10 */ - waitFor: withCallbacks(function waitFor([accept, reject], test, timeout=null, pollInterval=10) { - let end = timeout && Date.now() + timeout, result; + waitFor: function waitFor(test, timeout=null, pollInterval=10) { + return new Promise((resolve, reject) => { + let end = timeout && Date.now() + timeout, result; - let timer = services.Timer( - () => { - try { - var result = test(); - } - catch (e) { - timer.cancel(); - reject(e); - } - if (result) { - timer.cancel(); - accept(result); - } - }, - pollInterval, services.Timer.TYPE_REPEATING_SLACK); - }), + let timer = services.Timer( + () => { + try { + var result = test(); + } + catch (e) { + timer.cancel(); + reject(e); + } + if (result) { + timer.cancel(); + resolve(result); + } + }, + pollInterval, services.Timer.TYPE_REPEATING_SLACK); + }); + }, /** * Wraps the given function so that its first argument is an array diff --git a/common/modules/util.jsm b/common/modules/util.jsm index dd2f0968..d83ccc8e 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -828,14 +828,16 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), * @param {string} url The URL to fetch. * @param {object} params Parameter object, as in #httpGet. */ - fetchUrl: promises.withCallbacks(function fetchUrl([accept, reject, deferred], url, params) { - params = update({}, params); - params.onload = accept; - params.onerror = reject; + fetchUrl: function fetchUrl(url, params) { + return new CancelablePromise((accept, reject, canceled) => { + params = update({}, params); + params.onload = accept; + params.onerror = reject; - let req = this.httpGet(url, params); - promises.oncancel(deferred, req.cancel); - }), + let req = this.httpGet(url, params); + canceled.then(req.cancel); + }); + }, /** * The identity function.