liquid_assets 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2730 @@
1
+ /*!
2
+ * TinyLiquid模板引擎
3
+ *
4
+ * @author 老雷<leizongmin@gmail.com>
5
+ */
6
+
7
+
8
+ var TinyLiquid = (function (exports) {
9
+
10
+ var modules = {};
11
+
12
+ /*--------------- ./lib/md5.js ----------------*/
13
+ var m = {exports: {}};
14
+ (function (module, exports) {
15
+ 'use strict';
16
+
17
+ /*
18
+ * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
19
+ * Digest Algorithm, as defined in RFC 1321.
20
+ * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
21
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
22
+ * Distributed under the BSD License
23
+ * See http://pajhome.org.uk/crypt/md5 for more info.
24
+ */
25
+ var hexcase=0;function hex_md5(a){return rstr2hex(rstr_md5(str2rstr_utf8(a)))}function hex_hmac_md5(a,b){return rstr2hex(rstr_hmac_md5(str2rstr_utf8(a),str2rstr_utf8(b)))}function md5_vm_test(){return hex_md5("abc").toLowerCase()=="900150983cd24fb0d6963f7d28e17f72"}function rstr_md5(a){return binl2rstr(binl_md5(rstr2binl(a),a.length*8))}function rstr_hmac_md5(c,f){var e=rstr2binl(c);if(e.length>16){e=binl_md5(e,c.length*8)}var a=Array(16),d=Array(16);for(var b=0;b<16;b++){a[b]=e[b]^909522486;d[b]=e[b]^1549556828}var g=binl_md5(a.concat(rstr2binl(f)),512+f.length*8);return binl2rstr(binl_md5(d.concat(g),512+128))}function rstr2hex(c){try{hexcase}catch(g){hexcase=0}var f=hexcase?"0123456789ABCDEF":"0123456789abcdef";var b="";var a;for(var d=0;d<c.length;d++){a=c.charCodeAt(d);b+=f.charAt((a>>>4)&15)+f.charAt(a&15)}return b}function str2rstr_utf8(c){var b="";var d=-1;var a,e;while(++d<c.length){a=c.charCodeAt(d);e=d+1<c.length?c.charCodeAt(d+1):0;if(55296<=a&&a<=56319&&56320<=e&&e<=57343){a=65536+((a&1023)<<10)+(e&1023);d++}if(a<=127){b+=String.fromCharCode(a)}else{if(a<=2047){b+=String.fromCharCode(192|((a>>>6)&31),128|(a&63))}else{if(a<=65535){b+=String.fromCharCode(224|((a>>>12)&15),128|((a>>>6)&63),128|(a&63))}else{if(a<=2097151){b+=String.fromCharCode(240|((a>>>18)&7),128|((a>>>12)&63),128|((a>>>6)&63),128|(a&63))}}}}}return b}function rstr2binl(b){var a=Array(b.length>>2);for(var c=0;c<a.length;c++){a[c]=0}for(var c=0;c<b.length*8;c+=8){a[c>>5]|=(b.charCodeAt(c/8)&255)<<(c%32)}return a}function binl2rstr(b){var a="";for(var c=0;c<b.length*32;c+=8){a+=String.fromCharCode((b[c>>5]>>>(c%32))&255)}return a}function binl_md5(p,k){p[k>>5]|=128<<((k)%32);p[(((k+64)>>>9)<<4)+14]=k;var o=1732584193;var n=-271733879;var m=-1732584194;var l=271733878;for(var g=0;g<p.length;g+=16){var j=o;var h=n;var f=m;var e=l;o=md5_ff(o,n,m,l,p[g+0],7,-680876936);l=md5_ff(l,o,n,m,p[g+1],12,-389564586);m=md5_ff(m,l,o,n,p[g+2],17,606105819);n=md5_ff(n,m,l,o,p[g+3],22,-1044525330);o=md5_ff(o,n,m,l,p[g+4],7,-176418897);l=md5_ff(l,o,n,m,p[g+5],12,1200080426);m=md5_ff(m,l,o,n,p[g+6],17,-1473231341);n=md5_ff(n,m,l,o,p[g+7],22,-45705983);o=md5_ff(o,n,m,l,p[g+8],7,1770035416);l=md5_ff(l,o,n,m,p[g+9],12,-1958414417);m=md5_ff(m,l,o,n,p[g+10],17,-42063);n=md5_ff(n,m,l,o,p[g+11],22,-1990404162);o=md5_ff(o,n,m,l,p[g+12],7,1804603682);l=md5_ff(l,o,n,m,p[g+13],12,-40341101);m=md5_ff(m,l,o,n,p[g+14],17,-1502002290);n=md5_ff(n,m,l,o,p[g+15],22,1236535329);o=md5_gg(o,n,m,l,p[g+1],5,-165796510);l=md5_gg(l,o,n,m,p[g+6],9,-1069501632);m=md5_gg(m,l,o,n,p[g+11],14,643717713);n=md5_gg(n,m,l,o,p[g+0],20,-373897302);o=md5_gg(o,n,m,l,p[g+5],5,-701558691);l=md5_gg(l,o,n,m,p[g+10],9,38016083);m=md5_gg(m,l,o,n,p[g+15],14,-660478335);n=md5_gg(n,m,l,o,p[g+4],20,-405537848);o=md5_gg(o,n,m,l,p[g+9],5,568446438);l=md5_gg(l,o,n,m,p[g+14],9,-1019803690);m=md5_gg(m,l,o,n,p[g+3],14,-187363961);n=md5_gg(n,m,l,o,p[g+8],20,1163531501);o=md5_gg(o,n,m,l,p[g+13],5,-1444681467);l=md5_gg(l,o,n,m,p[g+2],9,-51403784);m=md5_gg(m,l,o,n,p[g+7],14,1735328473);n=md5_gg(n,m,l,o,p[g+12],20,-1926607734);o=md5_hh(o,n,m,l,p[g+5],4,-378558);l=md5_hh(l,o,n,m,p[g+8],11,-2022574463);m=md5_hh(m,l,o,n,p[g+11],16,1839030562);n=md5_hh(n,m,l,o,p[g+14],23,-35309556);o=md5_hh(o,n,m,l,p[g+1],4,-1530992060);l=md5_hh(l,o,n,m,p[g+4],11,1272893353);m=md5_hh(m,l,o,n,p[g+7],16,-155497632);n=md5_hh(n,m,l,o,p[g+10],23,-1094730640);o=md5_hh(o,n,m,l,p[g+13],4,681279174);l=md5_hh(l,o,n,m,p[g+0],11,-358537222);m=md5_hh(m,l,o,n,p[g+3],16,-722521979);n=md5_hh(n,m,l,o,p[g+6],23,76029189);o=md5_hh(o,n,m,l,p[g+9],4,-640364487);l=md5_hh(l,o,n,m,p[g+12],11,-421815835);m=md5_hh(m,l,o,n,p[g+15],16,530742520);n=md5_hh(n,m,l,o,p[g+2],23,-995338651);o=md5_ii(o,n,m,l,p[g+0],6,-198630844);l=md5_ii(l,o,n,m,p[g+7],10,1126891415);m=md5_ii(m,l,o,n,p[g+14],15,-1416354905);n=md5_ii(n,m,l,o,p[g+5],21,-57434055);o=md5_ii(o,n,m,l,p[g+12],6,1700485571);l=md5_ii(l,o,n,m,p[g+3],10,-1894986606);m=md5_ii(m,l,o,n,p[g+10],15,-1051523);n=md5_ii(n,m,l,o,p[g+1],21,-2054922799);o=md5_ii(o,n,m,l,p[g+8],6,1873313359);l=md5_ii(l,o,n,m,p[g+15],10,-30611744);m=md5_ii(m,l,o,n,p[g+6],15,-1560198380);n=md5_ii(n,m,l,o,p[g+13],21,1309151649);o=md5_ii(o,n,m,l,p[g+4],6,-145523070);l=md5_ii(l,o,n,m,p[g+11],10,-1120210379);m=md5_ii(m,l,o,n,p[g+2],15,718787259);n=md5_ii(n,m,l,o,p[g+9],21,-343485551);o=safe_add(o,j);n=safe_add(n,h);m=safe_add(m,f);l=safe_add(l,e)}return Array(o,n,m,l)}function md5_cmn(h,e,d,c,g,f){return safe_add(bit_rol(safe_add(safe_add(e,h),safe_add(c,f)),g),d)}function md5_ff(g,f,k,j,e,i,h){return md5_cmn((f&k)|((~f)&j),g,f,e,i,h)}function md5_gg(g,f,k,j,e,i,h){return md5_cmn((f&j)|(k&(~j)),g,f,e,i,h)}function md5_hh(g,f,k,j,e,i,h){return md5_cmn(f^k^j,g,f,e,i,h)}function md5_ii(g,f,k,j,e,i,h){return md5_cmn(k^(f|(~j)),g,f,e,i,h)}function safe_add(a,d){var c=(a&65535)+(d&65535);var b=(a>>16)+(d>>16)+(c>>16);return(b<<16)|(c&65535)}function bit_rol(a,b){return(a<<b)|(a>>>(32-b))};
26
+
27
+ module.exports = hex_md5;
28
+
29
+ return exports;
30
+ })(m, m.exports);
31
+ modules.md5 = m.exports;
32
+ /*-----------------------------------------------*/
33
+
34
+ /*--------------- ./lib/utils.js ----------------*/
35
+ var m = {exports: {}};
36
+ (function (module, exports) {
37
+ 'use strict';
38
+
39
+ /**
40
+ * 工具函数
41
+ *
42
+ * @author 老雷<leizongmin@gmail.com>
43
+ */
44
+
45
+
46
+ // MD5函数,在Node.js进程中使用crypto模块
47
+ try {
48
+ var crypto = modules.crypto;
49
+ var md5 = function (text) {
50
+ return crypto.createHash('md5').update(text).digest('hex');
51
+ };
52
+ } catch(e) {
53
+ var md5 = modules.md5;
54
+ }
55
+
56
+
57
+ /**
58
+ * MD5
59
+ *
60
+ * @param {string} str
61
+ * @return {string}
62
+ */
63
+ exports.md5 = md5;
64
+
65
+ /**
66
+ * 去掉字符串外面的引号
67
+ *
68
+ * @param {string} input
69
+ * @return {string}
70
+ */
71
+ exports.stripQuotes = function (input) {
72
+ input = String(input);
73
+ var s = 0;
74
+ var e = input.length;
75
+ var ei = e - 1;
76
+ if (input[0] === '\'' || input[0] === '"') {
77
+ s++;
78
+ e--;
79
+ }
80
+ if (input[ei] === '\'' || input[ei] === '"') e--;
81
+ return input.substr(s, e);
82
+ };
83
+
84
+ /**
85
+ * 合并多个对象
86
+ *
87
+ * @param {object} obja
88
+ * @param {object} objb
89
+ * @return {object}
90
+ */
91
+ exports.merge = function () {
92
+ var ret = {};
93
+ for (var i in arguments) {
94
+ var obj = arguments[i];
95
+ for (var j in obj) {
96
+ ret[j] = obj[j];
97
+ }
98
+ }
99
+ return ret;
100
+ };
101
+
102
+ /**
103
+ * 将对象转换为数组
104
+ *
105
+ * @param {object} data
106
+ * @return {array}
107
+ */
108
+ exports.toArray = function (data) {
109
+ if (Array.isArray(data)) return data;
110
+ var ret = [];
111
+ for (var i in data) {
112
+ if (i !== 'size') {
113
+ ret.push(data[i]);
114
+ }
115
+ }
116
+ return ret;
117
+ };
118
+
119
+ /**
120
+ * 取指定范围的数字数组
121
+ *
122
+ * @param {int} s
123
+ * @param {int} e
124
+ * @return {array}
125
+ */
126
+ exports.range = function (s, e) {
127
+ s = parseInt(s);
128
+ e = parseInt(e);
129
+ var r = [];
130
+ if (isNaN(s) || isNaN(e)) return r;
131
+ for (; s <= e; s++) {
132
+ r.push(s);
133
+ }
134
+ return r;
135
+ };
136
+
137
+ /**
138
+ * 输出文本
139
+ *
140
+ * @param {string} html
141
+ * @return {string}
142
+ */
143
+ exports.escape = function (html) {
144
+ return String(html) .replace(/&(?!\w+;)/g, '&amp;')
145
+ .replace(/</g, '&lt;')
146
+ .replace(/>/g, '&gt;')
147
+ .replace(/"/g, '&quot;');
148
+ };
149
+
150
+ /**
151
+ * 输出HTML
152
+ *
153
+ * @param {string} html
154
+ * @return {string}
155
+ */
156
+ exports.outputHtml = function (html) {
157
+ return html.replace(/\\/g, '\\\\')
158
+ .replace(/'/g, '\\\'')
159
+ .replace(/"/g, '\\\"')
160
+ .replace(/\r/g, '\\r')
161
+ .replace(/\n/g, '\\n');
162
+ };
163
+ var $_html = exports.outputHtml;
164
+
165
+ /**
166
+ * 出错信息
167
+ *
168
+ * @param {string} msg
169
+ */
170
+ exports.errorMessage = function (msg) {
171
+ var html = '<pre style="font-family:Courier; font-weight:bold; \
172
+ font-size:14px; color:red; padding:4px 20px 4px 20px; border:1px solid #CCC; \
173
+ background-color:#FFF5F0; line-height:1.6em; white-space:pre-wrap; \
174
+ white-space:-moz-pre-wrap; white-space:-pre-wrap; white-space:-o-pre-wrap; \
175
+ word-wrap:break-word; z-index:9999">' + msg + '</pre>';
176
+ return html;
177
+ };
178
+ var $_err = exports.errorMessage;
179
+
180
+ /**
181
+ * 抛出运行时出错信息
182
+ *
183
+ * @param {Error} err
184
+ * @param {string} filename
185
+ */
186
+ exports.rethrowError = function (err, filename) {
187
+ var msg = 'An error occurred while rendering\n' +
188
+ 'Line: ' + $_line_num + (filename ? ' File: ' + filename : '') +
189
+ '\n ' + err;
190
+ $_buf += $_err(msg);
191
+ };
192
+
193
+ var $_buf;
194
+
195
+ /**
196
+ * 包装变量
197
+ *
198
+ * @param {string} n
199
+ * @param {string} locals
200
+ * @param {function} saveFunc
201
+ * @return {string}
202
+ */
203
+ exports.localsWrap = function (n, locals, saveFunc) {
204
+ if (/^(forloop|tablerowloop)/i.test(n)) {
205
+ locals = '';
206
+ } else {
207
+ if (!locals) locals = 'locals';
208
+ locals += '.';
209
+ }
210
+ n = n.trim();
211
+ // 是否为常量
212
+ if (CONST_VAL.indexOf(n) > -1) return n;
213
+ // 是否为字符串
214
+ if (/^['"].*['"]$/.test(n)) return n;
215
+ // 是否为数值
216
+ if (/^\d[\d\.]*\d?$/.test(n)) return n;
217
+ // 是否为标识符
218
+ if (/^[a-zA-Z_][a-zA-Z0-9_\.]*$/.test(n) && n.substr(-1) !== '.') {
219
+ if (typeof saveFunc === 'function') saveFunc(n);
220
+ return locals + n;
221
+ }
222
+
223
+ var i = n.indexOf('[');
224
+ if (i !== -1 && typeof saveFunc === 'function') {
225
+ var s = n.substr(0, i);
226
+ if (s.substr(-1) === '.') s = s.substr(0, s.length - 1);
227
+ saveFunc(s);
228
+ }
229
+
230
+ //转换为字符串索引
231
+ n = n.replace(
232
+ /\.?((([\w\d\_]*[^\w\d\_\.\[\]]+[\w\d\_]*)+)|([\d]+[\w].*))\.?/img,
233
+ function (a) {
234
+ if (/^["']|["']$/img.test(a)) return a;
235
+ if (a[0] === '.') a = a.substr(1);
236
+ if (a.substr(-1) === '.') a = a.substr(0, a.length - 1);
237
+ a = a.replace(/"/img, '\\"');
238
+ return '["' + a + '"]';
239
+ });
240
+ n = n.replace(/"\]/img, '"].');
241
+
242
+ // 变量索引
243
+ var left = n.indexOf('[');
244
+ var right = n.lastIndexOf(']');
245
+ if (left !== -1 && right !== -1) {
246
+ if (typeof saveFunc === 'function') {
247
+ n.split('[').forEach(function (item) {
248
+ var i = item.indexOf(']');
249
+ if (i === -1) return;
250
+ var n = item.substr(0, i);
251
+ if (!/^['"].*['"]$/.test(n) && !/^\d[\d\.]*\d?$/.test(n) &&
252
+ /^[a-zA-Z_][a-zA-Z0-9_\.]*$/.test(n))
253
+ saveFunc(n);
254
+ });
255
+ }
256
+ n = n.replace(/\.?\[/img, '[' + locals)
257
+ .replace(RegExp((locals + '[\'"\\d]').replace(/\./img, '\\.'), 'img'),
258
+ function (a) {
259
+ return a.substr(locals.length);
260
+ });
261
+ }
262
+
263
+ if (n.substr(-1) === '.') n = n.substr(0, n.length - 1);
264
+ if (n[0] === '[') {
265
+ var ret = locals.substr(0, locals.length - 1) + n;
266
+ } else {
267
+ var ret = locals + n;
268
+ }
269
+
270
+ // 修正一些很奇怪的问题
271
+ ret = ret.replace(/\.\["/img, '["')
272
+ .replace(/"\]\.\]/img, '"]]');
273
+ return ret;
274
+ };
275
+ // 常量
276
+ var CONST_VAL = ['nil', 'null', 'empty', 'blank', 'true', 'false'];
277
+
278
+ /**
279
+ * 解析函数调用
280
+ *
281
+ * @param {string} js
282
+ * @param {object} options
283
+ * @param {object} context
284
+ * @return {string}
285
+ */
286
+ exports.filtered = function (js, options, context) {
287
+ options = options || {}
288
+ if (!options.locals) options.locals = 'locals';
289
+ if (!options.filters) options.filters = 'filters';
290
+ options.locals += '.';
291
+ options.filters += '.';
292
+
293
+ if (!context) context = {};
294
+
295
+ var localsWrap = exports.localsWrap;
296
+
297
+ var isFirst = true;
298
+ var hasFilters = false;
299
+
300
+ var ret = exports.splitBy(js, '|').reduce(function (js, filter) {
301
+ hasFilters = true;
302
+ var parts = exports.splitBy(filter, ':');
303
+ var name = parts.shift();
304
+ var args = (parts.shift() || '').trim();
305
+ if (isFirst) {
306
+ js = localsWrap(js, null, context.saveLocalsName);
307
+ isFirst = false;
308
+ }
309
+ if (args) {
310
+ var a = exports.splitBy(args, ',');
311
+ for (var i in a) {
312
+ a[i] = localsWrap(a[i], null, context.saveLocalsName);
313
+ }
314
+ args = ', ' + a.join(', ');
315
+ }
316
+ return options.filters + name.trim() + '(' + js + args + ')';
317
+ });
318
+
319
+ if (!hasFilters) {
320
+ ret = localsWrap(ret, null, context.saveLocalsName);
321
+ }
322
+
323
+ return ret;
324
+ };
325
+
326
+ /**
327
+ * 解析条件语句
328
+ *
329
+ * @param {string} cond
330
+ * @param {object} context
331
+ * @return {string}
332
+ */
333
+ exports.condition = function (cond, context) {
334
+ if (!context) context = {};
335
+ var localsWrap = function (a) {
336
+ return exports.localsWrap(a, null, context.saveLocalsName);
337
+ };
338
+
339
+ var blocks = exports.split(cond);
340
+ // console.log(blocks);
341
+ // 拆分成多个子条件
342
+ var conds = [[]];
343
+ var condi = 0;
344
+ for (var i in blocks) {
345
+ var b = blocks[i];
346
+ switch (b) {
347
+ // 连接元素
348
+ case '&&':
349
+ case '||':
350
+ case 'and':
351
+ case 'or':
352
+ if (b === '&&')
353
+ b = 'and';
354
+ else if (b === '||')
355
+ b = 'or';
356
+ condi++;
357
+ conds[condi] = b;
358
+ condi++;
359
+ conds[condi] = [];
360
+ break;
361
+ // 其他元素
362
+ default:
363
+ conds[condi].push(b);
364
+ }
365
+ }
366
+
367
+ // 生成单个条件的js代码
368
+ var op = ['>', '<', '==', '!=', '>=', '<>', '<=',
369
+ 'contains', 'hasValue', 'hasKey'];
370
+ var vempty = ['nil', 'null', 'empty', 'blank'];
371
+ var one = function (ca) {
372
+ if (ca.length === 1) {
373
+ return '(' + localsWrap(ca[0]) + ')';
374
+ }
375
+ if (ca.length === 3) {
376
+ var op1 = localsWrap(ca[0]);
377
+ var op2 = localsWrap(ca[2]);
378
+ ca[1] = ca[1].toLowerCase();
379
+ if (ca[1] === 'contains') {
380
+ // contains 语句
381
+ return '(Array.isArray(' + op1 + ') ? (' + op1 +
382
+ '.indexOf(' + op2 + ') !== -1) : ' +
383
+ '(String(' + op1 +
384
+ ').toLowerCase().indexOf(' + op2 +
385
+ ') !== -1))';
386
+ } else if (ca[1] === 'hasvalue') {
387
+ // hasValue 语句
388
+ return '(Array.isArray(' + op1 + ') ? (' + op1 +
389
+ '.indexOf(' + op2 + ') !== -1 ? true : false) : ' +
390
+ '(function () { for (var i in ' + op1 + ') if (' + op1 +
391
+ '[i] == ' + op2 + ') return true;' +
392
+ ' return false; })())';
393
+ } else if (ca[1] === 'haskey') {
394
+ // hasKey 语句
395
+ return '(' + op1 + ' && typeof ' + op1 + '[' + op2 +
396
+ '] !== \'undefined\')';
397
+ } else if (vempty.indexOf(ca[2]) > -1) {
398
+ // nil, empty
399
+ switch (ca[1]) {
400
+ case '!=':
401
+ case '<>':
402
+ return '(' + op1 + ')';
403
+ case '==':
404
+ return '(!' + op1 + ')';
405
+ default:
406
+ return null;
407
+ }
408
+ } else if (op.indexOf(ca[1]) > -1) {
409
+ // 其他
410
+ if (ca[1] === '<>')
411
+ ca[1] = '!=';
412
+ return '(' + op1 + ca[1] + op2 + ')';
413
+ } else {
414
+ // 出错
415
+ return null;
416
+ }
417
+ } else {
418
+ return null;
419
+ }
420
+ };
421
+
422
+ var ret = [];
423
+ for (var i in conds) {
424
+ var c = conds[i];
425
+ if (Array.isArray(c)) {
426
+ var s = one(c);
427
+ if (s === null) {
428
+ return null;
429
+ } else {
430
+ ret.push(s);
431
+ }
432
+ } else if (c === 'and') {
433
+ ret.push('&&');
434
+ } else if (c === 'or') {
435
+ ret.push('||');
436
+ }
437
+ }
438
+
439
+ if (ret.length > 1) {
440
+ return '(' + ret.join(' ') + ')';
441
+ } else {
442
+ return ret.join(' ');
443
+ }
444
+ };
445
+
446
+ /**
447
+ * 空格分割字符串
448
+ *
449
+ * @param {string} text
450
+ * @return {array}
451
+ */
452
+ exports.split = function (text) {
453
+ var isString = false;
454
+ var lastIndex = 0;
455
+ var ret = [];
456
+ var add = function (end) {
457
+ var w = text.slice(lastIndex, end).trim();
458
+ if (w.length > 0) ret.push(w);
459
+ lastIndex = end;
460
+ };
461
+
462
+ for (var i = 0, len = text.length; i < len; i++) {
463
+ var c = text[i];
464
+ if ((c === '"' || c === '\'') && text[i - 1] !== '\\') {
465
+ // 字符串开始或结束
466
+ if (isString === c) {
467
+ // 结束
468
+ i++;
469
+ add(i);
470
+ isString = false;
471
+ } else if (!isString) {
472
+ // 开始
473
+ add(i);
474
+ isString = c;
475
+ }
476
+ } else if (!isString) {
477
+ // 非字符串
478
+ var isOpChar = function (c) {
479
+ return (c === '<' || c === '>' || c === '=' || c === '!');
480
+ };
481
+ if (c === ' ') {
482
+ // 空格
483
+ add(i);
484
+ } else if (isOpChar(c)) {
485
+ // 中间的比较运算符 如 a<b
486
+ add(i);
487
+ do {
488
+ i++;
489
+ } while (isOpChar(text[i]));
490
+ add(i);
491
+ i--;
492
+ }
493
+ }
494
+ }
495
+ add(i);
496
+
497
+ return ret;
498
+ };
499
+
500
+ /**
501
+ * 使用指定字符分割
502
+ *
503
+ * @param {string} text
504
+ * @param {string} sep
505
+ * @return {array}
506
+ */
507
+ exports.splitBy = function (text, sep) {
508
+ var arr = text.split(sep);
509
+ var ret = [];
510
+ for (var i = 0, len = arr.length; i < len; i++) {
511
+ var g = arr[i];
512
+ // 合并误分割的字符串内分割符
513
+ var gl = g.trimLeft();
514
+ var gr = g.trimRight();
515
+ if ((gl[0] === '"' || gl[0] === "'") && gl[0] !== gr.substr(-1)) {
516
+ var j = i;
517
+ do {
518
+ j++;
519
+ } while (j < len && arr[j].trimRight().substr(-1) !== gl[0])
520
+ if (j < len) {
521
+ g = arr.slice(i, j + 1).join(sep);
522
+ i = j;
523
+ }
524
+ }
525
+ ret.push(g.trim());
526
+ }
527
+ return ret;
528
+ };
529
+
530
+ /**
531
+ * 解析for循环
532
+ *
533
+ * @param {string} loops
534
+ * @param {object} context
535
+ * @return {string}
536
+ */
537
+ exports.forloops = function (loops, context) {
538
+ var blocks = loops.split(/\s+/);
539
+
540
+ // 如果为for array,自动转化为默认的 for item in array
541
+ if (blocks.length === 1) {
542
+ blocks[1] = 'in';
543
+ blocks[2] = blocks[0];
544
+ blocks[0] = 'item';
545
+ }
546
+
547
+ var loopIndex = context.loop;
548
+
549
+ var localsWrap = exports.localsWrap;
550
+ // 索引
551
+ var n = '$_loop_' + loopIndex;
552
+ // 数字索引
553
+ var ni = '$_loop_i_' + loopIndex;
554
+ // 数组的名称
555
+ var array = localsWrap(blocks[2], null, context.saveLocalsName);
556
+ // 当前元素的名称
557
+ var item = localsWrap(blocks[0], null, context.saveLocalsName);
558
+
559
+ // loop item临时名称
560
+ context.loopName[context.loopName.length - 1].itemName = item;
561
+
562
+ var header = '(function (locals) {\n' +
563
+ 'var ' + ni + ' = 0;\n' +
564
+ 'locals.forloop = {};\n';
565
+
566
+ // for i in (1..item.quantity)
567
+ var r = /^\((.+)\.\.(.+)\)$/.exec(blocks[2]);
568
+ if (r !== null) {
569
+ array = localsWrap('_range_' + loopIndex, null, context.saveLocalsName);
570
+ header += array + ' = $_range(' +
571
+ localsWrap(r[1], null, context.saveLocalsName) + ', ' +
572
+ localsWrap(r[2], null, context.saveLocalsName) + ');\n';
573
+ }
574
+
575
+ // 将对象转换为数组
576
+ var _array = '$_loop_arr_' + loopIndex;
577
+ header += 'var ' + _array + ' = $_array(' + array + ');\n';
578
+ array = _array;
579
+
580
+ // 允许增加的标记属性
581
+ var OPTIONS = ['limit', 'offset'];
582
+ var options = {};
583
+ var getOptions = function (block) {
584
+ var b = block.split(':');
585
+ if (b.length !== 2) return false;
586
+ var name = b[0].trim();
587
+ var value = localsWrap(b[1], null, context.saveLocalsName);
588
+ if (OPTIONS.indexOf(name) === -1) return false;
589
+ options[name] = value;
590
+ return true;
591
+ };
592
+
593
+ // 格式化参数 limit: N offset: M => limit:N offset:M
594
+ for (var i = 3; i < blocks.length; i++) {
595
+ if (blocks[i].substr(-1) === ':') {
596
+ blocks[i] += blocks[i + 1];
597
+ blocks.splice(i + 1, 1);
598
+ }
599
+ }
600
+ // for item in arrays limit:N offset:M
601
+ for (var i = 3; i < blocks.length; i++) {
602
+ if (getOptions(blocks[i]) === false) return null;
603
+ }
604
+ if (options.limit && options.offset) {
605
+ header += array + ' = ' + array + '.slice(' + options.offset + ', ' +
606
+ options.offset + ' + ' + options.limit + ');\n';
607
+ } else if (options.limit) {
608
+ header += array + ' = ' + array + '.slice(0, ' + options.limit + ');\n';
609
+ } else if (options.offset) {
610
+ header += array + ' = ' + array + '.slice(' + options.offset + ');\n';
611
+ }
612
+
613
+ // 生成基本代码
614
+ var script = header +
615
+ 'locals.forloop.length = ' + array + '.length;\n' +
616
+ 'var forloop = locals.forloop;\n' +
617
+ 'for (var ' + n + ' = 0; ' + n + ' < forloop.length; ' +
618
+ n + '++) {\n' +
619
+ item + ' = ' + array + '[' + n + '];\n' +
620
+ 'forloop.name = \'' + blocks[0] + '\';\n' +
621
+ 'forloop.index0 = ' + ni + ';\n' +
622
+ 'forloop.index = ++' + ni + ';\n' +
623
+ 'forloop.rindex0 = forloop.length - forloop.index;\n' +
624
+ 'forloop.rindex = forloop.length - forloop.index0;\n' +
625
+ 'forloop.first = ' + ni + ' === 1 ? true : false;\n' +
626
+ 'forloop.last = ' + ni + ' === forloop.length ? true : false;\n' +
627
+ '/* for loops body */';
628
+
629
+ return script;
630
+ };
631
+
632
+ /**
633
+ * 解析tablerowloop循环
634
+ *
635
+ * @param {string} loops
636
+ * @param {object} context
637
+ * @return {string}
638
+ */
639
+ exports.tablerow = function (loops, context) {
640
+ var blocks = loops.split(/\s+/);
641
+
642
+ var loopIndex = context.loop;
643
+
644
+ if (blocks.length < 2) return null;
645
+
646
+ // 如果为tablerow array,自动转化为默认的 tablerow item in array
647
+ if (blocks.length === 2) {
648
+ blocks[3] = blocks[1];
649
+ blocks[1] = 'in';
650
+ blocks[2] = blocks[0];
651
+ blocks[0] = 'item';
652
+ }
653
+
654
+ var localsWrap = exports.localsWrap;
655
+ // 索引
656
+ var n = '$_loop_' + loopIndex;
657
+ // 数字索引
658
+ var ni = '$_loop_i_' + loopIndex;
659
+ // 数组的名称
660
+ var array = localsWrap(blocks[2], null, context.saveLocalsName);
661
+ // 当前元素的名称
662
+ var item = localsWrap(blocks[0], null, context.saveLocalsName);
663
+
664
+ // loop item临时名称
665
+ context.loopName[context.loopName.length - 1].itemName = item;
666
+
667
+ var header = '(function (locals) {\n' +
668
+ 'var ' + ni + ' = 0;\n' +
669
+ 'locals.tablerowloop = {};\n';
670
+
671
+ // tablerow i in (1..item.quantity)
672
+ var r = /^\((.+)\.\.(.+)\)$/.exec(blocks[2]);
673
+ if (r !== null) {
674
+ array = localsWrap('_range_' + loopIndex, null, context.saveLocalsName);
675
+ header += array + ' = $_range(' +
676
+ localsWrap(r[1], null, context.saveLocalsName) +
677
+ ', ' + localsWrap(r[2], null, context.saveLocalsName) + ');\n';
678
+ }
679
+
680
+ // 将对象转换为数组
681
+ var _array = '$_loop_arr_' + loopIndex;
682
+ header += 'var ' + _array + ' = $_array(' + array + ');\n';
683
+ array = _array;
684
+
685
+ // 允许增加的标记属性
686
+ var OPTIONS = ['cols', 'limit', 'offset'];
687
+ var options = {};
688
+ var getOptions = function (block) {
689
+ var b = block.split(':');
690
+ if (b.length !== 2) return false;
691
+ var name = b[0].trim();
692
+ var value = localsWrap(b[1], null, context.saveLocalsName);
693
+ if (OPTIONS.indexOf(name) === -1) return false;
694
+ options[name] = value;
695
+ return true;
696
+ };
697
+
698
+ // 格式化参数 limit: N offset: M => limit:N offset:M
699
+ for (var i = 3; i < blocks.length; i++) {
700
+ if (blocks[i].substr(-1) === ':') {
701
+ blocks[i] += blocks[i + 1];
702
+ blocks.splice(i + 1, 1);
703
+ }
704
+ }
705
+ // tablerow item in arrays cols:3 limit:N offset:M
706
+ for (var i = 3; i < blocks.length; i++) {
707
+ if (getOptions(blocks[i]) === false) return null;
708
+ }
709
+ if (options.limit && options.offset) {
710
+ header += array + ' = ' + array + '.slice(' + options.offset + ', ' +
711
+ options.offset + ' + ' + options.limit + ');\n';
712
+ } else if (options.limit) {
713
+ header += array + ' = ' + array + '.slice(0, ' + options.limit + ');\n';
714
+ } else if (options.offset) {
715
+ header += array + ' = ' + array + '.slice(' + options.offset + ');\n';
716
+ }
717
+
718
+ // 生成基本代码
719
+ var script = header +
720
+ 'locals.tablerowloop.length = ' + array + '.length;\n' +
721
+ 'var tablerowloop = locals.tablerowloop;\n' +
722
+ 'var ' + n + '_row = 0;\n' +
723
+ 'for (var ' + n + ' = 0; ' + n + ' < tablerowloop.length; ) {\n' +
724
+ n + '_row++;\n' +
725
+ '$_buf += \'<tr class=\"row\' + (' + n + '_row) + \'\">\\n\';' +
726
+ 'for (tablerowloop.col0 = 0; tablerowloop.col0 < ' + options.cols +
727
+ ' && ' + n + ' < tablerowloop.length; tablerowloop.col0++, ' +
728
+ n + '++) {\n' +
729
+ item + ' = ' + array + '[' + n + '];\n' +
730
+ 'tablerowloop.name = \'' + blocks[0] + '\';\n' +
731
+ 'tablerowloop.col = tablerowloop.col0 + 1;\n' +
732
+ 'tablerowloop.col_first = tablerowloop.col === 1 ? true : false;\n' +
733
+ 'tablerowloop.col_last = tablerowloop.col === ' + options.cols +
734
+ ' ? true : false;\n' +
735
+ 'tablerowloop.index0 = ' + ni + ';\n' +
736
+ 'tablerowloop.index = ++' + ni + ';\n' +
737
+ 'tablerowloop.rindex0 = tablerowloop.length - tablerowloop.index;\n' +
738
+ 'tablerowloop.rindex = tablerowloop.length - tablerowloop.index0;\n' +
739
+ 'tablerowloop.first = ' + ni + ' === 1 ? true : false;\n' +
740
+ 'tablerowloop.last = ' + ni + ' === tablerowloop.length ? true : false;\n' +
741
+ 'if (tablerowloop.last === true) tablerowloop.col_last = true;\n' +
742
+ '$_buf += \'<td class=\"col\' + tablerowloop.col + \'\">\';' +
743
+ '/* tablerow loops body */';
744
+
745
+ return script;
746
+ };
747
+
748
+ /**
749
+ * 解析assign
750
+ *
751
+ * @param {string} expression
752
+ * @param {object} context
753
+ * @return {string}
754
+ */
755
+ exports.assign = function (expression, context) {
756
+ if (expression === '[]' || expression === 'array()') {
757
+ // 如果为 [], array() 则创建一个数组
758
+ var ret = '[]';
759
+ } else if (expression === 'object()') {
760
+ // 如果为 {}, object(), {"a":"xxx"} 则创建相应的对象
761
+ var ret = '{}';
762
+ } else if (/^\{.*\}$/img.test(expression)) {
763
+ var ret = 'JSON.parse(\'' + expression + '\')';
764
+ } else {
765
+ var ret = exports.filtered(expression, null, context);
766
+ }
767
+
768
+ // 替换用assign定义的名称为global
769
+ // console.log(expression, context.assignNames);
770
+ for (var i in context.assignNames) {
771
+ // 忽略loop中的名称名称(即优先使用loop内定义的名称)
772
+ if (context.loopName.length > 0) {
773
+ if (i === context.loopName[context.loopName.length - 1].itemName ||
774
+ i.substr(0, 8) === 'forloop.' ||
775
+ i.substr(0, 13) === 'tablerowloop.') continue;
776
+ }
777
+
778
+ ret = ret.replace(RegExp(i, 'img'), 'global.' + i);
779
+ }
780
+ // console.log(ret);
781
+ return ret;
782
+ };
783
+
784
+ /**
785
+ * 解析cycle
786
+ *
787
+ * @param {string} strlist
788
+ * @param {object} context
789
+ * @return {string}
790
+ */
791
+ exports.cycle = function (strlist, context) {
792
+ var localsWrap = exports.localsWrap;
793
+
794
+ var list = exports.splitBy(strlist, ',');
795
+
796
+ var hasKey = false;
797
+ var _list = exports.splitBy(list[0], ':');
798
+ if (_list.length > 1) {
799
+ hasKey = _list[0];
800
+ list[0] = _list[1];
801
+ } else if (list[0].substr(-1) === ':') {
802
+ hasKey = list[0].substr(0, list[0].length - 1);
803
+ list.splice(0, 1);
804
+ } else if (list[1] === ':') {
805
+ hasKey = list[0];
806
+ list.splice(0, 2);
807
+ }
808
+
809
+ for (var i in list) {
810
+ list[i] = localsWrap(list[i], null, context.saveLocalsName);
811
+ }
812
+
813
+ var cycleKey = md5((hasKey || list.join(','))).substr(0, 8);
814
+ context.addCycle(cycleKey, list);
815
+
816
+ var cycleName = '$_cycle_' + cycleKey;
817
+ var script = '$_tmpbuf=(' + cycleName + '.items[' + cycleName + '.i]);\n' +
818
+ '$_buf+=($_tmpbuf===null||typeof($_tmpbuf)==="undefined"?"":$_tmpbuf);\n' +
819
+ '$_cycle_next(' + cycleName + ');\n';
820
+ return script;
821
+ };
822
+
823
+
824
+ /**
825
+ * 异步获取数据对象
826
+ *
827
+ * @param {object} models
828
+ * @param {array} names
829
+ * @param {object} env
830
+ */
831
+ var AsyncDataList = function (models, names, env) {
832
+ if (!(this instanceof AsyncDataList)) {
833
+ return new AsyncDataList(models, names, env);
834
+ }
835
+ this.models = models || {};
836
+ this.names = names || {};
837
+ this.env = env || {};
838
+ this.data = {};
839
+ };
840
+ exports.AsyncDataList = AsyncDataList;
841
+
842
+ /**
843
+ * 获取一个数据
844
+ *
845
+ * @param {string} name
846
+ * @param {function} callback
847
+ */
848
+ AsyncDataList.prototype.getItem = function (name, callback) {
849
+ var self = this;
850
+ var data = self.data;
851
+ var models = self.models;
852
+ try {
853
+ var model = models[name];
854
+ if (typeof model === 'undefined') {
855
+ // 智能分析,比如需要 a.b.c 如果该项没注册,会自动递归查找其父项 a.b 和 a
856
+ var ns = name.split('.');
857
+ while (ns.pop() && ns.length > 0) {
858
+ name = ns.join('.');
859
+ model = models[name];
860
+ if (typeof model !== 'undefined') break;
861
+ }
862
+ }
863
+
864
+ // 如果为function,则调用其以取得数据
865
+ var modelType = typeof model;
866
+ if (modelType === 'function') {
867
+ return model(self.env, function (err, d) {
868
+ if (err) return callback(err);
869
+ self.saveItem(name, d);
870
+ return callback(null);
871
+ });
872
+ } else if (modelType !== 'undefined') {
873
+ self.saveItem(name, model);
874
+ return callback(null);
875
+ }
876
+
877
+ return callback(null);
878
+ } catch (err) {
879
+ callback(err);
880
+ return false;
881
+ }
882
+ };
883
+
884
+ /**
885
+ * 保存一个数据
886
+ *
887
+ * @param {string} name
888
+ * @param {object} value
889
+ */
890
+ AsyncDataList.prototype.saveItem = function (name, value) {
891
+ var data = this.data;
892
+ var ns = name.split('.');
893
+ var oldns = [];
894
+ var key = ns.pop();
895
+ var getFather = function (node, ns, oldns) {
896
+ if (ns.length < 1) return node;
897
+ var key = ns.shift();
898
+ if (!node[key]) node[key] = {};
899
+ oldns.push(key);
900
+ if (typeof node[key] !== 'object') {
901
+ throw Error('Cannot set childs because "' + oldns.join('.') +
902
+ '" is not an object');
903
+ }
904
+ return getFather(node[key], ns, oldns);
905
+ };
906
+ var node = getFather(data, ns, oldns);
907
+ node[key] = value;
908
+
909
+ return data;
910
+ };
911
+
912
+ /**
913
+ * 队列式读取数据
914
+ *
915
+ * @param {function} callback function (err, data)
916
+ */
917
+ AsyncDataList.prototype.start = function (callback) {
918
+ var models = this.models;
919
+ var names = this.names;
920
+ var data = this.data;
921
+ var self = this;
922
+ try {
923
+ var next = function (err) {
924
+ if (err) return callback(err);
925
+ if (names.length < 1) return callback(null, data);
926
+ var name = names.shift();
927
+ self.getItem(name, next);
928
+ };
929
+ next();
930
+ } catch (err) {
931
+ return callback(err);
932
+ }
933
+ };
934
+
935
+ /**
936
+ * 并行式读取数据
937
+ *
938
+ * @param {function} callback function (err, data)
939
+ */
940
+ AsyncDataList.prototype.startParallel = function (callback) {
941
+ var models = this.models;
942
+ var names = this.names;
943
+ var data = this.data;
944
+ var self = this;
945
+
946
+ var isReturn = false;
947
+
948
+ var getItem = function (name, names) {
949
+ self.getItem(name, function (err) {
950
+ if (err && !isReturn) {
951
+ isReturn = true;
952
+ return callback(err);
953
+ }
954
+ var i = names.indexOf(name);
955
+ names.splice(i, 1);
956
+ if (names.length < 1 && !isReturn) {
957
+ isReturn = true;
958
+ return callback(null, data);
959
+ }
960
+ });
961
+ };
962
+
963
+ try {
964
+ for (var i in names) {
965
+ getItem(names[i], names);
966
+ }
967
+ } catch (err) {
968
+ return callback(err);
969
+ }
970
+ };
971
+
972
+ return exports;
973
+ })(m, m.exports);
974
+ modules.utils = m.exports;
975
+ /*-----------------------------------------------*/
976
+
977
+ /*-------------- ./lib/filters.js ---------------*/
978
+ var m = {exports: {}};
979
+ (function (module, exports) {
980
+ 'use strict';
981
+
982
+ /**
983
+ * 内置函数
984
+ *
985
+ * @author 老雷<leizongmin@gmail.com>
986
+ */
987
+
988
+
989
+ /**
990
+ * 转换为字符串,如果是undefined或者null则返回空字符串
991
+ *
992
+ * @param {Object} text
993
+ * @return {String}
994
+ */
995
+ var toString = function (text) {
996
+ return (text === null || typeof(text) === 'undefined') ? '' : String(text);
997
+ };
998
+
999
+ /*---------------------------- HTML Filters ----------------------------------*/
1000
+ /**
1001
+ * 创建一个img标签
1002
+ *
1003
+ * @param {string} url
1004
+ * @param {string} alt
1005
+ * @return {string}
1006
+ */
1007
+ exports.img_tag = function (url, alt) {
1008
+ return '<img src="' + exports.escape(url) + '" alt="' +
1009
+ exports.escape(alt || '') + '">';
1010
+ };
1011
+
1012
+ /**
1013
+ * 创建一个script标签
1014
+ *
1015
+ * @param {string} url
1016
+ * @return {string}
1017
+ */
1018
+ exports.script_tag = function (url) {
1019
+ return '<script src="' + exports.escape(url) + '"></script>';
1020
+ };
1021
+
1022
+ /**
1023
+ * 创建一个样式表link标签
1024
+ *
1025
+ * @param {string} url
1026
+ * @param {string} media
1027
+ * @return {string}
1028
+ */
1029
+ exports.stylesheet_tag = function (url, media) {
1030
+ return '<link href="' + exports.escape(url) +
1031
+ '" rel="stylesheet" type="text/css" media="' +
1032
+ exports.escape(media || 'all') + '" />';
1033
+ };
1034
+
1035
+ /**
1036
+ * A链接标签
1037
+ *
1038
+ * @param {string} link
1039
+ * @param {string} url
1040
+ * @param {string} title
1041
+ * @return {string}
1042
+ */
1043
+ exports.link_to = function (link, url, title) {
1044
+ return '<a href="' + exports.escape(url || '') + '" title="' +
1045
+ exports.escape(title || '') + '">' + exports.escape(link) + '</a>';
1046
+ };
1047
+
1048
+ /*-----------------------------Math Filters-----------------------------------*/
1049
+ /**
1050
+ * 相加
1051
+ *
1052
+ * @param {number} input
1053
+ * @param {number} operand
1054
+ * @return {number}
1055
+ */
1056
+ exports.plus = function (input, operand) {
1057
+ input = Number(input) || 0;
1058
+ operand = Number(operand) || 0;
1059
+ return input + operand;
1060
+ };
1061
+
1062
+ /**
1063
+ * 相减
1064
+ *
1065
+ * @param {number} input
1066
+ * @param {number} operand
1067
+ * @return {number}
1068
+ */
1069
+ exports.minus = function (input, operand) {
1070
+ input = Number(input) || 0;
1071
+ operand = Number(operand) || 0;
1072
+ return input - operand;
1073
+ };
1074
+
1075
+ /**
1076
+ * 相乘
1077
+ *
1078
+ * @param {number} input
1079
+ * @param {number} operand
1080
+ * @return {number}
1081
+ */
1082
+ exports.times = function (input, operand) {
1083
+ input = Number(input) || 0;
1084
+ operand = Number(operand) || 0;
1085
+ return input * operand;
1086
+ };
1087
+
1088
+ /**
1089
+ * 相除
1090
+ *
1091
+ * @param {number} input
1092
+ * @param {number} operand
1093
+ * @return {number}
1094
+ */
1095
+ exports.divided_by = function (input, operand) {
1096
+ input = Number(input) || 0;
1097
+ operand = Number(operand) || 0;
1098
+ return input / operand;
1099
+ };
1100
+
1101
+ /**
1102
+ * 四舍五入
1103
+ *
1104
+ * @param {number} input
1105
+ * @param {int} point
1106
+ * @return {number}
1107
+ */
1108
+ exports.round = function (input, point) {
1109
+ point = parseInt(point, 10) || 0;
1110
+ if (point < 1) return Math.round(input);
1111
+ var n = Math.pow(10, point);
1112
+ return Math.round(input * n) / n;
1113
+ };
1114
+
1115
+ /**
1116
+ * 整数
1117
+ *
1118
+ * @param {number} input
1119
+ * @return {int}
1120
+ */
1121
+ exports.integer = function (input) {
1122
+ return parseInt(input, 10) || 0;
1123
+ };
1124
+
1125
+ /**
1126
+ * 返回指定范围的随机数
1127
+ *
1128
+ * @param {number} m
1129
+ * @param {number} n
1130
+ * @return {number}
1131
+ */
1132
+ exports.random = function (m, n) {
1133
+ m = parseInt(m);
1134
+ n = parseInt(n);
1135
+ if (!isFinite(m)) return Math.random();
1136
+ if (!isFinite(n)) {
1137
+ n = m;
1138
+ m = 0;
1139
+ }
1140
+ return Math.random() * (n - m) + m;
1141
+ };
1142
+
1143
+ /*---------------------------Manipulation Filters-----------------------------*/
1144
+ /**
1145
+ * 在后面拼接字符串
1146
+ *
1147
+ * @param {string} input
1148
+ * @param {string} characters
1149
+ * @return {string}
1150
+ */
1151
+ exports.append = function (input, characters) {
1152
+ if (!characters) return toString(input);
1153
+ return toString(input) + toString(characters);
1154
+ };
1155
+
1156
+ /**
1157
+ * 在前面拼接字符串
1158
+ *
1159
+ * @param {string} input
1160
+ * @param {string} characters
1161
+ * @return {string}
1162
+ */
1163
+ exports.prepend = function (input, characters) {
1164
+ if (!characters) return toString(input);
1165
+ return toString(characters) + toString(input);
1166
+ };
1167
+
1168
+ /**
1169
+ * 将字符串转化为驼峰命名方式
1170
+ *
1171
+ * @param {string} input
1172
+ * @return {string}
1173
+ */
1174
+ exports.camelize = function (input) {
1175
+ input = toString(input);
1176
+ return input.replace(/[^a-zA-Z0-9]+(\w)/g, function(_, ch) {
1177
+ return ch.toUpperCase();
1178
+ });
1179
+ };
1180
+
1181
+ /**
1182
+ * 字符串首字母大写
1183
+ *
1184
+ * @param {string} input
1185
+ * @return {string}
1186
+ */
1187
+ exports.capitalize = function (input) {
1188
+ input = toString(input);
1189
+ return input[0].toUpperCase() + input.substr(1);
1190
+ };
1191
+
1192
+ /**
1193
+ * 取当前毫秒时间戳
1194
+ *
1195
+ * @param {int} input
1196
+ * @return {int}
1197
+ */
1198
+ exports.timestamp = function (input) {
1199
+ input = parseInt(input, 10) || 0;
1200
+ return new Date().getTime() + input;
1201
+ };
1202
+
1203
+ /**
1204
+ * 格式化日期字符串
1205
+ *
1206
+ * @param {string} input
1207
+ * @param {string} format
1208
+ * @return {string}
1209
+ */
1210
+ exports.date = function (input, format) {
1211
+ if (toString(input).toLowerCase() == 'now') {
1212
+ var time = new Date();
1213
+ } else {
1214
+ var timestamp = parseInt(input, 10);
1215
+ if (timestamp == input) {
1216
+ var time = new Date(timestamp);
1217
+ } else {
1218
+ var time = new Date(input);
1219
+ }
1220
+ }
1221
+ if (!time || !isFinite(time.valueOf())) return 'Invalid Date';
1222
+ if (!format) format = '%Y-%m-%j %H:%M:%S';
1223
+ // 返回结果格式 ["Wed", "Apr", "11", "2012"]
1224
+ var dates = time.toDateString().split(/\s/);
1225
+ // 返回结果格式 ["Wednesday,", "April", "11,", "2012"]
1226
+ var dateS = time.toLocaleDateString().split(/\s/);
1227
+ // 返回结果格式 ["10", "37", "44", "GMT", "0800", "(中国标准时间)"]
1228
+ var times = time.toTimeString().split(/[\s:\+]/);
1229
+ var n2 = function (n) {
1230
+ return n > 10 ? n : '0' + n;
1231
+ };
1232
+ var replace = {
1233
+ a: dates[0], // 星期
1234
+ A: dateS[0],
1235
+ b: dates[1], // 月份
1236
+ B: dateS[1],
1237
+ c: time.toLocaleString(),
1238
+ d: dates[2],
1239
+ H: times[0], // 24小时制
1240
+ I: times[0] % 12, // 12小时制
1241
+ j: dates[2], // 日
1242
+ m: n2(time.getMonth() + 1), // 月份
1243
+ M: times[1], // 分钟
1244
+ p: Number(times[0]) < 12 ? 'AM' : 'PM', // 上午/下午
1245
+ S: times[2], // 秒
1246
+ U: weekNo(time), // 当年的第几周,星期日开始
1247
+ W: weekNo(time, true), // 星期一开始
1248
+ w: time.getDay(), // 星期几(0-6)
1249
+ x: time.toDateString(),
1250
+ X: time.toTimeString(),
1251
+ y: dates[3].substr(-2), // 年份
1252
+ Y: dates[3],
1253
+ Z: times[4] // 时区
1254
+ };
1255
+ var ret = toString(format);
1256
+ for (var i in replace) {
1257
+ ret = ret.replace(new RegExp('%' + i, 'g'), replace[i]);
1258
+ }
1259
+ return ret;
1260
+ };
1261
+
1262
+ function weekNo (now, mondayFirst) {
1263
+ var totalDays = 0;
1264
+ var years = now.getFullYear();
1265
+ var days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
1266
+ if (years % 100 === 0) {
1267
+ if (years % 400 === 0) days[1] = 29;
1268
+ } else if (years % 4 === 0) {
1269
+ days[1] = 29;
1270
+ }
1271
+ if (now.getMonth() === 0) {
1272
+ totalDays = totalDays + now.getDate();
1273
+ } else {
1274
+ var curMonth = now.getMonth();
1275
+ for (var count = 1; count <= curMonth; count++) {
1276
+ totalDays = totalDays + days[count - 1];
1277
+ }
1278
+ totalDays = totalDays + now.getDate();
1279
+ }
1280
+ // 默认是以星期日开始的
1281
+ var week = Math.round(totalDays / 7);
1282
+ if (mondayFirst && new Date(toString(years)).getDay() === 0) week += 1;
1283
+ return week;
1284
+ }
1285
+
1286
+ /**
1287
+ * 将字符串转换为小写
1288
+ *
1289
+ * @param {string} input
1290
+ * @return {string}
1291
+ */
1292
+ exports.downcase = function (input) {
1293
+ return toString(input).toLowerCase();
1294
+ };
1295
+
1296
+ /**
1297
+ * 将字符串转换为大写
1298
+ *
1299
+ * @param {string} input
1300
+ * @return {string}
1301
+ */
1302
+ exports.upcase = function (input) {
1303
+ return toString(input).toUpperCase();
1304
+ };
1305
+
1306
+ /**
1307
+ * 字符串转义(HTML)
1308
+ *
1309
+ * @param {string} input
1310
+ * @return {string}
1311
+ */
1312
+ exports.escape = function (input) {
1313
+ return toString(input).replace(/&(?!\w+;)/g, '&amp;')
1314
+ .replace(/</g, '&lt;')
1315
+ .replace(/>/g, '&gt;')
1316
+ .replace(/"/g, '&quot;');
1317
+ };
1318
+
1319
+ function getFirstKey (obj) {
1320
+ if (Array.isArray(obj)) {
1321
+ return 0;
1322
+ } else {
1323
+ var keys = Object.keys(obj);
1324
+ return keys[0] || '';
1325
+ }
1326
+ };
1327
+
1328
+ function getLastKey (obj) {
1329
+ if (Array.isArray(obj)) {
1330
+ return obj.length - 1;
1331
+ } else {
1332
+ var keys = Object.keys(obj);
1333
+ return keys.pop() || '';
1334
+ }
1335
+ };
1336
+
1337
+ /**
1338
+ * 返回对象的所有键
1339
+ *
1340
+ * @param {object} input
1341
+ * @return {array}
1342
+ */
1343
+ exports.keys = function (input) {
1344
+ try {
1345
+ return Object.keys(input);
1346
+ } catch (err) {
1347
+ return [];
1348
+ }
1349
+ };
1350
+
1351
+ /**
1352
+ * 取第一个元素
1353
+ *
1354
+ * @param {array} array
1355
+ * @return {object}
1356
+ */
1357
+ exports.first = function (array) {
1358
+ return array[getFirstKey(array)];
1359
+ };
1360
+
1361
+ /**
1362
+ * 取最后一个元素
1363
+ *
1364
+ * @param {array} array
1365
+ * @return {object}
1366
+ */
1367
+ exports.last = function (array) {
1368
+ return array[getLastKey(array)];
1369
+ };
1370
+
1371
+ /**
1372
+ * 转化为handle字符串
1373
+ *
1374
+ * @param {string} input
1375
+ * @return {string}
1376
+ */
1377
+ exports.handleize = function (input) {
1378
+ return toString(input).replace(/[^0-9a-zA-Z ]/g, '')
1379
+ .replace(/[ ]+/g, '-')
1380
+ .toLowerCase();
1381
+ };
1382
+
1383
+ /**
1384
+ * 将数组以指定的字符串拼接起来
1385
+ *
1386
+ * @param {array} input
1387
+ * @param {string} segmenter
1388
+ * @return {string}
1389
+ */
1390
+ exports.join = function (input, segmenter) {
1391
+ if (!segmenter) segmenter = ' ';
1392
+ if (Array.isArray(input)) {
1393
+ return input.join(segmenter);
1394
+ } else {
1395
+ return '';
1396
+ }
1397
+ };
1398
+
1399
+ /**
1400
+ * 替换第一次出现的字符串
1401
+ *
1402
+ * @param {string} input
1403
+ * @param {string} substring
1404
+ * @param {string} replacement
1405
+ * @return {string}
1406
+ */
1407
+ exports.replace_first = function (input, substring, replacement) {
1408
+ return toString(input).replace(substring, replacement);
1409
+ };
1410
+
1411
+ /**
1412
+ * 替换指定字符串
1413
+ *
1414
+ * @param {string} input
1415
+ * @param {string} substring
1416
+ * @param {string} replacement
1417
+ * @return {string}
1418
+ */
1419
+ exports.replace = function (input, substring, replacement) {
1420
+ input = toString(input);
1421
+ while (input.indexOf(substring) > -1) {
1422
+ input = input.replace(substring, replacement);
1423
+ }
1424
+ return input;
1425
+ };
1426
+
1427
+ /**
1428
+ * 删除指定字符串
1429
+ *
1430
+ * @param {string} input
1431
+ * @param {string} substring
1432
+ * @return {string}
1433
+ */
1434
+ exports.remove = function (input, substring) {
1435
+ return exports.replace(input, substring, '');
1436
+ };
1437
+
1438
+ /**
1439
+ * 删除第一次出现的指定字符串
1440
+ *
1441
+ * @param {string} input
1442
+ * @param {string} substring
1443
+ * @return {string}
1444
+ */
1445
+ exports.remove_first = function (input, substring) {
1446
+ return exports.replace_first(input, substring, '');
1447
+ };
1448
+
1449
+ /**
1450
+ * 将\n转换为<br>
1451
+ *
1452
+ * @param {string} input
1453
+ * @return {string}
1454
+ */
1455
+ exports.newline_to_br = function (input) {
1456
+ return toString(input).replace(/\n/img, '<br>');
1457
+ };
1458
+
1459
+ /**
1460
+ * 如果输入的数大于1则输出第2个参数,否则输出第3个参数
1461
+ *
1462
+ * @param {int} input
1463
+ * @param {string} singular
1464
+ * @param {string} plural
1465
+ * @return {string}
1466
+ */
1467
+ exports.pluralize = function (input, singular, plural) {
1468
+ return Number(input) > 1 ? plural : singular;
1469
+ };
1470
+
1471
+ /**
1472
+ * 返回数组或字符串的长度
1473
+ *
1474
+ * @param {array|string} input
1475
+ * @return {string}
1476
+ */
1477
+ exports.size = function (input) {
1478
+ if (!input) return 0;
1479
+ var len = input.length;
1480
+ return len > 0 ? len : 0;
1481
+ };
1482
+
1483
+ /**
1484
+ * 分割字符串
1485
+ *
1486
+ * @param {string} input
1487
+ * @param {string} delimiter
1488
+ * @return {string}
1489
+ */
1490
+ exports.split = function (input, delimiter) {
1491
+ if (!delimiter) delimiter = '';
1492
+ return toString(input).split(delimiter);
1493
+ };
1494
+
1495
+ /**
1496
+ * 去除HTML标签
1497
+ *
1498
+ * @param {string} text
1499
+ * @return {string}
1500
+ */
1501
+ exports.strip_html = function (text) {
1502
+ return toString(text).replace(/<[^>]*>/img, '');
1503
+ };
1504
+
1505
+ /**
1506
+ * 去除换行符
1507
+ *
1508
+ * @param {string} input
1509
+ * @return {string}
1510
+ */
1511
+ exports.strip_newlines = function (input) {
1512
+ return toString(input).replace(/[\r\n]+/g, '');
1513
+ };
1514
+
1515
+ /**
1516
+ * 取字符串前N个字符
1517
+ *
1518
+ * @param {string} input
1519
+ * @param {int} characters
1520
+ * @return {string}
1521
+ */
1522
+ exports.truncate = function (input, characters) {
1523
+ characters = parseInt(characters, 10);
1524
+ if (!isFinite(characters) || characters < 0) characters = 100;
1525
+ return toString(input).substr(0, characters);
1526
+ };
1527
+
1528
+ /**
1529
+ * 取字符串的前N个单词
1530
+ *
1531
+ * @param {string} input
1532
+ * @param {int} words
1533
+ * @return {string}
1534
+ */
1535
+ exports.truncatewords = function (input, words) {
1536
+ words = parseInt(words, 10);
1537
+ if (!isFinite(words) || words < 0) words = 15;
1538
+ return toString(input).trim().split(/ +/).slice(0, words).join(' ');
1539
+ };
1540
+
1541
+ /**
1542
+ * 转换为json字符串
1543
+ *
1544
+ * @param {object} input
1545
+ * @return {string}
1546
+ */
1547
+ exports.json = function (input) {
1548
+ try {
1549
+ var ret = JSON.stringify(input);
1550
+ } catch (err) {
1551
+ return '{}';
1552
+ }
1553
+ return typeof ret !== 'string' ? '{}' : ret;
1554
+ };
1555
+
1556
+ /**
1557
+ * 从起始索引号提取字符串中指定数目的字符
1558
+ *
1559
+ * @param {string} input
1560
+ * @param {int} start
1561
+ * @param {int} length
1562
+ * @return {string}
1563
+ */
1564
+ exports.substr = function (input, start, length) {
1565
+ return toString(input).substr(start, length);
1566
+ }
1567
+
1568
+ /**
1569
+ *
1570
+
1571
+ /**
1572
+ * 取指定属性值
1573
+ *
1574
+ * @param {object} obj
1575
+ * @param {string} prop
1576
+ * @return {object}
1577
+ */
1578
+ exports.get = function(obj, prop){
1579
+ if (!obj) obj = {};
1580
+ return obj[prop];
1581
+ };
1582
+
1583
+ /**
1584
+ * 反转字符串或数组
1585
+ *
1586
+ * @param {string|array} arr
1587
+ * @return {string|array}
1588
+ */
1589
+ exports.reverse = function (arr) {
1590
+ return Array.isArray(arr) ? arr.reverse()
1591
+ : toString(arr).split('').reverse().join('');
1592
+ };
1593
+
1594
+ /**
1595
+ * 返回字符串所在的位置 或 返回该值在数组中的位置
1596
+ *
1597
+ * @param {string|array} arr
1598
+ * @param {object} searchvalue
1599
+ * @param {int} fromindex
1600
+ * @return {int}
1601
+ */
1602
+ exports.indexOf = function (arr, searchvalue, fromindex) {
1603
+ if (!Array.isArray(arr)) arr = toString(arr);
1604
+ return arr.indexOf(searchvalue, fromindex);
1605
+ };
1606
+
1607
+ /**
1608
+ * 取数组的指定列的数据
1609
+ *
1610
+ * @param {array} arr
1611
+ * @param {string} prop
1612
+ * @return {array}
1613
+ */
1614
+ exports.map = function (arr, prop) {
1615
+ if (!Array.isArray(arr)) return [];
1616
+ return arr.map(function(obj){
1617
+ return obj && obj[prop];
1618
+ });
1619
+ };
1620
+
1621
+ /**
1622
+ * 数组排序,默认升序
1623
+ *
1624
+ * @param {array} arr
1625
+ * @param {int} order
1626
+ * @return {array}
1627
+ */
1628
+ exports.sort = function (arr, order) {
1629
+ if (!Array.isArray(arr)) return [];
1630
+ order = toString(order).trim().toLowerCase();
1631
+ var ret1 = order === 'desc' ? -1 : 1;
1632
+ var ret2 = 0 - ret1;
1633
+ return arr.sort(function (a, b) {
1634
+ if (a > b) return ret1;
1635
+ if (a < b) return ret2;
1636
+ return 0;
1637
+ });
1638
+ };
1639
+
1640
+ /**
1641
+ * 按照数组元素的指定属性排序
1642
+ *
1643
+ * @param {array} obj
1644
+ * @param {string} prop
1645
+ * @param {int} order
1646
+ * @return {array}
1647
+ */
1648
+ exports.sort_by = function (obj, prop, order) {
1649
+ if (!Array.isArray(obj)) return [];
1650
+ order = toString(order).trim().toLowerCase();
1651
+ var ret1 = order === 'desc' ? -1 : 1;
1652
+ var ret2 = 0 - ret1;
1653
+ return Object.create(obj).sort(function (a, b) {
1654
+ a = a[prop];
1655
+ b = b[prop];
1656
+ if (a > b) return ret1;
1657
+ if (a < b) return ret2;
1658
+ return 0;
1659
+ });
1660
+ };
1661
+
1662
+ /**
1663
+ * 根据数量生成导航页码
1664
+ *
1665
+ * @param {int} count 总数
1666
+ * @param {int} size 每页显示数量
1667
+ * @param {int} page 当前页码
1668
+ * @listurn {array}
1669
+ */
1670
+ exports.pagination = function (count, size, page) {
1671
+ if (count % size === 0) {
1672
+ var maxPage = parseInt(count / size, 10);
1673
+ } else {
1674
+ var maxPage = parseInt(count / size, 10) + 1;
1675
+ }
1676
+ if (isNaN(page) || page < 1) {
1677
+ page = 1;
1678
+ }
1679
+ page = parseInt(page);
1680
+
1681
+ var list = [page - 2, page - 1, page, page + 1, page + 2];
1682
+ for (var i = 0; i < list.length;) {
1683
+ if (list[i] < 1 || list[i] > maxPage) {
1684
+ list.splice(i, 1);
1685
+ } else {
1686
+ i++;
1687
+ }
1688
+ }
1689
+ if (list[0] !== 1) {
1690
+ list.unshift('...');
1691
+ list.unshift(1);
1692
+ }
1693
+ if (list[list.length - 1] < maxPage) {
1694
+ list.push('...');
1695
+ list.push(maxPage);
1696
+ }
1697
+
1698
+ var ret = {
1699
+ current: page,
1700
+ next: page + 1,
1701
+ previous: page - 1,
1702
+ list: list
1703
+ };
1704
+ if (ret.next > maxPage) ret.next = maxPage;
1705
+ if (ret.previous < 1) ret.previous = 1;
1706
+
1707
+ return ret;
1708
+ };
1709
+
1710
+ //------------------------------------------------------------------------------
1711
+ // 所有函数名可以以大写字母开头
1712
+ var ns = Object.keys(exports);
1713
+ for (var i in ns) {
1714
+ var n = ns[i];
1715
+ var n2 = n[0].toUpperCase() + n.substr(1);
1716
+ exports[n2] = exports[n];
1717
+ }
1718
+
1719
+ return exports;
1720
+ })(m, m.exports);
1721
+ modules.filters = m.exports;
1722
+ /*-----------------------------------------------*/
1723
+
1724
+ /*--------------- ./lib/parser.js ---------------*/
1725
+ var m = {exports: {}};
1726
+ (function (module, exports) {
1727
+ 'use strict';
1728
+
1729
+ /**
1730
+ * 代码分析器
1731
+ *
1732
+ * @author 老雷<leizongmin@gmail.com>
1733
+ */
1734
+
1735
+ var utils = modules.utils;
1736
+ var template = modules.template;
1737
+
1738
+
1739
+ exports.output = function (text, start, context) {
1740
+ if (context.isRaw || context.isComment) return null;
1741
+
1742
+ // 查找结束标记
1743
+ var end = text.indexOf('}}', start);
1744
+ if (end === -1) return null;
1745
+
1746
+ // 检查结束标记是否为同一行的
1747
+ var lineend = text.indexOf('\n', start);
1748
+ if (lineend > -1 && lineend < end) return null;
1749
+
1750
+ context.ignoreOutput = false;
1751
+
1752
+ var line = text.slice(start + 2, end).trim();
1753
+ end += 2;
1754
+
1755
+ // 支持函数调用
1756
+ var script = '$_line_num = ' + context.line_num + ';\n' +
1757
+ '$_tmpbuf = ' + utils.filtered(line, null, context) + ';\n' +
1758
+ '$_buf+=($_tmpbuf===null||typeof($_tmpbuf)==="undefined"?"":$_tmpbuf);';
1759
+
1760
+ return {start: start, end: end, script: script};
1761
+ };
1762
+
1763
+
1764
+ exports.tags = function (text, start, context) {
1765
+ // 查找结束标记
1766
+ var end = text.indexOf('%}', start);
1767
+ if (end === -1) return null;
1768
+
1769
+ // 检查结束标记是否为同一行的
1770
+ var lineend = text.indexOf('\n', start);
1771
+ if (lineend > -1 && lineend < end) return null;
1772
+
1773
+ var line = text.slice(start + 2, end).trim();
1774
+ end += 2;
1775
+
1776
+ // 解析语句
1777
+ var space_start = line.indexOf(' ');
1778
+ var script = '';
1779
+
1780
+ // 设置行号,以便检查运行时错误
1781
+ var setLineNumber = function () {
1782
+ if (script.substr(-1) === '\n') {
1783
+ script += '$_line_num = ' + context.line_num + ';\n';
1784
+ } else {
1785
+ script += '\n$_line_num = ' + context.line_num + ';\n';
1786
+ }
1787
+ };
1788
+
1789
+ // 当前在raw标记内,则只有遇到 enddraw 标记时才能终止
1790
+ if (context.isRaw) {
1791
+ if (line === 'endraw') {
1792
+ context.isRaw = false;
1793
+ setLineNumber();
1794
+ script += '/* endraw */';
1795
+ return {start: start, end: end, script: script};
1796
+ } else {
1797
+ return null;
1798
+ }
1799
+ }
1800
+
1801
+ // 当前在comment标记内,则只有遇到 endcomment 标记时才能终止
1802
+ if (context.isComment) {
1803
+ if (line === 'endcomment') {
1804
+ context.isComment = false;
1805
+ context.ignoreOutput = true;
1806
+ setLineNumber();
1807
+ return {start: start, end: end, script: script};
1808
+ } else {
1809
+ return null;
1810
+ }
1811
+ }
1812
+
1813
+ // 嵌套开始
1814
+ var enterLoop = function (name) {
1815
+ context.loop++;
1816
+ context.loopName.push({
1817
+ name: name,
1818
+ start: start,
1819
+ end: end,
1820
+ line: line,
1821
+ line_num: context.line_num
1822
+ });
1823
+ };
1824
+
1825
+ // 退出嵌套
1826
+ var outLoop = function () {
1827
+ context.loop--;
1828
+ context.loopName.pop();
1829
+ };
1830
+
1831
+ // 嵌套结束标记不匹配
1832
+ var loopNotMatch = function () {
1833
+ context.error = {
1834
+ message: 'Unexpected token: ' + line,
1835
+ start: start,
1836
+ end: end,
1837
+ line: line
1838
+ };
1839
+ };
1840
+
1841
+ // 意外的标记
1842
+ var syntaxError = function () {
1843
+ context.error = {
1844
+ message: 'SyntaxError: ' + line,
1845
+ start: start,
1846
+ end: end,
1847
+ line: line
1848
+ };
1849
+ };
1850
+
1851
+ // 无法识别的标记
1852
+ var unknownTag = function () {
1853
+ context.error = {
1854
+ message: 'unknownTag: ' + line,
1855
+ start: start,
1856
+ end: end,
1857
+ line: line
1858
+ };
1859
+ };
1860
+
1861
+ // 用于给自定义标签调用的函数
1862
+ var methods = {
1863
+ enterLoop: enterLoop,
1864
+ outLoop: outLoop,
1865
+ loopNotMatch: loopNotMatch,
1866
+ syntaxError: syntaxError,
1867
+ unknownTag: unknownTag,
1868
+ filtered: utils.filtered,
1869
+ localsWrap: utils.localsWrap,
1870
+ printString: function (str) {
1871
+ return '$_buf += "' + utils.outputHtml(str) + '";\n';
1872
+ },
1873
+ printLocals: function (name) {
1874
+ return '$_buf += ' + utils.localsWrap(name) + ';\n';
1875
+ }
1876
+ };
1877
+
1878
+ // 当前嵌套名称
1879
+ if (context.loopName.length > 0) {
1880
+ var loopName = context.loopName[context.loopName.length - 1].name;
1881
+ } else {
1882
+ var loopName = '';
1883
+ }
1884
+
1885
+ context.ignoreOutput = false;
1886
+
1887
+ // 简单标记(一般为标记结尾)
1888
+ if (space_start === -1) {
1889
+ // 是否为自定义标记
1890
+ if (typeof context.customTags[line] === 'function') {
1891
+ setLineNumber();
1892
+ var s = context.customTags[line]([], line, context, methods);
1893
+ if (s === null) {
1894
+ syntaxError();
1895
+ } else if (typeof s === 'string') {
1896
+ script += s + '\n';
1897
+ }
1898
+ } else {
1899
+ switch (line) {
1900
+ // raw 标记
1901
+ case 'raw':
1902
+ context.isRaw = true;
1903
+ setLineNumber();
1904
+ script += '/* raw */';
1905
+ break;
1906
+ // endif
1907
+ case 'endif':
1908
+ if (loopName !== 'if') {
1909
+ loopNotMatch();
1910
+ } else {
1911
+ setLineNumber();
1912
+ script += '}';
1913
+ outLoop();
1914
+ }
1915
+ break;
1916
+ // endunless
1917
+ case 'endunless':
1918
+ if (loopName !== 'unless') {
1919
+ loopNotMatch();
1920
+ } else {
1921
+ setLineNumber();
1922
+ script += '}';
1923
+ outLoop();
1924
+ }
1925
+ break;
1926
+ // else
1927
+ case 'else':
1928
+ if (loopName === 'if' || loopName === 'unless') {
1929
+ setLineNumber();
1930
+ script += '} else {';
1931
+ setLineNumber();
1932
+ } else if (loopName === 'case') {
1933
+ setLineNumber();
1934
+ script += 'break;\n' +
1935
+ 'default:';
1936
+ setLineNumber();
1937
+ } else if (loopName === 'for') {
1938
+ setLineNumber();
1939
+ script += '}\n' +
1940
+ 'if (forloop.length < 1) {';
1941
+ } else {
1942
+ loopNotMatch();
1943
+ }
1944
+ break;
1945
+ // endcase
1946
+ case 'endcase':
1947
+ if (loopName !== 'case') {
1948
+ loopNotMatch();
1949
+ } else {
1950
+ setLineNumber();
1951
+ script += '}';
1952
+ outLoop();
1953
+ }
1954
+ break;
1955
+ // endfor
1956
+ case 'endfor':
1957
+ if (loopName !== 'for') {
1958
+ loopNotMatch();
1959
+ } else {
1960
+ setLineNumber();
1961
+ script += '}\n' +
1962
+ '})(locals);';
1963
+ outLoop();
1964
+ }
1965
+ break;
1966
+ // endtablerow
1967
+ case 'endtablerow':
1968
+ if (loopName !== 'tablerow') {
1969
+ loopNotMatch();
1970
+ } else {
1971
+ setLineNumber();
1972
+ script += '$_buf += \'</td>\';\n' +
1973
+ '}\n' +
1974
+ '$_buf += \'</tr>\\n\';\n' +
1975
+ '}\n' +
1976
+ '})(locals);';
1977
+ outLoop();
1978
+ }
1979
+ break;
1980
+ // endcapture
1981
+ case 'endcapture':
1982
+ if (loopName !== 'capture') {
1983
+ loopNotMatch();
1984
+ } else {
1985
+ setLineNumber();
1986
+ script += '} catch (err) {\n' +
1987
+ ' $_rethrow(err);\n' +
1988
+ '}\n' +
1989
+ 'return $_buf;\n' +
1990
+ '})();';
1991
+ outLoop();
1992
+ }
1993
+ break;
1994
+ // comment
1995
+ case 'comment':
1996
+ setLineNumber();
1997
+ context.isComment = true;
1998
+ break;
1999
+ // 出错
2000
+ default:
2001
+ unknownTag();
2002
+ }
2003
+ }
2004
+ }
2005
+ // 复杂标记(一般为标记开头)
2006
+ else {
2007
+ var line_left = line.substr(0, space_start);
2008
+ var line_right = line.substr(space_start).trim();
2009
+ // 是否为自定义标记
2010
+ if (typeof context.customTags[line_left] === 'function') {
2011
+ setLineNumber();
2012
+ var s = context.customTags[line_left](line_right.split(/\s+/),
2013
+ line_right, context, methods);
2014
+ if (s === null) {
2015
+ syntaxError();
2016
+ } else if (typeof s === 'string') {
2017
+ script += s + '\n';
2018
+ }
2019
+ } else {
2020
+ switch (line_left) {
2021
+ // if / unless 判断
2022
+ case 'if':
2023
+ enterLoop(line_left);
2024
+ setLineNumber();
2025
+ script += 'if ' + utils.condition(line_right, context) + ' {';
2026
+ break;
2027
+ case 'unless':
2028
+ enterLoop(line_left);
2029
+ setLineNumber();
2030
+ script += 'if (!' + utils.condition(line_right, context) + ') {';
2031
+ break;
2032
+ // elsif / elseif
2033
+ case 'elsif':
2034
+ case 'elseif':
2035
+ if (loopName !== 'if') {
2036
+ loopNotMatch();
2037
+ } else {
2038
+ setLineNumber();
2039
+ script += '} else if ' +
2040
+ utils.condition(line_right, context) + ' {';
2041
+ }
2042
+ break;
2043
+ // case 判断
2044
+ case 'case':
2045
+ enterLoop(line_left);
2046
+ setLineNumber();
2047
+ script += 'switch (' +
2048
+ utils.localsWrap(line_right, null, context.saveLocalsName) +
2049
+ ') {';
2050
+ break;
2051
+ case 'when':
2052
+ if (context.hasWhen) {
2053
+ script += 'break;\n';
2054
+ context.ignoreOutput = false;
2055
+ } else {
2056
+ context.ignoreOutput = true;
2057
+ }
2058
+ if (loopName !== 'case') {
2059
+ loopNotMatch();
2060
+ } else {
2061
+ script += 'case ' +
2062
+ utils.localsWrap(line_right, null,
2063
+ context.saveLocalsName) +
2064
+ ':';
2065
+ setLineNumber();
2066
+ context.hasWhen = true;
2067
+ }
2068
+ break;
2069
+ // for 循环
2070
+ case 'for':
2071
+ enterLoop(line_left);
2072
+ var s = utils.forloops(line_right, context);
2073
+ if (s === null) {
2074
+ syntaxError();
2075
+ } else {
2076
+ setLineNumber();
2077
+ script += s;
2078
+ }
2079
+ break;
2080
+ // tablerow 循环
2081
+ case 'tablerow':
2082
+ enterLoop(line_left);
2083
+ var s = utils.tablerow(line_right, context);
2084
+ if (s === null) {
2085
+ syntaxError();
2086
+ } else {
2087
+ setLineNumber();
2088
+ script += s;
2089
+ }
2090
+ break;
2091
+ // assign 定义变量
2092
+ case 'assign':
2093
+ var eq_op = line_right.indexOf('=');
2094
+ if (eq_op === -1) {
2095
+ syntaxError();
2096
+ } else {
2097
+ var assign_name = utils.localsWrap(
2098
+ line_right.substr(0, eq_op).trim(),
2099
+ null,
2100
+ context.saveLocalsName);
2101
+ context.assignNames[assign_name] = true;
2102
+ var assign_expr = utils.assign(line_right.substr(eq_op + 1).trim(),
2103
+ context);
2104
+ setLineNumber();
2105
+ script += 'global.' + assign_name + ' = ' + assign_name +
2106
+ ' = ' + assign_expr + ';';
2107
+ }
2108
+ break;
2109
+ // capture 定义变量块
2110
+ case 'capture':
2111
+ enterLoop(line_left);
2112
+ var n = utils.localsWrap(line_right, null, context.saveLocalsName);
2113
+ setLineNumber();
2114
+ script += 'global.' + n + ' = ' + n + ' = (function () {\n' +
2115
+ 'var $_buf = \'\';\n' +
2116
+ 'try {\n' +
2117
+ '/* captures */\n';
2118
+ break;
2119
+ // include 标记
2120
+ case 'include':
2121
+ var inc_blocks = utils.split(line_right);
2122
+ var inc_tag = {};
2123
+ var inc_ok = false;
2124
+ if (inc_blocks.length === 1) {
2125
+ inc_tag.name = utils.stripQuotes(inc_blocks[0]);
2126
+ inc_ok = true;
2127
+ } else if (inc_blocks.length === 3) {
2128
+ inc_tag.name = utils.stripQuotes(inc_blocks[0]);
2129
+ inc_tag.with = utils.stripQuotes(inc_blocks[2]);
2130
+ inc_ok = true;
2131
+ } else {
2132
+ syntaxError();
2133
+ }
2134
+ if (inc_ok) {
2135
+ // 添加到依赖的资源文件
2136
+ context.addIncludes(inc_tag.name);
2137
+ // 如果提供了该资源文件,则插入代码
2138
+ // if (context.files[inc_tag.name]) {
2139
+ setLineNumber();
2140
+ var include_parts = inc_tag.name.split('/');
2141
+ include_parts[ include_parts.length-1] = '_' + include_parts[ include_parts.length - 1 ];
2142
+ var partial_function = context.partials_namespace + '[\'' + include_parts.join('/') + '\']';
2143
+ script += 'if ( ' + partial_function + '){' +
2144
+ ' $_buf+=' + partial_function + '(' + (inc_tag.with ? inc_tag.with : 'locals') + ',filters);' +
2145
+ '} else {' +
2146
+ ' $_buf+=\'No such template ' + include_parts.join('/') + '\';' +
2147
+ '}';
2148
+ // script += '/* === include "' + inc_tag.name + '"' +
2149
+ // (inc_tag.with ? ' with "' + inc_tag.with + '"' : '') +
2150
+ // ' === */\n' +
2151
+ // 'try {\n' +
2152
+ // '$_buf+=((function (locals) {\n' +
2153
+ // context.files[inc_tag.name] + '\n' +
2154
+ // 'return $_buf;\n' +
2155
+ // '})(' + (inc_tag.with ? utils.localsWrap(inc_tag.with)
2156
+ // : 'locals') + '));\n' +
2157
+ // '} catch (err) {\n' +
2158
+ // ' $_rethrow(err);\n' +
2159
+ // '}\n' +
2160
+ // '/* === end include "' + inc_tag.name + '" === */';
2161
+ // }
2162
+ }
2163
+ break;
2164
+ // cycle 循环字符串
2165
+ case 'cycle':
2166
+ var s = utils.cycle(line_right, context);
2167
+ if (s === null) {
2168
+ syntaxError();
2169
+ } else {
2170
+ setLineNumber();
2171
+ script += s;
2172
+ }
2173
+ break;
2174
+ // 其他
2175
+ default:
2176
+ unknownTag();
2177
+ }
2178
+ }
2179
+ }
2180
+
2181
+ return {start: start, end: end, script: script};
2182
+ };
2183
+ return exports;
2184
+ })(m, m.exports);
2185
+ modules.parser = m.exports;
2186
+ /*-----------------------------------------------*/
2187
+
2188
+ /*-------------- ./lib/template.js --------------*/
2189
+ var m = {exports: {}};
2190
+ (function (module, exports) {
2191
+ //'use strict';
2192
+
2193
+ /**
2194
+ * 模板引擎
2195
+ *
2196
+ * @author 老雷<leizongmin@gmail.com>
2197
+ */
2198
+
2199
+
2200
+ var parser = modules.parser;
2201
+ var utils = modules.utils;
2202
+ var filters = modules.filters;
2203
+
2204
+
2205
+
2206
+ /**
2207
+ * 编译代码(仅解析模板)
2208
+ *
2209
+ * @param {string} text
2210
+ * @param {object} options
2211
+ * - {Object} files 子模版文件代码,用parse编译
2212
+ * @return {object}
2213
+ */
2214
+ exports.parse = function (text, options) {
2215
+ options = options || {};
2216
+ options.tags = options.tags || {};
2217
+ var line_number = 1; // 行号
2218
+ var html_start = 0; // HTML代码开始
2219
+ var scripts = []; // 编译后的代码
2220
+ var context = {} // 编译时传递的环境变量
2221
+
2222
+ scripts.add = function (s) {
2223
+ scripts.push(s);
2224
+ };
2225
+
2226
+ // 初始化编译环境
2227
+ context.partials_namespace = options.partials_namespace;
2228
+ context.customTags = options.tags; // 自定义的标记解析
2229
+ context.loop = 0; // { 嵌套层数
2230
+ context.loopName = []; // 当前嵌套标记名称
2231
+ context.isRaw = false; // 是否为raw标记
2232
+ context.isComment = false; // 是否为comment标记
2233
+ context.ignoreOutput = false; // 忽略该部分的HTML代码
2234
+ context.assignNames = {}; // 使用assign标记定义的变量名称
2235
+ context.varNames = {}; // 变量的名称及引用的次数
2236
+ context.saveLocalsName = function (name) { // 使用变量名称
2237
+ // 忽略tablerowloop和forloop
2238
+ if (name.substr(0, 13) === 'tablerowloop.' ||
2239
+ name.substr(0, 8) === 'forloop.') return;
2240
+ if (!context.varNames[name]) {
2241
+ context.varNames[name] = 1;
2242
+ } else {
2243
+ context.varNames[name]++;
2244
+ }
2245
+ };
2246
+ context.includes = {}; // 包含的子模版
2247
+ context.files = options.files || {}; // 提供的资源文件
2248
+ context.addIncludes = function (name) { // 包含子模版
2249
+ if (!context.includes[name]) {
2250
+ context.includes[name] = 1;
2251
+ } else {
2252
+ context.includes[name]++;
2253
+ }
2254
+ };
2255
+ context.cycles = {}; // cycle标记中的变量列表
2256
+ context.addCycle = function (key, list) { // 添加cycle
2257
+ context.cycles[key] = list;
2258
+ };
2259
+
2260
+ // 捕捉严重的错误
2261
+ var catchError = function (data) {
2262
+ if (!context.error && data) {
2263
+ context.error = {
2264
+ start: data.start,
2265
+ end: data.end,
2266
+ line: data.line,
2267
+ message: 'SyntaxError: Unexpected end of input'
2268
+ }
2269
+ }
2270
+
2271
+ // 生成出错信息描述
2272
+ var html_top = utils.outputHtml(text.slice(0, context.error.start));
2273
+ var html_bottom = utils.outputHtml(text.slice(context.error.end));
2274
+ var html_error = 'Line:' + line_number + '\n' +
2275
+ ' ' + context.error.line + '\n\n' +
2276
+ context.error.message + '\n';
2277
+ // 嵌套栈
2278
+ var loop;
2279
+ while (loop = context.loopName.pop()) {
2280
+ html_error += ' at ' + loop.line + ' (line: ' + loop.line_num + ')\n';
2281
+ }
2282
+
2283
+ // 输出出错信息
2284
+ html_error = utils.outputHtml(html_error);
2285
+ scripts.splice(0, scripts.length);
2286
+ scripts.add('$_buf+=(\'' + html_top + '\');');
2287
+ scripts.add('$_buf+=($_err(\'' + html_error + '\'));');
2288
+ scripts.add('$_buf+=(\'' + html_bottom + '\');');
2289
+
2290
+ html_start = text.length;
2291
+ };
2292
+
2293
+ for (var i = 0, len; len = text.length, i < len; i++) {
2294
+ var block = text.substr(i, 2);
2295
+ if (text[i] === '\n') line_number++;
2296
+ context.line_num = line_number;
2297
+
2298
+ //console.log('Block: ' + block);
2299
+ switch (block) {
2300
+ // 变量
2301
+ case '{{':
2302
+ var ret = parser.output(text, i, context);
2303
+ break;
2304
+ // 语句
2305
+ case '{%':
2306
+ var ret = parser.tags(text, i, context);
2307
+ break;
2308
+ // HTML代码
2309
+ default:
2310
+ var ret = null;
2311
+ }
2312
+
2313
+ // 检查是否出错
2314
+ if (context.error) {
2315
+ catchError();
2316
+ break;
2317
+ }
2318
+
2319
+ if (ret !== null) {
2320
+ //console.log(ret);
2321
+ var html = text.slice(html_start, ret.start);
2322
+ if (html.length > 0 && context.ignoreOutput !== true) {
2323
+ html = utils.outputHtml(html);
2324
+ scripts.add('$_buf+=(\'' + html + '\');');
2325
+ }
2326
+ // 代码
2327
+ scripts.add(ret.script);
2328
+
2329
+ i = ret.end - 1;
2330
+ html_start = ret.end;
2331
+ }
2332
+ }
2333
+
2334
+ // 最后一部分的HTML
2335
+ var html = text.slice(html_start, len);
2336
+ if (html.length > 0) {
2337
+ html = utils.outputHtml(html);
2338
+ scripts.add('$_buf+=(\'' + html + '\');');
2339
+ }
2340
+
2341
+ // 检查是否出错(嵌套是否匹配)
2342
+ if (context.loopName.length > 0) {
2343
+ catchError(context.loopName.pop());
2344
+ }
2345
+
2346
+ // 生成cycle定义
2347
+ var define_cycle = '/* == define cycles == */\n';
2348
+ for (var i in context.cycles) {
2349
+ var c = context.cycles[i];
2350
+ var n = '$_cycle_' + i;
2351
+ var s = 'var ' + n + ' = {i: 0, length: ' +
2352
+ c.length + ', items: [' + c.join(',') + ']}\n';
2353
+ define_cycle += s;
2354
+ }
2355
+ define_cycle += 'var $_cycle_next = function (n) {\n' +
2356
+ 'n.i++;\n' +
2357
+ 'if (n.i >= n.length) n.i = 0;\n' +
2358
+ '}\n';
2359
+
2360
+ // 包装
2361
+ var wrap_top = '/* == Template Begin == */\n' +
2362
+ 'var $_buf = \'\';\n' +
2363
+ 'var $_line_num = 0;\n' +
2364
+ define_cycle;
2365
+ // var wrap_bottom = '\n/* == Template End == */\n';
2366
+ var code = wrap_top + scripts.join('\n');// + wrap_bottom;
2367
+
2368
+ return {code: code, names: context.varNames, includes: context.includes};
2369
+ };
2370
+
2371
+ /**
2372
+ * 编译代码(可运行的函数代码)
2373
+ *
2374
+ * @param {string} text 模板内容
2375
+ * @param {object} options 选项
2376
+ * - {Object} files 子模版文件代码
2377
+ * - {Boolean} original 是否返回原始代码
2378
+ * - {Object} tags 自定义标记解析,
2379
+ * - {String} filename 当前模板文件名(用于显示出错信息)
2380
+ * - {Boolean} noeval 不执行eval(用于调试),直接返回 {code, names, includes}
2381
+ * @return {function}
2382
+ */
2383
+ exports.compile = function (text, options) {
2384
+ options = options || {};
2385
+
2386
+ // 编译代码
2387
+ var tpl = exports.parse(text, options);
2388
+
2389
+ var script = '(function (locals, filters) { \n' +
2390
+ 'var $_tmpbuf;\n' +
2391
+ 'var $_html = ' + utils.outputHtml.toString() + ';\n' +
2392
+ 'var $_err = ' + utils.errorMessage.toString() + ';\n' +
2393
+ 'var $_rethrow = ' + utils.rethrowError.toString() + ';\n' +
2394
+ 'var $_merge = ' + utils.merge.toString() + ';\n' +
2395
+ 'var $_range = ' + utils.range.toString() + ';\n' +
2396
+ 'var $_array = ' + utils.toArray.toString() + ';\n' +
2397
+ 'locals = $_merge(locals);\n' +
2398
+ 'filters = filters || {};\n' +
2399
+ 'var global = {locals: locals, filters: filters};\n' +
2400
+ 'try { \n' +
2401
+ tpl.code + '\n' +
2402
+ '} catch (err) {\n' +
2403
+ ' $_rethrow(err, "' +
2404
+ (options.filename || '').replace(/"/img, '\\"') + '");\n' +
2405
+ '}\n' +
2406
+ 'return $_buf;\n' +
2407
+ '})';
2408
+
2409
+ // 用于调试
2410
+ if (options.noeval) {
2411
+ return {
2412
+ code: script,
2413
+ names: tpl.names,
2414
+ includes: tpl.includes
2415
+ };
2416
+ }
2417
+
2418
+ try {
2419
+ var fn = eval(script);
2420
+
2421
+ // 设置依赖的资源
2422
+ fn.names = tpl.names; // 变量
2423
+ fn.includes = tpl.includes; // 子模版
2424
+
2425
+ // 如果设置了original=true选项,则直接返回原始代码,否则自动封装filters
2426
+ if (options.original) return fn;
2427
+
2428
+ // 封装filters
2429
+ var fnWrap = function (d, f) {
2430
+ return fn(d, f || filters);
2431
+ };
2432
+ fnWrap.names = fn.names;
2433
+ fnWrap.includes = fn.includes;
2434
+ return fnWrap;
2435
+ } catch (err) {
2436
+ throw Error('Compile error: ' + err);
2437
+ }
2438
+ };
2439
+
2440
+ /**
2441
+ * 渲染
2442
+ *
2443
+ * @param {string} text 模板内容
2444
+ * @param {object} data 数据
2445
+ * @param {object} f 自定义函数
2446
+ * @return {text}
2447
+ */
2448
+ exports.render = function (text, data, f) {
2449
+ var fn = exports.compile(text);
2450
+ return fn(data, f);
2451
+ };
2452
+
2453
+ return exports;
2454
+ })(m, m.exports);
2455
+ modules.template = m.exports;
2456
+ /*-----------------------------------------------*/
2457
+
2458
+ /*------------ ./lib/advtemplate.js -------------*/
2459
+ var m = {exports: {}};
2460
+ (function (module, exports) {
2461
+ 'use strict';
2462
+
2463
+ /**
2464
+ * 编译整套模板
2465
+ *
2466
+ * @author 老雷<leizongmin@gmail.com>
2467
+ */
2468
+
2469
+ var template = modules.template;
2470
+ var utils = modules.utils;
2471
+ var AsyncDataList = utils.AsyncDataList;
2472
+
2473
+
2474
+ /**
2475
+ * 编译所有模板
2476
+ *
2477
+ * @param {object} files 模板文件内容,如: {abc: '...', efc: '...'}
2478
+ * @param {object} options 选项
2479
+ * - {Boolean} original 是否返回原始代码
2480
+ * @return {object}
2481
+ */
2482
+ exports.compileAll = function (files, options) {
2483
+ options = options || {};
2484
+
2485
+ // 第一遍编译
2486
+ var pCodes = {};
2487
+ var pFiles = {};
2488
+ for (var i in files) {
2489
+ var tpl = template.parse(files[i]);
2490
+ pCodes[i] = tpl;
2491
+ pFiles[i] = tpl.code;
2492
+ }
2493
+
2494
+ // 合并模板文件依赖的变量
2495
+ var mergeRequire = function (f, field) {
2496
+ // console.log('merge', f, field);
2497
+ var ns = {}; // 名称
2498
+ var _f = {}; // 已分析过的模板名称
2499
+
2500
+ var addName = function (n, c) {
2501
+ if (!ns[n]) {
2502
+ ns[n] = c;
2503
+ } else {
2504
+ ns[n] += c;
2505
+ }
2506
+ };
2507
+
2508
+ // 初始化ns
2509
+ var t = pCodes[f];
2510
+ for (var i in t[field]) {
2511
+ addName(i, t[field][i]);
2512
+ }
2513
+
2514
+ // 合并子模版中的名称
2515
+ var m = function (f) {
2516
+ if (f in _f) {
2517
+ return false;
2518
+ } else {
2519
+ _f[f] = true;
2520
+ }
2521
+
2522
+ var t = pCodes[f];
2523
+ if (!t) throw Error('Cannot find include file "' + f + '".');
2524
+
2525
+ // 合并名称
2526
+ for (var i in t[field]) {
2527
+ addName(i, t[field][i]);
2528
+ }
2529
+
2530
+ // 合并子模版
2531
+ for (var i in t.includes) {
2532
+ m(i);
2533
+ }
2534
+
2535
+ return true;
2536
+ };
2537
+ m(f);
2538
+
2539
+ return ns;
2540
+ };
2541
+
2542
+ // 计算深度的依赖关系
2543
+ for (var i in files) {
2544
+ pCodes[i].names = mergeRequire(i, 'names');
2545
+ pCodes[i].includes = mergeRequire(i, 'includes');
2546
+ // 如果出现闭环,则抛出异常
2547
+ if (i in pCodes[i].includes) {
2548
+ throw Error('Cannot include file "' + i + '" in file "' + i + '".');
2549
+ }
2550
+ }
2551
+
2552
+ // 根据依赖关系安排模板文件的编译顺序
2553
+ // 计算得分
2554
+ var scores = {};
2555
+ for (var i in pCodes) {
2556
+ scores[i] = 0;
2557
+ }
2558
+ for (var i in pCodes) {
2559
+ scores[i]++;
2560
+ for (var j in pCodes[i].includes) {
2561
+ scores[j]++;
2562
+ }
2563
+ }
2564
+ // 按照得分排序
2565
+ var _scores = [];
2566
+ for (var i in scores) {
2567
+ _scores.push({n: i, s: scores[i]});
2568
+ }
2569
+ scores = _scores.sort(function (a, b) {
2570
+ return a.s < b.s;
2571
+ });
2572
+ // console.log(scores);
2573
+
2574
+ // 第二遍编译
2575
+ var opt = utils.merge(options, {files: pFiles});
2576
+ for (var i in scores) {
2577
+ var n = scores[i].n;
2578
+ var tpl = template.parse(files[n], opt);
2579
+ pFiles[n] = tpl.code;
2580
+ }
2581
+
2582
+ // 最后编译
2583
+ var cFn = {};
2584
+ var opt = utils.merge(options, {files: pFiles});
2585
+ for (var i in files) {
2586
+ opt.filename = i;
2587
+ var tpl = template.compile(files[i], opt);
2588
+ cFn[i] = tpl;
2589
+ cFn[i].names = pCodes[i].names;
2590
+ cFn[i].includes = pCodes[i].includes;
2591
+ }
2592
+
2593
+ return cFn;
2594
+ };
2595
+
2596
+
2597
+ /**
2598
+ * 高级渲染
2599
+ *
2600
+ * @param {function} render 通过compile()编译出的模板渲染函数
2601
+ * @param {object} models 获取数据的函数 {'name': function (env, callback) {}}
2602
+ * @param {object} options
2603
+ * - {Boolean} parallel true并行方式获取,默认为false
2604
+ * - {Object} filters 自定义函数
2605
+ * - {Object} env 环境变量,即models函数中的第一个参数
2606
+ * @param {function} callback 回调 function (err, text)
2607
+ */
2608
+ exports.advRender = function (render, models, options, callback) {
2609
+ // 获取模板需要的变量数据
2610
+ var names = Object.keys(render.names);
2611
+ var dataList = AsyncDataList(models, names, options.env);
2612
+
2613
+ var cb = function (err, d) {
2614
+ if (err) return callback(err);
2615
+ try {
2616
+ var data = {};
2617
+ for (var i in models) {
2618
+ data[i] = models[i];
2619
+ }
2620
+ for (var i in d) {
2621
+ data[i] = d[i];
2622
+ }
2623
+ var text = render(data, options.filters);
2624
+ return callback(null, text);
2625
+ } catch (err) {
2626
+ return callback(err);
2627
+ }
2628
+ };
2629
+
2630
+ if (options.parallel) {
2631
+ dataList.startParallel(cb);
2632
+ } else {
2633
+ dataList.start(cb);
2634
+ }
2635
+ };
2636
+
2637
+
2638
+ return exports;
2639
+ })(m, m.exports);
2640
+ modules.advtemplate = m.exports;
2641
+ /*-----------------------------------------------*/
2642
+
2643
+ /*------------------ ./index.js -----------------*/
2644
+ 'use strict';
2645
+
2646
+ /**
2647
+ * 模板引擎
2648
+ *
2649
+ * @author 老雷<leizongmin@gmail.com>
2650
+ */
2651
+
2652
+
2653
+ var template = modules.template;
2654
+ var advtemplate = modules.advtemplate;
2655
+ var filters = modules.filters;
2656
+
2657
+
2658
+ // 兼容Liquid中数组和字符串的size,first,last属性
2659
+ try {
2660
+ Object.defineProperty(Array.prototype, 'size', {
2661
+ get: function () {
2662
+ return this.length;
2663
+ }});
2664
+ Object.defineProperty(Array.prototype, 'first', {
2665
+ get: function () {
2666
+ var a = this; return a[0];
2667
+ }});
2668
+ Object.defineProperty(Array.prototype, 'last', {
2669
+ get: function () {
2670
+ var a = this; return a[a.length - 1];
2671
+ }});
2672
+ } catch (err) {
2673
+ // console.error(err.stack);
2674
+ }
2675
+
2676
+ // 兼容Liquid中字符串的size属性
2677
+ try {
2678
+ Object.defineProperty(String.prototype, 'size', {
2679
+ get: function () {
2680
+ return this.length;
2681
+ }});
2682
+ } catch (err) {
2683
+ // console.error(err.stack);
2684
+ }
2685
+
2686
+ // 版本
2687
+ exports.version = '0.1.4';
2688
+
2689
+ // 解析代码
2690
+ exports.parse = wrap('parse', template.parse);
2691
+
2692
+ // 编译函数
2693
+ exports.compile = wrap('compile', template.compile);
2694
+
2695
+ // 渲染函数
2696
+ exports.render = wrap('render', template.render);
2697
+
2698
+ // 编译整套模板
2699
+ exports.compileAll = wrap('compileAll', advtemplate.compileAll);
2700
+
2701
+ // 高级渲染
2702
+ exports.advRender = wrap('advRender', advtemplate.advRender);
2703
+
2704
+ // 内置函数
2705
+ exports.filters = filters;
2706
+
2707
+
2708
+
2709
+ // 用于测试函数被调用次数及来源
2710
+ function wrap (name, fn) {
2711
+ if (typeof process !== 'undefined' && process.env &&
2712
+ /true/.test(process.env.TINYLIQUID_TEST)) {
2713
+ var i = 0;
2714
+ return function () {
2715
+ i++;
2716
+ var source = new Error().stack.split('\n').slice(2).join('\n');
2717
+ console.log('call tinyliquid.' + name + '() ' + i + ' times \n' + source);
2718
+ return fn.apply(null, arguments);
2719
+ };
2720
+ } else {
2721
+ return fn;
2722
+ }
2723
+ };
2724
+
2725
+ return exports;
2726
+ /*-----------------------------------------------*/
2727
+ })({});
2728
+
2729
+ // 如果是在Node.js环境,则输出module.exports
2730
+ if (typeof module !== 'undefined' && module.exports) module.exports = TinyLiquid;