| @@ -2,3 +2,4 @@ runner.js | |||||
| jquery.mustache.js | jquery.mustache.js | ||||
| dojox | dojox | ||||
| yui3 | yui3 | ||||
| commonjs.mustache.js | |||||
| @@ -2,6 +2,11 @@ | |||||
| ## 0.3.0 (??-??-????) | ## 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. | * Fix Comments. | ||||
| * Added inverted sections. | * Added inverted sections. | ||||
| * Avoid double encoding of entities. | * Avoid double encoding of entities. | ||||
| @@ -9,7 +14,6 @@ | |||||
| * Added higher order sections. | * Added higher order sections. | ||||
| ## 0.2.3 (28-03-2010) | ## 0.2.3 (28-03-2010) | ||||
| * Better error message for missing partials. | * Better error message for missing partials. | ||||
| @@ -11,44 +11,46 @@ end | |||||
| desc "Run all specs" | desc "Run all specs" | ||||
| task :spec | 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 | 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 | 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." | desc "Remove temporary files." | ||||
| task :clean do | task :clean do | ||||
| `git clean -fdx` | |||||
| sh "git clean -fdx" | |||||
| end | end | ||||
| @@ -16,3 +16,5 @@ Mustache.js wouldn't kick ass if it weren't for these fine souls: | |||||
| * Will Leinweber / will | * Will Leinweber / will | ||||
| * dpree | * dpree | ||||
| * Jason Smith / jhs | * 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: { | pragmas_implemented: { | ||||
| "IMPLICIT-ITERATOR": true | "IMPLICIT-ITERATOR": true | ||||
| }, | }, | ||||
| context: {}, | |||||
| render: function(template, context, partials, in_recursion) { | 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 | // fail fast | ||||
| if(!this.includes("", template)) { | if(!this.includes("", template)) { | ||||
| if(in_recursion) { | if(in_recursion) { | ||||
| @@ -31,10 +34,6 @@ var Mustache = function() { | |||||
| } | } | ||||
| } | } | ||||
| if(!in_recursion) { | |||||
| this.buffer = []; | |||||
| } | |||||
| template = this.render_pragmas(template); | template = this.render_pragmas(template); | ||||
| var html = this.render_section(template, context, partials); | var html = this.render_section(template, context, partials); | ||||
| if(in_recursion) { | if(in_recursion) { | ||||
| @@ -63,12 +62,13 @@ var Mustache = function() { | |||||
| } | } | ||||
| var that = this; | 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) { | return template.replace(regex, function(match, pragma, options) { | ||||
| if(!that.pragmas_implemented[pragma]) { | 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] = {}; | that.pragmas[pragma] = {}; | ||||
| if(options) { | 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) { | render_partial: function(name, context, partials) { | ||||
| name = this.trim(name); | |||||
| if(!partials || !partials[name]) { | if(!partials || !partials[name]) { | ||||
| throw({message: "unknown_partial '" + 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; | var that = this; | ||||
| // CSW - Added "+?" so it finds the tighest bound, not the widest | // 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"); | "\\s*", "mg"); | ||||
| // for each {{#foo}}{{/foo}} section do... | // for each {{#foo}}{{/foo}} section do... | ||||
| return template.replace(regex, function(match, type, name, content) { | return template.replace(regex, function(match, type, name, content) { | ||||
| var value = that.find(name, context); | var value = that.find(name, context); | ||||
| if(type == "^") { // inverted section | 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 | // false or empty list, render it | ||||
| return that.render(content, context, partials, true); | return that.render(content, context, partials, true); | ||||
| } else { | } else { | ||||
| @@ -118,17 +121,17 @@ var Mustache = function() { | |||||
| } else if(type == "#") { // normal section | } else if(type == "#") { // normal section | ||||
| if(that.is_array(value)) { // Enumerable, Let's loop! | if(that.is_array(value)) { // Enumerable, Let's loop! | ||||
| return that.map(value, function(row) { | 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(""); | }).join(""); | ||||
| } else if(that.is_object(value)) { // Object, Use it as subcontext! | } 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") { | } else if(typeof value === "function") { | ||||
| // higher order section | // higher order section | ||||
| return value.call(context, content, function(text) { | return value.call(context, content, function(text) { | ||||
| return that.render(text, context, partials, true); | return that.render(text, context, partials, true); | ||||
| }) | |||||
| }); | |||||
| } else if(value) { // boolean section | } else if(value) { // boolean section | ||||
| return that.render(content, context, partials, true); | return that.render(content, context, partials, true); | ||||
| } else { | } else { | ||||
| @@ -146,37 +149,38 @@ var Mustache = function() { | |||||
| var that = this; | var that = this; | ||||
| var new_regex = function() { | var new_regex = function() { | ||||
| return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\/#\^]+?)\\1?" + | |||||
| return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" + | |||||
| that.ctag + "+", "g"); | that.ctag + "+", "g"); | ||||
| }; | }; | ||||
| var regex = new_regex(); | 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"); | 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) { | set_delimiters: function(delimiters) { | ||||
| @@ -196,7 +200,7 @@ var Mustache = function() { | |||||
| '(\\' + specials.join('|\\') + ')', 'g' | '(\\' + 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) { | find: function(name, context) { | ||||
| name = this.trim(name); | 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 | // silently ignore unkown variables | ||||
| return ""; | return ""; | ||||
| @@ -226,37 +243,19 @@ var Mustache = function() { | |||||
| Does away with nasty characters | Does away with nasty characters | ||||
| */ | */ | ||||
| escape: function(s) { | 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) { | 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 | // by @langalex, support for arrays of strings | ||||
| create_context: function(_context) { | create_context: function(_context) { | ||||
| if(this.is_object(_context)) { | if(this.is_object(_context)) { | ||||
| @@ -293,7 +292,7 @@ var Mustache = function() { | |||||
| } else { | } else { | ||||
| var r = []; | var r = []; | ||||
| var l = array.length; | var l = array.length; | ||||
| for(var i=0;i<l;i++) { | |||||
| for(var i = 0; i < l; i++) { | |||||
| r.push(fn(array[i])); | r.push(fn(array[i])); | ||||
| } | } | ||||
| return r; | 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" | |||||
| } | |||||