diff options
-rwxr-xr-x | common/bootstrap.js | 2 | ||||
-rw-r--r-- | common/content/buffer.js | 54 | ||||
-rw-r--r-- | common/content/commandline.js | 29 | ||||
-rw-r--r-- | common/content/dactyl.js | 4 | ||||
-rw-r--r-- | common/content/statusline.js | 39 | ||||
-rw-r--r-- | common/modules/storage.jsm | 64 | ||||
-rw-r--r-- | common/modules/util.jsm | 94 | ||||
-rw-r--r-- | common/skin/dactyl.css | 2 |
8 files changed, 163 insertions, 125 deletions
diff --git a/common/bootstrap.js b/common/bootstrap.js index 1d64596b..21514102 100755 --- a/common/bootstrap.js +++ b/common/bootstrap.js @@ -171,10 +171,10 @@ function init() { function shutdown(data, reason) { dump("dactyl: bootstrap: shutdown\n"); + services.observer.notifyObservers(null, "dactyl-cleanup", null); for (let factory in values(components)) // TODO: Categories; factory.unregister(); - services.observer.notifyObservers(null, "dactyl-cleanup", null); } function reasonToString(reason) { diff --git a/common/content/buffer.js b/common/content/buffer.js index 456062e8..04dc93ed 100644 --- a/common/content/buffer.js +++ b/common/content/buffer.js @@ -147,6 +147,40 @@ const Buffer = Module("buffer", { let elem = event.originalTarget; buffer.viewSource([elem.getAttribute("href"), Number(elem.getAttribute("line"))]) }; + + this.replaceProgressListener(this.progressListener); + }, + + cleanup: function () { + for (let prop in properties(this.progressListener)) + if (!this.progressListener.__lookupGetter__(prop) && + !callable(this.progressListener[prop])) + this.origProgressListener[prop] = this.progressListener[prop] + + this.replaceProgressListener(this.origProgressListener); + }, + + replaceProgressListener: function (newListener) { + // I hate this whole hack. --Kris + let obj = window.XULBrowserWindow, getter; + for (let prop in properties(obj)) + if ((getter = obj.__lookupGetter__(prop)) && !obj.__lookupSetter__(prop)) { + newListener.__defineGetter__(prop, getter); + delete obj[prop]; + } + + this.origProgressListener = window.XULBrowserWindow; + try { + config.browser.removeProgressListener(window.XULBrowserWindow); + } + catch (e) {} // Why? --djk + + config.browser.addProgressListener(newListener, Ci.nsIWebProgress.NOTIFY_ALL); + window.XULBrowserWindow = newListener; + window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShellTreeItem).treeOwner + .QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIXULWindow) + .XULBrowserWindow = newListener; }, destroy: function () { @@ -1502,26 +1536,6 @@ const Buffer = Module("buffer", { }; }, events: function () { - try { - config.browser.removeProgressListener(window.XULBrowserWindow); - } - catch (e) {} // Why? --djk - - // I hate this whole hack. --Kris - let obj = window.XULBrowserWindow, getter; - for (let p in properties(obj)) - if ((getter = obj.__lookupGetter__(p)) && !obj.__lookupSetter__(p)) { - this.progressListener.__defineGetter__(p, getter); - delete obj[p]; - } - - config.browser.addProgressListener(this.progressListener, Ci.nsIWebProgress.NOTIFY_ALL); - window.XULBrowserWindow = this.progressListener; - window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShellTreeItem).treeOwner - .QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIXULWindow) - .XULBrowserWindow = this.progressListener; - events.addSessionListener(config.browser, "DOMContentLoaded", this.closure.onDOMContentLoaded, true); events.addSessionListener(config.browser, "load", this.closure.onPageLoad, true); events.addSessionListener(config.browser, "scroll", this.closure._updateBufferPosition, false); diff --git a/common/content/commandline.js b/common/content/commandline.js index e4ca3534..3454f0e0 100644 --- a/common/content/commandline.js +++ b/common/content/commandline.js @@ -135,9 +135,25 @@ const CommandWidgets = Class("CommandWidgets", { getGroup: function (value) { if (this.command && !options.get("guioptions").has("M")) return this.statusbar; + let statusElem = this.statusbar.message; - if (value && statusElem.inputField.editor.rootElement.scrollWidth > statusElem.scrollWidth) - return this.commandbar; + if (!statusElem.editor) { + util.dump(commandline == window.dactyl.modules.commandline, + window.dactyl.modules.commandline.widgets == this, + commandline.widgets == this); + util.dumpStack(); + + for (let i=0, e = statusElem; e; e = e.parentNode) + util.dump(i++, e == statusline._statusLine.firstChild, + e == statusline.widgets.container, + e); + util.dump(statusElem == statusline.widgets.message); + util.dump(statusline._statusLine.firstChild == statusline.widgets.container); + } + else { + if (value && statusElem.editor.rootElement.scrollWidth > statusElem.scrollWidth) + return this.commandbar; + } return this.activeGroup.mode; } }); @@ -165,13 +181,13 @@ const CommandWidgets = Class("CommandWidgets", { const self = this; this.elements[obj.name] = obj; - function get(id) obj.getElement ? obj.getElement(id) : document.getElementById(id); + function get(prefix, map, id) (obj.getElement || util.identity)(map[id] || document.getElementById(prefix + id)); this.active.__defineGetter__(obj.name, function () self.activeGroup[obj.name][obj.name]); this.activeGroup.__defineGetter__(obj.name, function () self.getGroup(obj.name)); - memoize(this.statusbar, obj.name, function () get("dactyl-statusline-field-" + (obj.id || obj.name))); - memoize(this.commandbar, obj.name, function () get("dactyl-" + (obj.id || obj.name))); + memoize(this.statusbar, obj.name, function () get("dactyl-statusline-field-", statusline.widgets, (obj.id || obj.name))); + memoize(this.commandbar, obj.name, function () get("dactyl-", {}, (obj.id || obj.name))); if (!(obj.noValue || obj.getValue)) Object.defineProperty(this, obj.name, Modes.boundProperty({ @@ -259,8 +275,7 @@ const CommandWidgets = Class("CommandWidgets", { multilineInput: Class.memoize(function () document.getElementById("dactyl-multiline-input")), mowContainer: Class.memoize(function () this.multilineOutput.parentNode) }, { - getEditor: function (id) { - let elem = document.getElementById(id); + getEditor: function (elem) { elem.inputField.QueryInterface(Ci.nsIDOMNSEditableElement); return elem; } diff --git a/common/content/dactyl.js b/common/content/dactyl.js index b5e04249..eaeaa7fc 100644 --- a/common/content/dactyl.js +++ b/common/content/dactyl.js @@ -53,13 +53,15 @@ const Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), observe: { "dactyl-cleanup": function () { - for (let [, mod] in iter(array(values(modules)).reverse())) + for (let name in values(Object.getOwnPropertyNames(modules).reverse())) { + let mod = modules[name]; if (mod instanceof ModuleBase) { if ("cleanup" in mod) mod.cleanup(); if ("destroy" in mod) mod.destroy(); } + } } }, diff --git a/common/content/statusline.js b/common/content/statusline.js index 44dc84b9..22541a22 100644 --- a/common/content/statusline.js +++ b/common/content/statusline.js @@ -10,6 +10,19 @@ const StatusLine = Module("statusline", { init: function () { + this._statusLine = document.getElementById("status-bar"); + this.statusBar = document.getElementById("addon-bar") || this._statusLine; + this.statusBar.collapsed = true; // it is later restored unless the user sets laststatus=0 + + if (this.statusBar.localName == "toolbar") { + styles.system.add("addon-bar", config.styleableChrome, <css><![CDATA[ + #status-bar { margin-top: 0 !important; } + #addon-bar { padding: 0 !important; min-height: 18px !important; } + #addon-bar > statusbar { -moz-box-flex: 1 } + #addon-bar > #addonbar-closebutton { visibility: collapse; } + #addon-bar > xul|toolbarspring { visibility: collapse; } + ]]></css>); + } let _commandline = "if (window.dactyl) return dactyl.modules.commandline"; let prepend = <e4x xmlns={XUL} xmlns:dactyl={NS}> @@ -21,8 +34,8 @@ const StatusLine = Module("statusline", { <hbox class="dactyl-container" dactyl:highlight="CmdLine StatusCmdLine"> <label class="plain" key="mode" crop="end" collapsed="true"/> <stack flex="1" class="dactyl-container" dactyl:highlight="CmdLine StatusCmdLine"> - <textbox class="plain" key="url" crop="end" flex="1" readonly="true"/> - <textbox class="plain" key="message" crop="end" flex="1" readonly="true" dactyl:highlight="Normal StatusNormal"/> + <textbox key="url" crop="end" flex="1" readonly="true" class="plain dactyl-status-field-url"/> + <textbox key="message" crop="end" flex="1" readonly="true" class="plain" dactyl:highlight="Normal StatusNormal"/> </stack> </hbox> @@ -45,31 +58,11 @@ const StatusLine = Module("statusline", { </statusbar> </e4x>; - for each (let attr in prepend..@key) - attr.parent().@id = "dactyl-statusline-field-" + attr; - + util.dump("statusbar: load overlay"); util.overlayWindow(window, { objects: this.widgets = { get status() this.container }, prepend: prepend.elements() }); - - this._statusLine = document.getElementById("status-bar"); - this.statusBar = document.getElementById("addon-bar") || this._statusLine; - this.statusBar.collapsed = true; // it is later restored unless the user sets laststatus=0 - - - if (this.statusBar.localName == "toolbar") { - styles.system.add("addon-bar", config.styleableChrome, <css><![CDATA[ - #status-bar { margin-top: 0 !important; } - #addon-bar { padding: 0 !important; min-height: 18px !important; } - #addon-bar > statusbar { -moz-box-flex: 1 } - #addon-bar > #addonbar-closebutton { visibility: collapse; } - #addon-bar > xul|toolbarspring { visibility: collapse; } - ]]></css>); - let parent = this.widgets.status.parentNode; - parent.removeChild(this.widgets.status); - parent.insertBefore(this.widgets.status, parent.firstChild); - } }, get visible() !this.statusBar.collapsed && !this.statusBar.hidden, diff --git a/common/modules/storage.jsm b/common/modules/storage.jsm index 730e3dde..6e06377b 100644 --- a/common/modules/storage.jsm +++ b/common/modules/storage.jsm @@ -142,25 +142,39 @@ const ObjectStore = Class("ObjectStore", StoreBase, { __iterator__: function () Iterator(this._object), }); -var keys = {}; -var observers = {}; - const Storage = Module("Storage", { alwaysReload: {}, + init: function () { + this.cleanup(); + }, + + cleanup: function () { + for (let key in keys(this.keys)) + delete this[key]; + for (let ary in values(this.observers)) + for (let obj in values(ary)) + if (obj.ref && obj.ref.get()) + delete obj.ref.get().dactylStorageRefs; + + this.keys = {}; + this.observers = {}; + }, + newObject: function newObject(key, constructor, params) { if (params == null || !isObject(params)) throw Error("Invalid argument type"); - if (!(key in keys) || params.reload || this.alwaysReload[key]) { + if (!(key in this.keys) || params.reload || this.alwaysReload[key]) { if (key in this && !(params.reload || this.alwaysReload[key])) throw Error(); let load = function () loadData(key, params.store, params.type || myObject); - keys[key] = new constructor(key, params.store, load, params); - keys[key].timer = new Timer(1000, 10000, function () storage.save(key)); - this.__defineGetter__(key, function () keys[key]); + + this.keys[key] = new constructor(key, params.store, load, params); + this.keys[key].timer = new Timer(1000, 10000, function () storage.save(key)); + this.__defineGetter__(key, function () this.keys[key]); } - return keys[key]; + return this.keys[key]; }, newMap: function newMap(key, options) { @@ -182,38 +196,36 @@ const Storage = Module("Storage", { callbackRef = { get: function () callback }; } this.removeDeadObservers(); - if (!(key in observers)) - observers[key] = []; - if (!observers[key].some(function (o) o.callback.get() == callback)) - observers[key].push({ ref: ref && Cu.getWeakReference(ref), callback: callbackRef }); + if (!(key in this.observers)) + this.observers[key] = []; + if (!this.observers[key].some(function (o) o.callback.get() == callback)) + this.observers[key].push({ ref: ref && Cu.getWeakReference(ref), callback: callbackRef }); }, removeObserver: function (key, callback) { this.removeDeadObservers(); - if (!(key in observers)) + if (!(key in this.observers)) return; - observers[key] = observers[key].filter(function (elem) elem.callback.get() != callback); - if (observers[key].length == 0) + this.observers[key] = this.observers[key].filter(function (elem) elem.callback.get() != callback); + if (this.observers[key].length == 0) delete obsevers[key]; }, removeDeadObservers: function () { - for (let [key, ary] in Iterator(observers)) { - observers[key] = ary = ary.filter(function (o) o.callback.get() && (!o.ref || o.ref.get() && o.ref.get().dactylStorageRefs)); + for (let [key, ary] in Iterator(this.observers)) { + this.observers[key] = ary = ary.filter(function (o) o.callback.get() && (!o.ref || o.ref.get() && o.ref.get().dactylStorageRefs)); if (!ary.length) - delete observers[key]; + delete this.observers[key]; } }, - get observers() observers, - fireEvent: function fireEvent(key, event, arg) { this.removeDeadObservers(); - if (key in observers) + if (key in this.observers) // Safe, since we have our own Array object here. - for each (let observer in observers[key]) + for each (let observer in this.observers[key]) observer.callback.get()(key, event, arg); - if (key in keys) + if (key in this.keys) this[key].timer.tell(); }, @@ -223,11 +235,11 @@ const Storage = Module("Storage", { }, save: function save(key) { - saveData(keys[key]); + saveData(this.keys[key]); }, saveAll: function storeAll() { - for each (let obj in keys) + for each (let obj in this.keys) saveData(obj); }, @@ -237,7 +249,7 @@ const Storage = Module("Storage", { if (val && !this._privateMode) this.saveAll(); if (!val && this._privateMode) - for (let key in keys) + for (let key in this.keys) this.load(key); return this._privateMode = Boolean(val); } diff --git a/common/modules/util.jsm b/common/modules/util.jsm index be16ed9e..4acf60b7 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -57,8 +57,8 @@ const Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]) cleanup: function cleanup() { for (let win in iter(services.windowMediator.getEnumerator(null))) { for (let elem in values(win.document.dactylOverlayElements || [])) - if (elem.get() && elem.get().parentNode) - elem.get().parentNode.removeChild(elem.get()); + if (elem.parentNode) + elem.parentNode.removeChild(elem); delete win.document.dactylOverlayElements; delete win.document.dactylOverlays; } @@ -849,7 +849,7 @@ const Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]) let tag = "<" + [namespaced(elem)].concat( [namespaced(a) + "=" + template.highlight(a.value, true) for ([i, a] in array.iterItems(elem.attributes))]).join(" "); - return tag + (hasChildren ? "/>" : ">...</" + namespaced(elem) + ">"); + return tag + (!hasChildren ? "/>" : ">...</" + namespaced(elem) + ">"); } catch (e) { return {}.toString.call(elem); @@ -907,6 +907,47 @@ const Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]) return color ? string : [s for each (s in string)].join(""); }, + observe: { + "dactyl-cleanup": function () { + util.dump("dactyl: util: observe: dactyl-cleanup"); + // Let window cleanup functions run synchronously before we + // destroy modules. + util.timeout(function () { + for (let module in values(defineModule.modules)) + if (module.cleanup) + module.cleanup(); + + services.observer.addObserver(this, "dactyl-rehash", true); + + /* + let getOwnPropertyNames = Object.getOwnPropertyNames; + for each (let global in defineModule.globals.reverse()) + for each (let k in getOwnPropertyNames(global)) + try { + delete global[k]; + } + catch (e) {} + */ + }); + }, + "dactyl-rehash": function () { + util.dump("dactyl: util: observe: dactyl-rehash"); + for (let module in values(defineModule.modules)) + if (module.reinit) + module.reinit(); + else + module.init(); + }, + "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) + } + }, + _loadOverlays: function _loadOverlays(window) { if (!window.dactylOverlays) window.dactylOverlays = []; @@ -925,17 +966,19 @@ const Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]) if (!doc.dactylOverlayElements) doc.dactylOverlayElements = []; + util.dump("load overlay", doc.documentURI, String(obj).substr(0, 60)); + function overlay(key, fn) { if (obj[key]) { let iterator = Iterator(obj[key]); if (!isObject(obj[key])) - iterator = ([elem.@id, elem.*, elem.@*::*] for each (elem in 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); for (let n in array.iterValues(node.childNodes)) - doc.dactylOverlayElements.push(Cu.getWeakReference(n)); + doc.dactylOverlayElements.push(n); fn(elem, node); for each (let attr in attr || []) // FIXME: Cleanup... elem.setAttributeNS(attr.namespace(), attr.localName(), attr); @@ -963,47 +1006,6 @@ const Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]) }), true); }, - observe: { - "dactyl-cleanup": function () { - util.dump("dactyl: util: observe: dactyl-cleanup"); - // Let window cleanup functions run synchronously before we - // destroy modules. - util.timeout(function () { - for (let module in values(defineModule.modules)) - if (module.cleanup) - module.cleanup(); - - services.observer.addObserver(this, "dactyl-rehash", true); - - /* - let getOwnPropertyNames = Object.getOwnPropertyNames; - for each (let global in defineModule.globals.reverse()) - for each (let k in getOwnPropertyNames(global)) - try { - delete global[k]; - } - catch (e) {} - */ - }); - }, - "dactyl-rehash": function () { - util.dump("dactyl: util: observe: dactyl-rehash"); - for (let module in values(defineModule.modules)) - if (module.reinit) - module.reinit(); - else - module.init(); - }, - "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) - } - }, - overlayWindow: function (url, fn) { if (url instanceof Ci.nsIDOMWindow) util._loadOverlay(url, fn); diff --git a/common/skin/dactyl.css b/common/skin/dactyl.css index 200c3500..f145dacd 100644 --- a/common/skin/dactyl.css +++ b/common/skin/dactyl.css @@ -122,7 +122,7 @@ statusbarpanel { background: transparent; } -#dactyl-statusline-field-url { +.dactyl-status-field-url { background-color: inherit !important; color: inherit !important; } |