diff options
author | Kris Maglione <maglione.k@gmail.com> | 2011-08-15 00:03:57 -0400 |
---|---|---|
committer | Kris Maglione <maglione.k@gmail.com> | 2011-08-15 00:03:57 -0400 |
commit | 07d6099a953c1367efdc57eb141f5a973e843aec (patch) | |
tree | e2c8ac5735659e6c90b753644fe98f2ae0f2e50e /common | |
parent | 681af3e618eed5d24c581c3ea5dee1907e404e7d (diff) | |
download | pentadactyl-07d6099a953c1367efdc57eb141f5a973e843aec.tar.gz |
Move overlay magic from util to overlay module.
Diffstat (limited to 'common')
-rw-r--r-- | common/content/browser.js | 4 | ||||
-rw-r--r-- | common/content/commandline.js | 2 | ||||
-rw-r--r-- | common/content/dactyl.js | 4 | ||||
-rw-r--r-- | common/content/events.js | 2 | ||||
-rw-r--r-- | common/content/mow.js | 2 | ||||
-rw-r--r-- | common/content/statusline.js | 4 | ||||
-rw-r--r-- | common/modules/base.jsm | 11 | ||||
-rw-r--r-- | common/modules/config.jsm | 38 | ||||
-rw-r--r-- | common/modules/overlay.jsm | 266 | ||||
-rw-r--r-- | common/modules/util.jsm | 210 |
10 files changed, 283 insertions, 260 deletions
diff --git a/common/content/browser.js b/common/content/browser.js index 38ffda2c..ff3fbc1a 100644 --- a/common/content/browser.js +++ b/common/content/browser.js @@ -13,8 +13,8 @@ */ var Browser = Module("browser", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { init: function init() { - this.cleanupProgressListener = util.overlayObject(window.XULBrowserWindow, - this.progressListener); + this.cleanupProgressListener = overlay.overlayObject(window.XULBrowserWindow, + this.progressListener); util.addObserver(this); }, diff --git a/common/content/commandline.js b/common/content/commandline.js index 0675153b..4dfe2f08 100644 --- a/common/content/commandline.js +++ b/common/content/commandline.js @@ -15,7 +15,7 @@ var CommandWidgets = Class("CommandWidgets", { let s = "dactyl-statusline-field-"; XML.ignoreWhitespace = true; - util.overlayWindow(window, { + overlay.overlayWindow(window, { objects: { eventTarget: commandline }, diff --git a/common/content/dactyl.js b/common/content/dactyl.js index b9395f84..721abc1c 100644 --- a/common/content/dactyl.js +++ b/common/content/dactyl.js @@ -40,7 +40,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { styles.registerSheet("resource://dactyl-skin/dactyl.css"); this.cleanups = []; - this.cleanups.push(util.overlayObject(window, { + this.cleanups.push(overlay.overlayObject(window, { focusAndSelectUrlBar: function focusAndSelectUrlBar() { switch (options.get("strictfocus").getKey(document.documentURIObject || util.newURI(document.documentURI), "moderate")) { case "laissez-faire": @@ -305,7 +305,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { }; XML.ignoreWhitespace = true; if (!elems.bell) - util.overlayWindow(window, { + overlay.overlayWindow(window, { objects: elems, prepend: <> <window id={document.documentElement.id} xmlns={XUL}> diff --git a/common/content/events.js b/common/content/events.js index 6f3090df..6981f596 100644 --- a/common/content/events.js +++ b/common/content/events.js @@ -410,7 +410,7 @@ var Events = Module("events", { EventHive.prototype.wrapListener = this.closure.wrapListener; XML.ignoreWhitespace = true; - util.overlayWindow(window, { + overlay.overlayWindow(window, { append: <e4x xmlns={XUL}> <window id={document.documentElement.id}> <!-- http://developer.mozilla.org/en/docs/XUL_Tutorial:Updating_Commands --> diff --git a/common/content/mow.js b/common/content/mow.js index 4254cb9c..b02c00c9 100644 --- a/common/content/mow.js +++ b/common/content/mow.js @@ -44,7 +44,7 @@ var MOW = Module("mow", { true); XML.ignoreWhitespace = true; - util.overlayWindow(window, { + overlay.overlayWindow(window, { objects: { eventTarget: this }, diff --git a/common/content/statusline.js b/common/content/statusline.js index 2d93e512..ba290b72 100644 --- a/common/content/statusline.js +++ b/common/content/statusline.js @@ -23,7 +23,7 @@ var StatusLine = Module("statusline", { #addon-bar > xul|toolbarspring { visibility: collapse; } ]]></css>); - util.overlayWindow(window, { append: <><statusbar id="status-bar" ordinal="0"/></> }); + overlay.overlayWindow(window, { append: <><statusbar id="status-bar" ordinal="0"/></> }); highlight.loadCSS(util.compileMacro(<![CDATA[ !AddonBar;#addon-bar { @@ -83,7 +83,7 @@ var StatusLine = Module("statusline", { for each (let attr in prepend..@key) attr.parent().@id = "dactyl-statusline-field-" + attr; - util.overlayWindow(window, { + overlay.overlayWindow(window, { objects: this.widgets = { get status() this.container }, prepend: prepend.elements() }); diff --git a/common/modules/base.jsm b/common/modules/base.jsm index 8cde5ce2..7bd4e1cd 100644 --- a/common/modules/base.jsm +++ b/common/modules/base.jsm @@ -740,6 +740,10 @@ function Class() { constructor: { value: Constructor }, }); self.instance = self; + + if ("_metaInit_" in self && self._metaInit_) + self._metaInit_.apply(self, arguments); + var res = self.init.apply(self, arguments); return res !== undefined ? res : self; }; @@ -1062,6 +1066,13 @@ var ErrorBase = Class("ErrorBase", Error, { */ function Module(name, prototype) { let init = callable(prototype) ? 4 : 3; + let proto = arguments[callable(prototype) ? 2 : 1]; + + proto._metaInit_ = function () { + delete module.prototype._metaInit_; + currentModule[name.toLowerCase()] = instance; + }; + const module = Class.apply(Class, Array.slice(arguments, 0, init)); let instance = module(); module.className = name.toLowerCase(); diff --git a/common/modules/config.jsm b/common/modules/config.jsm index 2623b84b..f5d231cb 100644 --- a/common/modules/config.jsm +++ b/common/modules/config.jsm @@ -31,6 +31,44 @@ var ConfigBase = Class("ConfigBase", { }); }, + modules: { + global: ["addons", + "base", + "io", + "commands", + "completion", + "config", + "contexts", + "downloads", + "finder", + "highlight", + "javascript", + "messages", + "options", + "overlay", + "prefs", + "sanitizer", + "services", + "storage", + "styles", + "template", + "util"], + + window: ["dactyl", + "modes", + "commandline", + "abbreviations", + "autocommands", + "buffer", + "editor", + "events", + "hints", + "mappings", + "marks", + "mow", + "statusline"] + }, + loadStyles: function loadStyles(force) { const { highlight } = require("highlight"); const { _ } = require("messages"); diff --git a/common/modules/overlay.jsm b/common/modules/overlay.jsm index ec329f05..587ee7f8 100644 --- a/common/modules/overlay.jsm +++ b/common/modules/overlay.jsm @@ -9,7 +9,7 @@ try { Components.utils.import("resource://dactyl/bootstrap.jsm"); defineModule("overlay", { exports: ["ModuleBase", "overlay"], - require: ["config", "io", "services", "util"] + require: ["config", "highlight", "io", "services", "util"] }, this); /** @@ -26,15 +26,26 @@ var ModuleBase = Class("ModuleBase", { toString: function () "[module " + this.constructor.className + "]" }); -var Overlay = Module("Overlay", { +var getAttr = function getAttr(elem, ns, name) + elem.hasAttributeNS(ns, name) ? elem.getAttributeNS(ns, name) : null; +var setAttr = function setAttr(elem, ns, name, val) { + if (val == null) + elem.removeAttributeNS(ns, name); + else + elem.setAttributeNS(ns, name, val); +} + + +var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), { init: function init() { - let overlay = this; + util.addObserver(this); + this.overlays = {}; services["dactyl:"]; // Hack. Force module initialization. config.loadStyles(); - util.overlayWindow(config.overlayChrome, function _overlay(window) ({ + this.overlayWindow(config.overlayChrome, function _overlay(window) ({ init: function onInit(document) { /** * @constructor Module @@ -161,43 +172,11 @@ var Overlay = Module("Overlay", { let prefix = [BASE, "resource://dactyl-local-content/"]; defineModule.time("load", null, function _load() { - ["addons", - "base", - "io", - "commands", - "completion", - "config", - "contexts", - "downloads", - "finder", - "highlight", - "javascript", - "messages", - "options", - "overlay", - "prefs", - "sanitizer", - "services", - "storage", - "styles", - "template", - "util" - ].forEach(function (name) defineModule.time("load", name, require, null, jsmodules, name)); - - ["dactyl", - "modes", - "commandline", - "abbreviations", - "autocommands", - "buffer", - "editor", - "events", - "hints", - "mappings", - "marks", - "mow", - "statusline" - ].forEach(function (name) defineModule.time("load", name, modules.load, modules, name)); + config.modules.global + .forEach(function (name) defineModule.time("load", name, require, null, jsmodules, name)); + + config.modules.window + .forEach(function (name) defineModule.time("load", name, modules.load, modules, name)); }, this); }, load: function onLoad(document) { @@ -288,7 +267,9 @@ var Overlay = Module("Overlay", { frobModules(); frob("init"); + modules.config.scripts.forEach(modules.load); + frobModules(); defineModule.modules.forEach(function defModule({ lazyInit, constructor: { className } }) { @@ -310,8 +291,6 @@ var Overlay = Module("Overlay", { defineModule.loadLog.push("Loaded in " + (Date.now() - start) + "ms"); - util.dump(overlay); - overlay.windows = array.uniq(overlay.windows.concat(window), true); modules.events.listen(window, "unload", function onUnload() { @@ -330,6 +309,207 @@ var Overlay = Module("Overlay", { })); }, + cleanup: function cleanup() { + for (let { document: doc } in iter(services.windowMediator.getEnumerator(null))) { + for (let elem in values(doc.dactylOverlayElements || [])) + if (elem.parentNode) + elem.parentNode.removeChild(elem); + + for (let [elem, ns, name, orig, value] in values(doc.dactylOverlayAttributes || [])) + if (getAttr(elem, ns, name) === value) + setAttr(elem, ns, name, orig); + + delete doc.dactylOverlayElements; + delete doc.dactylOverlayAttributes; + delete doc.dactylOverlays; + } + }, + + observers: { + "toplevel-window-ready": function (window, data) { + window.addEventListener("DOMContentLoaded", util.wrapCallback(function listener(event) { + if (event.originalTarget === window.document) { + window.removeEventListener("DOMContentLoaded", listener.wrapper, true); + overlay._loadOverlays(window); + } + }), true); + }, + "chrome-document-global-created": function (window, uri) { this.observe(window, "toplevel-window-ready", null); }, + "content-document-global-created": function (window, uri) { this.observe(window, "toplevel-window-ready", null); } + }, + + overlayWindow: function (url, fn) { + if (url instanceof Ci.nsIDOMWindow) + overlay._loadOverlay(url, fn); + else { + Array.concat(url).forEach(function (url) { + if (!this.overlays[url]) + this.overlays[url] = []; + this.overlays[url].push(fn); + }, this); + + for (let doc in util.iterDocuments()) + if (["interactive", "complete"].indexOf(doc.readyState) >= 0) + this._loadOverlays(doc.defaultView); + else + this.observe(doc.defaultView, "toplevel-window-ready"); + } + }, + + _loadOverlays: function _loadOverlays(window) { + if (!window.dactylOverlays) + window.dactylOverlays = []; + + for each (let obj in overlay.overlays[window.document.documentURI] || []) { + if (window.dactylOverlays.indexOf(obj) >= 0) + continue; + window.dactylOverlays.push(obj); + this._loadOverlay(window, obj(window)); + } + }, + + _loadOverlay: function _loadOverlay(window, obj) { + let doc = window.document; + if (!doc.dactylOverlayElements) { + doc.dactylOverlayElements = []; + doc.dactylOverlayAttributes = []; + } + + function overlay(key, fn) { + if (obj[key]) { + let iterator = Iterator(obj[key]); + if (!isObject(obj[key])) + iterator = ([elem.@id, elem.elements(), elem.@*::*.(function::name() != "id")] for each (elem in obj[key])); + + for (let [elem, xml, attr] in iterator) { + if (elem = doc.getElementById(elem)) { + let node = util.xmlToDom(xml, doc, obj.objects); + if (!(node instanceof Ci.nsIDOMDocumentFragment)) + doc.dactylOverlayElements.push(node); + else + for (let n in array.iterValues(node.childNodes)) + doc.dactylOverlayElements.push(n); + + fn(elem, node); + for each (let attr in attr || []) { + let ns = attr.namespace(), name = attr.localName(); + doc.dactylOverlayAttributes.push([elem, ns, name, getAttr(elem, ns, name), String(attr)]); + if (attr.name() != "highlight") + elem.setAttributeNS(ns, name, String(attr)); + else + highlight.highlightNode(elem, String(attr)); + } + } + } + } + } + + overlay("before", function (elem, dom) elem.parentNode.insertBefore(dom, elem)); + overlay("after", function (elem, dom) elem.parentNode.insertBefore(dom, elem.nextSibling)); + overlay("append", function (elem, dom) elem.appendChild(dom)); + overlay("prepend", function (elem, dom) elem.insertBefore(dom, elem.firstChild)); + if (obj.init) + obj.init(window); + + if (obj.load) + if (doc.readyState === "complete") + obj.load(window); + else + doc.addEventListener("load", util.wrapCallback(function load(event) { + if (event.originalTarget === event.target) { + doc.removeEventListener("load", load.wrapper, true); + obj.load(window, event); + } + }), true); + }, + + /** + * Overlays an object with the given property overrides. Each + * property in *overrides* is added to *object*, replacing any + * original value. Functions in *overrides* are augmented with the + * new properties *super*, *supercall*, and *superapply*, in the + * same manner as class methods, so that they man call their + * overridden counterparts. + * + * @param {object} object The object to overlay. + * @param {object} overrides An object containing properties to + * override. + * @returns {function} A function which, when called, will remove + * the overlay. + */ + overlayObject: function (object, overrides) { + let original = Object.create(object); + overrides = update(Object.create(original), overrides); + + Object.getOwnPropertyNames(overrides).forEach(function (k) { + let orig, desc = Object.getOwnPropertyDescriptor(overrides, k); + if (desc.value instanceof Class.Property) + desc = desc.value.init(k) || desc.value; + + if (k in object) { + for (let obj = object; obj && !orig; obj = Object.getPrototypeOf(obj)) + if (orig = Object.getOwnPropertyDescriptor(obj, k)) + Object.defineProperty(original, k, orig); + + if (!orig) + if (orig = Object.getPropertyDescriptor(object, k)) + Object.defineProperty(original, k, orig); + } + + // Guard against horrible add-ons that use eval-based monkey + // patching. + let value = desc.value; + if (callable(desc.value)) { + + delete desc.value; + delete desc.writable; + desc.get = function get() value; + desc.set = function set(val) { + 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; + util.reportError(Error(_("error.monkeyPatchOverlay", package_))); + util.dactyl.echoerr(_("error.monkeyPatchOverlay", package_)); + } + }; + } + + try { + Object.defineProperty(object, k, desc); + + if (callable(value)) { + let sentinel = "(function DactylOverlay() {}())" + value.toString = function toString() toString.toString.call(this).replace(/\}?$/, sentinel + "; $&"); + value.toSource = function toSource() toSource.toSource.call(this).replace(/\}?$/, sentinel + "; $&"); + } + } + catch (e) { + try { + if (value) { + object[k] = value; + return; + } + } + catch (f) {} + util.reportError(e); + } + }, this); + + return function unwrap() { + for each (let k in Object.getOwnPropertyNames(original)) + if (Object.getOwnPropertyDescriptor(object, k).configurable) + Object.defineProperty(object, k, Object.getOwnPropertyDescriptor(original, k)); + else { + try { + object[k] = original[k]; + } + catch (e) {} + } + }; + }, + + /** * The most recently active dactyl window. */ diff --git a/common/modules/util.jsm b/common/modules/util.jsm index eeae6adf..c33b55c1 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -51,41 +51,17 @@ var wrapCallback = function wrapCallback(fn) { return fn.wrapper; } -var getAttr = function getAttr(elem, ns, name) - elem.hasAttributeNS(ns, name) ? elem.getAttributeNS(ns, name) : null; -var setAttr = function setAttr(elem, ns, name, val) { - if (val == null) - elem.removeAttributeNS(ns, name); - else - elem.setAttributeNS(ns, name, val); -} - var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), { init: function () { this.Array = array; this.addObserver(this); - this.overlays = {}; this.windows = []; }, - cleanup: function cleanup() { - for (let { document: doc } in iter(services.windowMediator.getEnumerator(null))) { - for (let elem in values(doc.dactylOverlayElements || [])) - if (elem.parentNode) - elem.parentNode.removeChild(elem); - - for (let [elem, ns, name, orig, value] in values(doc.dactylOverlayAttributes || [])) - if (getAttr(elem, ns, name) === value) - setAttr(elem, ns, name, orig); - - delete doc.dactylOverlayElements; - delete doc.dactylOverlayAttributes; - delete doc.dactylOverlays; - } - }, - 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 }), dactyl: update(function dactyl(obj) { if (obj) @@ -971,188 +947,6 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), "dactyl-purge": function () { this.rehashing = 1; }, - - "toplevel-window-ready": function (window, data) { - window.addEventListener("DOMContentLoaded", wrapCallback(function listener(event) { - if (event.originalTarget === window.document) { - window.removeEventListener("DOMContentLoaded", listener.wrapper, true); - util._loadOverlays(window); - } - }), true); - }, - "chrome-document-global-created": function (window, uri) { this.observe(window, "toplevel-window-ready", null); }, - "content-document-global-created": function (window, uri) { this.observe(window, "toplevel-window-ready", null); } - }, - - _loadOverlays: function _loadOverlays(window) { - if (!window.dactylOverlays) - window.dactylOverlays = []; - - for each (let obj in util.overlays[window.document.documentURI] || []) { - if (window.dactylOverlays.indexOf(obj) >= 0) - continue; - window.dactylOverlays.push(obj); - this._loadOverlay(window, obj(window)); - } - }, - - _loadOverlay: function _loadOverlay(window, obj) { - let doc = window.document; - if (!doc.dactylOverlayElements) { - doc.dactylOverlayElements = []; - doc.dactylOverlayAttributes = []; - } - - function overlay(key, fn) { - if (obj[key]) { - let iterator = Iterator(obj[key]); - if (!isObject(obj[key])) - iterator = ([elem.@id, elem.elements(), elem.@*::*.(function::name() != "id")] for each (elem in obj[key])); - - for (let [elem, xml, attr] in iterator) { - if (elem = doc.getElementById(elem)) { - let node = util.xmlToDom(xml, doc, obj.objects); - if (!(node instanceof Ci.nsIDOMDocumentFragment)) - doc.dactylOverlayElements.push(node); - else - for (let n in array.iterValues(node.childNodes)) - doc.dactylOverlayElements.push(n); - - fn(elem, node); - for each (let attr in attr || []) { - let ns = attr.namespace(), name = attr.localName(); - doc.dactylOverlayAttributes.push([elem, ns, name, getAttr(elem, ns, name), String(attr)]); - if (attr.name() != "highlight") - elem.setAttributeNS(ns, name, String(attr)); - else - highlight.highlightNode(elem, String(attr)); - } - } - } - } - } - - overlay("before", function (elem, dom) elem.parentNode.insertBefore(dom, elem)); - overlay("after", function (elem, dom) elem.parentNode.insertBefore(dom, elem.nextSibling)); - overlay("append", function (elem, dom) elem.appendChild(dom)); - overlay("prepend", function (elem, dom) elem.insertBefore(dom, elem.firstChild)); - if (obj.init) - obj.init(window); - - if (obj.load) - if (doc.readyState === "complete") - obj.load(window); - else - doc.addEventListener("load", wrapCallback(function load(event) { - if (event.originalTarget === event.target) { - doc.removeEventListener("load", load.wrapper, true); - obj.load(window, event); - } - }), true); - }, - - /** - * Overlays an object with the given property overrides. Each - * property in *overrides* is added to *object*, replacing any - * original value. Functions in *overrides* are augmented with the - * new properties *super*, *supercall*, and *superapply*, in the - * same manner as class methods, so that they man call their - * overridden counterparts. - * - * @param {object} object The object to overlay. - * @param {object} overrides An object containing properties to - * override. - * @returns {function} A function which, when called, will remove - * the overlay. - */ - overlayObject: function (object, overrides) { - let original = Object.create(object); - overrides = update(Object.create(original), overrides); - - Object.getOwnPropertyNames(overrides).forEach(function (k) { - let orig, desc = Object.getOwnPropertyDescriptor(overrides, k); - if (desc.value instanceof Class.Property) - desc = desc.value.init(k) || desc.value; - - if (k in object) { - for (let obj = object; obj && !orig; obj = Object.getPrototypeOf(obj)) - if (orig = Object.getOwnPropertyDescriptor(obj, k)) - Object.defineProperty(original, k, orig); - - if (!orig) - if (orig = Object.getPropertyDescriptor(object, k)) - Object.defineProperty(original, k, orig); - } - - // Guard against horrible add-ons that use eval-based monkey - // patching. - let value = desc.value; - if (callable(desc.value)) { - - delete desc.value; - delete desc.writable; - desc.get = function get() value; - desc.set = function set(val) { - 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; - util.reportError(Error(_("error.monkeyPatchOverlay", package_))); - util.dactyl.echoerr(_("error.monkeyPatchOverlay", package_)); - } - }; - } - - try { - Object.defineProperty(object, k, desc); - - if (callable(value)) { - let sentinel = "(function DactylOverlay() {}())" - value.toString = function toString() toString.toString.call(this).replace(/\}?$/, sentinel + "; $&"); - value.toSource = function toSource() toSource.toSource.call(this).replace(/\}?$/, sentinel + "; $&"); - } - } - catch (e) { - try { - if (value) { - object[k] = value; - return; - } - } - catch (f) {} - util.reportError(e); - } - }, this); - - return function unwrap() { - for each (let k in Object.getOwnPropertyNames(original)) - if (Object.getOwnPropertyDescriptor(object, k).configurable) - Object.defineProperty(object, k, Object.getOwnPropertyDescriptor(original, k)); - else { - try { - object[k] = original[k]; - } - catch (e) {} - } - }; - }, - - overlayWindow: function (url, fn) { - if (url instanceof Ci.nsIDOMWindow) - util._loadOverlay(url, fn); - else { - Array.concat(url).forEach(function (url) { - if (!this.overlays[url]) - this.overlays[url] = []; - this.overlays[url].push(fn); - }, this); - - for (let doc in util.iterDocuments()) - if (["interactive", "complete"].indexOf(doc.readyState) >= 0) - this._loadOverlays(doc.defaultView); - else - this.observe(doc.defaultView, "toplevel-window-ready"); - } }, /** |