diff --git a/common/content/commandline.js b/common/content/commandline.js index ea0a3013..74b203fc 100644 --- a/common/content/commandline.js +++ b/common/content/commandline.js @@ -255,16 +255,25 @@ var CommandWidgets = Class("CommandWidgets", { commandbar: Class.memoize(function () ({ group: "Cmd" })), statusbar: Class.memoize(function () ({ group: "Status" })), - _whenReady: function _whenReady(name, id) { + _ready: function _ready(elem) { + return elem.contentDocument.documentURI === elem.getAttribute("src") && + ["viewable", "complete"].indexOf(elem.contentDocument.readyState) >= 0; + }, + + _whenReady: function _whenReady(id) { let elem = document.getElementById(id); - util.waitFor(function () elem.contentDocument.documentURI === elem.getAttribute("src") && - ["viewable", "complete"].indexOf(elem.contentDocument.readyState) >= 0); + util.waitFor(bind(this._ready, this, elem)); return elem; }, - completionList: Class.memoize(function () this._whenReady("completionList", "dactyl-completions"), true), + completionList: Class.memoize(function () { + let elem = document.getElementById(elem); + while (!this._ready(elem)) + yield 10; + yield elem; + }, true), completionContainer: Class.memoize(function () this.completionList.parentNode), @@ -279,11 +288,14 @@ var CommandWidgets = Class("CommandWidgets", { }), multilineOutput: Class.memoize(function () { - let elem = this._whenReady("multilineOutput", "dactyl-multiline-output"); + let elem = document.getElementById("dactyl-multiline-output"); + while (!this._ready(elem)) + yield 10; + elem.contentWindow.addEventListener("unload", function (event) { event.preventDefault(); }, true); elem.contentDocument.documentElement.id = "dactyl-multiline-output-top"; elem.contentDocument.body.id = "dactyl-multiline-output-content"; - return elem; + yield elem; }, true), multilineInput: Class.memoize(function () document.getElementById("dactyl-multiline-input")), @@ -569,7 +581,7 @@ var CommandLine = Module("commandline", { get completionList() { let node = this.widgets.active.commandline; if (!node.completionList) { - let elem = this.widgets._whenReady("completionList", "dactyl-completions-" + node.id); + let elem = this.widgets._whenReady("dactyl-completions-" + node.id); node.completionList = ItemList(elem.id); } return node.completionList; diff --git a/common/modules/base.jsm b/common/modules/base.jsm index 5dee1a0c..ef4dc379 100644 --- a/common/modules/base.jsm +++ b/common/modules/base.jsm @@ -205,7 +205,7 @@ defineModule("base", { exports: [ "ErrorBase", "Cc", "Ci", "Class", "Cr", "Cu", "Module", "JSMLoader", "Object", "Runnable", "Struct", "StructBase", "Timer", "UTF8", "XPCOM", "XPCOMUtils", "XPCSafeJSObjectWrapper", - "array", "call", "callable", "ctypes", "curry", "debuggerProperties", "defineModule", + "array", "bind", "call", "callable", "ctypes", "curry", "debuggerProperties", "defineModule", "deprecated", "endModule", "forEach", "isArray", "isGenerator", "isinstance", "isObject", "isString", "isSubclass", "iter", "iterAll", "keys", "memoize", "octal", "properties", "require", "set", "update", "values", "withCallerGlobal" @@ -580,6 +580,14 @@ function curry(fn, length, self, acc) { }; } +if (curry.bind) + var bind = function bind(func) func.bind.apply(func, Array.slice(arguments, bind.length)); +else + var bind = function bind(func, self) { + let args = Array.slice(arguments, bind.length); + return function bound() func.apply(self, args.concat(Array.slice(arguments))); + }; + let sandbox = Cu.Sandbox(this); sandbox.__proto__ = this; /** @@ -774,26 +782,37 @@ Class.memoize = function memoize(getter, wait) enumerable: true, init: function (key) { let done = false; - let prop = { configurable: true, enumerable: true, value: null, writable: true }; - if (wait) - prop = { - configurable: true, enumerable: false, - get: function get() { - util.waitFor(function () done); - return this[key]; - } - } - this.get = function replace() { - let obj = this.instance || this; - Object.defineProperty(obj, key, prop); - try { + if (wait) + this.get = function replace() { + let obj = this.instance || this; + Object.defineProperty(obj, key, { + configurable: true, enumerable: false, + get: function get() { + util.waitFor(function () done); + return this[key]; + } + }); + + util.yieldable(function () { + let wait; + for (var res in getter.call(obj)) { + if (wait !== undefined) + yield wait; + wait = res; + } + Class.replaceProperty(obj, key, res); + done = true; + })(); + + return this[key]; + }; + else + this.get = function replace() { + let obj = this.instance || this; + Class.replaceProperty(obj, key, null); return Class.replaceProperty(obj, key, getter.call(this, key)); - } - finally { - done = true; - } - } + }; this.set = function replace(val) Class.replaceProperty(this.instance || this, val); } diff --git a/common/modules/config.jsm b/common/modules/config.jsm index d63e188c..bbc8426d 100644 --- a/common/modules/config.jsm +++ b/common/modules/config.jsm @@ -56,17 +56,18 @@ var ConfigBase = Class("ConfigBase", { get addonID() this.name + "@dactyl.googlecode.com", addon: Class.memoize(function () { let addon; - util.waitFor(function () { + do { addon = services.fuel.storage.get("dactyl.bootstrap", {}).addon; - if (addon && !addon.getResourceURI) + if (addon && !addon.getResourceURI) { util.reportError(Error("Don't have add-on yet")); - - return !addon || addon.getResourceURI; - }); + yield 10; + } + } + while (addon && !addon.getResourceURI); if (!addon) addon = require("addons").AddonManager.getAddonByID(this.addonID); - return addon; + yield addon; }, true), /**