Bug 684721 - GCLI templater and devtools templater need to be in sync; f=mratcliffe, r=rcampbell

This commit is contained in:
Joe Walker 2011-10-03 12:05:41 -03:00
Родитель 31a7394182
Коммит 736033156f
1 изменённых файлов: 31 добавлений и 21 удалений

Просмотреть файл

@ -47,6 +47,8 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Services.jsm");
var Node = Ci.nsIDOMNode;
/** /**
* A templater that allows one to quickly template DOM nodes. * A templater that allows one to quickly template DOM nodes.
*/ */
@ -56,10 +58,17 @@ function Templater() {
/** /**
* Recursive function to walk the tree processing the attributes as it goes. * Recursive function to walk the tree processing the attributes as it goes.
* @param node the node to process. * @param node the node to process. If you pass a string in instead of a DOM
* element, it is assumed to be an id for use with document.getElementById()
* @param data the data to use for node processing. * @param data the data to use for node processing.
*/ */
Templater.prototype.processNode = function(node, data) { Templater.prototype.processNode = function(node, data) {
if (typeof node === 'string') {
node = document.getElementById(node);
}
if (data === null || data === undefined) {
data = {};
}
this.scope.push(node.nodeName + (node.id ? '#' + node.id : '')); this.scope.push(node.nodeName + (node.id ? '#' + node.id : ''));
try { try {
// Process attributes // Process attributes
@ -81,7 +90,7 @@ Templater.prototype.processNode = function(node, data) {
// It's good to clean up the attributes when we've processed them, // It's good to clean up the attributes when we've processed them,
// but if we do it straight away, we mess up the array index // but if we do it straight away, we mess up the array index
var attrs = Array.prototype.slice.call(node.attributes); var attrs = Array.prototype.slice.call(node.attributes);
for (let i = 0, attLen = attrs.length; i < attLen; i++) { for (var i = 0; i < attrs.length; i++) {
var value = attrs[i].value; var value = attrs[i].value;
var name = attrs[i].name; var name = attrs[i].name;
this.scope.push(name); this.scope.push(name);
@ -107,10 +116,9 @@ Templater.prototype.processNode = function(node, data) {
} }
} else { } else {
// Replace references in all other attributes // Replace references in all other attributes
var self = this;
var newValue = value.replace(/\$\{[^}]*\}/g, function(path) { var newValue = value.replace(/\$\{[^}]*\}/g, function(path) {
return self.envEval(path.slice(2, -1), data, value); return this.envEval(path.slice(2, -1), data, value);
}); }.bind(this));
// Remove '_' prefix of attribute names so the DOM won't try // Remove '_' prefix of attribute names so the DOM won't try
// to use them before we've processed the template // to use them before we've processed the template
if (name.charAt(0) === '_') { if (name.charAt(0) === '_') {
@ -128,12 +136,12 @@ Templater.prototype.processNode = function(node, data) {
// Loop through our children calling processNode. First clone them, so the // Loop through our children calling processNode. First clone them, so the
// set of nodes that we visit will be unaffected by additions or removals. // set of nodes that we visit will be unaffected by additions or removals.
var children = Array.prototype.slice.call(node.childNodes); var childNodes = Array.prototype.slice.call(node.childNodes);
for (let j = 0, numChildren = children.length; j < numChildren; j++) { for (var j = 0; j < childNodes.length; j++) {
this.processNode(children[j], data); this.processNode(childNodes[j], data);
} }
if (node.nodeType === Ci.nsIDOMNode.TEXT_NODE) { if (node.nodeType === Node.TEXT_NODE) {
this.processTextNode(node, data); this.processTextNode(node, data);
} }
} finally { } finally {
@ -196,9 +204,7 @@ Templater.prototype.processForEach = function(node, data) {
try { try {
var self = this; var self = this;
// Process a single iteration of a loop // Process a single iteration of a loop
var processSingle = function(member, node, ref) { var processSingle = function(member, clone, ref) {
var clone = node.cloneNode(true);
clone.removeAttribute('foreach');
ref.parentNode.insertBefore(clone, ref); ref.parentNode.insertBefore(clone, ref);
data[paramName] = member; data[paramName] = member;
self.processNode(clone, data); self.processNode(clone, data);
@ -206,29 +212,32 @@ Templater.prototype.processForEach = function(node, data) {
}; };
// processSingle is no good for <loop> nodes where we want to work on // processSingle is no good for <loop> nodes where we want to work on
// the children rather than the node itself // the childNodes rather than the node itself
var processAll = function(scope, member) { var processAll = function(scope, member) {
self.scope.push(scope); self.scope.push(scope);
try { try {
if (node.nodeName === 'loop') { if (node.nodeName.toLowerCase() === 'loop') {
for (let i = 0, numChildren = node.children.length; i < numChildren; i++) { for (var i = 0; i < node.childNodes.length; i++) {
processSingle(member, node.children[i], node); var clone = node.childNodes[i].cloneNode(true);
processSingle(member, clone, node);
} }
} else { } else {
processSingle(member, node, node); var clone = node.cloneNode(true);
clone.removeAttribute('foreach');
processSingle(member, clone, node);
} }
} finally { } finally {
self.scope.pop(); self.scope.pop();
} }
}; };
let reply = this.envEval(value, data, originalValue); var reply = this.envEval(value, data, originalValue);
if (Array.isArray(reply)) { if (Array.isArray(reply)) {
reply.forEach(function(data, i) { reply.forEach(function(data, i) {
processAll('' + i, data) processAll('' + i, data);
}, this); }, this);
} else { } else {
for (let param in reply) { for (var param in reply) {
if (reply.hasOwnProperty(param)) { if (reply.hasOwnProperty(param)) {
processAll(param, param); processAll(param, param);
} }
@ -364,7 +373,8 @@ Templater.prototype.envEval = function(script, env, context) {
this.scope.push(context); this.scope.push(context);
return eval(script); return eval(script);
} catch (ex) { } catch (ex) {
this.handleError('Template error evaluating \'' + script + '\'', ex); this.handleError('Template error evaluating \'' + script + '\'' +
' environment=' + Object.keys(env).join(', '), ex);
return script; return script;
} finally { } finally {
this.scope.pop(); this.scope.pop();