diff --git a/common/content/commandline.js b/common/content/commandline.js index 63d86d07..0b103997 100644 --- a/common/content/commandline.js +++ b/common/content/commandline.js @@ -1117,7 +1117,6 @@ var CommandLine = Module("commandline", { // TODO: Wouldn't multiple handlers be cleaner? --djk if (event.type == "click" && event.target instanceof HTMLAnchorElement) { - util.dump(event.getPreventDefault(), event.target); if (event.getPreventDefault()) return; diff --git a/common/modules/downloads.jsm b/common/modules/downloads.jsm index 33fcb2cc..de11b6b3 100644 --- a/common/modules/downloads.jsm +++ b/common/modules/downloads.jsm @@ -25,7 +25,9 @@ var Download = Class("Download", { this.instance = this; this.list = list; - this.nodes = {}; + this.nodes = { + commandTarget: self + }; util.xmlToDom(
  • @@ -54,22 +56,6 @@ var Download = Class("Download", {
  • , this.list.document, this.nodes); - for (let [key, node] in Iterator(this.nodes)) { - node.dactylDownload = self; - if (node.getAttributeNS(NS, "highlight") == "Button") { - node.setAttributeNS(NS, "command", "download.command"); - update(node, { - set collapsed(collapsed) { - if (collapsed) - this.setAttribute("collapsed", "true"); - else - this.removeAttribute("collapsed"); - }, - get collapsed() !!this.getAttribute("collapsed") - }); - } - } - self.updateStatus(); return self; }, @@ -293,12 +279,6 @@ var Downloads = Module("downloads", { { argCount: "?" }); - }, - dactyl: function (dactyl, modules, window) { - dactyl.commands["download.command"] = function (event) { - let elem = event.originalTarget; - elem.dactylDownload.command(elem.getAttribute("key")); - } } }); diff --git a/common/modules/template.jsm b/common/modules/template.jsm index e1f3fec4..178d0259 100644 --- a/common/modules/template.jsm +++ b/common/modules/template.jsm @@ -13,6 +13,68 @@ defineModule("template", { default xml namespace = XHTML; +var Binding = Class("Binding", { + init: function (node) { + this.node = node; + node.dactylBinding = this; + + Object.defineProperties(node, this.constructor.properties); + + for (let [event, handler] in values(this.constructor.events)) + node.addEventListener(event, handler, false); + }, + + set collapsed(collapsed) { + if (collapsed) + this.setAttribute("collapsed", "true"); + else + this.removeAttribute("collapsed"); + }, + get collapsed() !!this.getAttribute("collapsed"), + + __noSuchMethod__: function __noSuchMethod__(meth, args) { + return this.node[meth].apply(this.node, args); + } +}, { + get bindings() { + let bindingProto = Object.getPrototypeOf(Binding.prototype); + for (let obj = this.prototype; obj !== bindingProto; obj = Object.getPrototypeOf(obj)) + yield obj; + }, + + bind: function bind(func) function bound() { + try { + return func.apply(this.dactylBinding, arguments); + } + catch (e) { + util.reportError(e); + throw e; + } + }, + + events: Class.memoize(function () { + let res = []; + for (let obj in this.bindings) + if (Object.getOwnPropertyDescriptor(obj, "events")) + for (let [event, handler] in Iterator(obj.events)) + res.push([event, this.bind(handler)]); + return res; + }), + + properties: Class.memoize(function () { + let res = {}; + for (let obj in this.bindings) + for (let prop in properties(obj)) { + let desc = Object.getOwnPropertyDescriptor(obj, prop); + for (let k in values(["get", "set", "value"])) + if (typeof desc[k] === "function") + desc[k] = this.bind(desc[k]); + res[prop] = desc; + } + return res; + }) +}); + var Template = Module("Template", { add: function add(a, b) a + b, join: function join(c) function (a, b) a + c + b, @@ -36,6 +98,25 @@ var Template = Module("Template", { return ret; }, + bindings: { + Button: Class("Button", Binding, { + init: function init(node, params) { + init.supercall(this, node); + + this.target = params.commandTarget; + if (callable(this.target)) + this.target = { command: this.target } + }, + + events: { + "click": function onClick(event) { + event.preventDefault(); + this.target.command(this.getAttribute("key")); + } + } + }) + }, + bookmarkDescription: function (item, text) <> { diff --git a/common/modules/util.jsm b/common/modules/util.jsm index 18925beb..a58a116e 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -1587,27 +1587,33 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), XML.prettyPrinting = false; if (typeof node === "string") // Sandboxes can't currently pass us XML objects. node = XML(node); + if (node.length() != 1) { let domnode = doc.createDocumentFragment(); for each (let child in node) domnode.appendChild(xmlToDom(child, doc, nodes)); return domnode; } + switch (node.nodeKind()) { case "text": return doc.createTextNode(String(node)); case "element": let domnode = doc.createElementNS(node.namespace(), node.localName()); - for each (let attr in node.@*::*) - if (attr.name() != "highlight") - domnode.setAttributeNS(attr.namespace(), attr.localName(), String(attr)); - else - highlight.highlightNode(domnode, String(attr)); for each (let child in node.*::*) domnode.appendChild(xmlToDom(child, doc, nodes)); if (nodes && node.@key) nodes[node.@key] = domnode; + + for each (let attr in node.@*::*) + if (attr.name() != "highlight") + domnode.setAttributeNS(attr.namespace(), attr.localName(), String(attr)); + else { + highlight.highlightNode(domnode, String(attr)); + if (attr in template.bindings) + template.bindings[attr](domnode, nodes); + } return domnode; default: return null;