liquid_assets 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +37 -0
- data/LICENSE.txt +20 -0
- data/README.md +160 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/lib/liquid_assets/config.rb +102 -0
- data/lib/liquid_assets/engine.rb +25 -0
- data/lib/liquid_assets/template_handler.rb +52 -0
- data/lib/liquid_assets/tilt_engine.rb +54 -0
- data/lib/liquid_assets/tiny_liquid.rb +41 -0
- data/lib/liquid_assets/version.rb +3 -0
- data/lib/liquid_assets.rb +21 -0
- data/liquid_assets.gemspec +76 -0
- data/test/helper.rb +77 -0
- data/test/test_liquid_assets.rb +33 -0
- data/vendor/assets/javascripts/liquid_assets.js +57 -0
- data/vendor/tinyliquid.js +2730 -0
- metadata +183 -0
@@ -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, '&')
|
145
|
+
.replace(/</g, '<')
|
146
|
+
.replace(/>/g, '>')
|
147
|
+
.replace(/"/g, '"');
|
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, '&')
|
1314
|
+
.replace(/</g, '<')
|
1315
|
+
.replace(/>/g, '>')
|
1316
|
+
.replace(/"/g, '"');
|
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;
|