// Copyright (c) 2006-2008 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2007-2011 by Doug Kearns <dougkearns@gmail.com>
-// Copyright (c) 2008-2012 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);
}
}
});
- obj.observe.unregister = function () register("removeObserver");
+ obj.observe.unregister = () => register("removeObserver");
register("addObserver");
}, { dump: dump, Error: Error }),
* @param {string} name The name to mangle.
* @returns {string} The mangled name.
*/
- camelCase: function camelCase(name) String.replace(name, /-(.)/g, function (m, m1) m1.toUpperCase()),
+ camelCase: function camelCase(name) String.replace(name, /-(.)/g,
+ (m, m1) => m1.toUpperCase()),
/**
* Capitalizes the first character of the given string.
function frame() update(
function _frame(obj)
- _frame === stack.top || _frame.valid(obj) ?
- _frame.elements.map(function (e) callable(e) ? e(obj) : e).join("") : "",
+ _frame === stack.top || _frame.valid(obj)
+ ? _frame.elements.map(e => callable(e) ? e(obj) : e)
+ .join("")
+ : "",
{
elements: [],
seen: {},
- valid: function valid(obj) this.elements.every(function (e) !e.test || e.test(obj))
+ valid: function valid(obj) this.elements.every(e => !e.test || e.test(obj))
});
let end = 0;
char = char.toLowerCase();
stack.top.elements.push(update(
- function (obj) obj[char] != null ? quote(obj, char) : "",
+ function (obj) obj[char] != null ? quote(obj, char)
+ : "",
{ test: function test(obj) obj[char] != null }));
for (let elem in array.iterValues(stack))
let unknown = util.identity;
if (!keepUnknown)
- unknown = function () "";
+ unknown = () => "";
function frame() update(
function _frame(obj)
- _frame === stack.top || _frame.valid(obj) ?
- _frame.elements.map(function (e) callable(e) ? e(obj) : e).join("") : "",
+ _frame === stack.top || _frame.valid(obj)
+ ? _frame.elements.map(e => callable(e) ? e(obj) : e)
+ .join("")
+ : "",
{
elements: [],
- seen: {},
- valid: function valid(obj) this.elements.every(function (e) !e.test || e.test(obj))
+ seen: RealSet(),
+ valid: function valid(obj) this.elements.every(e => (!e.test || e.test(obj)))
});
let defaults = { lt: "<", gt: ">" };
}
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;
if (idx) {
idx = Number(idx) - 1;
stack.top.elements.push(update(
- function (obj) obj[name] != null && idx in obj[name] ? quote(obj[name][idx])
- : Set.has(obj, name) ? "" : unknown(full),
+ obj => obj[name] != null && idx in obj[name] ? quote(obj[name][idx])
+ : 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(
- function (obj) obj[name] != null ? quote(obj[name])
- : Set.has(obj, name) ? "" : unknown(full),
+ obj => obj[name] != null ? quote(obj[name])
+ : 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);
}
}
}
acc.push(vals);
if (acc.length == pattern.length)
- this.res.push(acc.join(""))
+ this.res.push(acc.join(""));
else
for (let val in values(vals))
this.rec(acc.concat(val));
return obj.res;
}
- if (pattern.indexOf("{") == -1)
+ if (!pattern.contains("{"))
return [pattern];
let res = [];
fn(match);
}
res.push(pattern.substr(end));
- return res.map(function (s) util.dequote(s, dequote));
- }
+ return res.map(s => util.dequote(s, dequote));
+ };
let patterns = [];
let substrings = split(pattern, /((?:[^\\{]|\\.)*)\{((?:[^\\}]|\\.)*)\}/gy,
else
for (let [, pattern] in Iterator(patterns[acc.length]))
rec(acc.concat(pattern));
- }
+ };
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(/\\(.)/, function (m0, m1) chars.indexOf(m1) >= 0 ? m1 : m0),
+ pattern.replace(/\\(.)/, (m0, m1) => chars.contains(m1) ? m1 : m0),
/**
* Returns the nsIDocShell for the given window.
* @param {string} msg The trace message.
* @param {number} frames The number of frames to print.
*/
- dumpStack: function dumpStack(msg, frames) {
+ dumpStack: function dumpStack(msg="Stack", frames=null) {
let stack = util.stackLines(Error().stack);
stack = stack.slice(1, 1 + (frames || stack.length)).join("\n").replace(/^/gm, " ");
- util.dump((arguments.length == 0 ? "Stack" : msg) + "\n" + stack + "\n");
+ util.dump(msg + "\n" + stack + "\n");
},
/**
[hours, minutes] = div(minutes, 60);
[days, hours] = div(hours, 24);
if (days)
- return /*L*/days + " days " + hours + " hours"
+ return /*L*/days + " days " + hours + " hours";
if (hours)
return /*L*/hours + "h " + minutes + "m";
if (minutes)
*
* @returns {XMLHttpRequest}
*/
- httpGet: function httpGet(url, callback, self) {
- let params = callback;
- if (!isObject(params))
- params = { callback: params && function () callback.apply(self, arguments) };
+ 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)) {
let data = [encodeURIComponent(k) + "=" + encodeURIComponent(v)
for ([k, v] in iter(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.
*
* top-level window and sub-frames thereof.
*/
iterDocuments: function iterDocuments(types) {
- types = types ? types.map(function (s) "type" + util.capitalize(s))
+ types = types ? types.map(s => "type" + util.capitalize(s))
: ["typeChrome", "typeContent"];
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())
let (viewer = docShells.getNext().QueryInterface(Ci.nsIDocShell).contentViewer) {
if (viewer)
yield viewer.DOMDocument;
- }
+ };
}
}
},
// ripped from Firefox; modified
- unsafeURI: Class.Memoize(function () util.regexp(String.replace(literal(/*
+ unsafeURI: Class.Memoize(() => util.regexp(String.replace(literal(/*
[
\s
// Invisible characters (bug 452979)
: val,
isDOM ? /['%]/g
: /['"%&<>]/g,
- function (m) map[m]);
+ m => map[m]);
}
- return iter(obj).map(function ([k, v])
+ return iter(obj).map(([k, v]) =>
["<!ENTITY ", k, " '", escape(v), "'>"].join(""))
.join("\n");
},
if (color) {
obj = template.highlightFilter(util.clip(obj, 150), "\n",
- function () ["span", { highlight: "NonText" }, "^J"]);
+ () => ["span", { highlight: "NonText" },
+ "^J"]);
+
var head = ["span", { highlight: "Title Object" }, obj, "::\n"];
}
else
// 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__))
- keyIter = keys(object)
+ 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) {
let value = Magic("<no value>");
value = object[i];
}
catch (e) {}
+
if (!hasValue) {
if (isArray(i) && i.length == 2)
[i, value] = i;
return String.localeCompare(a[0], b[0]);
}
- let vals = template.map(keys.sort(compare), function (f) f[1], "\n");
+ let vals = template.map(keys.sort(compare), f => f[1],
+ "\n");
+
if (color) {
return ["div", { style: "white-space: pre-wrap" }, head, vals];
}
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;
if (data.length == 0)
res.push("[]");
else {
- res.push("[\n")
+ res.push("[\n");
for (let [i, val] in Iterator(data)) {
if (i)
res.push(",\n");
- res.push(prefix)
+ res.push(prefix);
rec(val, prefix, seen);
}
res.push("\n", level, "]");
}
}
else if (isObject(data)) {
- res.push("{\n")
+ res.push("{\n");
let i = 0;
for (let [key, val] in Iterator(data)) {
if (i++)
res.push(",\n");
- res.push(prefix, JSON.stringify(key), ": ")
+ res.push(prefix, JSON.stringify(key), ": ");
rec(val, prefix, seen);
}
if (i > 0)
- res.push("\n", level, "}")
+ res.push("\n", level, "}");
else
res[res.length - 1] = "{}";
}
}
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,
- function (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))
- expr = String.replace(expr, /(\\.)|\/\/[^\n]*|\/\*[^]*?\*\/|\s+/gm, function (m, m1) m1 || "");
+ expr = String.replace(expr, /(\\.)|\/\/[^\n]*|\/\*[^]*?\*\/|\s+/gm,
+ (m, m1) => m1 || "");
// Replace (?P<named> parameters)
if (/\(\?P</.test(expr)) {
}
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)
});
* @param {RegExp} re The regexp showable source of which is to be returned.
* @returns {string}
*/
- getSource: function regexp_getSource(re) re.source.replace(/\\(.)/g, function (m0, m1) m1 === "/" ? "/" : m0),
+ getSource: function regexp_getSource(re) re.source.replace(/\\(.)/g,
+ (m0, m1) => m1 === "/" ? m1
+ : m0),
/**
* Iterates over all matches of the given regexp in the given
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;
},
errorCount: 0,
- errors: Class.Memoize(function () []),
+ errors: Class.Memoize(() => []),
maxErrors: 15,
/**
* Reports an error to the Error Console and the standard output,
let ary = host.split(".");
ary = [ary.slice(i).join(".") for (i in util.range(ary.length, 0, -1))];
- return ary.filter(function (h) h.length >= base.length);
+ return ary.filter(h => h.length >= base.length);
},
/**
* 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
* @param {function} func The function to call
* @param {object} self The 'this' object for the function.
*/
- trapErrors: function trapErrors(func, self) {
+ trapErrors: function trapErrors(func, self, ...args) {
try {
if (!callable(func))
func = self[func];
- return func.apply(self || this, Array.slice(arguments, 2));
+ return func.apply(self || this, args);
}
catch (e) {
this.reportError(e);
* @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(function (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(function (h) !Set.add(seen, h.spec));
+ return res.filter(h => !seen.add(h.spec));
},
/**
* @param {object} self The 'this' object of the method.
* @param ... Arguments to pass to *meth*.
*/
- withProperErrors: function withProperErrors(meth, self) {
+ withProperErrors: function withProperErrors(meth, self, ...args) {
try {
- return (callable(meth) ? meth : self[meth]).apply(self, Array.slice(arguments, withProperErrors.length));
+ return (callable(meth) ? meth : self[meth]).apply(self, args);
}
catch (e) {
throw e.stack ? e : Error(e);
Array: array
});
-
/**
* Math utility methods.
* @singleton
} catch(e){ if (!e.stack) e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
-// vim: set fdm=marker sw=4 ts=4 et ft=javascript:
+// vim: set fdm=marker sw=4 sts=4 ts=8 et ft=javascript: