A template engine in 42 lines of code.
I was thinking of a way to generate HTML without using strings as embedding strings in Javascript is a pain if they are multi-lined. There isn't a nice triple quote like there exists in Python.
So I took my inspiration from Lisp HTML generators that use S-expressions to generate HTML. I thought, hell, S-expressions are just a bunch of nested lists, I could do the same thing in Javascript.
So here's the result. It's not sure if it's a good idea or not, but "Let's not concentrate on whether it's a good idea or not".
crazy_template starts with a single list and transforms that into a DOM Element:
["div"]
Would become:
<div></div>
To set attributes on the element:
["div", {"class": "example"}]
To set the CDATA of the element:
["div", {"class": "example"}, "I am a div."]
To produce nested elemests, you simple nest these arrays:
["div", {"class": "example"}, "I am a div. ", ["em", "My spoon is too big!"] ["a", {"href": "http://www.youtube.com/watch?v=MuOvqeABHvQ"}, " I am a banana."] ]
The final result is this:
<div class="example"> I am a div. <em>My spoon is too big!</em> <a href="http://www.youtube.com/watch?v=MuOvqeABHvQ">I am a banana.</a> </div>
What's the use of a templating engine if you can't insert data into that template? Obviously this template engine supports dynamic creation of elements. It is accomplished by using a function:
var tmpl = ["ul", function(data, callback) { for(var i = 0; i < items.length; i++) { callback(["li", items[i]]); } }] var el = crazy_template(tmpl, ["one", "two", "three"]);
The callback is called every time you want to add a child node. Because the callback accepts a node list, you can create templates that use other templates:
var post_tmpl = ["div", {"class": "post"}, function(post, callback) { callback(["div", {"class": "entry-title"}, ["a", {"href": post.url}, post.title]]); callback(["div", {"class": "entry-summary"}, post.summary]); }]; var post_list = ["div", {"class": "hfeed"}, function(post_list, callback) { for(var i = 0; i < post_list.length; i++) { callback(post_tmpl, post_list[i]); } }];
You can even build the children asynchronously if you're wild like that:
var post_list = ["div", {"class": "hfeed"}, function(_, callback) { jQuery.getJSON("/feed/entries.json", function(post_list) { for(var i = 0; i < post_list.length; i++) { callback(post_tmpl, post_list[i]); } }); }];
The child nodes will magically appear when the JSON data is loaded. It's pretty snazzy.