'::hui_template::';
'use strict';
// __ __ ______ ______ _____ __ __
// /\ \ /\ \ /'\_/`\ /\ _ \ /\__ _\/\ __`\ /\ \/\ \
// \ `\`\\/'//\ \\ \ \/\ \\/_/\ \/\ \ \/\ \\ \ \ \ \
// `\ `\ /' \ \ \__\ \\ \ __ \ \ \ \ \ \ \ \ \\ \ \ \ \
// `\ \ \ \ \ \_/\ \\ \ \/\ \ \ \ \ \ \ \_\ \\ \ \_\ \
// \ \_\ \ \_\\ \_\\ \_\ \_\ \ \_\ \ \_____\\ \_____\
// \/_/ \/_/ \/_/ \/_/\/_/ \/_/ \/_____/ \/_____/
//
/**
* @name Template模板管理类
* @public
* @author wanghaiyang
* @date 2014/05/05
*/
hui.define('hui_template', [], function () {
hui.Template = {
/**
* @name 解析前 originTargetContainer, 解析后 parsedTargetContainer
*/
originTargetContainer: {},
parsedTargetContainer: {},
targetRule: /<!--\s*target:\s*([a-zA-Z0-9\.\-_]+)\s*-->/g,
importRule: /<!--\s*import:\s*([a-zA-Z0-9\.\-_]+)\s*-->/g,
/**
* @name 解析模板字符串流[增加target]
* @public
* @param {String} tplStr 模板字符串流tpl:<!-- target:mergeTest -->hello {{myName}}!
* @param {Object|string...} opts 提供相应数据的对象或多个字符串
* @returns {String} 格式化后的字符串
*/
parseTemplate: function (tplStr, lazyParse) {
var me = this,
k,
targetNameList,
targetContentList,
targetList,
sep;
//基本思路: 使用正则提取targetName与targetContent分别放入两个数组
tplStr = !tplStr ? '' : String(tplStr);
//坑爹的String.split(RegExp)有兼容性问题!!!
//找到一个不重复的字符串做分隔符
sep = String(Math.random()).replace('.', '');
for (var i = 0; tplStr.indexOf(sep) > -1 && i < 1000; i++) {
sep = String(Math.random()).replace('.', '');
}
if (tplStr.indexOf(sep) > -1) {
throw new Error({
title: 'HUI Template Error: ',
name: 'Math.random()'
});
}
targetList = {};
targetNameList = tplStr.match(me.targetRule) || [];
targetContentList = tplStr.replace(me.targetRule, sep).split(sep);
//抛弃掉第一个<!-- target: XXX -->之前的内容
if (targetContentList.length - targetNameList.length == 1) {
targetContentList.shift();
}
if (targetContentList.length != targetNameList.length) {
throw new Error({
title: 'HUI Template Error: ',
name: 'Methond "parseTemplate()" error.'
});
}
for (var i = 0, len = targetNameList.length; i < len; i++) {
k = targetNameList[i].replace(me.targetRule, '$1');
targetList[k] = targetContentList[i];
//存入全局target容器(parsedTargetContainer中的后面将会替换)
me.originTargetContainer[k] = targetContentList[i];
}
if (lazyParse !== true) {
me.parseAllTarget();
}
return targetList;
},
/**
* @name 获取Target
* @public
* @param {String} targetName Target名字
* @returns {String} 未解析的target
*/
getTarget: function (targetName) {
var me = this;
if (targetName === null || targetName === '') return '';
if (me.parsedTargetContainer[targetName] === undefined) {
throw new Error('Target "' + targetName + '" not exist.');
}
return me.parsedTargetContainer[targetName];
},
/**
* @name 依赖于me.originTargetContainer循环解析targetList中的target
* @public
* @param {String} tplStr 模板字符串流tpl:<!-- target:mergeTest -->hello {{myName}}!
* @param {Object|String...} opts 提供相应数据的对象或多个字符串
* @returns {String} 格式化后的字符串
*/
parseAllTarget: function () {
var me = this,
targetList = {};
/**
* 解析所有target
*/
for (var i in me.originTargetContainer) {
if (!i) continue;
targetList[i] = me.originTargetContainer[i];
}
for (var i in me.originTargetContainer) {
if (!i) continue;
var v = me.originTargetContainer[i];
for (var j in targetList) {
if (!j || i == j) continue;
//importRule
targetList[j] = targetList[j].replace(new RegExp('<!--\\s*import\\s*:\\s*(' + i + ')\\s*-->', 'g'), v);
}
}
me.parsedTargetContainer = targetList;
return targetList;
},
/**
* @name 合并模板与数据
* @public
* @param {HTMLElement} targetContent 原始模板内容.
* @param {Object} model 数据模型
* @return {String} 替换掉{{varName}}变量后的模板内容.
*/
merge: function (targetContent, model) {
return hui.Template.parse(targetContent, model);
},
format: function (source, opts) {
source = String(source);
var data = Array.prototype.slice.call(arguments, 1);
var toString = Object.prototype.toString;
if (data.length) {
data = (data.length == 1 ?
/* ie 下 Object.prototype.toString.call(null) == '[object Object]' */
(opts !== null && (/\[object (Array|Object)\]/.test(toString.call(opts))) ? opts : data) : data);
var handler = function (match, key) {
var type = String(key).indexOf('*') === 0 ? 'decode' : String(key).indexOf('!!') === 0 ? '' : 'encode';
var str = key.replace(/^!!/, '').replace(/^\*/, '').replace(/[\(\)]/g, '');
var variable;
if (!str.replace(/[0-9a-zA-Z\.]/g, '')) {
var parts = str.split('.');
var part = parts.shift();
var cur = data;
while (part) {
if (cur[part] !== undefined) {
cur = cur[part];
}
else {
cur = undefined;
break;
}
part = parts.shift();
}
variable = cur;
}
else {
variable = Function('data', 'with(data){return ' + str + '}')(data);
}
// 加解码
if (undefined !== variable) {
variable = String(variable);
// encodeURIComponent not encode '
var fr = '&|<|>| |\'|"|\\'.split('|'),
to = '&|<|>| |'|"|\'.split('|');
if (type === 'decode') {
for (var i = fr.length - 1; i > -1; i--) {
variable = variable.replace(new RegExp('\\' + to[i], 'ig'), fr[i]);
}
}
else if (type === 'encode') {
for (var i = 0, l = fr.length; i < l; i++) {
variable = variable.replace(new RegExp('\\' + fr[i], 'ig'), to[i]);
}
}
}
return (undefined === variable ? '' : variable);
};
return source.replace(/#\{(.+?)\}/g, handler).replace(/\{\{([^\{]+?)\}\}/g, handler);
}
return source;
},
error: function (msg) {
msg = 'Template: ' + msg;
if (hui.window.console) {
hui.window.console.log(msg);
}
else throw Error(msg);
},
varConvert: function (token, model, strMap, str) {
var s2,
value,
c,
m;
model = model || {};
for (var i = 0, ilen = token.length; i < ilen; i++) {
s2 = token[i];
if (s2 === ',') continue;
value = s2[s2.length - 1];
if (s2.length === 2 || value === '') {
throw new Error('Template syntax error: ' + s2 + ' in ' + str);
}
value = hui.Template.getExpValue(value, model, strMap);
// Deal with a=b=, attention: won't want break s2, so use length-1 instead pop()
for (var j = 0, jlen = s2.length; j < jlen - 1; j++) {
if (s2[j] !== '=') {
if (s2[j].length > 1 && s2[j].indexOf('.') !== -1) {
m = s2[j];
m = m.split('.').join('=.=').split('=');
c = hui.Template.expCalculate(m, model, strMap, 'keep_var');
c.parent[c.child] = value;
}
else {
model[s2[j]] = value;
}
}
}
}
return model;
},
varTokenization: function (str) {
var list,
c,
m,
notValue = true,
preQuot = -1,
isJSON = false,
preBracket = [],
lineNum,
s1 = [],
s2 = [],
s3 = [],
t1 = [],
t2 = [],
s4;
list = String(str).split('');
for (var i = 0, ilen = list.length; i < ilen; i++) {
c = list[i];
// 单引或双引
if (/^[\'\"]$/.test(c)) { //'
if (notValue === true && preQuot === -1) {
notValue = false;
preQuot = i;
t1.push(c);
continue;
}
// 值 !notValue == isValue
if (!notValue) {
// 前面反斜杠个数
lineNum = 0;
for (var j = i - 1; j > -1; j--) {
if (list[j] === '\\') {
lineNum++;
}
else {
j = -1;
}
}
// 个数为偶数且和开始引号相同
// 结束引号
if (lineNum % 2 === 0) {
if (list[preQuot] === c) {
t1.push(c);
s1.push('{{' + t2.length + '}}');
t2.push(t1);
t1 = [];
notValue = true;
preQuot = -1;
}
}
else {
t1.push(c);
}
}
// 非值 notValue = true;
else {
// 开始引号
if (preQuot === -1) {
notValue = false;
preQuot = i;
t1.push(c);
}
// 结束引号
else if (list[preQuot] === c) {
notValue = true;
preQuot = -1;
}
}
}
else {
// is String value
if (!notValue) {
t1.push(c);
}
// 非值 notValue = true
else {
if (c + list[i + 1] === '{{') {
s1.push(' ');
for (var j = i + 2; j < ilen; j++) {
if (list[j] + list[j + 1] === '}}') {
i = j + 1;
break;
}
s1.push(list[j]);
}
s1.push(' ');
}
else if (c === '{' || c === '[') {
isJSON = true;
preBracket.push(c);
s1.push(c);
}
else if (c === '}' || c === ']') {
if (preBracket[preBracket.length - 1] === (c === '}' ? '{' : '[')) {
preBracket.pop();
}
if (preBracket.length === 0) {
isJSON = false;
s1.push(c);
}
}
// 逗号
else if (!isJSON && c === ',') {
s2.push(s1);
s3.push(s2);
s3.push(',');
s1 = [];
s2 = [];
}
// 等号, 且不是 != , >= , <= , ==
else if ((c === '=' || c === '是') && list[i - 1] !== '不' && list[i - 1] !== '!' && list[i - 1] !== '>' &&
list[i - 1] !== '<' && list[i - 1] !== '=' && list[i + 1] !== '=') {
s2.push(s1);
s2.push('=');
s1 = [];
}
else {
s1.push(c);
}
}
}
}
if (t1.join('')) {
s1.push('{{' + t2.length + '}}');
t2.push(t1);
}
s2.push(s1);
s3.push(s2);
for (var i = 0, ilen = s3.length; i < ilen; i++) {
s4 = s3[i];
if (Object.prototype.toString.call(s4) === '[object Array]') {
for (var j = 0, jlen = s4.length; j < jlen; j++) {
if (Object.prototype.toString.call(s4[j]) === '[object Array]') {
s4[j] = s4[j].join('');
}
s4[j] = String(s4[j]).replace(/(^\s+|\s+$)/g, '');
}
}
}
for (var i = 0, ilen = t2.length; i < ilen; i++) {
c = t2[i];
if (c[c.length - 1] === '"' || c[c.length - 1] === '\'') {
c.pop();
}
if (c[0] === '"' || c[0] === '\'') {
c.shift();
}
t2[i] = c.join('');
}
for (var i = 0, ilen = s3.length; i < ilen; i++) {
c = s3[i];
if (Object.prototype.toString.call(c) === '[object Array]') {
for (var j = 0, jlen = c.length; j < jlen; j++) {
m = c[j];
c[j] = hui.Template.overloadOperator(m);
}
}
else {
s3[i] = hui.Template.overloadOperator(c);
}
}
return {
token: s3,
strMap: t2
};
},
overloadOperator: function (str) {
var opList = [
'有', '.',
'的', '.',
'自加加', '++',
'自减减', '--',
'非', '!',
'正', '+',
'负', '-',
'乘以', '*',
'除以', '/',
'求余', '%',
'加上', '+',
'减去', '-',
'不大于', '<=',
'不小于', '>=',
'不等于', '!=',
'不是', '!==',
'恒等于', '===',
'真的是', '===',
'不恒等于', '!==',
'大于', '>',
'小于', '<',
'等于', '==',
'且', '&&',
'或', '||',
'实体', '{}',
'数组', '[]'
];
for (var i = 0, ilen = opList.length; i < ilen;) {
str = str.split(opList[i++]).join(opList[i++]);
}
return str;
},
getExpValue: function (v1, model, strMap) {
v1 = String(v1);
strMap = strMap || [];
var keyword = {
'null': {
v: null
},
'undefined': {
v: undefined
},
'true': {
v: true
},
'false': {
v: false
}
};
var value = v1,
v = v1;
// Number
if (v.replace(/^[+\-]?(\d+\.)?\d+/g, '') === '' ||
'"\''.indexOf(v.substr(0, 1)) !== -1 ||
'{['.indexOf(v.substr(0, 1)) !== -1 ||
keyword[v] ||
v.replace(/^[a-zA-Z_]+[a-zA-Z0-9_]*/g, '') === '') {
value = hui.Template.getKeyValue(v, model, strMap);
}
// Exp
else {
// != , >= , <= , ==
var token1 = hui.Template.expTokenization(v, model);
var token2 = hui.Template.expConvertBracket(token1, model, strMap);
var token3 = hui.Template.expConvertTree(token2, model, strMap);
value = hui.Template.expCalculate(token3, model, strMap);
}
// console.log(value);
return value;
},
// <!-- if: a = 123 --> => <!-- var: a = 123 --> <!-- if: a -->
//hui.Template.expBuildTree(['w.a','&&','w.a','/','w.a'])
expCalculate: function (list, model, strMap, keep_var) {
if (!list.opr) {
if (list.length === 1) {
if (Object.prototype.toString.call(list[0]) === '[object Array]') {
result = hui.Template.expCalculate(list[0], model, strMap, keep_var);
}
// a[aa]
else {
result = hui.Template.getKeyValue(list[0], model, strMap);
}
return result;
}
for (var i = 0, ilen = list.length; i < ilen; i++) {
if (hui.Template.expIsOperator(list[i])) {
list.opr = list[i];
break;
}
}
}
var c, m, result, data;
/* var degree = {
'.': 11,
'的': 11,
'[': 11,
']': 11,
'(': 10,
')': 10,
'++': 9,
'自加加': 9,
'--': 9,
'自减减': 9,
'^!': 8,
'非': 8,
'^+': 8,
'正': 8,
'^-': 8,
'负': 8,
'*': 7,
'乘以': 7,
'/': 7,
'除以': 7,
'%': 7,
'求余': 7,
'+': 6,
'加上': 6,
'-': 6,
'减去': 6,
'<': 5,
'小于': 5,
'<=': 5,
'不大于': 5,
'>': 5,
'大于': 5,
'>=': 5,
'不小于': 5,
'==': 4,
'等于': 4,
'!=': 4,
'不等于': 4,
'===': 4,
'恒等于': 4,
'!==': 4,
'不恒等于': 4,
'&&': 3,
'且': 3,
'||': 2,
'或': 2
};*/
if (list.opr === '++' || list.opr === '--') {
c = list[0] === '++' || list[0] === '--' ? list[1] : list[0];
if (Object.prototype.toString.call(c) !== '[object Array]' && (!c || c.replace(/^[a-zA-Z_]+[a-zA-Z0-9_]*/g, '') !== '')) {
throw new Error('Syntax error: "++","--" in ' + hui.Template.format(list.join(' '), strMap));
}
c = c.join ? hui.Template.expCalculate(c, model, strMap, 'keep_var') : {
parent: model,
child: c
};
result = c.parent[c.child];
c.parent[c.child] = result + (list.opr === '++' ? 1 : -1);
result = list[0] === '++' || list[0] === '--' ? c.parent[c.child] : result;
}
else if (list.opr === '.') {
for (var i = 0, ilen = list.length; i < ilen; i++) {
c = list[i];
if (Object.prototype.toString.call(c) === '[object Array]') {
c = hui.Template.expCalculate(c, model, strMap);
}
if (c && String(c).indexOf('{{') === 0) {
c = strMap[c.replace(/(^{{|}}$)/g, '')];
}
list[i] = c;
}
data = model;
var ilen = list.length + (keep_var === 'keep_var' ? -1 : 0);
for (var i = 0; i < ilen; i++) {
c = list[i];
if (!data) {
break;
}
data = data[c];
i++;
}
result = keep_var === 'keep_var' ? {
parent: data || {},
child: list[list.length - 1]
} : data;
}
else {
for (var i = 0, ilen = list.length; i < ilen; i++) {
c = list[i];
if (Object.prototype.toString.call(c) === '[object Array]') {
c = hui.Template.expCalculate(c, model, strMap);
list[i] = c;
}
else {
list[i] = hui.Template.expIsOperator(c) ? list[i] : hui.Template.getKeyValue(c, model, strMap);
}
}
if (list.opr === '!') {
result = list.pop();
for (var i = list.length - 1; i > -1; i--) {
result = !result;
}
}
else if (list.opr === '?') {
c = list[0];
if (c) {
result = list[2];
}
else {
result = list[4];
}
}
else if (list.opr === '||') {
result = false || list[0];
for (var i = 1, ilen = list.length; i < ilen && !result; i++) {
c = list[i];
if (c === '||' && !result) {
m = list[i + 1];
result = result || m;
}
i++;
}
}
else if (list.opr === '&&') {
result = true && list[0];
for (var i = 1, ilen = list.length; i < ilen && result; i++) {
c = list[i];
if (c === '&&' && result) {
m = list[i + 1];
result = result && m;
}
i++;
}
}
else if (list.opr === '!==' || list.opr === '===' || list.opr === '!=' || list.opr === '==') {
result = list[0];
for (var i = 1, ilen = list.length; i < ilen; i++) {
c = list[i];
m = list[i + 1];
if (c === '!==' || c === '!=') {
result = String(result) !== String(m);
}
else if (c === '===' || c === '==') {
result = String(result) === String(m);
}
i++;
}
}
else if (list.opr === '>' || list.opr === '>=' || list.opr === '<' || list.opr === '<=') {
result = list[0];
for (var i = 1, ilen = list.length; i < ilen; i++) {
c = list[i];
m = list[i + 1];
if (c === '>') {
result = result > m;
}
else if (c === '>=') {
result = result >= m;
}
else if (c === '<') {
result = result < m;
}
else if (c === '<=') {
result = result <= m;
}
i++;
}
}
else if (list.opr === '+' || list.opr === '-') {
if (list[0] === '+' || list[0] === '-') {
result = list.pop();
for (var i = list.length - 1; i > -1; i--) {
result = list[i] === '-' ? 0 - result : result;
}
}
else {
result = list[0];
for (var i = 1, ilen = list.length; i < ilen; i++) {
c = list[i];
m = list[i + 1];
if (c === '+') {
result = result + m;
}
else if (c === '-') {
result = result - m;
}
i++;
}
}
}
else if (list.opr === '*' || list.opr === '/' || list.opr === '%') {
result = list[0];
for (var i = 1, ilen = list.length; i < ilen; i++) {
c = list[i];
m = list[i + 1];
if (c === '*') {
result = result * m;
}
else if (c === '/') {
result = result / m;
}
else if (c === '%') {
result = result % m;
}
i++;
}
}
}
return result;
},
getKeyValue: function (v1, model, strMap, keep_str) {
v1 = String(v1);
strMap = strMap || [];
var keyword = {
'null': {
v: null
},
'undefined': {
v: undefined
},
'true': {
v: true
},
'false': {
v: false
}
};
var value = v1,
v = v1;
// Number
if (v.replace(/^[+\-]?(\d+\.)?\d+/g, '') === '') {
value = Number(v);
}
// String
else if (~'"\''.indexOf(v.substr(0, 1))) {
value = v.replace(/(^[\"\']|[\"\']$)/g, ''); //"
}
// {{0}}
else if (v.indexOf('{{') > -1) {
value = hui.Template.format(strMap[v.replace(/(^{{|}}$)/g, '')], model);
//value = v;
}
// JSON
else if (~'{['.indexOf(v.substr(0, 1))) {
v = v1.replace(/{{(\d+)}}/g, function (match, key) {
return strMap[key];
});
value = (new Function('return ' + v))();
value = value;
}
// null, undefined, true, false
else if (keyword[v]) {
value = keyword[v].v;
}
// model[v]
else {
//else if (v.replace(/^[a-zA-Z_]+[a-zA-Z0-9_]*/g, '') === '') {
value = model[v];
}
return value;
},
// b.a !== {{0}}, b[{{1}}] !== {{2}}, a+b
expTokenization: function (str) {
var list,
pre,
next,
c,
isOperator = false,
s1 = [],
s2 = [];
list = String(str).split('');
for (var i = 0, ilen = list.length; i < ilen; i++) {
c = list[i];
pre = ',' + String(list[i - 1]) + c + ',';
next = String(list[i - 1]) + c + String(list[i + 1]);
if ('[]()+-!*/%<=>&|?:,.'.indexOf(c) !== -1) {
isOperator = true;
if (',++,--,==,!=,>=,<=,&&,||,'.indexOf(pre) !== -1 || /\d\.\d/.test(next)) {
s1.push(c);
}
else {
if (s1.length) {
s2.push(s1);
}
s1 = [];
s1.push(c);
}
}
else if (c + list[i + 1] === '{{') {
if (s1.length) {
s2.push(s1);
}
s1 = [];
for (var j = i; j < ilen; j++) {
s1.push(list[j]);
if (list[j] + list[j + 1] === '}}') {
i = j + 1;
s1.push(list[j + 1]);
break;
}
}
s2.push(s1);
s1 = [];
}
else if (c === ' ' || c === '\t') {
continue;
}
else if (list[i - 1] === '.' && '0123456789'.indexOf(c) !== -1) {
s1.push(c);
}
else {
if (isOperator) {
isOperator = false;
if (s1.length) {
s2.push(s1);
}
s1 = [];
}
s1.push(c);
}
}
if (s1.length) {
s2.push(s1);
}
for (var i = 0, ilen = s2.length; i < ilen; i++) {
if (s2[i] && s2[i].join) {
s2[i] = s2[i].join('');
}
}
return s2;
},
expConvertBracket: function (token, model, strMap) {
//
token = token || [];
var root = [],
parent = null,
cur = root,
list = [root],
c;
for (var i = 0, len = token.length; i < len; i++) {
c = token[i];
if (c === '(' || c === '[') {
parent = cur;
if (c === '[') {
cur.push('.');
}
cur = [];
parent.push(cur);
list.push(cur);
}
else if (list.length > 1 && c === ')' || c === ']') {
list.pop();
cur = parent || cur;
if (c === ']') {
//cur.push(c);
}
parent = list[list.length - 2];
}
else {
cur.push(c);
}
}
return root;
},
expConvertTree: function (token, model, strMap) {
for (var i = 0, ilen = token.length; i < ilen; i++) {
if (Object.prototype.toString.call(token[i]) === '[object Array]') {
token[i] = hui.Template.expConvertTree(token[i]);
i = i;
}
}
return hui.Template.expBuildTree(token);
},
expBuildTree: function (token) {
token = token && token.length && token.join ? token : [];
var degree = {
'.': 11,
'[': 11,
']': 11,
'(': 10,
')': 10,
'++': 9,
'--': 9,
'^!': 8,
'^+': 8,
'^-': 8,
'*': 7,
'/': 7,
'%': 7,
'+': 6,
'-': 6,
'<': 5,
'<=': 5,
'>': 5,
'>=': 5,
'==': 4,
'!=': 4,
'===': 4,
'!==': 4,
'&&': 3,
'||': 2,
'的': 11,
'自加加': 9,
'非': 8,
'自减减': 9,
'正': 8,
'负': 8,
'乘以': 7,
'除以': 7,
'求余': 7,
'加上': 6,
'减去': 6,
'小于': 5,
'不大于': 5,
'大于': 5,
'不小于': 5,
'等于': 4,
'不等于': 4,
'恒等于': 4,
'不恒等于': 4,
'且': 3,
'或': 2
};
var c,
pre,
nxt,
cd,
newtoken,
n;
// .
token = token;
newtoken = [];
for (var i = 0, len = token.length; i < len; i++) {
c = token[i];
if (c === '.') {
cd = degree[c];
pre = newtoken[newtoken.length - 1];
// a.b
if (hui.Template.expIsOperand(pre) && hui.Template.expIsOperand(token[i + 1])) {
if (pre && pre.lev && pre.lev === cd) {
pre.push(c);
pre.push(token[i + 1]);
i++;
}
else {
pre = [];
pre.push(newtoken.pop());
pre.push(c);
pre.push(token[i + 1]);
i++;
pre.lev = cd;
pre.opr = c;
newtoken.push(pre);
}
}
else {
throw new Error('SyntaxError: invalid Dot(.) operand in "' + token[i - 1] + ' ' + token[i] + ' ' + token[i + 1] + '"');
}
}
else {
newtoken.push(c);
}
}
// ++, --
token = newtoken;
newtoken = [];
for (var i = 0, len = token.length; i < len; i++) {
c = token[i];
if (c === '++' || c === '--') {
// i++
if (hui.Template.expIsOperand(token[i - 1]) && !hui.Template.expIsOperand(token[i + 1])) {
n = [];
n.push(newtoken.pop());
n.push(c);
n.lev = degree[c];
n.opr = c;
newtoken.push(n);
}
// ++i
else if (!hui.Template.expIsOperand(token[i - 1]) && hui.Template.expIsOperand(token[i + 1])) {
n = [];
n.push(c);
n.push(token[i + 1]);
n.lev = degree[c];
n.opr = c;
newtoken.push(n);
i++;
}
else {
throw new Error('SyntaxError: invalid Increment(++),Decrement(--) operand in "' + token[i - 1] + ' ' + token[i] + ' ' + token[i + 1] + '"');
}
}
else {
newtoken.push(c);
}
}
// ! + -
token = newtoken;
newtoken = [token.pop()];
for (var i = token.length - 1; i > -1; i--) {
c = token[i];
if ((c === '+' || c === '-' || c === '!') && (hui.Template.expIsOperator(token[i - 1]) || i === 0)) {
// ! ! ! + - - - + a
cd = degree['^' + c];
pre = newtoken[0];
if (hui.Template.expIsOperand(pre)) {
if (pre && pre.lev && pre.lev === cd) {
pre.unshift(c);
}
else {
pre = [];
pre.unshift(newtoken.shift());
pre.unshift(c);
pre.lev = cd;
pre.opr = c;
newtoken.unshift(pre);
}
}
else {
throw new Error('SyntaxError: invalid Negative(+),Positive(-) operand in "' + token[i - 1] + ' ' + token[i] + ' ' + token[i + 1] + '"');
}
}
else {
newtoken.unshift(c);
}
}
// * / %
token = newtoken;
newtoken = [];
for (var i = 0, len = token.length; i < len; i++) {
c = token[i];
if (c === '*' || c === '/' || c === '%') {
cd = degree[c];
pre = newtoken[newtoken.length - 1];
// a.b
if (hui.Template.expIsOperand(pre) && hui.Template.expIsOperand(token[i + 1])) {
if (pre && pre.lev && pre.lev === cd) {
pre.push(c);
pre.push(token[i + 1]);
i++;
}
else {
pre = [];
pre.push(newtoken.pop());
pre.push(c);
pre.push(token[i + 1]);
i++;
pre.lev = cd;
pre.opr = c;
newtoken.push(pre);
}
}
else {
throw new Error('SyntaxError: invalid MUL(*),DIV(/),(MOD)% operand in "' + token[i - 1] + ' ' + token[i] + ' ' + token[i + 1] + '"');
}
}
else {
newtoken.push(c);
}
}
// a + b
token = newtoken;
newtoken = [];
for (var i = 0, len = token.length; i < len; i++) {
c = token[i];
if (c === '+' || c === '-') {
cd = degree[c];
pre = newtoken[newtoken.length - 1];
// a.b
if (hui.Template.expIsOperand(pre) && hui.Template.expIsOperand(token[i + 1])) {
if (pre && pre.lev && pre.lev === cd) {
pre.push(c);
pre.push(token[i + 1]);
i++;
}
else {
pre = [];
pre.push(newtoken.pop());
pre.push(c);
pre.push(token[i + 1]);
i++;
pre.lev = cd;
pre.opr = c;
newtoken.push(pre);
}
}
else {
throw new Error('SyntaxError: invalid ADD(+) or SUB(-) operand in "' + token[i - 1] + ' ' + token[i] + ' ' + token[i + 1] + '"');
}
}
else {
newtoken.push(c);
}
}
// a >= b
token = newtoken;
newtoken = [];
for (var i = 0, len = token.length; i < len; i++) {
c = token[i];
if (c === '>' || c === '>=' || c === '<' || c === '<=') {
cd = degree[c];
pre = newtoken[newtoken.length - 1];
// a.b
if (hui.Template.expIsOperand(pre) && hui.Template.expIsOperand(token[i + 1])) {
if (pre && pre.lev && pre.lev === cd) {
pre.push(c);
pre.push(token[i + 1]);
i++;
}
else {
pre = [];
pre.push(newtoken.pop());
pre.push(c);
pre.push(token[i + 1]);
i++;
pre.lev = cd;
pre.opr = c;
newtoken.push(pre);
}
}
else {
throw new Error('SyntaxError: invalid Morethan(>,>=),Lessthan(<=,<) operand in "' + token[i - 1] + ' ' + token[i] + ' ' + token[i + 1] + '"');
}
}
else {
newtoken.push(c);
}
}
// a === b
token = newtoken;
newtoken = [];
for (var i = 0, len = token.length; i < len; i++) {
c = token[i];
if (c === '==' || c === '!=' || c === '===' || c === '!==') {
cd = degree[c];
pre = newtoken[newtoken.length - 1];
// a.b
if (hui.Template.expIsOperand(pre) && hui.Template.expIsOperand(token[i + 1])) {
if (pre && pre.lev && pre.lev === cd) {
pre.push(c);
pre.push(token[i + 1]);
i++;
}
else {
pre = [];
pre.push(newtoken.pop());
pre.push(c);
pre.push(token[i + 1]);
i++;
pre.lev = cd;
pre.opr = c;
newtoken.push(pre);
}
}
else {
throw new Error('SyntaxError: invalid Equal(==,!==) operand in "' + token[i - 1] + ' ' + token[i] + ' ' + token[i + 1] + '"');
}
}
else {
newtoken.push(c);
}
}
// a && b
token = newtoken;
newtoken = [];
for (var i = 0, len = token.length; i < len; i++) {
c = token[i];
if (c === '&&') {
cd = degree[c];
pre = newtoken[newtoken.length - 1];
// a.b
if (hui.Template.expIsOperand(pre) && hui.Template.expIsOperand(token[i + 1])) {
if (pre && pre.lev && pre.lev === cd) {
pre.push(c);
pre.push(token[i + 1]);
i++;
}
else {
pre = [];
pre.push(newtoken.pop());
pre.push(c);
pre.push(token[i + 1]);
i++;
pre.lev = cd;
pre.opr = c;
newtoken.push(pre);
}
}
else {
throw new Error('SyntaxError: invalid AND(&&) operand in "' + token[i - 1] + ' ' + token[i] + ' ' + token[i + 1] + '"');
}
}
else {
newtoken.push(c);
}
}
// a || b
token = newtoken;
newtoken = [];
for (var i = 0, len = token.length; i < len; i++) {
c = token[i];
if (c === '||') {
cd = degree[c];
pre = newtoken[newtoken.length - 1];
// a.b
if (hui.Template.expIsOperand(pre) && hui.Template.expIsOperand(token[i + 1])) {
if (pre && pre.lev && pre.lev === cd) {
pre.push(c);
pre.push(token[i + 1]);
i++;
}
else {
pre = [];
pre.push(newtoken.pop());
pre.push(c);
pre.push(token[i + 1]);
i++;
pre.lev = cd;
pre.opr = c;
newtoken.push(pre);
}
}
else {
throw new Error('SyntaxError: invalid OR(||) operand in "' + token[i - 1] + ' ' + token[i] + ' ' + token[i + 1] + '"');
}
}
else {
newtoken.push(c);
}
}
// a ? b : c
token = newtoken;
newtoken = [];
for (var i = token.length - 1; i > -1; i--) {
c = token[i];
if (c === '?') {
// a ? b : c
cd = degree[c];
pre = token[i - 1];
if (hui.Template.expIsOperand(pre) && hui.Template.expIsOperand(newtoken[0]) && newtoken[1] === ':' && hui.Template.expIsOperand(newtoken[2])) {
nxt = [];
nxt.push(pre);
nxt.push(c);
nxt.push(newtoken.shift());
nxt.push(newtoken.shift());
nxt.push(newtoken.shift());
i--;
nxt.lev = cd;
nxt.opr = c;
newtoken.unshift(nxt);
}
else {
throw new Error('SyntaxError: invalid "A ? B : C" operand in "' + token[i - 1] + ' ' + token[i] + ' ' + token[i + 1] + '"');
}
}
else {
newtoken.unshift(c);
}
}
return newtoken;
},
expIsOperator: function (key) {
key = key === null || key === undefined ? '' : key;
if (Object.prototype.toString.call(key) === '[object Array]') {
key = '';
}
key = String(key).replace(/(^\s+|\s+$)/g, '');
var result = key.length < 4 && ',+,-,*,/,%,&&,||,!,==,===,!=,!==,>,<,>=,<=,.,[,],(,),'.indexOf(',' + key + ',') != -1;
return result;
},
expIsOperand: function (v) {
return v !== null && v !== undefined && !hui.Template.expIsOperator(v);
},
// Regular Expressions for parsing tags and attributes
startTag: /^<!--\s*([A-Za-z0-9\u4e00-\u9fa5]+):(.*?)-->/,
endTag: /^<!--\s*\/([A-Za-z0-9\u4e00-\u9fa5]+)\s*-->/,
// Block Elements
typeBlock: {
'if': 1,
'elif': 1,
'else': 1,
'for': 1
},
// Elements that you can':1,' intentionally':1,' leave open
// (and which close themselves)
typeCloseSelf: {
'var': 1,
'use': 1
},
typeEndAndStart: {
'elif': 1,
'else': 1
},
typeScope: {
'for': 1,
'use': 1,
'html': 1
},
// Strict xml model!!
parse: function (html, model, root) {
var me = this;
var stack = me.tokenization(html);
if (root === undefined) {
// 根节点
root = hui.Template.createElement('html', {
childNodes: [],
nodeType: 'startTag',
labelValue: ''
});
hui.Template.rootNode = root;
}
if (model) {
root.scopeChain = root.scopeChain || {};
for (var i in model) {
if (model.hasOwnProperty(i)) {
root.scopeChain[i] = model[i];
}
}
}
me.treeConstruction(stack, root);
var c = root;
var result = '';
var tplList = [];
for (var j = 0, jlen = c.childNodes.length; j < jlen; j++) {
tplList.push(me.mergeModel(c.childNodes[j]));
}
result = tplList.join('');
return result;
//me.domtree;
},
overloadTagName: function (node) {
var tagNameList = [
'安排', 'var',
'定义', 'var',
'设定', 'var',
'如果', 'if',
'如果结束', 'if',
'假如', 'if',
'假设', 'if',
'假设结束', 'if',
'又假设', 'elif',
'又假如', 'elif',
'否则', 'else',
'循环', 'for',
'循环结束', 'for'
];
if (node) {
for (var i = 0, ilen = tagNameList.length; i < ilen; i++) {
if (node.tagName === tagNameList[i++]) {
node.tagName = tagNameList[i];
}
}
}
return node;
},
// Token serial
tokenization: function (html) {
var me = this,
tokenserial = [],
index,
m, n,
token,
nodeValue,
match,
html = String(html);
// <!--comment--> <html>1234</html>
while (html) {
// start tag
if (html.indexOf('<!--') === 0 && me.startTag.test(html)) {
match = html.match(me.startTag);
token = {
tagName: match[1],
nodeValue: match[2],
labelValue: match[0],
nodeType: 'startTag'
};
token = hui.Template.overloadTagName(token);
token.nodeType = me.typeCloseSelf[token.tagName] ? 'selfClose' : (me.typeEndAndStart[token.tagName] ? 'typeEndAndStart' : token.nodeType);
tokenserial.push(token);
html = html.substring(match[0].length);
}
// end tag
else if (html.indexOf('<!--') === 0 && me.endTag.test(html)) {
match = html.match(me.endTag);
token = {
tagName: match[1],
nodeType: 'endTag'
};
tokenserial.push(hui.Template.overloadTagName(token));
html = html.substring(match[0].length);
}
// Comment
else if (html.indexOf('<!--') === 0) {
m = html.indexOf('<!--');
n = html.indexOf('-->', m + 4);
n = n == -1 ? html.length : n;
nodeValue = html.substring(m + 4, n);
token = {
tagName: 'comment',
nodeValue: nodeValue,
labelValue: '<!--' + nodeValue + '-->',
nodeType: 'selfClose'
};
tokenserial.push(hui.Template.overloadTagName(token));
html = html.substring(0, m) + html.substring(n + 3, html.length);
}
// text
else {
m = html.indexOf('<!--', 1);
index = m == -1 ? html.length : m;
nodeValue = html.substring(0, index);
token = {
tagName: 'nodetext',
nodeValue: nodeValue,
labelValue: nodeValue,
nodeType: 'selfClose'
};
tokenserial.push(hui.Template.overloadTagName(token));
html = html.substring(index, html.length);
}
}
return tokenserial;
},
treeConstruction: function (tokens, parentNode) {
var me = this,
domtree = parentNode || hui.Template.rootNode,
curentParent = domtree,
token,
elem,
parentElem;
for (var i = 0, len = tokens.length; i < len; i++) {
token = tokens[i];
if (token.nodeType == 'selfClose') {
elem = me.createElement(token.tagName, token);
curentParent.childNodes.push(elem);
// elem.parentNode = curentParent.getGUID();
elem.parentNode = curentParent;
}
else if (token.nodeType == 'startTag') {
// 'if,elif,else' is special.
if (token.tagName == 'if') {
elem = me.createElement('ifif', {});
curentParent.childNodes.push(elem);
// elem.parentNode = curentParent.getGUID();
elem.parentNode = curentParent;
elem.childNodes = [];
curentParent = elem;
}
elem = me.createElement(token.tagName, token);
curentParent.childNodes.push(elem);
// elem.parentNode = curentParent.getGUID();
elem.parentNode = curentParent;
// Not empty tag
if (!me.typeCloseSelf[token.tagName]) {
elem.childNodes = [];
curentParent = elem;
}
}
else if (token.nodeType == 'endTag') {
if (!me.typeCloseSelf[token.tagName]) {
if (token.tagName == 'if' && ~',if,elif,else,'.indexOf(',' + curentParent.tagName)) {
parentElem = curentParent.parentNode;
if (parentElem.tagName == 'ifif') {
curentParent = parentElem.parentNode;
}
}
else if (token.tagName == curentParent.tagName) {
curentParent = curentParent.parentNode;
}
// Only deal with typeBlock!
else if (me.typeBlock[token.tagName]) {
parentElem = curentParent;
while (parentElem) {
if (parentElem.tagName == token.tagName) {
curentParent = parentElem.parentNode;
}
else {
parentElem = parentElem.parentNode;
}
}
}
}
}
else if (token.nodeType == 'typeEndAndStart') {
if (me.typeEndAndStart[token.tagName]) {
if (~',if,elif,'.indexOf(',' + curentParent.tagName + ',') && ~',elif,else,'.indexOf(',' + token.tagName)) {
curentParent = curentParent.parentNode;
}
elem = me.createElement(token.tagName, token);
curentParent.childNodes.push(elem);
// elem.parentNode = curentParent.getGUID();
elem.parentNode = curentParent;
// Not empty tag
if (!me.typeCloseSelf[token.tagName]) {
elem.childNodes = [];
curentParent = elem;
}
}
}
}
return domtree;
},
createElement: function (tagName, options) {
var me = this,
clazz = hui.Template.NodeElement,
elem = new clazz();
options = options || {};
options.tagName = tagName;
for (var i in options) {
elem[i] = options[i];
}
if (me.typeScope[String(tagName).toLowerCase()]) {
elem.scopeChain = elem.scopeChain || {};
}
return elem;
},
mergeModel: function (nodeItem) {
var me = this,
str,
k,
v,
c,
list,
tplList,
model,
result;
if (nodeItem && nodeItem.tagName) {
var tagName = String(nodeItem.tagName).toLowerCase();
if (tagName === 'var') {
str = nodeItem.nodeValue;
list = hui.Template.varTokenization(str);
result = '';
model = nodeItem.getScopeChainModel();
hui.Template.varConvert(list.token, model, list.strMap, str);
nodeItem.updateScopeChainModel(model);
}
else if (tagName === 'ifif') {
model = nodeItem.getScopeChainModel();
result = '';
for (var i = 0, ilen = nodeItem.childNodes.length; i < ilen; i++) {
c = nodeItem.childNodes[i];
if (c.tagName === 'else') {
tplList = [];
for (var j = 0, jlen = c.childNodes.length; j < jlen; j++) {
tplList.push(me.mergeModel(c.childNodes[j]));
}
result = tplList.join('');
break;
}
else {
k = hui.Template.varTokenization(c.nodeValue);
var k2 = hui.Template.getExpValue(k.token[0][0], model, k.strMap);
if (k2) {
tplList = [];
for (var j = 0, jlen = c.childNodes.length; j < jlen; j++) {
tplList.push(me.mergeModel(c.childNodes[j]));
}
result = tplList.join('');
break;
}
}
}
}
else if (tagName === 'for') {
var scopeChain = nodeItem.scopeChain;
str = nodeItem.nodeValue;
model = nodeItem.getScopeChainModel();
v = str.split(' in ');
k = v[0].replace(/(^\s+|\s+$)/g, '').replace(/(^{{|}}$)/g, '');
var vname = v[1].replace(/(^\s+|\s+$)/g, '').replace(/(^{{|}}$)/g, '');
var str2;
var start;
var end;
var step = 1;
var tail = false;
if (vname.indexOf('..') !== -1) {
if (vname.indexOf('...') !== -1) {
tail = true;
vname = vname.replace('...', '..');
}
str2 = vname.split(' step ');
step = Number((str2[1] ? str2[1].replace(/\s/g, '') : step) || step);
start = Number(str2[0].split('..')[0]);
end = Number(str2[0].split('..')[1]);
list = [];
for (var i = start; i < end || (tail && i === end); i += step) {
list.push(i);
}
}
else {
list = hui.Template.getExpValue(vname, model);
}
if (Object.prototype.toString.call(list) !== '[object Array]') {
throw new Error('SyntaxError: invalid "list" operand in "' + str + '"');
}
c = nodeItem;
result = '';
tplList = [];
for (var i in list) {
if (list.hasOwnProperty(i)) {
scopeChain[k] = model[k] = list[i];
}
for (var j = 0, jlen = c.childNodes.length; j < jlen; j++) {
tplList.push(me.mergeModel(c.childNodes[j]));
}
}
result = tplList.join('');
return result;
}
/**
'<!-- use: item(main=${p.name}, sub=${p.email}) -->',
'<!-- target: item --><li>${main}[${sub}]</li>'
*/
else if (tagName === 'use') {
str = nodeItem.nodeValue.replace(/(^\s+|\s+$)/g, '');
model = nodeItem.getScopeChainModel();
nodeItem.childNodes = [];
var varStr = str.substring(str.indexOf('(') + 1, str.lastIndexOf(')')),
targetName = str.substring(0, str.indexOf('(')),
targetContent = hui.Template.getTarget(targetName);
//varStr = hui.Template.format(varStr, model);
me.parse('<!--var:' + varStr + '-->', model, nodeItem);
model = nodeItem.getScopeChainModel();
result = me.parse(targetContent, model, nodeItem);
}
else if (tagName === 'nodetext') {
str = nodeItem.nodeValue;
model = nodeItem.getScopeChainModel();
result = hui.Template.format(str, model).replace(/\{(\\*)\\\{/g, '{$1{').replace(/\}(\\*)\\\}/g, '}$1}');
}
else {
result = nodeItem.labelValue;
}
}
return result;
}
};
hui.Template.NodeElement = function (options) {
this.nodeValue = '';
this.guid = hui.Template.NodeElement.makeGUID();
};
hui.Template.NodeElement.prototype = {
getGUID: function () {
var me = this;
return me.guid;
},
getScopeChain: function () {
var me = this,
parent = me,
result = [],
typeScope = hui.Template.typeScope;
while (parent) {
if (typeScope[String(parent.tagName).toLowerCase()]) {
result.unshift(parent.scopeChain);
}
parent = parent.parentNode;
}
return result;
},
getScopeChainModel: function () {
var me = this,
list = me.getScopeChain(),
model = {};
for (var j = list.length - 1; j > -1; j--) {
for (var i in list[j]) {
if (!model.hasOwnProperty(i)) {
model[i] = list[j][i];
}
}
}
return model;
},
updateScopeChainModel: function (model) {
var me = this,
list = me.getScopeChain();
for (var i in model) {
if (model.hasOwnProperty(i)) {
for (var j = list.length - 1; j > -1; j--) {
if (list[j].hasOwnProperty(i)) {
list[j][i] = model[i];
j = -1;
i = undefined;
}
}
if (i !== undefined) {
list[list.length - 1][i] = model[i];
}
}
}
}
};
/**
* @name 获取唯一id
* @public
* @return {String}
*/
hui.Template.NodeElement.makeGUID = (function () {
var guid = 1000; // 0 -> root
return function () {
return String('tpl_' + guid++);
};
})();
hui.format = hui.Template.format;
});