No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

171 líneas
4.2KB

  1. /*
  2. Shamless port of http://github.com/defunkt/mustache
  3. by Jan Lehnardt <jan@apache.org>
  4. Thanks @defunkt for the awesome code.
  5. See http://github.com/defunkt/mustache for more info.
  6. */
  7. var Mustache = {
  8. name: "mustache.js",
  9. version: "0.1",
  10. context: {},
  11. /*
  12. Public method. Turns a template and view into HTML
  13. */
  14. to_html: function(template, view) {
  15. return this.render(template, view);
  16. },
  17. // Private Methods
  18. render: function(template, view) {
  19. // fail fast
  20. if(template.indexOf("{{") == -1) {
  21. return template;
  22. }
  23. // keep context around for recursive calls
  24. this.context = context = this.merge((this.context || {}), view);
  25. // first, render all sections
  26. var html = this.render_section(template);
  27. // restore context, recursion might have messed it up
  28. this.context = context;
  29. // finally, render tags
  30. return this.render_tags(html);
  31. },
  32. /*
  33. Tries to find a partial in the global scope and render it
  34. */
  35. render_partial: function(name) {
  36. // FIXME: too hacky
  37. var evil_name = eval(name)
  38. switch(typeof evil_name) {
  39. case "string": // a tring partial, we simply render
  40. return this.to_html(evil_name, "");
  41. case "object": // a view partial needs a `name_template` template to render
  42. var tpl = name + "_template";
  43. return this.to_html(eval(tpl), evil_name);
  44. default: // should not happen #famouslastwords
  45. throw("Unknown partial type.");
  46. }
  47. },
  48. /*
  49. Renders boolean and enumerable sections
  50. */
  51. render_section: function(template) {
  52. if(template.indexOf("{{#") == -1) {
  53. return template;
  54. }
  55. var that = this;
  56. // for each {{#foo}}{{/foo}} section do...
  57. return template.replace(/\{\{\#(.+)\}\}\s*([\s\S]+)\{\{\/\1\}\}\s*/mg,
  58. function(match, name, content) {
  59. var value = that.find(name);
  60. if(that.is_array(value)) { // Enumerable, Let's loop!
  61. return value.map(function(row) {
  62. return that.render(content, row);
  63. }).join('');
  64. } else if(value) { // boolean section
  65. return that.render(content);
  66. } else {
  67. return "";
  68. }
  69. }
  70. );
  71. },
  72. /*
  73. Replace {{foo}} and friends with values from our view
  74. */
  75. render_tags: function(template) {
  76. // tit for tat
  77. var that = this;
  78. // for each {{(!<{)?foo}} tag, do...
  79. return template.replace(/\{\{(!|<|\{)?([^\/#]+?)\1?\}\}+/mg,
  80. function (match, operator, name) {
  81. switch(operator) {
  82. case "!": // ignore comments
  83. return match;
  84. case "<": // render partial
  85. return that.render_partial(name);
  86. case '{': // the triple mustache is unescaped
  87. return that.find(name);
  88. default: // escape the value
  89. return that.escape(that.find(name));
  90. }
  91. }, this);
  92. },
  93. /*
  94. find `name` in current `context`. That is find me a value
  95. from the view object
  96. */
  97. find: function(name) {
  98. name = this.trim(name);
  99. var context = this.context;
  100. if(typeof context[name] === "function") {
  101. return context[name].apply(context);
  102. }
  103. if(context[name] !== undefined) {
  104. return context[name];
  105. }
  106. throw("Can't find " + name + " in " + context);
  107. },
  108. // Utility methods
  109. /*
  110. Does away with nasty characters
  111. */
  112. escape: function(s) {
  113. return s.toString().replace(/[&"<>\\]/g, function(s) {
  114. switch(s) {
  115. case "&": return "&amp;";
  116. case "\\": return "\\\\";;
  117. case '"': return '\"';;
  118. case "<": return "&lt;";
  119. case ">": return "&gt;";
  120. default: return s;
  121. }
  122. });
  123. },
  124. /*
  125. Merges all properties of object `b` into object `a`.
  126. `b.property` overwrites a.property`
  127. */
  128. merge: function(a, b) {
  129. for(var name in b) {
  130. if(b.hasOwnProperty(name)) {
  131. a[name] = b[name];
  132. }
  133. }
  134. return a;
  135. },
  136. /*
  137. Thanks Doug Crockford
  138. JavaScript — The Good Parts lists an alternative that works better with
  139. frames. Frames can suck it, we use the simple version.
  140. */
  141. is_array: function(a) {
  142. return (a &&
  143. typeof a === 'object' &&
  144. a.constructor === Array);
  145. },
  146. /*
  147. Gets rid of leading and trailing whitespace
  148. */
  149. trim: function(s) {
  150. return s.replace(/^\s*|\s*$/g, '');
  151. },
  152. };