X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=common%2Fmodules%2Futil.jsm;fp=common%2Fmodules%2Futil.jsm;h=0e83efe7a15a6ea7e81fb1111181360e06d296c0;hb=8b6fcae7eaa413bc62d645d2d0c99835c47265e6;hp=c5cd610fbcf8ecf6fabc31dea584a43331857e59;hpb=5ebd29f56d17f62011cdd596b1d351947ee534ff;p=dactyl.git diff --git a/common/modules/util.jsm b/common/modules/util.jsm index c5cd610..0e83efe 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -1,20 +1,31 @@ // Copyright (c) 2006-2008 by Martin Stubenschrott // Copyright (c) 2007-2011 by Doug Kearns -// Copyright (c) 2008-2011 by Kris Maglione +// Copyright (c) 2008-2012 Kris Maglione // // This work is licensed for reuse under an MIT license. Details are // given in the LICENSE.txt file included with this file. -/* use strict */ +"use strict"; try { -Components.utils.import("resource://dactyl/bootstrap.jsm"); defineModule("util", { exports: ["DOM", "$", "FailedAssertion", "Math", "NS", "Point", "Util", "XBL", "XHTML", "XUL", "util"], require: ["dom", "services"] -}, this); +}); + +lazyRequire("overlay", ["overlay"]); +lazyRequire("storage", ["File", "storage"]); +lazyRequire("template", ["template"]); + +var Magic = Class("Magic", { + init: function init(str) { + this.str = str; + }, + + get message() this.str, -this.lazyRequire("overlay", ["overlay"]); + toString: function () this.str +}); var FailedAssertion = Class("FailedAssertion", ErrorBase, { init: function init(message, level, noTrace) { @@ -51,7 +62,9 @@ var wrapCallback = function wrapCallback(fn, isEvent) { } var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), { - init: function () { + Magic: Magic, + + init: function init() { this.Array = array; this.addObserver(this); @@ -76,6 +89,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), 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)), @@ -90,7 +104,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), var global = Class.objectGlobal(obj); return { - __noSuchMethod__: function (meth, args) { + __noSuchMethod__: function __noSuchMethod__(meth, args) { let win = overlay.activeWindow; var dactyl = global && global.dactyl || win && win.dactyl; @@ -104,7 +118,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), } }; }, { - __noSuchMethod__: function () this().__noSuchMethod__.apply(null, arguments) + __noSuchMethod__: function __noSuchMethod__() this().__noSuchMethod__.apply(null, arguments) }), /** @@ -159,7 +173,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), * @param {string} message The message to present to the * user on failure. */ - assert: function (condition, message, quiet) { + assert: function assert(condition, message, quiet) { if (!condition) throw FailedAssertion(message, 1, quiet === undefined ? true : quiet); return condition; @@ -252,7 +266,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), { elements: [], seen: {}, - valid: function (obj) this.elements.every(function (e) !e.test || e.test(obj)) + valid: function valid(obj) this.elements.every(function (e) !e.test || e.test(obj)) }); let end = 0; @@ -282,7 +296,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), stack.top.elements.push(update( function (obj) obj[char] != null ? quote(obj, char) : "", - { test: function (obj) obj[char] != null })); + { test: function test(obj) obj[char] != null })); for (let elem in array.iterValues(stack)) elem.seen[char] = true; @@ -335,19 +349,19 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), { elements: [], seen: {}, - valid: function (obj) this.elements.every(function (e) !e.test || e.test(obj)) + valid: function valid(obj) this.elements.every(function (e) !e.test || e.test(obj)) }); let defaults = { lt: "<", gt: ">" }; - let re = util.regexp() | // 3 4 5 (\}>) // 6 ) - ]]>, "gixy"); + */), "gixy"); macro = String(macro); let end = 0; for (let match in re.iterate(macro)) { @@ -363,7 +377,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), } else if (close) { stack.pop(); - util.assert(stack.length, /*L*/"Unmatched %] in macro"); + util.assert(stack.length, /*L*/"Unmatched }> in macro"); } else { let [, flags, name] = /^((?:[a-z]-)*)(.*)/.exec(macro); @@ -385,9 +399,9 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), function (obj) obj[name] != null && idx in obj[name] ? quote(obj[name][idx]) : Set.has(obj, name) ? "" : unknown(full), { - test: function (obj) obj[name] != null && idx in obj[name] - && obj[name][idx] !== false - && (!flags.e || obj[name][idx] != "") + test: function test(obj) obj[name] != null && idx in obj[name] + && obj[name][idx] !== false + && (!flags.e || obj[name][idx] != "") })); } else { @@ -395,9 +409,9 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), function (obj) obj[name] != null ? quote(obj[name]) : Set.has(obj, name) ? "" : unknown(full), { - test: function (obj) obj[name] != null - && obj[name] !== false - && (!flags.e || obj[name] != "") + test: function test(obj) obj[name] != null + && obj[name] !== false + && (!flags.e || obj[name] != "") })); } @@ -505,6 +519,17 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), } }, + /** + * Briefly delay the execution of the passed function. + * + * @param {function} callback The function to delay. + */ + delay: function delay(callback) { + let { mainThread } = services.threading; + mainThread.dispatch(callback, + mainThread.DISPATCH_NORMAL); + }, + /** * Removes certain backslash-quoted characters while leaving other * backslash-quoting sequences untouched. @@ -542,7 +567,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), * @param {string} stack The stack trace from an Error. * @returns {[string]} The stack frames. */ - stackLines: function (stack) { + stackLines: function stackLines(stack) { let lines = []; let match, re = /([^]*?)@([^@\n]*)(?:\n|$)/g; while (match = re.exec(stack)) @@ -674,7 +699,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), * @param {string} url * @returns {string|null} */ - getHost: function (url) { + getHost: function getHost(url) { try { return util.createURI(url).host; } @@ -795,7 +820,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), * @param {Object} r2 * @returns {Object} */ - intersection: function (r1, r2) ({ + intersection: function intersection(r1, r2) ({ get width() this.right - this.left, get height() this.bottom - this.top, left: Math.max(r1.left, r2.left), @@ -863,7 +888,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), }, // ripped from Firefox; modified - unsafeURI: Class.Memoize(function () util.regexp(String.replace(, /U/g, "\\u"), + */), /U/g, "\\u"), "gx")), losslessDecodeURI: function losslessDecodeURI(url) { return url.split("%25").map(function (url) { @@ -901,12 +926,21 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), * for *obj*. */ makeDTD: let (map = { "'": "'", '"': """, "%": "%", "&": "&", "<": "<", ">": ">" }) - function makeDTD(obj) iter(obj) - .map(function ([k, v]) ["]/g, - function (m) map[m]), - "'>"].join("")) - .join("\n"), + function makeDTD(obj) { + function escape(val) { + let isDOM = DOM.isJSONXML(val); + return String.replace(val == null ? "null" : + isDOM ? DOM.toXML(val) + : val, + isDOM ? /['%]/g + : /['"%&<>]/g, + function (m) map[m]); + } + + return iter(obj).map(function ([k, v]) + [""].join("")) + .join("\n"); + }, /** * Converts a URI string into a URI object. @@ -943,13 +977,6 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), * @returns {string} */ objectToString: function objectToString(object, color) { - // Use E4X literals so html is automatically quoted - // only when it's asked for. No one wants to see < - // on their console or :map :foo in their buffer - // when they expect :map :foo. - XML.prettyPrinting = false; - XML.ignoreWhitespace = false; - if (object == null) return object + "\n"; @@ -970,8 +997,14 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), catch (e) { obj = Object.prototype.toString.call(obj); } - obj = template.highlightFilter(util.clip(obj, 150), "\n", !color ? function () "^J" : function () ^J); - let string = <>{obj}:: ; + + if (color) { + obj = template.highlightFilter(util.clip(obj, 150), "\n", + function () ["span", { highlight: "NonText" }, "^J"]); + var head = ["span", { highlight: "Title Object" }, obj, "::\n"]; + } + else + head = util.clip(obj, 150).replace(/\n/g, "^J") + "::\n"; let keys = []; @@ -987,7 +1020,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), keyIter = keys(object) for (let i in keyIter) { - let value = ]]>; + let value = Magic(""); try { value = object[i]; } @@ -1001,13 +1034,27 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), } } - value = template.highlight(value, true, 150, !color); - let key = {i}; + let key = i; if (!isNaN(i)) i = parseInt(i); else if (/^[A-Z_]+$/.test(i)) i = ""; - keys.push([i, <>{noVal ? value : <>{key}: {value}} ]); + + if (color) + value = template.highlight(value, true, 150, !color); + else if (value instanceof Magic) + value = String(value); + else + value = util.clip(String(value).replace(/\n/g, "^J"), 150); + + if (noVal) + var val = value; + else if (color) + val = [["span", { highlight: "Key" }, key], ": ", value]; + else + val = key + ": " + value; + + keys.push([i, val]); } } catch (e) { @@ -1019,12 +1066,75 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), return a[0] - b[0]; return String.localeCompare(a[0], b[0]); } - string += template.map(keys.sort(compare), function (f) f[1]); - return color ?
{string}
: [s for each (s in string)].join(""); + + let vals = template.map(keys.sort(compare), function (f) f[1], "\n"); + if (color) { + return ["div", { style: "white-space: pre-wrap" }, head, vals]; + } + return head + vals.join(""); + }, + + prettifyJSON: function prettifyJSON(data, indent, invalidOK) { + const INDENT = indent || " "; + + function rec(data, level, seen) { + if (isObject(data)) { + if (~seen.indexOf(data)) + throw Error("Recursive object passed"); + seen = seen.concat([data]); + } + + let prefix = level + INDENT; + + if (data === undefined) + data = null; + + if (~["boolean", "number"].indexOf(typeof data) || data === null) + res.push(String(data)); + else if (isinstance(data, ["String", _])) + res.push(JSON.stringify(String(data))); + else if (isArray(data)) { + if (data.length == 0) + res.push("[]"); + else { + res.push("[\n") + for (let [i, val] in Iterator(data)) { + if (i) + res.push(",\n"); + res.push(prefix) + rec(val, prefix, seen); + } + res.push("\n", level, "]"); + } + } + else if (isObject(data)) { + res.push("{\n") + + let i = 0; + for (let [key, val] in Iterator(data)) { + if (i++) + res.push(",\n"); + res.push(prefix, JSON.stringify(key), ": ") + rec(val, prefix, seen); + } + if (i > 0) + res.push("\n", level, "}") + else + res[res.length - 1] = "{}"; + } + else if (invalidOK) + res.push({}.toString.call(data)); + else + throw Error("Invalid JSON object"); + } + + let res = []; + rec(data, "", []); + return res.join(""); }, observers: { - "dactyl-cleanup-modules": function (subject, reason) { + "dactyl-cleanup-modules": function cleanupModules(subject, reason) { defineModule.loadLog.push("dactyl: util: observe: dactyl-cleanup-modules " + reason); for (let module in values(defineModule.modules)) @@ -1038,7 +1148,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), if (!this.rehashing) services.observer.addObserver(this, "dactyl-rehash", true); }, - "dactyl-rehash": function () { + "dactyl-rehash": function dactylRehash() { services.observer.removeObserver(this, "dactyl-rehash"); defineModule.loadLog.push("dactyl: util: observe: dactyl-rehash"); @@ -1051,7 +1161,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), module.init(); } }, - "dactyl-purge": function () { + "dactyl-purge": function dactylPurge() { this.rehashing = 1; }, }, @@ -1135,7 +1245,11 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), // Replace replacement . 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); + 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); // Strip comments and white space. if (/x/.test(flags)) @@ -1157,7 +1271,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), let res = update(RegExp(expr, flags.replace("x", "")), { closure: Class.Property(Object.getOwnPropertyDescriptor(Class.prototype, "closure")), dactylPropertyNames: ["exec", "match", "test", "toSource", "toString", "global", "ignoreCase", "lastIndex", "multiLine", "source", "sticky"], - iterate: function (str, idx) util.regexp.iterate(this, str, idx) + iterate: function iterate(str, idx) util.regexp.iterate(this, str, idx) }); // Return a struct with properties for named parameters if we @@ -1220,8 +1334,8 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), * Reloads dactyl in entirety by disabling the add-on and * re-enabling it. */ - rehash: function (args) { - storage.session.commandlineArgs = args; + rehash: function rehash(args) { + storage.storeForSession("commandlineArgs", args); this.timeout(function () { this.flushCache(); this.rehashing = true; @@ -1253,7 +1367,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), let obj = update({}, error, { toString: function () String(error), - stack: <>{util.stackLines(String(error.stack || Error().stack)).join("\n").replace(/^/mg, "\t")} + stack: Magic(util.stackLines(String(error.stack || Error().stack)).join("\n").replace(/^/mg, "\t")) }); services.console.logStringMessage(obj.stack); @@ -1307,7 +1421,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), * @param {Window} window * @returns {nsISelectionController} */ - selectionController: function (win) + selectionController: function selectionController(win) win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsISelectionDisplay) .QueryInterface(Ci.nsISelectionController), @@ -1326,7 +1440,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), * * @param {number} delay The time period for which to sleep in milliseconds. */ - sleep: function (delay) { + sleep: function sleep(delay) { let mainThread = services.threading.mainThread; let end = Date.now() + delay; @@ -1347,7 +1461,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), * @param {number} limit The maximum number of elements to return. * @returns {[string]} */ - split: function (str, re, limit) { + split: function split(str, re, limit) { re.lastIndex = 0; if (!re.global) re = RegExp(re.source || re, "g"); @@ -1407,7 +1521,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), * interrupted by pressing , in which case, * Error("Interrupted") will be thrown. */ - threadYield: function (flush, interruptable) { + threadYield: function threadYield(flush, interruptable) { this.yielders++; try { let mainThread = services.threading.mainThread; @@ -1546,7 +1660,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), * @param {nsIDOMWindow} win The window for which to find domains. * @returns {[string]} The visible domains. */ - visibleHosts: function (win) { + visibleHosts: function visibleHosts(win) { let res = [], seen = {}; (function rec(frame) { try { @@ -1566,7 +1680,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), * @param {nsIDOMWindow} win The window for which to find URIs. * @returns {[nsIURI]} The visible URIs. */ - visibleURIs: function (win) { + visibleURIs: function visibleURIs(win) { let res = [], seen = {}; (function rec(frame) { try { @@ -1602,9 +1716,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), catch (e) { throw e.stack ? e : Error(e); } - }, - - xmlToDom: function () DOM.fromXML.apply(DOM, arguments) + } }, { Array: array }); @@ -1615,7 +1727,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), * @singleton */ var GlobalMath = Math; -var Math = update(Object.create(GlobalMath), { +this.Math = update(Object.create(GlobalMath), { /** * Returns the specified *value* constrained to the range *min* - *max*. *