HTML templating library for JS
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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