X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=common%2Fmodules%2Foverlay.jsm;h=c52ba4ad95a9fceb4d599fa9131b302854be3a4f;hb=354a049cce8415487552ce405cce167b7071fe1f;hp=0ccf502c00984159200124271c2ff193df84b416;hpb=9044153cb63835e39b9de8ec4ade237c03e3888a;p=dactyl.git diff --git a/common/modules/overlay.jsm b/common/modules/overlay.jsm index 0ccf502..c52ba4a 100644 --- a/common/modules/overlay.jsm +++ b/common/modules/overlay.jsm @@ -1,16 +1,17 @@ -// Copyright (c) 2009-2011 by Kris Maglione +// Copyright (c) 2009-2013 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("overlay", { exports: ["overlay"], require: ["util"] -}, this); +}); + +lazyRequire("highlight", ["highlight"]); var getAttr = function getAttr(elem, ns, name) elem.hasAttributeNS(ns, name) ? elem.getAttributeNS(ns, name) : null; @@ -19,15 +20,15 @@ var setAttr = function setAttr(elem, ns, name, val) { elem.removeAttributeNS(ns, name); else elem.setAttributeNS(ns, name, val); -} +}; var Overlay = Class("Overlay", { init: function init(window) { this.window = window; }, - cleanups: Class.Memoize(function () []), - objects: Class.Memoize(function () ({})), + cleanups: Class.Memoize(() => []), + objects: Class.Memoize(() => ({})), get doc() this.window.document, @@ -41,16 +42,17 @@ var Overlay = Class("Overlay", { } }); - var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), { init: function init() { util.addObserver(this); this.overlays = {}; + this.weakMap = WeakMap(); + this.onWindowVisible = []; }, - id: Class.Memoize(function () config.addon.id), + id: Class.Memoize(() => config.addon.id), /** * Adds an event listener for this session and removes it on @@ -146,39 +148,48 @@ var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReferen "content-document-global-created": function (window, uri) { this.observe(window, "toplevel-window-ready", null); }, "xul-window-visible": function () { if (this.onWindowVisible) - this.onWindowVisible.forEach(function (f) f.call(this), this); + this.onWindowVisible.forEach(f => { f.call(this); }); this.onWindowVisible = null; } }, getData: function getData(obj, key, constructor) { - let { id } = this; - if (!(id in obj && obj[id])) - obj[id] = {}; + if (!this.weakMap.has(obj)) + try { + this.weakMap.set(obj, {}); + } + catch (e if e instanceof TypeError) { + // util.dump("Bad WeakMap key: " + obj + " " + Components.stack.caller); + let { id } = this; + + if (!(id in obj && obj[id])) + obj[id] = {}; + + var data = obj[id]; + } + + data = data || this.weakMap.get(obj); if (arguments.length == 1) - return obj[id]; + return data; - if (obj[id][key] === undefined) + if (data[key] === undefined) if (constructor === undefined || callable(constructor)) - obj[id][key] = (constructor || Array)(); + data[key] = (constructor || Array)(); else - obj[id][key] = constructor; + data[key] = constructor; - return obj[id][key]; + return data[key]; }, setData: function setData(obj, key, val) { - let { id } = this; - - if (!(id in obj)) - obj[id] = {}; + let data = this.getData(obj); - return obj[id][key] = val; + return data[key] = val; }, - overlayWindow: function (url, fn) { + overlayWindow: function overlayWindow(url, fn) { if (url instanceof Ci.nsIDOMWindow) overlay._loadOverlay(url, fn); else { @@ -214,42 +225,66 @@ var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReferen _loadOverlay: function _loadOverlay(window, obj) { let doc = window.document; - let elems = this.getData(doc, "overlayElements"); - let attrs = this.getData(doc, "overlayAttributes"); + let savedElems = this.getData(doc, "overlayElements"); + let savedAttrs = this.getData(doc, "overlayAttributes"); function insert(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])); + if (isArray(obj[key])) { + iterator = ([elem[1].id, elem.slice(2), elem[1]] + for each (elem in obj[key])); + } + + for (let [elem, xml, attrs] in iterator) { + if (elem = doc.getElementById(String(elem))) { + // Urgh. Hack. + let namespaces; + if (attrs && !isXML(attrs)) + namespaces = iter([k.slice(6), DOM.fromJSON.namespaces[v] || v] + for ([k, v] in Iterator(attrs)) + if (/^xmlns(?:$|:)/.test(k))).toObject(); + + let node; + if (isXML(xml)) + node = DOM.fromXML(xml, doc, obj.objects); + else + node = DOM.fromJSON(xml, doc, obj.objects, namespaces); - for (let [elem, xml, attr] in iterator) { - if (elem = doc.getElementById(elem)) { - let node = DOM.fromXML(xml, doc, obj.objects); if (!(node instanceof Ci.nsIDOMDocumentFragment)) - elems.push(node); + savedElems.push(node); else for (let n in array.iterValues(node.childNodes)) - elems.push(n); + savedElems.push(n); fn(elem, node); - for each (let attr in attr || []) { - let ns = attr.namespace(), name = attr.localName(); - attrs.push([elem, ns, name, getAttr(elem, ns, name), String(attr)]); - if (attr.name() != "highlight") - elem.setAttributeNS(ns, name, String(attr)); + + if (isXML(attrs)) + // Evilness and such. + let (oldAttrs = attrs) { + attrs = (attr for each (attr in oldAttrs)); + } + + for (let attr in attrs || []) { + let [ns, localName] = DOM.parseNamespace(attr); + let name = attr; + let val = attrs[attr]; + + savedAttrs.push([elem, ns, name, getAttr(elem, ns, name), val]); + if (name === "highlight") + highlight.highlightNode(elem, val); else - highlight.highlightNode(elem, String(attr)); + elem.setAttributeNS(ns || "", name, val); } } } } } - insert("before", function (elem, dom) elem.parentNode.insertBefore(dom, elem)); - insert("after", function (elem, dom) elem.parentNode.insertBefore(dom, elem.nextSibling)); - insert("append", function (elem, dom) elem.appendChild(dom)); - insert("prepend", function (elem, dom) elem.insertBefore(dom, elem.firstChild)); + insert("before", (elem, dom) => elem.parentNode.insertBefore(dom, elem)); + insert("after", (elem, dom) => elem.parentNode.insertBefore(dom, elem.nextSibling)); + insert("append", (elem, dom) => elem.appendChild(dom)); + insert("prepend", (elem, dom) => elem.insertBefore(dom, elem.firstChild)); if (obj.ready) util.trapErrors("ready", obj, window); @@ -345,7 +380,7 @@ var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReferen Object.defineProperty(object, k, desc); if (callable(value)) { - var sentinel = "(function DactylOverlay() {}())" + var sentinel = "(function DactylOverlay() {}())"; value.toString = function toString() toString.toString.call(this).replace(/\}?$/, sentinel + "; $&"); value.toSource = function toSource() toSource.toSource.call(this).replace(/\}?$/, sentinel + "; $&"); } @@ -377,23 +412,23 @@ var Overlay = Module("Overlay", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReferen get activeModules() this.activeWindow && this.activeWindow.dactyl.modules, - get modules() this.windows.map(function (w) w.dactyl.modules), + get modules() this.windows.map(w => w.dactyl.modules), /** * The most recently active dactyl window. */ get activeWindow() this.windows[0], - set activeWindow(win) this.windows = [win].concat(this.windows.filter(function (w) w != win)), + set activeWindow(win) this.windows = [win].concat(this.windows.filter(w => w != win)), /** * A list of extant dactyl windows. */ - windows: Class.Memoize(function () []) + windows: Class.Memoize(() => []) }); endModule(); } 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: