6 ms·
T.js - A tiny templating framework in ~400 bytes
- whalesalad 14y agoThe one thing that sucks about projects with one-char names is finding them weeks after you first discover them, when you really want to experiment with using them in a real project.
- dasil003 14y agopinboard or equivalent.
- mintplant 14y agoThere's always the "Star" button on GitHub. Or, there is now, anyway.
- mcpherrinm 14y agoBrowser bookmarks are a way unrated feature. A descriptive title and you're good to go. Who cares what the name is when your bookmark title has "t.js A tiny javascript templating framework". I already can't remember the name of half the libraries I see even when they are clever and appropriate.
- jamesbritt 14y agoBrowser bookmarks are a way unrated feature. 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.
- deweerdt 14y agoNot to mention googling them.
- vain 14y agofunction 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 http://pastebin.com/txM6NZBS here, to copy and paste
- alexgartrell 14y agorender("{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
- vain 14y agolooks like something broke in copying and pasting. try: http://pastebin.com/txM6NZBS http://pastebin.com/txM6NZBS
- deleted 14y ago[deleted]
- pfraze 14y agofunction 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
- jasonmoo 14y agoI like it. Here's a slightly more stable version. But still not crazy about using eval on arbitrary code. O.O function render(tpl,data){ return tpl.replace(/{([^\}]+)}/g,function(_, key) { try { return eval("data."+key); } catch (e) { return ""; } }); }
- vain 14y agothe code i use in production doesn't use eval, but a recursive function. i like the anonymous function passed to replace, but think the catch destroys code beauty :)
- sharkbrainguy 14y agoYou can achieve the same effect without using eval, which his many known problems in terms of security and performance. 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" } }));
- stcredzero 14y agoI wonder if it would be possible to fit an entire webserver and web framework runtime into L2 cache? (I'm thinking Lua VM or something like that.) EDIT Xeon 3050 has 2MB of L2 cache, so the answer is probably yes!
- novalis 14y agoOut of curiosity, do you get to directly place code on the L2 cache through the Lua VM ? Is that a module ? If so, what is this voodoo and where can I find it...
- stcredzero 14y agoNo, I'm just thinking that one could minimize cache misses a whole lot.
- ars 14y agoYou don't need to store the framework you are sending to clients in the CPU cache - a good network card can read the data directly from disk, or main memory and send it off, bypassing the cpu.
- stcredzero 14y agoThat's useful. I was thinking mainly of the actual server-side app server and not what would count as its payload.
- jfaucett 14y agolooking at the replace chains on s(val) reminded me of something a while back, is there a faster/better way to do this king of stuff? something like: return s(val).replace(re, function(t){ if( t == '>' ) return '>'; if( t == '<' ) return '<'; if( t == '&' ) return '&'; if( t == '"' ) return '"'; return t; });
- jedschmidt 14y agonew Option("<div>in the browser, yes.</div>").innerHTML
- jasonmoo 14y agoOh I like this. I was messing with a similar tactic appending a textNode to an HTML element but this is much more elegant.
- jedschmidt 14y agoThe text node approach is cross-browser, whereas I don't think this works on oldIE.
- jsharpe 14y agoI just tried this and it doesn't seem to escape " to ".
- jfaucett 14y agoyes! awesome snippit :)
- petercooper 14y agoThis isn't for the whole thing, but a common pattern to clean up that inner part could be something like: return { '>': '>', '<': '<', '&': '&', '"': '"' }[t] || t All formatted nicer than that, of course ;-)
- tedunangst 14y agoYou can make it 50% faster by observing that replacing > is unnecessary, and only one of < or " needs replacing in any particular context.
- endlessvoid94 14y agoI'm not sure anyone's ever said "this templating framework is too big"
- EvilTerran 14y agoMaybe when talking about PHP?
- damncabbage 14y agoSmarty PHP? :)
- tjtrapp 14y agocool but what was wrong w mustache or handlebars?
- apendleton 14y agoThe main advantage that I see at first glance is that this library, unlike lots of others (including those two), doesn't use eval or "new Function" to build compiled templates, which meets it meets Chrome's new security requirements for extensions.
- tjtrapp 14y agoi did not know that, kewl!
- riobard 14y agoCan we stop calling these things “frameworks” if they are so lightweight?
- joshschreuder 14y agoNot to play semantics, but "A software framework is a universal, reusable software platform used to develop applications, products and solutions." http://en.wikipedia.org/wiki/Software_framework 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.
- shardling 14y ago>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.
- sakai 14y agoThank you... and sorry for the rant but -- the word "pedantic" is incredibly overused of late on this site. 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.
- shock3naw 14y agoStating his opinion is not being pedantic, quoting the definition to make a point is being pedantic. I think what he's saying has merit; I would call this a utility, or something more along those lines, rather than a framework.
- riobard 14y agoNo, this thing isn't a software platform. You cannot build any applications with this alone. This is a library. We have these precise terms. Don't abuse them.
- thezilch 14y agoAnd a few less-featureful templating-frameworks in 140 bytes or less: http://www.140byt.es/keywords/template http://www.140byt.es/keywords/template Notably, the examples found at https://gist.github.com/964762#file_test.js 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!"
- obituary_latte 14y agoI had to zoom in like 3 times on my phone to vote this up. I know it may be bad form and all to comment on such, but guhdamn if as newb this doesn't wrinkle my britches.
- thezilch 14y agoCouldn't update my original post, but I was in a rush earlier and couldn't make the proper complete-parity examples: http://news.ycombinator.com/item?id=4379417 http://news.ycombinator.com/item?id=4379417
- nreece 14y agoAlso see Tweet-Templ (0.1 kB): http://mir.aculo.us/2011/03/09/little-helpers-a-tweet-sized-javascript-templating-engine/ http://mir.aculo.us/2011/03/09/little-helpers-a-tweet-sized-... More micro-frameworks at http://microjs.com http://microjs.com
- Kilimanjaro 14y agoI use this little helper in my underground lab: 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'
- thezilch 14y agoAlso https://gist.github.com/984375 https://gist.github.com/984375
- VMG 14y agoWatch out for 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 http://stackoverflow.com/a/588276)
- drgath 14y agoWhile true, 'data' should always just be an object-literal. If template() is ever passed an instance of an object, there's something else seriously wrong elsewhere in your script.
- rabidsnail 14y agoThe 80% case: var render = function(src, data) { return src.replace(/{{(.*?)}}/g, function(w, p) { return data[p]; }); };
- rauar 14y agoThis is the 0% case. No escaping and therefore not safe w.r.t. XSS attacks.
- thezilch 14y agoI promised myself I'd show parity with https://gist.github.com/3346253#file_t_js_parity.js https://gist.github.com/3346253#file_t_js_parity.js at http://news.ycombinator.com/item?id=4378847 http://news.ycombinator.com/item?id=4378847, but comments eventually go non-editable. 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"}));
- HugoDias 14y agoAwesome work. Starting to test it right now :)