| @@ -2,3 +2,4 @@ runner.js | |||
| jquery.mustache.js | |||
| dojox | |||
| yui3 | |||
| commonjs.mustache.js | |||
| @@ -2,6 +2,11 @@ | |||
| ## 0.3.0 (??-??-????) | |||
| * Fix Rhino compat. | |||
| * CommonJS packaging is no longer a special case. | |||
| * DRY Rakefile. | |||
| * Allow whitespace around tag names. | |||
| * Fix partial scope. | |||
| * Fix Comments. | |||
| * Added inverted sections. | |||
| * Avoid double encoding of entities. | |||
| @@ -9,7 +14,6 @@ | |||
| * Added higher order sections. | |||
| ## 0.2.3 (28-03-2010) | |||
| * Better error message for missing partials. | |||
| @@ -11,44 +11,46 @@ end | |||
| desc "Run all specs" | |||
| task :spec | |||
| desc "Package for CommonJS" | |||
| task :commonjs do | |||
| puts "Packaging for CommonJS" | |||
| `mkdir lib` | |||
| `cp mustache.js lib/mustache.js` | |||
| puts "Done." | |||
| def templated_build(name, opts={}) | |||
| # Create a rule that uses the .tmpl.{pre,post} stuff to make a final, | |||
| # wrapped, output file. | |||
| # There is some extra complexity because Dojo and YUI3 use different | |||
| # template files and final locations. | |||
| short = name.downcase | |||
| source = "mustache-#{short}" | |||
| dependencies = ["mustache.js"] + Dir.glob("#{source}/*.tpl.*") | |||
| desc "Package for #{name}" | |||
| task short.to_sym => dependencies do | |||
| target_js = opts[:location] ? "mustache.js" : "#{short}.mustache.js" | |||
| puts "Packaging for #{name}" | |||
| sh "mkdir -p #{opts[:location]}" if opts[:location] | |||
| sh "cat #{source}/#{target_js}.tpl.pre mustache.js \ | |||
| #{source}/#{target_js}.tpl.post > #{opts[:location] || '.'}/#{target_js}" | |||
| # extra | |||
| if opts[:extra] | |||
| sh "sed -e 's/{{version}}/#{version}/' #{source}/#{opts[:extra]} \ | |||
| > #{opts[:location]}/#{opts[:extra]}" | |||
| end | |||
| puts "Done, see #{opts[:location] || '.'}/#{target_js}" | |||
| end | |||
| end | |||
| desc "Package for jQuery" | |||
| task :jquery do | |||
| puts "Packaging for jQuery" | |||
| source = "mustache-jquery" | |||
| target_jq = "jquery.mustache.js" | |||
| `cat #{source}/#{target_jq}.tpl.pre mustache.js #{source}/#{target_jq}.tpl.post > #{target_jq}` | |||
| puts "Done, see ./#{target_jq}" | |||
| end | |||
| templated_build "CommonJS", :location => "lib", :extra => "package.json" | |||
| templated_build "jQuery" | |||
| templated_build "Dojo", :location => "dojox/string" | |||
| templated_build "YUI3", :location => "yui3/mustache" | |||
| desc "Package for dojo" | |||
| task :dojo do | |||
| puts "Packaging for dojo" | |||
| source = "mustache-dojo" | |||
| target_js = "mustache.js" | |||
| `mkdir -p dojox; mkdir -p dojox/string` | |||
| `cat #{source}/#{target_js}.tpl.pre mustache.js #{source}/#{target_js}.tpl.post > dojox/string/#{target_js}` | |||
| puts "Done, see ./dojox/string/#{target_js} Include using dojo.require('dojox.string.mustache.'); " | |||
| def version | |||
| File.read("mustache.js").match('version: "([^\"]+)",$')[1] | |||
| end | |||
| desc "Package for YUI3" | |||
| task :yui3 do | |||
| puts "Packaging for YUI3" | |||
| source = "mustache-yui3" | |||
| target_js = "mustache.js" | |||
| `mkdir -p yui3; mkdir -p yui3/mustache` | |||
| `cat #{source}/#{target_js}.tpl.pre mustache.js #{source}/#{target_js}.tpl.post > yui3/mustache/#{target_js}` | |||
| puts "Done, see ./yui3/mustache/#{target_js}" | |||
| end | |||
| desc "Remove temporary files." | |||
| task :clean do | |||
| `git clean -fdx` | |||
| sh "git clean -fdx" | |||
| end | |||
| @@ -16,3 +16,5 @@ Mustache.js wouldn't kick ass if it weren't for these fine souls: | |||
| * Will Leinweber / will | |||
| * dpree | |||
| * Jason Smith / jhs | |||
| * Aaron Gibralter / agibralter | |||
| * Ross Boucher / boucher | |||
| @@ -0,0 +1 @@ | |||
| {{.}} | |||
| @@ -0,0 +1,5 @@ | |||
| Here is some stuff! | |||
| {{%IMPLICIT-ITERATOR}} | |||
| {{#numbers}} | |||
| {{>partial}} | |||
| {{/numbers}} | |||
| @@ -0,0 +1,3 @@ | |||
| var partial_context = { | |||
| numbers: ['1', '2', '3', '4'] | |||
| }; | |||
| @@ -0,0 +1,5 @@ | |||
| Here is some stuff! | |||
| 1 | |||
| 2 | |||
| 3 | |||
| 4 | |||
| @@ -0,0 +1 @@ | |||
| {{i}} | |||
| @@ -0,0 +1,4 @@ | |||
| Here is some stuff! | |||
| {{#numbers}} | |||
| {{>partial}} | |||
| {{/numbers}} | |||
| @@ -0,0 +1,3 @@ | |||
| var partial_context = { | |||
| numbers: [{i: '1'}, {i: '2'}, {i: '3'}, {i: '4'}] | |||
| }; | |||
| @@ -0,0 +1,5 @@ | |||
| Here is some stuff! | |||
| 1 | |||
| 2 | |||
| 3 | |||
| 4 | |||
| @@ -0,0 +1 @@ | |||
| {{tag}} foo | |||
| @@ -0,0 +1,3 @@ | |||
| var bug_11_eating_whitespace = { | |||
| tag: "yo" | |||
| }; | |||
| @@ -0,0 +1 @@ | |||
| yo foo | |||
| @@ -0,0 +1,4 @@ | |||
| {{name}} | |||
| {{#children}} | |||
| {{>partial}} | |||
| {{/children}} | |||
| @@ -0,0 +1,4 @@ | |||
| {{name}} | |||
| {{#kids}} | |||
| {{>partial}} | |||
| {{/kids}} | |||
| @@ -0,0 +1,11 @@ | |||
| var partial_context = { | |||
| name: '1', | |||
| kids: [ | |||
| { | |||
| name: '1.1', | |||
| children: [ | |||
| {name: '1.1.1'} | |||
| ] | |||
| } | |||
| ] | |||
| }; | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | |||
| 1.1 | |||
| 1.1.1 | |||
| @@ -0,0 +1,5 @@ | |||
| Hello {{ name}} | |||
| You have just won ${{value }}! | |||
| {{# in_ca }} | |||
| Well, ${{ taxed_value }}, after taxes. | |||
| {{/ in_ca }} | |||
| @@ -0,0 +1,3 @@ | |||
| <h1>{{ greeting }}</h1> | |||
| {{> partial }} | |||
| <h3>{{ farewell }}</h3> | |||
| @@ -0,0 +1,19 @@ | |||
| var partial_context = { | |||
| greeting: function() { | |||
| return "Welcome"; | |||
| }, | |||
| farewell: function() { | |||
| return "Fair enough, right?"; | |||
| }, | |||
| partial: { | |||
| name: "Chris", | |||
| value: 10000, | |||
| taxed_value: function() { | |||
| return this.value - (this.value * 0.4); | |||
| }, | |||
| in_ca: true | |||
| } | |||
| }; | |||
| @@ -0,0 +1,6 @@ | |||
| <h1>Welcome</h1> | |||
| Hello Chris | |||
| You have just won $10000! | |||
| Well, $6000, after taxes. | |||
| <h3>Fair enough, right?</h3> | |||
| @@ -1,296 +0,0 @@ | |||
| /* | |||
| mustache.js — Logic-less templates in JavaScript | |||
| See http://mustache.github.com/ for more info. | |||
| */ | |||
| var Mustache = function() { | |||
| var Renderer = function() {}; | |||
| Renderer.prototype = { | |||
| otag: "{{", | |||
| ctag: "}}", | |||
| pragmas: {}, | |||
| buffer: [], | |||
| pragmas_implemented: { | |||
| "IMPLICIT-ITERATOR": true | |||
| }, | |||
| render: function(template, context, partials, in_recursion) { | |||
| // fail fast | |||
| if(template.indexOf(this.otag) == -1) { | |||
| if(in_recursion) { | |||
| return template; | |||
| } else { | |||
| this.send(template); | |||
| return; | |||
| } | |||
| } | |||
| if(!in_recursion) { | |||
| this.buffer = []; | |||
| } | |||
| template = this.render_pragmas(template); | |||
| var html = this.render_section(template, context, partials); | |||
| if(in_recursion) { | |||
| return this.render_tags(html, context, partials, in_recursion); | |||
| } | |||
| this.render_tags(html, context, partials, in_recursion); | |||
| }, | |||
| /* | |||
| Sends parsed lines | |||
| */ | |||
| send: function(line) { | |||
| if(line != "") { | |||
| this.buffer.push(line); | |||
| } | |||
| }, | |||
| /* | |||
| Looks for %PRAGMAS | |||
| */ | |||
| render_pragmas: function(template) { | |||
| // no pragmas | |||
| if(template.indexOf(this.otag + "%") == -1) { | |||
| return template; | |||
| } | |||
| var that = this; | |||
| var regex = new RegExp(this.otag + "%([\\w_-]+) ?([\\w]+=[\\w]+)?" | |||
| + this.ctag); | |||
| return template.replace(regex, function(match, pragma, options) { | |||
| if(!that.pragmas_implemented[pragma]) { | |||
| throw({message: "This implementation of mustache doesn't understand the '" | |||
| + pragma + "' pragma"}); | |||
| } | |||
| that.pragmas[pragma] = {}; | |||
| if(options) { | |||
| var opts = options.split("="); | |||
| that.pragmas[pragma][opts[0]] = opts[1]; | |||
| } | |||
| return ""; | |||
| // ignore unknown pragmas silently | |||
| }); | |||
| }, | |||
| /* | |||
| Tries to find a partial in the global scope and render it | |||
| */ | |||
| render_partial: function(name, context, partials) { | |||
| if(!partials || !partials[name]) { | |||
| throw({message: "unknown_partial '" + name + "'"}); | |||
| } | |||
| if(typeof(context[name]) != "object") { | |||
| return partials[name]; | |||
| } | |||
| return this.render(partials[name], context[name], partials, true); | |||
| }, | |||
| /* | |||
| Renders boolean and enumerable sections | |||
| */ | |||
| render_section: function(template, context, partials) { | |||
| if(template.indexOf(this.otag + "#") == -1) { | |||
| return template; | |||
| } | |||
| var that = this; | |||
| // CSW - Added "+?" so it finds the tighest bound, not the widest | |||
| var regex = new RegExp(this.otag + "\\#(.+)" + this.ctag + | |||
| "\\s*([\\s\\S]+?)" + this.otag + "\\/\\1" + this.ctag + "\\s*", "mg"); | |||
| // for each {{#foo}}{{/foo}} section do... | |||
| return template.replace(regex, function(match, name, content) { | |||
| var value = that.find(name, context); | |||
| if(that.is_array(value)) { // Enumerable, Let's loop! | |||
| return that.map(value, function(row) { | |||
| return that.render(content, that.merge(context, | |||
| that.create_context(row)), partials, true); | |||
| }).join(""); | |||
| } else if(value) { // boolean section | |||
| return that.render(content, context, partials, true); | |||
| } else { | |||
| return ""; | |||
| } | |||
| }); | |||
| }, | |||
| /* | |||
| Replace {{foo}} and friends with values from our view | |||
| */ | |||
| render_tags: function(template, context, partials, in_recursion) { | |||
| // tit for tat | |||
| var that = this; | |||
| var new_regex = function() { | |||
| return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\/#]+?)\\1?" + | |||
| that.ctag + "+", "g"); | |||
| }; | |||
| var regex = new_regex(); | |||
| var lines = template.split("\n"); | |||
| for (var i=0; i < lines.length; i++) { | |||
| lines[i] = lines[i].replace(regex, function(match, operator, name) { | |||
| switch(operator) { | |||
| case "!": // ignore comments | |||
| return match; | |||
| case "=": // set new delimiters, rebuild the replace regexp | |||
| that.set_delimiters(name); | |||
| regex = new_regex(); | |||
| return ""; | |||
| case ">": // render partial | |||
| return that.render_partial(name, context, partials); | |||
| case "{": // the triple mustache is unescaped | |||
| return that.find(name, context); | |||
| default: // escape the value | |||
| return that.escape(that.find(name, context)); | |||
| } | |||
| }, this); | |||
| if(!in_recursion) { | |||
| this.send(lines[i]); | |||
| } | |||
| } | |||
| if(in_recursion) { | |||
| return lines.join("\n"); | |||
| } | |||
| }, | |||
| set_delimiters: function(delimiters) { | |||
| var dels = delimiters.split(" "); | |||
| this.otag = this.escape_regex(dels[0]); | |||
| this.ctag = this.escape_regex(dels[1]); | |||
| }, | |||
| escape_regex: function(text) { | |||
| // thank you Simon Willison | |||
| if(!arguments.callee.sRE) { | |||
| var specials = [ | |||
| '/', '.', '*', '+', '?', '|', | |||
| '(', ')', '[', ']', '{', '}', '\\' | |||
| ]; | |||
| arguments.callee.sRE = new RegExp( | |||
| '(\\' + specials.join('|\\') + ')', 'g' | |||
| ); | |||
| } | |||
| return text.replace(arguments.callee.sRE, '\\$1'); | |||
| }, | |||
| /* | |||
| find `name` in current `context`. That is find me a value | |||
| from the view object | |||
| */ | |||
| find: function(name, context) { | |||
| name = this.trim(name); | |||
| if(typeof context[name] === "function") { | |||
| return context[name].apply(context); | |||
| } | |||
| if(context[name] !== undefined) { | |||
| return context[name]; | |||
| } | |||
| // silently ignore unkown variables | |||
| return ""; | |||
| }, | |||
| // Utility methods | |||
| /* | |||
| Does away with nasty characters | |||
| */ | |||
| escape: function(s) { | |||
| return ((s == null) ? "" : s).toString().replace(/[&"<>\\]/g, function(s) { | |||
| switch(s) { | |||
| case "&": return "&"; | |||
| case "\\": return "\\\\";; | |||
| case '"': return '\"';; | |||
| case "<": return "<"; | |||
| case ">": return ">"; | |||
| default: return s; | |||
| } | |||
| }); | |||
| }, | |||
| /* | |||
| Merges all properties of object `b` into object `a`. | |||
| `b.property` overwrites a.property` | |||
| */ | |||
| merge: function(a, b) { | |||
| var _new = {}; | |||
| for(var name in a) { | |||
| if(a.hasOwnProperty(name)) { | |||
| _new[name] = a[name]; | |||
| } | |||
| }; | |||
| for(var name in b) { | |||
| if(b.hasOwnProperty(name)) { | |||
| _new[name] = b[name]; | |||
| } | |||
| }; | |||
| return _new; | |||
| }, | |||
| // by @langalex, support for arrays of strings | |||
| create_context: function(_context) { | |||
| if(this.is_object(_context)) { | |||
| return _context; | |||
| } else if(this.pragmas["IMPLICIT-ITERATOR"]) { | |||
| var iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator || "."; | |||
| var ctx = {}; | |||
| ctx[iterator] = _context; | |||
| return ctx; | |||
| } | |||
| }, | |||
| is_object: function(a) { | |||
| return a && typeof a == "object"; | |||
| }, | |||
| is_array: function(a) { | |||
| return Object.prototype.toString.call(a) === '[object Array]'; | |||
| }, | |||
| /* | |||
| Gets rid of leading and trailing whitespace | |||
| */ | |||
| trim: function(s) { | |||
| return s.replace(/^\s*|\s*$/g, ""); | |||
| }, | |||
| /* | |||
| Why, why, why? Because IE. Cry, cry cry. | |||
| */ | |||
| map: function(array, fn) { | |||
| if (typeof array.map == "function") { | |||
| return array.map(fn); | |||
| } else { | |||
| var r = []; | |||
| var l = array.length; | |||
| for(var i=0;i<l;i++) { | |||
| r.push(fn(array[i])); | |||
| } | |||
| return r; | |||
| } | |||
| } | |||
| }; | |||
| return({ | |||
| name: "mustache.js", | |||
| version: "0.2.3", | |||
| /* | |||
| Turns a template and view into HTML | |||
| */ | |||
| to_html: function(template, view, partials, send_fun) { | |||
| var renderer = new Renderer(); | |||
| if(send_fun) { | |||
| renderer.send = send_fun; | |||
| } | |||
| renderer.render(template, view, partials); | |||
| if(!send_fun) { | |||
| return renderer.buffer.join("\n"); | |||
| } | |||
| } | |||
| }); | |||
| }(); | |||
| @@ -0,0 +1,7 @@ | |||
| exports.name = Mustache.name; | |||
| exports.version = Mustache.version; | |||
| exports.to_html = function() { | |||
| return Mustache.to_html.apply(this, arguments); | |||
| }; | |||
| @@ -0,0 +1,6 @@ | |||
| /* | |||
| * CommonJS-compatible mustache.js module | |||
| * | |||
| * See http://github.com/janl/mustache.js for more info. | |||
| */ | |||
| @@ -0,0 +1,7 @@ | |||
| { | |||
| "name": "mustache", | |||
| "author": "http://mustache.github.com/", | |||
| "description": "{{ mustache }} in JavaScript — Logic-less templates.", | |||
| "keywords": ["template"], | |||
| "version": "{{version}}" | |||
| } | |||
| @@ -15,12 +15,15 @@ var Mustache = function() { | |||
| pragmas_implemented: { | |||
| "IMPLICIT-ITERATOR": true | |||
| }, | |||
| context: {}, | |||
| render: function(template, context, partials, in_recursion) { | |||
| // reset buffer | |||
| // TODO: make this non-lazy | |||
| if(!in_recursion) | |||
| this.buffer = []; | |||
| // reset buffer & set context | |||
| if(!in_recursion) { | |||
| this.context = context; | |||
| this.buffer = []; // TODO: make this non-lazy | |||
| } | |||
| // fail fast | |||
| if(!this.includes("", template)) { | |||
| if(in_recursion) { | |||
| @@ -31,10 +34,6 @@ var Mustache = function() { | |||
| } | |||
| } | |||
| if(!in_recursion) { | |||
| this.buffer = []; | |||
| } | |||
| template = this.render_pragmas(template); | |||
| var html = this.render_section(template, context, partials); | |||
| if(in_recursion) { | |||
| @@ -63,12 +62,13 @@ var Mustache = function() { | |||
| } | |||
| var that = this; | |||
| var regex = new RegExp(this.otag + "%([\\w_-]+) ?([\\w]+=[\\w]+)?" | |||
| + this.ctag); | |||
| var regex = new RegExp(this.otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + | |||
| this.ctag); | |||
| return template.replace(regex, function(match, pragma, options) { | |||
| if(!that.pragmas_implemented[pragma]) { | |||
| throw({message: "This implementation of mustache doesn't understand the '" | |||
| + pragma + "' pragma"}); | |||
| throw({message: | |||
| "This implementation of mustache doesn't understand the '" + | |||
| pragma + "' pragma"}); | |||
| } | |||
| that.pragmas[pragma] = {}; | |||
| if(options) { | |||
| @@ -81,14 +81,17 @@ var Mustache = function() { | |||
| }, | |||
| /* | |||
| Tries to find a partial in the global scope and render it | |||
| Tries to find a partial in the curent scope and render it | |||
| */ | |||
| render_partial: function(name, context, partials) { | |||
| name = this.trim(name); | |||
| if(!partials || !partials[name]) { | |||
| throw({message: "unknown_partial '" + name + "'"}); | |||
| } | |||
| return this.render(partials[name], context, partials, true); | |||
| if(typeof(context[name]) != "object") { | |||
| return this.render(partials[name], context, partials, true); | |||
| } | |||
| return this.render(partials[name], context[name], partials, true); | |||
| }, | |||
| /* | |||
| @@ -101,15 +104,15 @@ var Mustache = function() { | |||
| var that = this; | |||
| // CSW - Added "+?" so it finds the tighest bound, not the widest | |||
| var regex = new RegExp(this.otag + "(\\^|\\#)(.+)" + this.ctag + | |||
| "\\s*([\\s\\S]+?)" + this.otag + "\\/\\2" + this.ctag + | |||
| var regex = new RegExp(this.otag + "(\\^|\\#)\\s*(.+)\\s*" + this.ctag + | |||
| "\\s*([\\s\\S]+?)" + this.otag + "\\/\\s*\\2\\s*" + this.ctag + | |||
| "\\s*", "mg"); | |||
| // for each {{#foo}}{{/foo}} section do... | |||
| return template.replace(regex, function(match, type, name, content) { | |||
| var value = that.find(name, context); | |||
| if(type == "^") { // inverted section | |||
| if(!value || that.is_array(value) && value.length == 0) { | |||
| if(!value || that.is_array(value) && value.length === 0) { | |||
| // false or empty list, render it | |||
| return that.render(content, context, partials, true); | |||
| } else { | |||
| @@ -118,17 +121,17 @@ var Mustache = function() { | |||
| } else if(type == "#") { // normal section | |||
| if(that.is_array(value)) { // Enumerable, Let's loop! | |||
| return that.map(value, function(row) { | |||
| return that.render(content, that.merge(context, | |||
| that.create_context(row)), partials, true); | |||
| return that.render(content, that.create_context(row), | |||
| partials, true); | |||
| }).join(""); | |||
| } else if(that.is_object(value)) { // Object, Use it as subcontext! | |||
| return that.render(content, | |||
| that.merge(context, that.create_context(value)), partials, true); | |||
| return that.render(content, that.create_context(value), | |||
| partials, true); | |||
| } else if(typeof value === "function") { | |||
| // higher order section | |||
| return value.call(context, content, function(text) { | |||
| return that.render(text, context, partials, true); | |||
| }) | |||
| }); | |||
| } else if(value) { // boolean section | |||
| return that.render(content, context, partials, true); | |||
| } else { | |||
| @@ -146,37 +149,38 @@ var Mustache = function() { | |||
| var that = this; | |||
| var new_regex = function() { | |||
| return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\/#\^]+?)\\1?" + | |||
| return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" + | |||
| that.ctag + "+", "g"); | |||
| }; | |||
| var regex = new_regex(); | |||
| var tag_replace_callback = function(match, operator, name) { | |||
| switch(operator) { | |||
| case "!": // ignore comments | |||
| return ""; | |||
| case "=": // set new delimiters, rebuild the replace regexp | |||
| that.set_delimiters(name); | |||
| regex = new_regex(); | |||
| return ""; | |||
| case ">": // render partial | |||
| return that.render_partial(name, context, partials); | |||
| case "{": // the triple mustache is unescaped | |||
| return that.find(name, context); | |||
| default: // escape the value | |||
| return that.escape(that.find(name, context)); | |||
| } | |||
| }; | |||
| var lines = template.split("\n"); | |||
| for (var i=0; i < lines.length; i++) { | |||
| lines[i] = lines[i].replace(regex, function(match, operator, name) { | |||
| switch(operator) { | |||
| case "!": // ignore comments | |||
| return ""; | |||
| case "=": // set new delimiters, rebuild the replace regexp | |||
| that.set_delimiters(name); | |||
| regex = new_regex(); | |||
| return ""; | |||
| case ">": // render partial | |||
| return that.render_partial(name.replace(/^\s+/,""), context, partials); | |||
| case "{": // the triple mustache is unescaped | |||
| return that.find(name, context); | |||
| default: // escape the value | |||
| return that.escape(that.find(name, context)); | |||
| } | |||
| }, this); | |||
| if(!in_recursion) { | |||
| this.send(lines[i]); | |||
| } | |||
| } | |||
| if(in_recursion) { | |||
| return lines.join("\n"); | |||
| } | |||
| for(var i = 0; i < lines.length; i++) { | |||
| lines[i] = lines[i].replace(regex, tag_replace_callback, this); | |||
| if(!in_recursion) { | |||
| this.send(lines[i]); | |||
| } | |||
| } | |||
| if(in_recursion) { | |||
| return lines.join("\n"); | |||
| } | |||
| }, | |||
| set_delimiters: function(delimiters) { | |||
| @@ -196,7 +200,7 @@ var Mustache = function() { | |||
| '(\\' + specials.join('|\\') + ')', 'g' | |||
| ); | |||
| } | |||
| return text.replace(arguments.callee.sRE, '\\$1'); | |||
| return text.replace(arguments.callee.sRE, '\\$1'); | |||
| }, | |||
| /* | |||
| @@ -205,11 +209,24 @@ var Mustache = function() { | |||
| */ | |||
| find: function(name, context) { | |||
| name = this.trim(name); | |||
| if(typeof context[name] === "function") { | |||
| return context[name].apply(context); | |||
| // Checks whether a value is thruthy or false or 0 | |||
| function is_kinda_truthy(bool) { | |||
| return bool === false || bool === 0 || bool; | |||
| } | |||
| if(context[name] !== undefined) { | |||
| return context[name]; | |||
| var value; | |||
| if(is_kinda_truthy(context[name])) { | |||
| value = context[name]; | |||
| } else if(is_kinda_truthy(this.context[name])) { | |||
| value = this.context[name]; | |||
| } | |||
| if(typeof value === "function") { | |||
| return value.apply(context); | |||
| } | |||
| if(value !== undefined) { | |||
| return value; | |||
| } | |||
| // silently ignore unkown variables | |||
| return ""; | |||
| @@ -226,37 +243,19 @@ var Mustache = function() { | |||
| Does away with nasty characters | |||
| */ | |||
| escape: function(s) { | |||
| return ((s == null) ? "" : s).toString().replace(/&(?!\w+;)|["<>\\]/g, function(s) { | |||
| s = String(s === null ? "" : s); | |||
| return s.replace(/&(?!\w+;)|["<>\\]/g, function(s) { | |||
| switch(s) { | |||
| case "&": return "&"; | |||
| case "\\": return "\\\\";; | |||
| case '"': return '\"';; | |||
| case "<": return "<"; | |||
| case ">": return ">"; | |||
| default: return s; | |||
| case "&": return "&"; | |||
| case "\\": return "\\\\"; | |||
| case '"': return '\"'; | |||
| case "<": return "<"; | |||
| case ">": return ">"; | |||
| default: return s; | |||
| } | |||
| }); | |||
| }, | |||
| /* | |||
| Merges all properties of object `b` into object `a`. | |||
| `b.property` overwrites a.property` | |||
| */ | |||
| merge: function(a, b) { | |||
| var _new = {}; | |||
| for(var name in a) { | |||
| if(a.hasOwnProperty(name)) { | |||
| _new[name] = a[name]; | |||
| } | |||
| }; | |||
| for(var name in b) { | |||
| if(b.hasOwnProperty(name)) { | |||
| _new[name] = b[name]; | |||
| } | |||
| }; | |||
| return _new; | |||
| }, | |||
| // by @langalex, support for arrays of strings | |||
| create_context: function(_context) { | |||
| if(this.is_object(_context)) { | |||
| @@ -293,7 +292,7 @@ var Mustache = function() { | |||
| } else { | |||
| var r = []; | |||
| var l = array.length; | |||
| for(var i=0;i<l;i++) { | |||
| for(var i = 0; i < l; i++) { | |||
| r.push(fn(array[i])); | |||
| } | |||
| return r; | |||
| @@ -1,7 +0,0 @@ | |||
| { | |||
| "name": "mustache", | |||
| "author": "Jan Lehnardt", | |||
| "description": "{{mustaches}} in JavaScript — shameless port from @defunkt", | |||
| "keywords": ["template"], | |||
| "version": "0.2.3" | |||
| } | |||