T.js - A tiny templating framework in ~400 bytes
github.com
github.com
Or, there is now, anyway.
I already can't remember the name of half the libraries I see even when they are clever and appropriate.
Or Catch.com or pinboard.in or similar.
I also tend to print Web pages to PDF and stash them in a Dropbox folder for later review.
function template(str,data){
for(var i in data){
str=str.replace(new RegExp("{("+i+")}","g"),data[i])
}
return str
}
It can be used with arrays and object literals as well: txt = template('hello {name}!',{name:'Jen'})
txt = template('days: {0}, {1} and {2}',['mon','tue','wed'])
GPL and WTFPL just in case.* Looks coincidentally similar to Fuchs'
for (var prop in obj) {}
It may iterate over attributes defined in the objects prototype. The right way to iterate over an object is for(var prop in obj) {
if(obj.hasOwnProperty(prop))
doSomethingWith(obj[prop]);
}
(see http://stackoverflow.com/a/588276)Notably, the examples found at https://gist.github.com/964762#file_test.js has the closest parity.
Edit: On second thought, I think the previous gist can reach parity with just a helper function for iterating and escaping:
function engine(a,b){return function(c,d){return a.replace(/#{([^}]*)}/g,function(a,e){return Function("x","with(x)return "+e).call(c,d||b||{})})}}
function iterator(o, k, f){
var i, v = [];
for(i in o[k]){
v = v.concat(f(o, k, i));
}
return v.join('');
}
function print_kv(o, k, i){
return [" ", i, ":", o[k][i]];
}
hello = engine("Hello,#{iterator(this, 'users', print_user)}!")
// We don't have to pass iterator, on the next line, but it should demonstrate
// how we context can be overwritten
hello({users: {a: 1, b: 2, c:3}}, {iterator: iterator, print_user: print_kv})
// Or don't pass print_user
print_user = print_kv
hello({users: {a: 1, b: 2, c:3}})
// "Hello, a:1 b:2 c:3!"
// Overload it!
hello({users: {a: 1, b: 2, c:3}}, {print_user: function(o, k, i){return " "+i}})
// "Hello, a b c!" var render = function(src, data) {
return src.replace(/{{(.*?)}}/g, function(w, p) {
return data[p];
});
};EDIT Xeon 3050 has 2MB of L2 cache, so the answer is probably yes!
I haven't properly updated the gist fork yet, but as follows are the semi-minified additions [of `safe` and `map` (iter)] and parity tests.
function t(a,b){
return function(c,d){
return a.replace(/#{([^}]*)}/g, function(a,e){
function safe(v){return new Option(v).innerHTML;}
function map(o, f){
var k, v = [];
for(k in o) v.push(f(k, o[k]));
return v;
}
return Function("x",safe+map+"with(x)return "+e).call(c,d||b||{})
})
}
}
function l(v){
console.log(v);
}
// Simple interpolation: {{=value}}
l(t("Hello, #{this.name}!")({name: "Mike"}));
// Scrubbed interpolation: {{%unsafe_value}}
l(t("Saved from #{safe(this.xss)}!")({xss: "<script>alert('xss')<\/script>"}));
// Name-spaced variables: {{=User.address.city}}
l(t("Hello1, #{this.user.name}!")({user: {name: "Mike"}}));
// If/else blocks: {{value}} <<markup>> {{:value}} <<alternate markup>> {{/value}}
l(t("Hello2, #{this.name || 'World'}!")({name: "Mike"}));
l(t("Hello2, #{this.name || 'World'}!")());
l(t("Hello2, #{this.u ? this.u.name : 'World'}!")({u: {name: "Mike"}}));
// If not blocks: {{!value}} <<markup>> {{/value}}
l(t("Hello3, #{!this.u ? 'World' : ''}!")({user: {name: "Mike"}}));
// Object/Array iteration: {{@object_value}} {{=_key}}:{{=_val}} {{/@object_value}}
l(t("Hello4, #{map(this.users, print_user).join(', ')}!", {
print_user: function(k, user){return user;}
})({users: ["Mike", "John", "Bill"]}));
// Maybe you have one of those new-fangled browsers w/ builtin map
l(t("Hello4, #{this.users.map(print_user).join(', ')}!", {
print_user: function(user){return user;}
})({users: ["Mike", "John", "Bill"]}));
// Let's go deeper...
l(t("Hello4, #{map(this.users, user).join(', ')}!", {
user: function(_, user){
return t("#{safe(this.name)}")(user);
}
})({users:[{name: "Mike"}, {name: "John<3"}, {name: "Bill"}]}));
// Render the same template multiple times with different data
hello = t("Hello5, and #{this.goodbye}!");
l(hello({goodbye: "goodbye"}));
l(hello({goodbye: "good night"}));http://en.wikipedia.org/wiki/Software_framework
There's nothing in there about how lightweight they have to be to not be considered a framework, so I think you're being a tad pedantic.
That would make him wrong, not pedantic.
According to some quick Google site: searches:
WORD USE ON HACKER NEWS
pedantic 3340
thoughtful 3750
f*** 9930
idiot 6180
Which seems quite frequent, but is obviously highly anecdotal. On the other hand, it appearing 1/3 as much as f* may indicate that this is at least a fairly civil community -- even if prone to pedantry.Edit: formatting.
function render(tpl,data){
var matches = tpl.match(/{[^\}]+}/g);
for(var i in matches){
var rep = eval("data."+matches[i].replace('{','').replace('}',''));
tpl = tpl.replace(matches[i],rep);
}
return tpl;
}
alert(render("{a} is all that i've {b.a} {b.b} {b.c}", {a:"this", b:{a:"ever",b:"really",c:"needed"} }))
http://pastebin.com/txM6NZBS here, to copy and paste render("{a} is all that I've {a}", {'a' : 'b'});
"b is all that I've b"
render("{a} is all that I've {{a}}", {'a' : 'b'});
SyntaxError: Unexpected token {
Seems Legit function render(tpl,data){
var matches = tpl.match(/{[^\}]+}/g);
for(var i in matches){
var rep = eval("data."+matches[i].replace(/[{}]/g,''));
tpl = tpl.replace(matches[i],rep);
}
return tpl;
}
Fixed function render(tpl,data){
return tpl.replace(/{([^\}]+)}/g,function(_, key) {
try { return eval("data."+key); }
catch (e) { return ""; }
});
} function render(tpl,data){
function lookup (obj, keys) {
return (keys.length === 0) ? obj
: lookup(obj[keys[0]], keys.slice(1));
}
var matches = tpl.match(/\{[^\}]+\}/g),
max = matches.length,
i, rep, keys;
for (i = 0; i < max; i++) {
keys = matches[i].slice(1, -1).split('.');
rep = lookup(data, keys);
tpl = tpl.replace(matches[i],rep);
}
return tpl;
}
alert(render("{a} is all that i've {b.a} {b.b} {b.c}", {
a: "this",
b: {
a: "ever",
b: "really",
c: "needed"
}
}));More micro-frameworks at http://microjs.com
return s(val).replace(re, function(t){
if( t == '>' ) return '>';
if( t == '<' ) return '<';
if( t == '&' ) return '&';
if( t == '"' ) return '"';
return t;
}); new Option("<div>in the browser, yes.</div>").innerHTML return { '>': '>', '<': '<', '&': '&', '"': '"' }[t] || t
All formatted nicer than that, of course ;-)