|
|
var CompiledTemplate = Class.create();
Object.extend(CompiledTemplate, {
tagSplitter: /(\{(?:\$|\/?[a-z]{2,16}).*?\})/,
tagMatcher: /^\{(\$|\/?[a-z]{2,16})(.*?)\}$/,
varToken: '$'
});
CompiledTemplate.prototype = {
initialize: function(template, options) {
if (template) {
this.compile(template.toString(), options || {});
}
},
compile: function(template, options) {
this.assignments = {};
options = options || {};
var tagSplitter = options.tagSplitter || CompiledTemplate.tagSplitter;
var tagMatcher = options.tagMatcher || CompiledTemplate.tagMatcher;
this.varToken = options.varToken || CompiledTemplate.varToken;
this.varTokenGlobal = new RegExp('\\' + this.varToken, 'g');
this.compiled = '';
var spaceAt, match;
if (Prototype.Browser.IE || Prototype.Browser.WebKit) {
var stack = [],
match;
while (template.length > 0) {
if (match = template.match(tagSplitter)) {
stack.push(template.slice(0, match.index));
stack.push(template.slice(match.index, match.index + match[0].length));
template = template.slice(match.index + match[0].length);
} else {
stack.push(template);
template = '';
}
}
} else {
var stack = template.split(tagSplitter);
}
for (var i = 0,
length = stack.length; i < length; ++i) {
match = tagMatcher.exec(stack[i]);
if (match) {
if (match[1] == this.varToken) {
this.compiled += this.handlers._variable(match[2], this);
} else {
if (this.handlers[match[1]]) {
this.compiled += this.handlers[match[1]](match[2].substring(1), this);
} else {
throw new Exception('CompiledTemplate Exception: tag name "' + match[1] + '" not recognized by tag handler');
}
}
} else if (stack[i] != '') {
this.compiled += this.handlers._content(stack[i], this);
}
}
},
handlers: {
'_variable': function(name) {
return "output += object." + name + "===undefined ? '' : object." + name + ";\n";
},
'_content': function(content) {
return "output += '" + content.replace(/\n/g, " ").replace(/\r/g, " ").replace(/\\/g, "\\\\").replace(/\'/g, "\\'").replace(/\r/g, "\\r").replace(/\n/g, "\\n") + "';\n";
},
'if': function(expression, instance) {
return 'if (' + expression.replace(instance.varTokenGlobal, 'object.') + ') {\n';
},
'elseif': function(expression, instance) {
return '} else if (' + expression.replace(instance.varTokenGlobal, 'object.') + ') {\n';
},
'else': function() {
return '} else {\n';
},
'/if': function() {
return '}\n';
},
'foreach': function(options, instance) {
var tokenSize = instance.varToken.length;
var compiled = '';
var type = options.split(' in ');
if (type[1]) {
var alias = type[1].split(' as ');
compiled += 'for (var property in object.' + alias[0].substring(tokenSize) + ') {\n';
compiled += 'object.' + alias[0].substring(tokenSize) + ' = property;\n';
if (alias[1]) {
compiled += 'object.' + alias[1].substring(tokenSize) + ' = object.' + type[0].substring(tokenSize) + '[property];\n';
}
} else {
var alias = type[0].split(' as ');
compiled += 'for (var i=0, len=(object.' + alias[0].substring(tokenSize) + ' ? object.' + alias[0].substring(tokenSize) + '.length : 0); i ');
if (pair[1]) {
compiled += 'object.' + pair.shift().substring(tokenSize) + ' = i;\n';
}
compiled += 'object.' + pair[0].substring(tokenSize) + ' = object.' + alias[0].substring(1) + '[i];\n';
}
}
return compiled;
},
'/foreach': function() {
return '}\n';
}
},
assign: function(name, value) {
this.assignments[name] = value;
return this;
},
unassign: function(name) {
if (this.assignments[name] !== undefined) {
delete this.assignments[name];
}
return this;
},
unassignAll: function() {
this.assignments = {};
return this;
},
setHandler: function(name, callback) {
this.handlers[name] = callback;
return this;
},
evaluate: function(object) {
object = Object.extend(object || {},
this.assignments);
output = '';
eval(this.compiled);
return output;
}
};
// usage
var tpl = "| {$name} | {$phone} | \n";
var td = new CompiledTemplate(tpl);
var people = [
{name: 'John Doe', phone: '555-555-5555'},
{name: 'James Smith', phone: '555-555-6666'},
{name: 'William Johnson', phone: '555-555-7777'}
];
var html = people.inject('', function(memo, entry) {
return memo += td.evaluate(entry);
});
$('mytable').update(html);
|