-
Notifications
You must be signed in to change notification settings - Fork 2
/
jquery.template.js
158 lines (133 loc) · 5.11 KB
/
jquery.template.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
156
157
158
/*!
* jQuery.template
* A micro-templating plugin for jQuery by David Furfero <http://furf.com/>
* http://github.com/furf/jquery-template
* Adapted from an original work by John Resig <http://ejohn.org/>
* http://ejohn.org/blog/javascript-micro-templating/
* MIT Licensed
*/
(function ($) {
var templates = {}, // Cache for previously rendered templates
tokenExpr = /\{%/; // Rough test for non-templates, ie. URLs
/**
* Creates a template engine based on a specified template, either a string
* or URL to template file.
* @param Boolean cache (optional) Set false to avoid cache, default true
* @param String str Parseable HTML template (must contain at least one
* tag, {% ... %}) or URL to template file
* @param Object obj (optional) data object to render
* @param Boolean raw (optional) set true to render as pure HTML, set false to
* render as jQuery collection, default false
* @return Object jQuery collection containing one member, <jquery:template/>,
* which will contain contents of rendered template
*/
$.template = function (cache, str, obj, raw) {
var replace = 'replace',
split = 'split',
join = 'join',
tag = 'jquery:template',
source,
render,
proxy;
// If optional first argument is not supplied, shift arguments
if (typeof cache !== 'boolean') {
raw = obj;
obj = str;
str = cache;
cache = true;
}
/**
* If str matches a key in the cache, use the previously rendered template
*/
if (str in templates) {
proxy = templates[str];
/**
* If str does not contain any template tags, async load the Ajax template
*/
} else if ($.trim(str).length && !tokenExpr.test(str)) {
$.ajax({
url: str,
dataType: 'text',
async: false,
success: function (response) {
proxy = $.template(false, response);
if (cache) {
templates[str] = proxy;
}
}
});
/**
* Parse str as JavaScript source to create new template engine
*/
} else {
// Convert template to JavaScript source code
source = "var __=[];__.push('" +
str[replace](/[\r\t\n]/g, " ")
// remove unnecessary close and reopen (saves whitespace, fixes switch statement)
[split](/%\}\s*\{%/)[join]('')
[split]("{%")[join]("\t")
[replace](/((^|%\})[^\t]*)'/g, "$1\r")
/**
* NOTE! Due to a bug in the micro-template parser, where templates
* containing more than one single quote (') fail to render, we
* escape all single quotes. The downside is that you must use
* double quotes (") to encapsulate strings in your code blocks.
* Example: {% var foo = "bar"; }
*/
[split]("'")[join]("\\'")
[replace](/\t=(.*?)%\}/g, "',$1,'")
[split]("\t")[join]("');")
[split]("%}")[join](";__.push('")
[split]("\r")[join]("\\'") +
"');return __.join('');";
// Create the render function from generated source
render = new Function('__index__', source);
/**
* Using a proxy function helps us avoid use of the "with" keyword, used
* in the original micro-templating code. This provides a noticeable
* performance improvement (in most browsers), but requires the use of
* "this" keyword in the templates.
* It also protects against a potential danger where variables declared
* with the same name as a property of the data object will destroy the
* property of the object.
* Example:
* $('myTemplate.tpl', {name:'furf'});
* myTemplate.tpl:
* Hello, <em>{%= this.name %}</em>
*/
proxy = function (obj, raw) {
// If object is an Array, render its members , otherwise render object
var html = $.isArray(obj) ? $.map(obj, function (obj, n) {
return render.call(obj, n);
}).join('') : render.call(obj);
// Return rendered HTML as a string or as jQuery instance
return raw ? html : $('<' + tag + '>' + html + '</' + tag + '>');
};
/**
* Aliased toString and toSource methods allow access to rendered template
* function source code for improved debugging.
*/
proxy.toString = function () {
return render.toString();
};
if (render.toSource) {
proxy.toSource = function () {
return render.toSource();
};
}
// Cache proxy for faster retrieval on subsequent calls
if (cache) {
templates[str] = proxy;
}
}
// Return template engine or rendered HTML if an object is specified
return obj ? proxy(obj, raw) : proxy;
};
/**
* Parse selected elements as templates
* @todo make this function consistent among dome elements
*/
$.fn.template = function (obj, raw) {
return $.template(this[this[0].nodeName.toUpperCase() === 'TEXTAREA' ? 'val' : 'html'](), obj, raw);
};
})(jQuery);