diff options
author | Kris Maglione <maglione.k@gmail.com> | 2011-09-08 10:22:43 -0400 |
---|---|---|
committer | Kris Maglione <maglione.k@gmail.com> | 2011-09-08 10:22:43 -0400 |
commit | c6035ce6741311b0ad1dc00ec118ef97767194fc (patch) | |
tree | c66787955c9e4ac7cdc5b2e8ebbd9479d985fc0f /common/modules | |
parent | e9a0b1eea3c7aa70047655a2b6660ed0f089e94c (diff) | |
download | pentadactyl-c6035ce6741311b0ad1dc00ec118ef97767194fc.tar.gz |
Minorish refactoring.
Diffstat (limited to 'common/modules')
-rw-r--r-- | common/modules/base.jsm | 3 | ||||
-rw-r--r-- | common/modules/bookmarkcache.jsm | 15 | ||||
-rw-r--r-- | common/modules/io.jsm | 2 | ||||
-rw-r--r-- | common/modules/main.jsm | 259 | ||||
-rw-r--r-- | common/modules/overlay.jsm | 61 | ||||
-rw-r--r-- | common/modules/storage.jsm | 2 | ||||
-rw-r--r-- | common/modules/util.jsm | 6 |
7 files changed, 214 insertions, 134 deletions
diff --git a/common/modules/base.jsm b/common/modules/base.jsm index 9e18365c..a93ed81d 100644 --- a/common/modules/base.jsm +++ b/common/modules/base.jsm @@ -133,7 +133,8 @@ function defineModule(name, params, module) { module.NAME = name; module.EXPORTED_SYMBOLS = params.exports || []; - delete module.File; + if (!~module.EXPORTED_SYMBOLS.indexOf("File")) + delete module.File; defineModule.loadLog.push("[Begin " + name + "]"); defineModule.prefix += " "; diff --git a/common/modules/bookmarkcache.jsm b/common/modules/bookmarkcache.jsm index ea377e39..6f303226 100644 --- a/common/modules/bookmarkcache.jsm +++ b/common/modules/bookmarkcache.jsm @@ -10,6 +10,8 @@ defineModule("bookmarkcache", { require: ["services", "storage", "util"] }, this); +function newURI(url, charset, base) services.io.newURI(url, charset, base); + var Bookmark = Struct("url", "title", "icon", "post", "keyword", "tags", "charset", "id"); var Keyword = Struct("keyword", "title", "icon", "url"); Bookmark.defaultValue("icon", function () BookmarkCache.getFavicon(this.url)); @@ -19,7 +21,7 @@ update(Bookmark.prototype, { ["tags", this.tags.join(", "), "Tag"] ].filter(function (item) item[1]), - get uri() util.newURI(this.url), + get uri() newURI(this.url), set uri(uri) { let tags = this.tags; this.tags = null; @@ -36,7 +38,7 @@ update(Bookmark.prototype, { }) Bookmark.prototype.members.uri = Bookmark.prototype.members.url; Bookmark.setter = function (key, func) this.prototype.__defineSetter__(key, func); -Bookmark.setter("url", function (val) { this.uri = isString(val) ? util.newURI(val) : val; }); +Bookmark.setter("url", function (val) { this.uri = isString(val) ? newURI(val) : val; }); Bookmark.setter("title", function (val) { services.bookmarks.setItemTitle(this.id, val); }); Bookmark.setter("post", function (val) { bookmarkcache.annotate(this.id, bookmarkcache.POST, val); }); Bookmark.setter("charset", function (val) { bookmarkcache.annotate(this.id, bookmarkcache.CHARSET, val); }); @@ -79,7 +81,7 @@ var BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), { _loadBookmark: function loadBookmark(node) { if (node.uri == null) // How does this happen? return false; - let uri = util.newURI(node.uri); + let uri = newURI(node.uri); let keyword = services.bookmarks.getKeywordForBookmark(node.itemId); let tags = services.tagging.getTagsForURI(uri, {}) || []; let post = BookmarkCache.getAnnotation(node.itemId, this.POST); @@ -96,7 +98,7 @@ var BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), { }, get: function (url) { - let ids = services.bookmarks.getBookmarkIdsForURI(util.newURI(url), {}); + let ids = services.bookmarks.getBookmarkIdsForURI(newURI(url), {}); for (let id in values(ids)) if (id in this.bookmarks) return this.bookmarks[id]; @@ -129,7 +131,7 @@ var BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), { */ isBookmarked: function isBookmarked(uri) { if (isString(uri)) - uri = util.newURI(uri); + uri = newURI(uri); try { return services.bookmarks @@ -221,9 +223,10 @@ var BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), { getAnnotation: function getAnnotation(item, anno) services.annotation.itemHasAnnotation(item, anno) ? services.annotation.getItemAnnotation(item, anno) : null, + getFavicon: function getFavicon(uri) { try { - return services.favicon.getFaviconImageForPage(util.newURI(uri)).spec; + return services.favicon.getFaviconImageForPage(newURI(uri)).spec; } catch (e) { return ""; diff --git a/common/modules/io.jsm b/common/modules/io.jsm index a43c55e3..efc4ddca 100644 --- a/common/modules/io.jsm +++ b/common/modules/io.jsm @@ -339,7 +339,7 @@ var IO = Module("io", { */ isJarURL: function isJarURL(url) { try { - let uri = util.newURI(util.fixURI(url)); + let uri = util.newURI(url); if (uri instanceof Ci.nsIJARURI) return uri; diff --git a/common/modules/main.jsm b/common/modules/main.jsm index 295dfcd1..65dcca7c 100644 --- a/common/modules/main.jsm +++ b/common/modules/main.jsm @@ -12,6 +12,8 @@ defineModule("main", { require: ["config", "help", "highlight", "io", "overlay", "services", "util"] }, this); +const BASE = "resource://dactyl-content/"; + /** * @class ModuleBase * The base class for all modules. @@ -26,142 +28,149 @@ var ModuleBase = Class("ModuleBase", { toString: function () "[module " + this.constructor.className + "]" }); -config.loadStyles(); +var Modules = function Modules(window) { + /** + * @constructor Module + * + * Constructs a new ModuleBase class and makes arrangements for its + * initialization. Arguments marked as optional must be either + * entirely elided, or they must have the exact type specified. + * Loading semantics are as follows: + * + * - A module is guaranteed not to be initialized before any of its + * prerequisites as listed in its {@see ModuleBase#requires} member. + * - A module is considered initialized once it's been instantiated, + * its {@see Class#init} method has been called, and its + * instance has been installed into the top-level {@see modules} + * object. + * - Once the module has been initialized, its module-dependent + * initialization functions will be called as described hereafter. + * @param {string} name The module's name as it will appear in the + * top-level {@see modules} object. + * @param {ModuleBase} base The base class for this module. + * @optional + * @param {Object} prototype The prototype for instances of this + * object. The object itself is copied and not used as a prototype + * directly. + * @param {Object} classProperties The class properties for the new + * module constructor. + * @optional + * @param {Object} moduleInit The module initialization functions + * for the new module. Each function is called as soon as the named module + * has been initialized, but after the module itself. The constructors are + * guaranteed to be called in the same order that the dependent modules + * were initialized. + * @optional + * + * @returns {function} The constructor for the resulting module. + */ + function Module(name) { + let args = Array.slice(arguments); + + var base = ModuleBase; + if (callable(args[1])) + base = args.splice(1, 1)[0]; + let [, prototype, classProperties, moduleInit] = args; + const module = Class(name, base, prototype, classProperties); + + module.INIT = moduleInit || {}; + module.modules = modules; + module.prototype.INIT = module.INIT; + module.requires = prototype.requires || []; + Module.list.push(module); + Module.constructors[name] = module; + return module; + } + Module.list = []; + Module.constructors = {}; -overlay.overlayWindow(config.overlayChrome, function _overlay(window) ({ - ready: function onInit(document) { - /** - * @constructor Module - * - * Constructs a new ModuleBase class and makes arrangements for its - * initialization. Arguments marked as optional must be either - * entirely elided, or they must have the exact type specified. - * Loading semantics are as follows: - * - * - A module is guaranteed not to be initialized before any of its - * prerequisites as listed in its {@see ModuleBase#requires} member. - * - A module is considered initialized once it's been instantiated, - * its {@see Class#init} method has been called, and its - * instance has been installed into the top-level {@see modules} - * object. - * - Once the module has been initialized, its module-dependent - * initialization functions will be called as described hereafter. - * @param {string} name The module's name as it will appear in the - * top-level {@see modules} object. - * @param {ModuleBase} base The base class for this module. - * @optional - * @param {Object} prototype The prototype for instances of this - * object. The object itself is copied and not used as a prototype - * directly. - * @param {Object} classProperties The class properties for the new - * module constructor. - * @optional - * @param {Object} moduleInit The module initialization functions - * for the new module. Each function is called as soon as the named module - * has been initialized, but after the module itself. The constructors are - * guaranteed to be called in the same order that the dependent modules - * were initialized. - * @optional - * - * @returns {function} The constructor for the resulting module. - */ - function Module(name) { - let args = Array.slice(arguments); - - var base = ModuleBase; - if (callable(args[1])) - base = args.splice(1, 1)[0]; - let [, prototype, classProperties, moduleInit] = args; - const module = Class(name, base, prototype, classProperties); - - module.INIT = moduleInit || {}; - module.modules = modules; - module.prototype.INIT = module.INIT; - module.requires = prototype.requires || []; - Module.list.push(module); - Module.constructors[name] = module; - return module; - } - Module.list = []; - Module.constructors = {}; + const create = window.Object.create || (function () { + window.__dactyl_eval_string = "(function (proto) ({ __proto__: proto }))"; + JSMLoader.loadSubScript(BASE + "eval.js", window); - const BASE = "resource://dactyl-content/"; + let res = window.__dactyl_eval_result; + delete window.__dactyl_eval_string; + delete window.__dactyl_eval_result; + return res; + })(); - const create = window.Object.create || (function () { - window.__dactyl_eval_string = "(function (proto) ({ __proto__: proto }))"; - JSMLoader.loadSubScript(BASE + "eval.js", window); - let res = window.__dactyl_eval_result; - delete window.__dactyl_eval_string; - delete window.__dactyl_eval_result; - return res; - })(); + const BASES = [BASE, "resource://dactyl-local-content/"]; - const jsmodules = { NAME: "jsmodules" }; - const modules = update(create(jsmodules), { - yes_i_know_i_should_not_report_errors_in_these_branches_thanks: [], + const jsmodules = { NAME: "jsmodules" }; + const modules = update(create(jsmodules), { + yes_i_know_i_should_not_report_errors_in_these_branches_thanks: [], - jsmodules: jsmodules, + jsmodules: jsmodules, - get content() this.config.browser.contentWindow || window.content, + get content() this.config.browser.contentWindow || window.content, - window: window, + window: window, - Module: Module, + Module: Module, - load: function load(script) { - for (let [i, base] in Iterator(prefix)) { - try { - JSMLoader.loadSubScript(base + script + ".js", modules, "UTF-8"); - return; - } - catch (e) { - if (typeof e !== "string") { - util.dump("Trying: " + (base + script + ".js") + ":"); - util.reportError(e); - } - } - } + load: function load(script) { + for (let [i, base] in Iterator(BASES)) { try { - require(jsmodules, script); + JSMLoader.loadSubScript(base + script + ".js", modules, "UTF-8"); + return; } catch (e) { - util.dump("Loading script " + script + ":"); - util.reportError(e); + if (typeof e !== "string") { + util.dump("Trying: " + (base + script + ".js") + ":"); + util.reportError(e); + } } - }, - - newContext: function newContext(proto, normal) { - if (normal) - return create(proto); - let sandbox = Components.utils.Sandbox(window, { sandboxPrototype: proto || modules, wantXrays: false }); - // Hack: - sandbox.Object = jsmodules.Object; - sandbox.Math = jsmodules.Math; - sandbox.__proto__ = proto || modules; - return sandbox; - }, - - get ownPropertyValues() array.compact( - Object.getOwnPropertyNames(this) - .map(function (name) Object.getOwnPropertyDescriptor(this, name).value, this)), - - get moduleList() this.ownPropertyValues.filter(function (mod) mod instanceof this.ModuleBase || mod.isLocalModule, this) - }); - modules.plugins = create(modules); - modules.modules = modules; - window.dactyl = { modules: modules }; + } + try { + require(jsmodules, script); + } + catch (e) { + util.dump("Loading script " + script + ":"); + util.reportError(e); + } + }, + + newContext: function newContext(proto, normal) { + if (normal) + return create(proto); + let sandbox = Components.utils.Sandbox(window, { sandboxPrototype: proto || modules, wantXrays: false }); + // Hack: + sandbox.Object = jsmodules.Object; + sandbox.File = jsmodules.File; + sandbox.Math = jsmodules.Math; + sandbox.__proto__ = proto || modules; + return sandbox; + }, + + get ownPropertyValues() array.compact( + Object.getOwnPropertyNames(this) + .map(function (name) Object.getOwnPropertyDescriptor(this, name).value, this)), + + get moduleList() this.ownPropertyValues.filter(function (mod) mod instanceof this.ModuleBase || mod.isLocalModule, this) + }); + + modules.plugins = create(modules); + modules.modules = modules; + return modules; +} - let prefix = [BASE, "resource://dactyl-local-content/"]; +config.loadStyles(); + +overlay.overlayWindow(config.overlayChrome, function _overlay(window) ({ + ready: function onInit(document) { + const modules = Modules(window); + window.dactyl = { modules: modules }; defineModule.time("load", null, function _load() { config.modules.global - .forEach(function (name) defineModule.time("load", name, require, null, jsmodules, name)); + .forEach(function (name) defineModule.time("load", name, require, null, modules.jsmodules, name)); config.modules.window .forEach(function (name) defineModule.time("load", name, modules.load, modules, name)); }, this); }, + load: function onLoad(document) { // This is getting to be horrible. --Kris @@ -184,19 +193,23 @@ overlay.overlayWindow(config.overlayChrome, function _overlay(window) ({ try { if (module.className in loaded) return; + if (module.className in seen) throw Error("Module dependency loop."); + Set.add(seen, module.className); for (let dep in values(module.requires)) load(Module.constructors[dep], module.className); defineModule.loadLog.push("Load" + (isString(prereq) ? " " + prereq + " dependency: " : ": ") + module.className); + if (frame && frame.filename) defineModule.loadLog.push(" from: " + util.fixURI(frame.filename) + ":" + frame.lineNumber); let obj = defineModule.time(module.className, "init", module); Class.replaceProperty(modules, module.className, obj); + loaded[module.className] = true; if (loaded.dactyl && obj.signals) @@ -238,6 +251,7 @@ overlay.overlayWindow(config.overlayChrome, function _overlay(window) ({ mod.frobbed = true; }); } + defineModule.modules.forEach(function defModule(mod) { let names = Set(Object.keys(mod.INIT)); if ("init" in mod.INIT) @@ -269,20 +283,19 @@ overlay.overlayWindow(config.overlayChrome, function _overlay(window) ({ return modules[className] = modules[className]; }); }); + }, - modules.events.listen(window, "unload", function onUnload() { - window.removeEventListener("unload", onUnload.wrapped, false); - - overlay.windows = overlay.windows.filter(function (w) w != window); + unload: function unload(window) { + overlay.windows = overlay.windows.filter(function (w) w != window); - for each (let mod in modules.moduleList.reverse()) { - mod.stale = true; + for each (let mod in this.modules.moduleList.reverse()) { + mod.stale = true; - if ("destroy" in mod) - util.trapErrors("destroy", mod); - } - }, false); + if ("destroy" in mod) + util.trapErrors("destroy", mod); + } }, + visible: function visible(window) { // Module.list.forEach(load); this.frob("load"); diff --git a/common/modules/overlay.jsm b/common/modules/overlay.jsm index b28d287b..ed245550 100644 --- a/common/modules/overlay.jsm +++ b/common/modules/overlay.jsm @@ -52,6 +52,63 @@ var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReferen id: Class.Memoize(function () config.addon.id), + /** + * Adds an event listener for this session and removes it on + * dactyl shutdown. + * + * @param {Element} target The element on which to listen. + * @param {string} event The event to listen for. + * @param {function} callback The function to call when the event is received. + * @param {boolean} capture When true, listen during the capture + * phase, otherwise during the bubbling phase. + * @param {boolean} allowUntrusted When true, allow capturing of + * untrusted events. + */ + listen: function (target, event, callback, capture, allowUntrusted) { + let doc = target.ownerDocument || target.document || target; + let listeners = this.getData(doc, "listeners"); + + if (!isObject(event)) + var [self, events] = [null, array.toObject([[event, callback]])]; + else + [self, events] = [event, event[callback || "events"]]; + + for (let [event, callback] in Iterator(events)) { + let args = [Cu.getWeakReference(target), + event, + util.wrapCallback(callback, self), + capture, + allowUntrusted]; + + target.addEventListener.apply(target, args.slice(1)); + listeners.push(args); + } + }, + + /** + * Remove an event listener. + * + * @param {Element} target The element on which to listen. + * @param {string} event The event to listen for. + * @param {function} callback The function to call when the event is received. + * @param {boolean} capture When true, listen during the capture + * phase, otherwise during the bubbling phase. + */ + unlisten: function (target, event, callback, capture) { + let doc = target.ownerDocument || target.document || target; + let listeners = this.getData(doc, "listeners"); + if (event === true) + target = null; + + this.setData(doc, "listeners", listeners.filter(function (args) { + if (target == null || args[0].get() == target && args[1] == event && args[2].wrapped == callback && args[3] == capture) { + args[0].get().removeEventListener.apply(args[0].get(), args.slice(1)); + return false; + } + return !args[0].get(); + })); + }, + cleanup: function cleanup(reason) { for (let doc in util.iterDocuments()) { for (let elem in values(this.getData(doc, "overlayElements"))) @@ -65,6 +122,8 @@ var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReferen for (let callback in values(this.getData(doc, "cleanup"))) util.trapErrors(callback, doc, reason); + this.unlisten(doc, true); + delete doc[this.id]; delete doc.defaultView[this.id]; } @@ -265,7 +324,7 @@ var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReferen if (!callable(val) || Function.prototype.toString(val).indexOf(sentinel) < 0) Class.replaceProperty(this, k, val); else { - let package_ = util.newURI(util.fixURI(Components.stack.caller.filename)).host; + let package_ = util.newURI(Components.stack.caller.filename).host; util.reportError(Error(_("error.monkeyPatchOverlay", package_))); util.dactyl.echoerr(_("error.monkeyPatchOverlay", package_)); } diff --git a/common/modules/storage.jsm b/common/modules/storage.jsm index b73bf444..81b4e35b 100644 --- a/common/modules/storage.jsm +++ b/common/modules/storage.jsm @@ -294,7 +294,7 @@ var Storage = Module("Storage", { * current directory. @default true * @param {string} charset The charset of the file. @default File.defaultEncoding */ -this.File = Class("File", { +var File = Class("File", { init: function (path, checkPWD, charset) { let file = services.File(); diff --git a/common/modules/util.jsm b/common/modules/util.jsm index 2655a8c2..60296404 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -629,7 +629,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), getFile: function getFile(uri) { try { if (isString(uri)) - uri = util.newURI(util.fixURI(uri)); + uri = util.newURI(uri); if (uri instanceof Ci.nsIFileURL) return File(uri.file); @@ -837,6 +837,10 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), * @returns {nsIURI} */ newURI: function newURI(uri, charset, base) { + let idx = uri.lastIndexOf(" -> "); + if (~idx) + uri = uri.slice(idx + 4); + let res = this.withProperErrors("newURI", services.io, uri, charset, base); res instanceof Ci.nsIURL; return res; |