HTML templating library for JS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.js 2.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. var regStr = "{{(.+)}}";
  2. var localRegex = new RegExp(regStr);
  3. var globalRegex = new RegExp(regStr, "g");
  4. function hasMultipleStatements(str) {
  5. return (str.indexOf(";") !== -1)
  6. }
  7. function Func(args) {
  8. return Function.apply(this, args);
  9. }
  10. Func.prototype = Function.prototype;
  11. function Templish(str, vals) {
  12. str = str.replace(/\s+/g, " ").replace(/}}/g, "}}\n");
  13. this.string = str;
  14. this.vals = vals;
  15. this.subs = [];
  16. var matches = str.match(globalRegex);
  17. if (!matches)
  18. return;
  19. matches.forEach(function(m) {
  20. var str = m.match(localRegex)[1];
  21. //Add user defined arguments
  22. var args = [];
  23. vals.forEach(function(v) {
  24. args.push(v);
  25. });
  26. //We also need a callback function, for async things
  27. args.push("cb");
  28. //We want to automatically return if there's only one statement
  29. if (hasMultipleStatements(str))
  30. args.push(str);
  31. else
  32. args.push("return ("+str+")");
  33. this.subs.push({
  34. func: new Func(args),
  35. match: m+"\n"
  36. });
  37. }.bind(this));
  38. }
  39. Templish.prototype.exec = function(vals, cb) {
  40. var str = this.string;
  41. //Prepare generic arguments
  42. var args = [];
  43. for (var i in vals) {
  44. var index = this.vals.indexOf(i);
  45. if (index === -1)
  46. throw new Error("Error: argument "+i+" doesn't exist");
  47. args[index] = vals[i];
  48. }
  49. var numArgs = args.length;
  50. //Keep track of how many callbacks we're waiting for
  51. var cbsRemaining = this.subs.length;
  52. //Replace
  53. this.subs.forEach(function(sub, i) {
  54. //Create a callback function for each substitute
  55. args[numArgs] = function(err, res) {
  56. if (err)
  57. throw err;
  58. str = str.replace(sub.match, res);
  59. //If this is the last callback to be executed,
  60. //call back with the resulting string
  61. if (cbsRemaining <= 0)
  62. cb(null, str);
  63. cbsRemaining -= 1;
  64. }
  65. var ret = sub.func.apply(null, args);
  66. //If the substitute's function returns anything, we use that directly,
  67. //but if it doesn't, we wait for a callback
  68. if (ret !== undefined) {
  69. str = str.replace(sub.match, ret);
  70. if (cbsRemaining <= 0)
  71. cb(str);
  72. cbsRemaining -= 1;
  73. }
  74. });
  75. //If there's no asynchronous functions to wait for,
  76. //just call back immediately
  77. if (cbsRemaining === 0)
  78. return cb(null, str);
  79. }
  80. module.exports = Templish;