This repository has been archived by the owner on Aug 15, 2018. It is now read-only.
/
templatable.js
155 lines (118 loc) · 4.37 KB
/
templatable.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
define(function(require, exports, module) {
var $ = require('$');
var Handlebars = require('handlebars');
Handlebars.print = require('./ast-printer').print;
// 提供 Template 模板支持,默认引擎是 Handlebars
var Templatable = {
// Handlebars 的 helpers
templateHelpers: null,
// template 对应的 DOM-like object
templateObject: null,
// 根据配置的模板和传入的数据,构建 this.element 和 templateElement
parseElementFromTemplate: function() {
this.templateObject = convertTemplateToObject(this.template);
this.element = $(this.compile());
},
// 编译模板,混入数据,返回 html 结果
compile: function(template, model) {
template || (template = this.template);
model || (model = this.model);
if (model.toJSON) {
model = model.toJSON();
}
var helpers = this.templateHelpers;
// 注册 helpers
if (helpers) {
for (var name in helpers) {
if (helpers.hasOwnProperty(name)) {
Handlebars.registerHelper(name, helpers[name]);
}
}
}
// 注册 translate helper
var lang = this.get('lang') || {};
Handlebars.registerHelper(
'_', function(key) {return lang[key] || key;}
);
// 生成 html
var html = Handlebars.compile(template)(model);
// 卸载 helpers
if (helpers) {
for (name in helpers) {
if (helpers.hasOwnProperty(name)) {
delete Handlebars.helpers[name];
}
}
}
// 卸载 translate helper
delete Handlebars.helpers['_'];
return html;
},
// 刷新 selector 指定的局部区域
renderPartial: function(selector) {
var template = this._getTemplatePartial(selector);
this.$(selector).html(this.compile(template));
return this;
},
// 得到模板片段
_getTemplatePartial: function(selector) {
var template;
// 获取模板片段
if (selector) {
template = convertObjectToTemplate(
this.templateObject, selector);
}
// 没有选择器时,表示选择整个模板
else {
template = this.template;
}
return template;
}
};
module.exports = Templatable;
// Helpers
// -------
// 将 template 字符串转换成对应的 DOM-like object
function convertTemplateToObject(template) {
var statements = Handlebars.parse(template).statements;
var html = '';
for (var i = 0, len = statements.length; i < len; i++) {
var stat = statements[i];
// AST.ContentNode
if (stat.type === 'content') {
html += stat.string;
}
// AST.MustacheNode or AST.BlockNode
else {
html += '{{STAT ' + i + '}}';
}
}
html = encode(html);
var templateObject = $(html);
templateObject.template = html;
templateObject.statements = statements;
return templateObject;
}
// 根据 selector 得到 DOM-like template object,并转换为 template 字符串
function convertObjectToTemplate(templateObject, selector) {
var element = templateObject.find(selector);
if (element.length === 0) {
throw new Error('Invalid template selector: ' + selector);
}
var html = decode(element.html());
var statements = templateObject.statements;
// 将 html 中的 {{STAT n}} 还原为模板字符串
html = html.replace(STAT_RE, function(match, $1, $2) {
return Handlebars.print(statements[$2]);
});
return html;
}
var STAT_RE = /({{STAT (\d+)}})/g;
var STAT_DECODE_RE = /(?:<|<)!--({{STAT \d+}})--(?:>|>)/g;
function encode(template) {
return template.replace(STAT_RE, '<!--$1-->');
}
function decode(template) {
return template.replace(STAT_DECODE_RE, '$1');
}
});