]> git.donarmstrong.com Git - dactyl.git/blobdiff - common/modules/overlay.jsm
Import r6976 from upstream hg supporting Firefox up to 25.*
[dactyl.git] / common / modules / overlay.jsm
index 0ccf502c00984159200124271c2ff193df84b416..c52ba4ad95a9fceb4d599fa9131b302854be3a4f 100644 (file)
@@ -1,16 +1,17 @@
-// Copyright (c) 2009-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2009-2013 Kris Maglione <maglione.k@gmail.com>
 //
 // 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: