-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.js
198 lines (184 loc) · 6.16 KB
/
main.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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/**
* render
*
* This module implements the rendering engine for Sail.js applications.
* Rendering is used to construct fragments of HTML, which are inserted
* dynamically into the DOM.
*/
define(['exports', 'module',
'dom',
'./lib/dom/render'],
function(exports, module, DOM, Render) {
/**
* Render template `name` using given `locals`.
*
* By default, the rendering engine will append "-template" to the name and
* select the HTML element with that ID in order to load the template. For
* example, invoking:
*
* render('hello', { name: 'Dave' });
*
* will result in rendering the following template:
*
* <script id="hello-template" type="text/template">
* <p>Hello, {{name}}</p>
* </script>
*
* This return value from this function can take multiple forms:
*
* 1. A compiled template function. In this case, the returned function
* must be invoked in order to produce the fragment of HTML.
*
* Returning a template function allows that function to be attached to
* a wrapped DOM element. The element can then be re-rendered by
* invoking el.render({ name: 'Jane' }), for example.
*
* 2. A string containing HTML. In this case, the returned string is used
* to construct a DOM element or tree.
*
* This case is suitable for applications don't require re-rendering and
* can be used as an optimization to lower resource usage.
*
* Sail.js does not impose any specific template engine on the application.
* During initialization, an application configures the template format being
* used by registering an engine:
*
* render.engine('text/template', mustache());
*
* @param {String} name name of template to render
* @param {Object} locals local variables to insert into template
* @return {Function|String}
* @api public
*/
exports = module.exports = function(name, locals) {
var uc = _useCache
, out;
if (uc) {
out = _cache[name];
if (out) return out;
}
var tmpl = _load(name);
if (typeof tmpl == 'string') {
tmpl = { string: tmpl }
}
// TODO: Implement support for precompiled templates, where `_load` returns
// a function.
var type = tmpl.type || 'default';
var engine = _engines[type];
if (!engine) throw new Error('No engine to render template type: ' + type);
// TODO: Pass arbitrary number of arguments to engine.
//return engine(tmpl.string, locals, options);
out = engine(tmpl.string, locals);
if (uc) _cache[name] = out;
return out;
};
exports.render = exports;
/**
* Register template engine for given `type`.
*
* @param {String} type type of template
* @param {Function} fn template engine function
* @api public
*/
exports.engine = function(type, fn) {
if (typeof type == 'function') {
fn = type;
type = 'default';
}
_engines[type] = fn;
};
exports.cache = function(flag) {
_useCache = flag;
}
/**
* Register template loader function.
*
* By default, the rendering engine will load templates from the HTML document
* by selecting based on ID. This default was chosen because it allows
* applications to be developed with the minimal set of tooling (ie, just a
* text editor).
*
* Some developers prefer to define templates outside of the main HTML
* document, for example by exporting strings from a JavaScript module. In
* this case, the template loader can be overridden to support this behavior.
*
* render.loader(function(name) {
* return templates.name;
* });
*
* As an optimization, many deployments ship precompiled templates so as not
* to incur the overhead on the client side. Similarly, the template loader
* can be overrriden to return the compiled template directly.
*
* render.loader(function(name) {
* return compiledTemplates.name;
* });
*
* @param {Function} fn template loader function
* @api public
*/
exports.loader = function(fn) {
_load = fn;
}
/**
* DOM utility.
*
* This function exposes the DOM utility in use by the application.
*
* Because DOM access is so pervasive within a web application, the render
* module exposes a single entry point for this functionality. This also
* serves as a cheap form of dependency injection, so that the developer can
* choose which utility to employ. Developers of `View` modules are advised
* to acccess the DOM through this function, rather than through their own
* explicitly declared dependency (which may conflict with the application
* developer's preferred choice).
*
* By default, the [DOM](https://github.com/anchorjs/dom) module provided by
* Anchor is used. However, this can be overridden to use any compatible
* module.
*
* To use [jQuery](http://jquery.com/)
*
* render.$(jQuery);
*
* To use [Zepto](http://zeptojs.com/)
*
* render.$(Zepto);
*
* To use [Kimbo](http://kimbojs.com/)
*
* render.$(Kimbo);
*
* To use [bonzo](https://github.com/ded/bonzo)
*
* render.$(bonzo);
*
*
* Anchor's DOM module defines a strict subset of DOM utility functions, which
* are designed to be compatible with jQuery and jQuery-compatible libraries.
* Developers of `View` modules for use with Sail.js are advised to only
* invoke functions within this subset, so as not to create an unneccessary
* requirement to use an alternative DOM utility. Likewise, application
* developers are warned that using an incomptible DOM utility may result in
* incorrect or undefined behavior.
*
* @api public
*/
exports.$ = function(nodes) {
if (typeof nodes == 'function') {
_$ = nodes;
return;
}
return _$.apply(undefined, arguments);
};
// Augment the DOM with (re)rendering functionality.
DOM.augment(Render);
var _load = function(name) {
var el = _$('#' + name + '-template');
return { type: el.attr('type'), string: el.html() }
}
var _engines = {};
var _cache = {};
var _useCache = true;
var _$ = DOM;
});