Skip to content

Commit

Permalink
Views can now have deferred properties.
Browse files Browse the repository at this point in the history
I need this functionality for a sub-project, and it wasn't sensible to
make changes without tests!
  • Loading branch information
EdJ committed Jun 13, 2013
1 parent 2fe09fe commit e866c08
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 26 deletions.
53 changes: 27 additions & 26 deletions Views/viewParser.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,39 @@
// This is based on John Resig's tiny template engine.
// I grabbed the code off Rick Strahl's weblog: http://www.west-wind.com/weblog/posts/2008/Oct/13/Client-Templating-with-jQuery
// Edited to work a bit better with node (we don't have DOM in this context).

ViewParser = module.exports ={
cache : {},

parse : function(name, unParsedTemplate) {
if (this.cache[name]) {
return this.cache[name];
}
// Edited to allow the view function to include the results of deferreds.

ViewParser = module.exports = {
parse: function(name, unParsedTemplate) {
var extracted = this.extractProperties(unParsedTemplate);

var properties = extracted.properties;
var template = extracted.template;

var str = "var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+
var str = "var d = new Deferred();var dC = 0;var p=[]," +
"stackDeferred=function(index){ dC++;return function (r) { p[index] = r; dC--; if(!dC) {d.complete(p.join(''));}}}" +
",print=function(){p.push.apply(p,arguments);};with(obj){p.push('" +

// Now a big crazy Regex.
template.replace(/[\r\t\n]/g," ")
.replace(/'(?=[^%]*%>)/g,"\t")
.split("'").join("\\'")
.split("\t").join("'")
.replace(/<%=(.+?)%>/g,"',$1,'")
.split("<%").join("');")
.split("%>").join("p.push('")
+ "');}return p.join('');";
template.replace(/[\r\t\n]/g, " ")
.replace(/'(?=[^%]*%>)/g, "\t")
.split("'").join("\\'")
.split("\t").join("'")
.replace(/<%=(.+?)%>/g, "');if ($1 instanceof Deferred){$1.onComplete(stackDeferred(p.length));p.push('');}else{p.push($1);}p.push('")
.split("<%").join("');")
.split("%>").join("p.push('")

+ "');}if (!dC) {d.complete(p.join(''));}return d;";

var fn = new Function("obj", str);
var output = { properties : properties, view : fn };
this.cache[name] = output;
var output = {
properties: properties,
view: fn
};

return output;
},

extractProperties : function (viewText) {
extractProperties: function(viewText) {
var template = viewText;

var unParsedProperties = '';
Expand All @@ -46,13 +44,16 @@ ViewParser = module.exports ={
var toParse = viewText.substr(i, e + 2);
template = viewText.substr(e + 2);

unParsedProperties += toParse.replace(/<%!(.+?)%>/g,"$1") + ',';
unParsedProperties += toParse.replace(/<%!(.+?)%>/g, "$1") + ',';
}

unParsedProperties = unParsedProperties.substr(0, unParsedProperties.length -2);
unParsedProperties = unParsedProperties.substr(0, unParsedProperties.length - 2);

properties = new Function("obj", "return {" + unParsedProperties + "};")();

return { properties : properties, template : template };
return {
properties: properties,
template: template
};
}
};
};
106 changes: 106 additions & 0 deletions test/VIews/viewParser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
describe('ViewParser', function() {
var viewParser;
beforeEach(function() {
viewParser = require('../../Views/viewParser');
});

describe('parse', function() {
it('should return an empty string for an empty view.', function(done) {
var result = viewParser.parse('testViewName', '');

result.properties.should.eql([]);

var deferred = result.view({});

deferred.onComplete(function(resultHtml) {
resultHtml.should.equal('');

done();
});
});

it('should return raw HTML from a view with no properties.', function(done) {
var result = viewParser.parse('testViewName', '<html></html>');

result.properties.should.eql([]);

var deferred = result.view({});

deferred.onComplete(function(resultHtml) {
resultHtml.should.equal('<html></html>');

done();
});
});

it('should return just a variable for a view with only a bound variable.', function(done) {
var result = viewParser.parse('testViewName', '<%= test %>');

result.properties.should.eql([]);

var deferred = result.view({
test: 'Some data.'
});

deferred.onComplete(function(resultHtml) {
resultHtml.should.equal('Some data.');

done();
});
});

it('should return a variable embedded in HTML for a complex view.', function(done) {
var result = viewParser.parse('testViewName', '<div><%= test %></div>');

result.properties.should.eql([]);

var deferred = result.view({
test: 'Some data.'
});

deferred.onComplete(function(resultHtml) {
resultHtml.should.equal('<div>Some data.</div>');

done();
});
});

it('should allow arbitrary code in a view.', function(done) {
var result = viewParser.parse('testViewName', '<div><% if (showTest) { %><%= test %><% } %></div>');

result.properties.should.eql([]);

var deferred = result.view({
test: 'Some data.',
showTest: false
});

deferred.onComplete(function(resultHtml) {
resultHtml.should.equal('<div></div>');

done();
});
});

it('should wait for the result of a deferred parameter.', function(done) {
var result = viewParser.parse('testViewName', '<div><% if (showTest) { %><%= test %><% } %></div>');

result.properties.should.eql([]);

var testDeferred = new Deferred();

var deferred = result.view({
test: testDeferred,
showTest: true
});

deferred.onComplete(function(resultHtml) {
resultHtml.should.equal('<div>Some data.</div>');

done();
});

testDeferred.complete('Some data.');
});
});
});

0 comments on commit e866c08

Please sign in to comment.