// 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@gmail.com>
+// Copyright (c) 2008-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.
defineModule("util", {
exports: ["DOM", "$", "FailedAssertion", "Math", "NS", "Point", "Util", "XBL", "XHTML", "XUL", "util"],
- require: ["dom", "services"]
+ require: ["dom", "promises", "services"]
});
lazyRequire("overlay", ["overlay"]);
},
activeWindow: deprecated("overlay.activeWindow", { get: function activeWindow() overlay.activeWindow }),
- overlayObject: deprecated("overlay.overlayObject", { get: function overlayObject() overlay.closure.overlayObject }),
- overlayWindow: deprecated("overlay.overlayWindow", { get: function overlayWindow() overlay.closure.overlayWindow }),
+ overlayObject: deprecated("overlay.overlayObject", { get: function overlayObject() overlay.bound.overlayObject }),
+ overlayWindow: deprecated("overlay.overlayWindow", { get: function overlayWindow() overlay.bound.overlayWindow }),
compileMatcher: deprecated("DOM.compileMatcher", { get: function compileMatcher() DOM.compileMatcher }),
computedStyle: deprecated("DOM#style", function computedStyle(elem) DOM(elem).style),
parseForm: deprecated("DOM#formData", function parseForm(elem) values(DOM(elem).formData).toArray()),
scrollIntoView: deprecated("DOM#scrollIntoView", function scrollIntoView(elem, alignWithTop) DOM(elem).scrollIntoView(alignWithTop)),
validateMatcher: deprecated("DOM.validateMatcher", { get: function validateMatcher() DOM.validateMatcher }),
- xmlToDom: deprecated("DOM.fromJSON", function xmlToDom() DOM.fromXML.apply(DOM, arguments)),
map: deprecated("iter.map", function map(obj, fn, self) iter(obj).map(fn, self).toArray()),
writeToClipboard: deprecated("dactyl.clipboardWrite", function writeToClipboard(str, verbose) util.dactyl.clipboardWrite(str, verbose)),
readFromClipboard: deprecated("dactyl.clipboardRead", function readFromClipboard() util.dactyl.clipboardRead(false)),
chromePackages: deprecated("config.chromePackages", { get: function chromePackages() config.chromePackages }),
- haveGecko: deprecated("config.haveGecko", { get: function haveGecko() config.closure.haveGecko }),
+ haveGecko: deprecated("config.haveGecko", { get: function haveGecko() config.bound.haveGecko }),
OS: deprecated("config.OS", { get: function OS() config.OS }),
dactyl: update(function dactyl(obj) {
let cleanup = ["dactyl-cleanup-modules", "quit-application"];
function register(meth) {
- for (let target in Set(cleanup.concat(Object.keys(obj.observers))))
+ for (let target of RealSet(cleanup.concat(Object.keys(obj.observers))))
try {
services.observer[meth](obj, target, true);
}
: "",
{
elements: [],
- seen: {},
+ seen: RealSet(),
valid: function valid(obj) this.elements.every(e => (!e.test || e.test(obj)))
});
}
else {
let [, flags, name] = /^((?:[a-z]-)*)(.*)/.exec(macro);
- flags = Set(flags);
+ flags = RealSet(flags);
let quote = util.identity;
- if (flags.q)
+ if (flags.has("q"))
quote = function quote(obj) typeof obj === "number" ? obj : String.quote(obj);
- if (flags.e)
+ if (flags.has("e"))
quote = function quote(obj) "";
- if (Set.has(defaults, name))
+ if (hasOwnProperty(defaults, name))
stack.top.elements.push(quote(defaults[name]));
else {
let index = idx;
idx = Number(idx) - 1;
stack.top.elements.push(update(
obj => obj[name] != null && idx in obj[name] ? quote(obj[name][idx])
- : Set.has(obj, name) ? "" : unknown(full),
+ : hasOwnProperty(obj, name) ? "" : unknown(full),
{
test: function test(obj) obj[name] != null && idx in obj[name]
&& obj[name][idx] !== false
else {
stack.top.elements.push(update(
obj => obj[name] != null ? quote(obj[name])
- : Set.has(obj, name) ? "" : unknown(full),
+ : hasOwnProperty(obj, name) ? "" : unknown(full),
{
test: function test(obj) obj[name] != null
&& obj[name] !== false
}
for (let elem in array.iterValues(stack))
- elem.seen[name] = true;
+ elem.seen.add(name);
}
}
}
return obj.res;
}
- if (pattern.indexOf("{") == -1)
+ if (!pattern.contains("{"))
return [pattern];
let res = [];
rec([]);
return res;
}
- catch (e if e.message && ~e.message.indexOf("res is undefined")) {
+ catch (e if e.message && e.message.contains("res is undefined")) {
// prefs.safeSet() would be reset on :rehash
prefs.set("javascript.options.methodjit.chrome", false);
util.dactyl.warn(_(UTF8("error.damnYouJägermonkey")));
* @returns {string}
*/
dequote: function dequote(pattern, chars)
- pattern.replace(/\\(.)/, (m0, m1) => chars.indexOf(m1) >= 0 ? m1 : m0),
+ pattern.replace(/\\(.)/, (m0, m1) => chars.contains(m1) ? m1 : m0),
/**
* Returns the nsIDocShell for the given window.
*
* @returns {XMLHttpRequest}
*/
- httpGet: function httpGet(url, callback, self) {
- let params = callback;
- if (!isObject(params))
- params = { callback: params && ((...args) => callback.apply(self, args)) };
+ httpGet: function httpGet(url, params={}, self) {
+ if (callable(params))
+ // Deprecated.
+ params = { callback: params.bind(self) };
try {
let xmlhttp = services.Xmlhttp();
- xmlhttp.mozBackgroundRequest = Set.has(params, "background") ? params.background : true;
+ xmlhttp.mozBackgroundRequest = hasOwnProperty(params, "background") ? params.background : true;
let async = params.callback || params.onload || params.onerror;
if (async) {
- xmlhttp.addEventListener("load", function handler(event) { util.trapErrors(params.onload || params.callback, params, xmlhttp, event); }, false);
- xmlhttp.addEventListener("error", function handler(event) { util.trapErrors(params.onerror || params.callback, params, xmlhttp, event); }, false);
+ xmlhttp.addEventListener("load", event => { util.trapErrors(params.onload || params.callback, params, xmlhttp, event); }, false);
+ xmlhttp.addEventListener("error", event => { util.trapErrors(params.onerror || params.callback, params, xmlhttp, event); }, false);
}
if (isObject(params.params)) {
}
},
+ /**
+ * Like #httpGet, but returns a promise rather than accepting
+ * callbacks.
+ *
+ * @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;
+
+ let req = this.httpGet(url, params);
+ promises.oncancel(deferred, req.cancel);
+ }),
+
/**
* The identity function.
*
let windows = services.windowMediator.getXULWindowEnumerator(null);
while (windows.hasMoreElements()) {
let window = windows.getNext().QueryInterface(Ci.nsIXULWindow);
- for each (let type in types) {
+ for (let type of types) {
let docShells = window.docShell.getDocShellEnumerator(Ci.nsIDocShellTreeItem[type],
Ci.nsIDocShell.ENUMERATE_FORWARDS);
while (docShells.hasMoreElements())
// window.content often does not want to be queried with "var i in object"
try {
let hasValue = !("__iterator__" in object || isinstance(object, ["Generator", "Iterator"]));
+
if (object.dactyl && object.modules && object.modules.modules == object.modules) {
object = Iterator(object);
hasValue = false;
}
+
let keyIter = object;
- if ("__iterator__" in object && !callable(object.__iterator__))
+ if (iter.iteratorProp in object) {
+ keyIter = (k for (k of object));
+ hasValue = false;
+ }
+ else if ("__iterator__" in object && !callable(object.__iterator__))
keyIter = keys(object);
for (let i in keyIter) {
value = object[i];
}
catch (e) {}
+
if (!hasValue) {
if (isArray(i) && i.length == 2)
[i, value] = i;
function rec(data, level, seen) {
if (isObject(data)) {
- if (~seen.indexOf(data))
+ seen = RealSet(seen);
+ if (seen.add(data))
throw Error("Recursive object passed");
- seen = seen.concat([data]);
}
let prefix = level + INDENT;
}
let res = [];
- rec(data, "", []);
+ rec(data, "", RealSet());
return res.join("");
},
util.dump("cleanup: " + module.constructor.className);
util.trapErrors(module.cleanup, module, reason);
}
-
- JSMLoader.cleanup();
-
- if (!this.rehashing)
- services.observer.addObserver(this, "dactyl-rehash", true);
- },
- "dactyl-rehash": function dactylRehash() {
- services.observer.removeObserver(this, "dactyl-rehash");
-
- defineModule.loadLog.push("dactyl: util: observe: dactyl-rehash");
- if (!this.rehashing)
- for (let module in values(defineModule.modules)) {
- defineModule.loadLog.push("dactyl: util: init(" + module + ")");
- if (module.reinit)
- module.reinit();
- else
- module.init();
- }
- },
- "dactyl-purge": function dactylPurge() {
- this.rehashing = 1;
- },
+ }
},
/**
*
* This is similar to Perl's extended regular expression format.
*
- * @param {string|XML} expr The expression to compile into a RegExp.
+ * @param {string} expr The expression to compile into a RegExp.
* @param {string} flags Flags to apply to the new RegExp.
* @param {object} tokens The tokens to substitute. @optional
* @returns {RegExp} A custom regexp object.
// Replace replacement <tokens>.
if (tokens)
expr = String.replace(expr, /(\(?P)?<(\w+)>/g,
- (m, n1, n2) => !n1 && Set.has(tokens, n2) ? tokens[n2].dactylSource
- || tokens[n2].source
- || tokens[n2]
- : m);
+ (m, n1, n2) => !n1 && hasOwnProperty(tokens, n2) ? tokens[n2].dactylSource
+ || tokens[n2].source
+ || tokens[n2]
+ : m);
// Strip comments and white space.
if (/x/.test(flags))
}
let res = update(RegExp(expr, flags.replace("x", "")), {
- closure: Class.Property(Object.getOwnPropertyDescriptor(Class.prototype, "closure")),
+ bound: Class.Property(Object.getOwnPropertyDescriptor(Class.prototype, "bound")),
+ closure: Class.Property(Object.getOwnPropertyDescriptor(Class.prototype, "bound")),
dactylPropertyNames: ["exec", "match", "test", "toSource", "toString", "global", "ignoreCase", "lastIndex", "multiLine", "source", "sticky"],
iterate: function iterate(str, idx) util.regexp.iterate(this, str, idx)
});
storage.storeForSession("commandlineArgs", args);
this.timeout(function () {
this.flushCache();
- this.rehashing = true;
+ cache.flush(bind("test", /^literal:/));
let addon = config.addon;
addon.userDisabled = true;
addon.userDisabled = false;
* Waits for the function *test* to return true, or *timeout*
* milliseconds to expire.
*
- * @param {function} test The predicate on which to wait.
+ * @param {function|Promise} test The predicate on which to wait.
* @param {object} self The 'this' object for *test*.
* @param {Number} timeout The maximum number of milliseconds to
* wait.
* thrown.
*/
waitFor: function waitFor(test, self, timeout, interruptable) {
+ if (!callable(test)) {
+ let done = false;
+ var promise = test,
+ retVal;
+ promise.then((arg) => { retVal = arg; done = true; },
+ (arg) => { retVal = arg; done = true; });
+ test = () => done;
+ }
+
let end = timeout && Date.now() + timeout, result;
let timer = services.Timer(function () {}, 10, services.Timer.TYPE_REPEATING_SLACK);
finally {
timer.cancel();
}
- return result;
+ return promise ? retVal: result;
},
/**
* @returns {function} A new function which may not execute
* synchronously.
*/
- yieldable: function yieldable(func)
+ yieldable: deprecated("Task.spawn", function yieldable(func)
function magic() {
let gen = func.apply(this, arguments);
(function next() {
}
catch (e if e instanceof StopIteration) {};
})();
- },
+ }),
/**
* Wraps a callback function such that its errors are not lost. This
* @returns {[string]} The visible domains.
*/
visibleHosts: function visibleHosts(win) {
- let res = [], seen = {};
+ let res = [],
+ seen = RealSet();
(function rec(frame) {
try {
if (frame.location.hostname)
catch (e) {}
Array.forEach(frame.frames, rec);
})(win);
- return res.filter(h => !Set.add(seen, h));
+ return res.filter(h => !seen.add(h));
},
/**
* @returns {[nsIURI]} The visible URIs.
*/
visibleURIs: function visibleURIs(win) {
- let res = [], seen = {};
+ let res = [],
+ seen = RealSet();
(function rec(frame) {
try {
res = res.concat(util.newURI(frame.location.href));
catch (e) {}
Array.forEach(frame.frames, rec);
})(win);
- return res.filter(h => !Set.add(seen, h.spec));
+ return res.filter(h => !seen.add(h.spec));
},
/**