PageRenderTime 28ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/files/dustjs/1.2.3/dust-core-1.2.3.js

https://gitlab.com/Mirros/jsdelivr
JavaScript | 622 lines | 511 code | 74 blank | 37 comment | 107 complexity | 7cf7821256e9e0b02823dad5d325494b MD5 | raw file
  1. //
  2. // Dust - Asynchronous Templating v1.2.3
  3. // http://akdubya.github.com/dustjs
  4. //
  5. // Copyright (c) 2010, Aleksander Williams
  6. // Released under the MIT License.
  7. //
  8. var dust = {};
  9. function getGlobal(){
  10. return (function(){
  11. return this.dust;
  12. }).call(null);
  13. }
  14. (function(dust) {
  15. dust.helpers = {};
  16. dust.cache = {};
  17. dust.register = function(name, tmpl) {
  18. if (!name) return;
  19. dust.cache[name] = tmpl;
  20. };
  21. dust.render = function(name, context, callback) {
  22. var chunk = new Stub(callback).head;
  23. dust.load(name, chunk, Context.wrap(context)).end();
  24. };
  25. dust.stream = function(name, context) {
  26. var stream = new Stream();
  27. dust.nextTick(function() {
  28. dust.load(name, stream.head, Context.wrap(context)).end();
  29. });
  30. return stream;
  31. };
  32. dust.renderSource = function(source, context, callback) {
  33. return dust.compileFn(source)(context, callback);
  34. };
  35. dust.compileFn = function(source, name) {
  36. var tmpl = dust.loadSource(dust.compile(source, name));
  37. return function(context, callback) {
  38. var master = callback ? new Stub(callback) : new Stream();
  39. dust.nextTick(function() {
  40. tmpl(master.head, Context.wrap(context)).end();
  41. });
  42. return master;
  43. };
  44. };
  45. dust.load = function(name, chunk, context) {
  46. var tmpl = dust.cache[name];
  47. if (tmpl) {
  48. return tmpl(chunk, context);
  49. } else {
  50. if (dust.onLoad) {
  51. return chunk.map(function(chunk) {
  52. dust.onLoad(name, function(err, src) {
  53. if (err) return chunk.setError(err);
  54. if (!dust.cache[name]) dust.loadSource(dust.compile(src, name));
  55. dust.cache[name](chunk, context).end();
  56. });
  57. });
  58. }
  59. return chunk.setError(new Error("Template Not Found: " + name));
  60. }
  61. };
  62. dust.loadSource = function(source, path) {
  63. return eval(source);
  64. };
  65. if (Array.isArray) {
  66. dust.isArray = Array.isArray;
  67. } else {
  68. dust.isArray = function(arr) {
  69. return Object.prototype.toString.call(arr) == "[object Array]";
  70. };
  71. }
  72. dust.nextTick = (function() {
  73. if (typeof process !== "undefined") {
  74. return process.nextTick;
  75. } else {
  76. return function(callback) {
  77. setTimeout(callback,0);
  78. };
  79. }
  80. } )();
  81. dust.isEmpty = function(value) {
  82. if (dust.isArray(value) && !value.length) return true;
  83. if (value === 0) return false;
  84. return (!value);
  85. };
  86. // apply the filter chain and return the output string
  87. dust.filter = function(string, auto, filters) {
  88. if (filters) {
  89. for (var i=0, len=filters.length; i<len; i++) {
  90. var name = filters[i];
  91. if (name === "s") {
  92. auto = null;
  93. }
  94. // fail silently for invalid filters
  95. else if (typeof dust.filters[name] === 'function') {
  96. string = dust.filters[name](string);
  97. }
  98. }
  99. }
  100. // by default always apply the h filter, unless asked to unescape with |s
  101. if (auto) {
  102. string = dust.filters[auto](string);
  103. }
  104. return string;
  105. };
  106. dust.filters = {
  107. h: function(value) { return dust.escapeHtml(value); },
  108. j: function(value) { return dust.escapeJs(value); },
  109. u: encodeURI,
  110. uc: encodeURIComponent,
  111. js: function(value) { if (!JSON) { return value; } return JSON.stringify(value); },
  112. jp: function(value) { if (!JSON) { return value; } return JSON.parse(value); }
  113. };
  114. function Context(stack, global, blocks) {
  115. this.stack = stack;
  116. this.global = global;
  117. this.blocks = blocks;
  118. }
  119. dust.makeBase = function(global) {
  120. return new Context(new Stack(), global);
  121. };
  122. Context.wrap = function(context) {
  123. if (context instanceof Context) {
  124. return context;
  125. }
  126. return new Context(new Stack(context));
  127. };
  128. Context.prototype.get = function(key) {
  129. var ctx = this.stack, value;
  130. while(ctx) {
  131. if (ctx.isObject) {
  132. value = ctx.head[key];
  133. if (!(value === undefined)) {
  134. return value;
  135. }
  136. }
  137. ctx = ctx.tail;
  138. }
  139. return this.global ? this.global[key] : undefined;
  140. };
  141. Context.prototype.getPath = function(cur, down) {
  142. var ctx = this.stack,
  143. len = down.length;
  144. if (cur && len === 0) return ctx.head;
  145. ctx = ctx.head;
  146. var i = 0;
  147. while(ctx && i < len) {
  148. ctx = ctx[down[i]];
  149. i++;
  150. }
  151. return ctx;
  152. };
  153. Context.prototype.push = function(head, idx, len) {
  154. return new Context(new Stack(head, this.stack, idx, len), this.global, this.blocks);
  155. };
  156. Context.prototype.rebase = function(head) {
  157. return new Context(new Stack(head), this.global, this.blocks);
  158. };
  159. Context.prototype.current = function() {
  160. return this.stack.head;
  161. };
  162. Context.prototype.getBlock = function(key, chk, ctx) {
  163. if (typeof key === "function") {
  164. key = key(chk, ctx).data.join("");
  165. chk.data = []; //ie7 perf
  166. }
  167. var blocks = this.blocks;
  168. if (!blocks) return;
  169. var len = blocks.length, fn;
  170. while (len--) {
  171. fn = blocks[len][key];
  172. if (fn) return fn;
  173. }
  174. };
  175. Context.prototype.shiftBlocks = function(locals) {
  176. var blocks = this.blocks,
  177. newBlocks;
  178. if (locals) {
  179. if (!blocks) {
  180. newBlocks = [locals];
  181. } else {
  182. newBlocks = blocks.concat([locals]);
  183. }
  184. return new Context(this.stack, this.global, newBlocks);
  185. }
  186. return this;
  187. };
  188. function Stack(head, tail, idx, len) {
  189. this.tail = tail;
  190. this.isObject = !dust.isArray(head) && head && typeof head === "object";
  191. this.head = head;
  192. this.index = idx;
  193. this.of = len;
  194. }
  195. function Stub(callback) {
  196. this.head = new Chunk(this);
  197. this.callback = callback;
  198. this.out = '';
  199. }
  200. Stub.prototype.flush = function() {
  201. var chunk = this.head;
  202. while (chunk) {
  203. if (chunk.flushable) {
  204. this.out += chunk.data.join(""); //ie7 perf
  205. } else if (chunk.error) {
  206. this.callback(chunk.error);
  207. this.flush = function() {};
  208. return;
  209. } else {
  210. return;
  211. }
  212. chunk = chunk.next;
  213. this.head = chunk;
  214. }
  215. this.callback(null, this.out);
  216. };
  217. function Stream() {
  218. this.head = new Chunk(this);
  219. }
  220. Stream.prototype.flush = function() {
  221. var chunk = this.head;
  222. while(chunk) {
  223. if (chunk.flushable) {
  224. this.emit('data', chunk.data.join("")); //ie7 perf
  225. } else if (chunk.error) {
  226. this.emit('error', chunk.error);
  227. this.flush = function() {};
  228. return;
  229. } else {
  230. return;
  231. }
  232. chunk = chunk.next;
  233. this.head = chunk;
  234. }
  235. this.emit('end');
  236. };
  237. Stream.prototype.emit = function(type, data) {
  238. if (!this.events) return false;
  239. var handler = this.events[type];
  240. if (!handler) return false;
  241. if (typeof handler == 'function') {
  242. handler(data);
  243. } else {
  244. var listeners = handler.slice(0);
  245. for (var i = 0, l = listeners.length; i < l; i++) {
  246. listeners[i](data);
  247. }
  248. }
  249. };
  250. Stream.prototype.on = function(type, callback) {
  251. if (!this.events) {
  252. this.events = {};
  253. }
  254. if (!this.events[type]) {
  255. this.events[type] = callback;
  256. } else if(typeof this.events[type] === 'function') {
  257. this.events[type] = [this.events[type], callback];
  258. } else {
  259. this.events[type].push(callback);
  260. }
  261. return this;
  262. };
  263. Stream.prototype.pipe = function(stream) {
  264. this.on("data", function(data) {
  265. stream.write(data, "utf8");
  266. }).on("end", function() {
  267. stream.end();
  268. }).on("error", function(err) {
  269. stream.error(err);
  270. });
  271. return this;
  272. };
  273. function Chunk(root, next, taps) {
  274. this.root = root;
  275. this.next = next;
  276. this.data = []; //ie7 perf
  277. this.flushable = false;
  278. this.taps = taps;
  279. }
  280. Chunk.prototype.write = function(data) {
  281. var taps = this.taps;
  282. if (taps) {
  283. data = taps.go(data);
  284. }
  285. this.data.push(data);
  286. return this;
  287. };
  288. Chunk.prototype.end = function(data) {
  289. if (data) {
  290. this.write(data);
  291. }
  292. this.flushable = true;
  293. this.root.flush();
  294. return this;
  295. };
  296. Chunk.prototype.map = function(callback) {
  297. var cursor = new Chunk(this.root, this.next, this.taps),
  298. branch = new Chunk(this.root, cursor, this.taps);
  299. this.next = branch;
  300. this.flushable = true;
  301. callback(branch);
  302. return cursor;
  303. };
  304. Chunk.prototype.tap = function(tap) {
  305. var taps = this.taps;
  306. if (taps) {
  307. this.taps = taps.push(tap);
  308. } else {
  309. this.taps = new Tap(tap);
  310. }
  311. return this;
  312. };
  313. Chunk.prototype.untap = function() {
  314. this.taps = this.taps.tail;
  315. return this;
  316. };
  317. Chunk.prototype.render = function(body, context) {
  318. return body(this, context);
  319. };
  320. Chunk.prototype.reference = function(elem, context, auto, filters) {
  321. if (typeof elem === "function") {
  322. elem.isFunction = true;
  323. // Changed the function calling to use apply with the current context to make sure
  324. // that "this" is wat we expect it to be inside the function
  325. elem = elem.apply(context.current(), [this, context, null, {auto: auto, filters: filters}]);
  326. if (elem instanceof Chunk) {
  327. return elem;
  328. }
  329. }
  330. if (!dust.isEmpty(elem)) {
  331. return this.write(dust.filter(elem, auto, filters));
  332. } else {
  333. return this;
  334. }
  335. };
  336. Chunk.prototype.section = function(elem, context, bodies, params) {
  337. // anonymous functions
  338. if (typeof elem === "function") {
  339. elem = elem.apply(context.current(), [this, context, bodies, params]);
  340. // functions that return chunks are assumed to have handled the body and/or have modified the chunk
  341. // use that return value as the current chunk and go to the next method in the chain
  342. if (elem instanceof Chunk) {
  343. return elem;
  344. }
  345. }
  346. var body = bodies.block,
  347. skip = bodies['else'];
  348. // a.k.a Inline parameters in the Dust documentations
  349. if (params) {
  350. context = context.push(params);
  351. }
  352. /*
  353. Dust's default behavior is to enumerate over the array elem, passing each object in the array to the block.
  354. When elem resolves to a value or object instead of an array, Dust sets the current context to the value
  355. and renders the block one time.
  356. */
  357. //non empty array is truthy, empty array is falsy
  358. if (dust.isArray(elem)) {
  359. if (body) {
  360. var len = elem.length, chunk = this;
  361. if (len > 0) {
  362. // any custom helper can blow up the stack
  363. // and store a flattened context, guard defensively
  364. if(context.stack.head) {
  365. context.stack.head['$len'] = len;
  366. }
  367. for (var i=0; i<len; i++) {
  368. if(context.stack.head) {
  369. context.stack.head['$idx'] = i;
  370. }
  371. chunk = body(chunk, context.push(elem[i], i, len));
  372. }
  373. if(context.stack.head) {
  374. context.stack.head['$idx'] = undefined;
  375. context.stack.head['$len'] = undefined;
  376. }
  377. return chunk;
  378. }
  379. else if (skip) {
  380. return skip(this, context);
  381. }
  382. }
  383. }
  384. // true is truthy but does not change context
  385. else if (elem === true) {
  386. if (body) {
  387. return body(this, context);
  388. }
  389. }
  390. // everything that evaluates to true are truthy ( e.g. Non-empty strings and Empty objects are truthy. )
  391. // zero is truthy
  392. // for anonymous functions that did not returns a chunk, truthiness is evaluated based on the return value
  393. //
  394. else if (elem || elem === 0) {
  395. if (body) return body(this, context.push(elem));
  396. // nonexistent, scalar false value, scalar empty string, null,
  397. // undefined are all falsy
  398. } else if (skip) {
  399. return skip(this, context);
  400. }
  401. return this;
  402. };
  403. Chunk.prototype.exists = function(elem, context, bodies) {
  404. var body = bodies.block,
  405. skip = bodies['else'];
  406. if (!dust.isEmpty(elem)) {
  407. if (body) return body(this, context);
  408. } else if (skip) {
  409. return skip(this, context);
  410. }
  411. return this;
  412. };
  413. Chunk.prototype.notexists = function(elem, context, bodies) {
  414. var body = bodies.block,
  415. skip = bodies['else'];
  416. if (dust.isEmpty(elem)) {
  417. if (body) return body(this, context);
  418. } else if (skip) {
  419. return skip(this, context);
  420. }
  421. return this;
  422. };
  423. Chunk.prototype.block = function(elem, context, bodies) {
  424. var body = bodies.block;
  425. if (elem) {
  426. body = elem;
  427. }
  428. if (body) {
  429. return body(this, context);
  430. }
  431. return this;
  432. };
  433. Chunk.prototype.partial = function(elem, context, params) {
  434. var partialContext;
  435. if (params){
  436. //put the params context second to match what section does. {.} matches the current context without parameters
  437. // start with an empty context
  438. partialContext = dust.makeBase(context.global);
  439. partialContext.blocks = context.blocks;
  440. if (context.stack && context.stack.tail){
  441. // grab the stack(tail) off of the previous context if we have it
  442. partialContext.stack = context.stack.tail;
  443. }
  444. //put params on
  445. partialContext = partialContext.push(params);
  446. //reattach the head
  447. partialContext = partialContext.push(context.stack.head);
  448. } else {
  449. partialContext = context;
  450. }
  451. if (typeof elem === "function") {
  452. return this.capture(elem, partialContext, function(name, chunk) {
  453. dust.load(name, chunk, partialContext).end();
  454. });
  455. }
  456. return dust.load(elem, this, partialContext);
  457. };
  458. Chunk.prototype.helper = function(name, context, bodies, params) {
  459. // handle invalid helpers, similar to invalid filters
  460. if( dust.helpers[name]){
  461. return dust.helpers[name](this, context, bodies, params);
  462. } else {
  463. return this;
  464. }
  465. };
  466. Chunk.prototype.capture = function(body, context, callback) {
  467. return this.map(function(chunk) {
  468. var stub = new Stub(function(err, out) {
  469. if (err) {
  470. chunk.setError(err);
  471. } else {
  472. callback(out, chunk);
  473. }
  474. });
  475. body(stub.head, context).end();
  476. });
  477. };
  478. Chunk.prototype.setError = function(err) {
  479. this.error = err;
  480. this.root.flush();
  481. return this;
  482. };
  483. function Tap(head, tail) {
  484. this.head = head;
  485. this.tail = tail;
  486. }
  487. Tap.prototype.push = function(tap) {
  488. return new Tap(tap, this);
  489. };
  490. Tap.prototype.go = function(value) {
  491. var tap = this;
  492. while(tap) {
  493. value = tap.head(value);
  494. tap = tap.tail;
  495. }
  496. return value;
  497. };
  498. var HCHARS = new RegExp(/[&<>\"\']/),
  499. AMP = /&/g,
  500. LT = /</g,
  501. GT = />/g,
  502. QUOT = /\"/g,
  503. SQUOT = /\'/g;
  504. dust.escapeHtml = function(s) {
  505. if (typeof s === "string") {
  506. if (!HCHARS.test(s)) {
  507. return s;
  508. }
  509. return s.replace(AMP,'&amp;').replace(LT,'&lt;').replace(GT,'&gt;').replace(QUOT,'&quot;').replace(SQUOT, '&#39;');
  510. }
  511. return s;
  512. };
  513. var BS = /\\/g,
  514. FS = /\//g,
  515. CR = /\r/g,
  516. LS = /\u2028/g,
  517. PS = /\u2029/g,
  518. NL = /\n/g,
  519. LF = /\f/g,
  520. SQ = /'/g,
  521. DQ = /"/g,
  522. TB = /\t/g;
  523. dust.escapeJs = function(s) {
  524. if (typeof s === "string") {
  525. return s
  526. .replace(BS, '\\\\')
  527. .replace(FS, '\\/')
  528. .replace(DQ, '\\"')
  529. .replace(SQ, "\\'")
  530. .replace(CR, '\\r')
  531. .replace(LS, '\\u2028')
  532. .replace(PS, '\\u2029')
  533. .replace(NL, '\\n')
  534. .replace(LF, '\\f')
  535. .replace(TB, "\\t");
  536. }
  537. return s;
  538. };
  539. })(dust);
  540. if (typeof exports !== "undefined") {
  541. if (typeof process !== "undefined") {
  542. require('./server')(dust);
  543. }
  544. module.exports = dust;
  545. }