smt_rails 0.2.3 → 0.2.4
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/lib/smt_rails/version.rb +1 -1
- data/vendor/assets/javascripts/mustache.js +496 -410
- metadata +16 -10
data/lib/smt_rails/version.rb
CHANGED
@@ -2,535 +2,621 @@
|
|
2
2
|
* mustache.js - Logic-less {{mustache}} templates with JavaScript
|
3
3
|
* http://github.com/janl/mustache.js
|
4
4
|
*/
|
5
|
-
var Mustache = (typeof module !== "undefined" && module.exports) || {};
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
exports.name = "mustache.js";
|
10
|
-
exports.version = "0.5.0-dev";
|
11
|
-
exports.tags = ["{{", "}}"];
|
12
|
-
exports.parse = parse;
|
13
|
-
exports.compile = compile;
|
14
|
-
exports.render = render;
|
15
|
-
exports.clearCache = clearCache;
|
16
|
-
|
17
|
-
// This is here for backwards compatibility with 0.4.x.
|
18
|
-
exports.to_html = function (template, view, partials, send) {
|
19
|
-
var result = render(template, view, partials);
|
20
|
-
|
21
|
-
if (typeof send === "function") {
|
22
|
-
send(result);
|
23
|
-
} else {
|
24
|
-
return result;
|
25
|
-
}
|
26
|
-
};
|
6
|
+
/*global define: false*/
|
27
7
|
|
28
|
-
|
29
|
-
var _isArray = Array.isArray;
|
30
|
-
var _forEach = Array.prototype.forEach;
|
31
|
-
var _trim = String.prototype.trim;
|
8
|
+
var Mustache;
|
32
9
|
|
33
|
-
|
34
|
-
if (
|
35
|
-
|
10
|
+
(function (exports) {
|
11
|
+
if (typeof module !== "undefined" && module.exports) {
|
12
|
+
module.exports = exports; // CommonJS
|
13
|
+
} else if (typeof define === "function") {
|
14
|
+
define(exports); // AMD
|
36
15
|
} else {
|
37
|
-
|
38
|
-
return _toString.call(obj) === "[object Array]";
|
39
|
-
};
|
16
|
+
Mustache = exports; // <script>
|
40
17
|
}
|
18
|
+
}((function () {
|
41
19
|
|
42
|
-
var
|
43
|
-
if (_forEach) {
|
44
|
-
forEach = function (obj, callback, scope) {
|
45
|
-
return _forEach.call(obj, callback, scope);
|
46
|
-
};
|
47
|
-
} else {
|
48
|
-
forEach = function (obj, callback, scope) {
|
49
|
-
for (var i = 0, len = obj.length; i < len; ++i) {
|
50
|
-
callback.call(scope, obj[i], i, obj);
|
51
|
-
}
|
52
|
-
};
|
53
|
-
}
|
20
|
+
var exports = {};
|
54
21
|
|
55
|
-
|
22
|
+
exports.name = "mustache.js";
|
23
|
+
exports.version = "0.7.0";
|
24
|
+
exports.tags = ["{{", "}}"];
|
56
25
|
|
57
|
-
|
58
|
-
|
26
|
+
exports.Scanner = Scanner;
|
27
|
+
exports.Context = Context;
|
28
|
+
exports.Writer = Writer;
|
29
|
+
|
30
|
+
var whiteRe = /\s*/;
|
31
|
+
var spaceRe = /\s+/;
|
32
|
+
var nonSpaceRe = /\S/;
|
33
|
+
var eqRe = /\s*=/;
|
34
|
+
var curlyRe = /\s*\}/;
|
35
|
+
var tagRe = /#|\^|\/|>|\{|&|=|!/;
|
36
|
+
|
37
|
+
// Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
|
38
|
+
// See https://github.com/janl/mustache.js/issues/189
|
39
|
+
function testRe(re, string) {
|
40
|
+
return RegExp.prototype.test.call(re, string);
|
59
41
|
}
|
60
42
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
return string == null ? "" : _trim.call(string);
|
65
|
-
};
|
66
|
-
} else {
|
67
|
-
var trimLeft, trimRight;
|
43
|
+
function isWhitespace(string) {
|
44
|
+
return !testRe(nonSpaceRe, string);
|
45
|
+
}
|
68
46
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
} else {
|
73
|
-
// IE doesn't match non-breaking spaces with \s, thanks jQuery.
|
74
|
-
trimLeft = /^[\s\xA0]+/;
|
75
|
-
trimRight = /[\s\xA0]+$/;
|
76
|
-
}
|
47
|
+
var isArray = Array.isArray || function (obj) {
|
48
|
+
return Object.prototype.toString.call(obj) === "[object Array]";
|
49
|
+
};
|
77
50
|
|
78
|
-
|
79
|
-
|
80
|
-
String(string).replace(trimLeft, "").replace(trimRight, "");
|
81
|
-
};
|
51
|
+
function escapeRe(string) {
|
52
|
+
return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
|
82
53
|
}
|
83
54
|
|
84
|
-
var
|
55
|
+
var entityMap = {
|
85
56
|
"&": "&",
|
86
57
|
"<": "<",
|
87
58
|
">": ">",
|
88
59
|
'"': '"',
|
89
|
-
"'": '''
|
60
|
+
"'": ''',
|
61
|
+
"/": '/'
|
90
62
|
};
|
91
63
|
|
92
|
-
function
|
93
|
-
return String(string).replace(
|
94
|
-
return
|
64
|
+
function escapeHtml(string) {
|
65
|
+
return String(string).replace(/[&<>"'\/]/g, function (s) {
|
66
|
+
return entityMap[s];
|
95
67
|
});
|
96
68
|
}
|
97
69
|
|
70
|
+
// Export the escaping function so that the user may override it.
|
71
|
+
// See https://github.com/janl/mustache.js/issues/244
|
72
|
+
exports.escape = escapeHtml;
|
73
|
+
|
74
|
+
function Scanner(string) {
|
75
|
+
this.string = string;
|
76
|
+
this.tail = string;
|
77
|
+
this.pos = 0;
|
78
|
+
}
|
79
|
+
|
98
80
|
/**
|
99
|
-
*
|
100
|
-
* object and alters the message to provide more useful debugging information.
|
81
|
+
* Returns `true` if the tail is empty (end of string).
|
101
82
|
*/
|
102
|
-
function
|
103
|
-
|
104
|
-
|
105
|
-
var lines = template.split("\n"),
|
106
|
-
start = Math.max(line - 3, 0),
|
107
|
-
end = Math.min(lines.length, line + 3),
|
108
|
-
context = lines.slice(start, end);
|
109
|
-
|
110
|
-
var c;
|
111
|
-
for (var i = 0, len = context.length; i < len; ++i) {
|
112
|
-
c = i + start + 1;
|
113
|
-
context[i] = (c === line ? " >> " : " ") + context[i];
|
114
|
-
}
|
83
|
+
Scanner.prototype.eos = function () {
|
84
|
+
return this.tail === "";
|
85
|
+
};
|
115
86
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
87
|
+
/**
|
88
|
+
* Tries to match the given regular expression at the current position.
|
89
|
+
* Returns the matched text if it can match, the empty string otherwise.
|
90
|
+
*/
|
91
|
+
Scanner.prototype.scan = function (re) {
|
92
|
+
var match = this.tail.match(re);
|
120
93
|
|
121
|
-
|
122
|
-
|
94
|
+
if (match && match.index === 0) {
|
95
|
+
this.tail = this.tail.substring(match[0].length);
|
96
|
+
this.pos += match[0].length;
|
97
|
+
return match[0];
|
98
|
+
}
|
99
|
+
|
100
|
+
return "";
|
101
|
+
};
|
123
102
|
|
124
103
|
/**
|
125
|
-
*
|
104
|
+
* Skips all text until the given regular expression can be matched. Returns
|
105
|
+
* the skipped string, which is the entire tail if no match can be made.
|
126
106
|
*/
|
127
|
-
function
|
128
|
-
|
129
|
-
|
107
|
+
Scanner.prototype.scanUntil = function (re) {
|
108
|
+
var match, pos = this.tail.search(re);
|
109
|
+
|
110
|
+
switch (pos) {
|
111
|
+
case -1:
|
112
|
+
match = this.tail;
|
113
|
+
this.pos += this.tail.length;
|
114
|
+
this.tail = "";
|
115
|
+
break;
|
116
|
+
case 0:
|
117
|
+
match = "";
|
118
|
+
break;
|
119
|
+
default:
|
120
|
+
match = this.tail.substring(0, pos);
|
121
|
+
this.tail = this.tail.substring(pos);
|
122
|
+
this.pos += pos;
|
130
123
|
}
|
131
124
|
|
132
|
-
|
133
|
-
|
134
|
-
var target = names[lastIndex];
|
125
|
+
return match;
|
126
|
+
};
|
135
127
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
128
|
+
function Context(view, parent) {
|
129
|
+
this.view = view;
|
130
|
+
this.parent = parent;
|
131
|
+
this.clearCache();
|
132
|
+
}
|
140
133
|
|
141
|
-
|
142
|
-
|
143
|
-
|
134
|
+
Context.make = function (view) {
|
135
|
+
return (view instanceof Context) ? view : new Context(view);
|
136
|
+
};
|
144
137
|
|
145
|
-
|
146
|
-
|
147
|
-
|
138
|
+
Context.prototype.clearCache = function () {
|
139
|
+
this._cache = {};
|
140
|
+
};
|
148
141
|
|
149
|
-
|
150
|
-
|
142
|
+
Context.prototype.push = function (view) {
|
143
|
+
return new Context(view, this);
|
144
|
+
};
|
151
145
|
|
152
|
-
|
153
|
-
|
154
|
-
|
146
|
+
Context.prototype.lookup = function (name) {
|
147
|
+
var value = this._cache[name];
|
148
|
+
|
149
|
+
if (!value) {
|
150
|
+
if (name === ".") {
|
151
|
+
value = this.view;
|
152
|
+
} else {
|
153
|
+
var context = this;
|
154
|
+
|
155
|
+
while (context) {
|
156
|
+
if (name.indexOf(".") > 0) {
|
157
|
+
var names = name.split("."), i = 0;
|
158
|
+
|
159
|
+
value = context.view;
|
160
|
+
|
161
|
+
while (value && i < names.length) {
|
162
|
+
value = value[names[i++]];
|
163
|
+
}
|
164
|
+
} else {
|
165
|
+
value = context.view[name];
|
166
|
+
}
|
167
|
+
|
168
|
+
if (value != null) {
|
169
|
+
break;
|
170
|
+
}
|
171
|
+
|
172
|
+
context = context.parent;
|
173
|
+
}
|
155
174
|
}
|
156
|
-
}
|
157
175
|
|
158
|
-
|
159
|
-
if (typeof value === "function") {
|
160
|
-
value = value.call(localStack[localStack.length - 1]);
|
176
|
+
this._cache[name] = value;
|
161
177
|
}
|
162
178
|
|
163
|
-
if (value
|
164
|
-
|
179
|
+
if (typeof value === "function") {
|
180
|
+
value = value.call(this.view);
|
165
181
|
}
|
166
182
|
|
167
183
|
return value;
|
184
|
+
};
|
185
|
+
|
186
|
+
function Writer() {
|
187
|
+
this.clearCache();
|
168
188
|
}
|
169
189
|
|
170
|
-
function
|
171
|
-
|
172
|
-
|
190
|
+
Writer.prototype.clearCache = function () {
|
191
|
+
this._cache = {};
|
192
|
+
this._partialCache = {};
|
193
|
+
};
|
194
|
+
|
195
|
+
Writer.prototype.compile = function (template, tags) {
|
196
|
+
var fn = this._cache[template];
|
173
197
|
|
174
|
-
if (
|
175
|
-
|
176
|
-
|
177
|
-
// doesn't exist, is false, or is an empty list.
|
178
|
-
if (value == null || value === false || (isArray(value) && value.length === 0)) {
|
179
|
-
buffer += callback();
|
180
|
-
}
|
181
|
-
} else if (isArray(value)) {
|
182
|
-
forEach(value, function (value) {
|
183
|
-
stack.push(value);
|
184
|
-
buffer += callback();
|
185
|
-
stack.pop();
|
186
|
-
});
|
187
|
-
} else if (typeof value === "object") {
|
188
|
-
stack.push(value);
|
189
|
-
buffer += callback();
|
190
|
-
stack.pop();
|
191
|
-
} else if (typeof value === "function") {
|
192
|
-
var scope = stack[stack.length - 1];
|
193
|
-
var scopedRender = function (template) {
|
194
|
-
return render(template, scope);
|
195
|
-
};
|
196
|
-
buffer += value.call(scope, callback(), scopedRender) || "";
|
197
|
-
} else if (value) {
|
198
|
-
buffer += callback();
|
198
|
+
if (!fn) {
|
199
|
+
var tokens = exports.parse(template, tags);
|
200
|
+
fn = this._cache[template] = this.compileTokens(tokens, template);
|
199
201
|
}
|
200
202
|
|
201
|
-
return
|
202
|
-
}
|
203
|
+
return fn;
|
204
|
+
};
|
203
205
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
* - file The name of the file the template comes from (displayed in
|
210
|
-
* error messages)
|
211
|
-
* - tags An array of open and close tags the `template` uses. Defaults
|
212
|
-
* to the value of Mustache.tags
|
213
|
-
* - debug Set `true` to log the body of the generated function to the
|
214
|
-
* console
|
215
|
-
* - space Set `true` to preserve whitespace from lines that otherwise
|
216
|
-
* contain only a {{tag}}. Defaults to `false`
|
217
|
-
*/
|
218
|
-
function parse(template, options) {
|
219
|
-
options = options || {};
|
220
|
-
|
221
|
-
var tags = options.tags || exports.tags,
|
222
|
-
openTag = tags[0],
|
223
|
-
closeTag = tags[tags.length - 1];
|
224
|
-
|
225
|
-
var code = [
|
226
|
-
'var buffer = "";', // output buffer
|
227
|
-
"\nvar line = 1;", // keep track of source line number
|
228
|
-
"\ntry {",
|
229
|
-
'\nbuffer += "'
|
230
|
-
];
|
206
|
+
Writer.prototype.compilePartial = function (name, template, tags) {
|
207
|
+
var fn = this.compile(template, tags);
|
208
|
+
this._partialCache[name] = fn;
|
209
|
+
return fn;
|
210
|
+
};
|
231
211
|
|
232
|
-
|
233
|
-
|
234
|
-
|
212
|
+
Writer.prototype.compileTokens = function (tokens, template) {
|
213
|
+
var fn = compileTokens(tokens);
|
214
|
+
var self = this;
|
235
215
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
216
|
+
return function (view, partials) {
|
217
|
+
if (partials) {
|
218
|
+
if (typeof partials === "function") {
|
219
|
+
self._loadPartial = partials;
|
220
|
+
} else {
|
221
|
+
for (var name in partials) {
|
222
|
+
self.compilePartial(name, partials[name]);
|
223
|
+
}
|
242
224
|
}
|
243
|
-
} else {
|
244
|
-
spaces = [];
|
245
225
|
}
|
246
226
|
|
247
|
-
|
248
|
-
nonSpace = false;
|
227
|
+
return fn(self, Context.make(view), template);
|
249
228
|
};
|
229
|
+
};
|
250
230
|
|
251
|
-
|
231
|
+
Writer.prototype.render = function (template, view, partials) {
|
232
|
+
return this.compile(template)(view, partials);
|
233
|
+
};
|
252
234
|
|
253
|
-
|
254
|
-
|
255
|
-
nextOpenTag = tags[0];
|
256
|
-
nextCloseTag = tags[tags.length - 1];
|
257
|
-
};
|
235
|
+
Writer.prototype._section = function (name, context, text, callback) {
|
236
|
+
var value = context.lookup(name);
|
258
237
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
'\nvar partial = partials["' + trim(source) + '"];',
|
264
|
-
'\nif (partial) {',
|
265
|
-
'\n buffer += render(partial,stack[stack.length - 1],partials);',
|
266
|
-
'\n}',
|
267
|
-
'\nbuffer += "'
|
268
|
-
);
|
269
|
-
};
|
238
|
+
switch (typeof value) {
|
239
|
+
case "object":
|
240
|
+
if (isArray(value)) {
|
241
|
+
var buffer = "";
|
270
242
|
|
271
|
-
|
272
|
-
|
243
|
+
for (var i = 0, len = value.length; i < len; ++i) {
|
244
|
+
buffer += callback(this, context.push(value[i]));
|
245
|
+
}
|
273
246
|
|
274
|
-
|
275
|
-
throw debug(new Error("Section name may not be empty"), template, line, options.file);
|
247
|
+
return buffer;
|
276
248
|
}
|
277
249
|
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
'\nvar callback = (function () {',
|
285
|
-
'\n return function () {',
|
286
|
-
'\n var buffer = "";',
|
287
|
-
'\nbuffer += "'
|
288
|
-
);
|
289
|
-
};
|
250
|
+
return value ? callback(this, context.push(value)) : "";
|
251
|
+
case "function":
|
252
|
+
var self = this;
|
253
|
+
var scopedRender = function (template) {
|
254
|
+
return self.render(template, context);
|
255
|
+
};
|
290
256
|
|
291
|
-
|
292
|
-
|
293
|
-
|
257
|
+
return value.call(context.view, text, scopedRender) || "";
|
258
|
+
default:
|
259
|
+
if (value) {
|
260
|
+
return callback(this, context);
|
261
|
+
}
|
262
|
+
}
|
294
263
|
|
295
|
-
|
296
|
-
|
297
|
-
var openName = sectionStack.length != 0 && sectionStack[sectionStack.length - 1].name;
|
264
|
+
return "";
|
265
|
+
};
|
298
266
|
|
299
|
-
|
300
|
-
|
301
|
-
}
|
267
|
+
Writer.prototype._inverted = function (name, context, callback) {
|
268
|
+
var value = context.lookup(name);
|
302
269
|
|
303
|
-
|
270
|
+
// Use JavaScript's definition of falsy. Include empty arrays.
|
271
|
+
// See https://github.com/janl/mustache.js/issues/186
|
272
|
+
if (!value || (isArray(value) && value.length === 0)) {
|
273
|
+
return callback(this, context);
|
274
|
+
}
|
304
275
|
|
305
|
-
|
306
|
-
|
307
|
-
'\n return buffer;',
|
308
|
-
'\n };',
|
309
|
-
'\n})();'
|
310
|
-
);
|
276
|
+
return "";
|
277
|
+
};
|
311
278
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
279
|
+
Writer.prototype._partial = function (name, context) {
|
280
|
+
if (!(name in this._partialCache) && this._loadPartial) {
|
281
|
+
this.compilePartial(name, this._loadPartial(name));
|
282
|
+
}
|
283
|
+
|
284
|
+
var fn = this._partialCache[name];
|
285
|
+
|
286
|
+
return fn ? fn(context) : "";
|
287
|
+
};
|
288
|
+
|
289
|
+
Writer.prototype._name = function (name, context) {
|
290
|
+
var value = context.lookup(name);
|
291
|
+
|
292
|
+
if (typeof value === "function") {
|
293
|
+
value = value.call(context.view);
|
294
|
+
}
|
295
|
+
|
296
|
+
return (value == null) ? "" : String(value);
|
297
|
+
};
|
298
|
+
|
299
|
+
Writer.prototype._escaped = function (name, context) {
|
300
|
+
return exports.escape(this._name(name, context));
|
301
|
+
};
|
302
|
+
|
303
|
+
/**
|
304
|
+
* Calculates the bounds of the section represented by the given `token` in
|
305
|
+
* the original template by drilling down into nested sections to find the
|
306
|
+
* last token that is part of that section. Returns an array of [start, end].
|
307
|
+
*/
|
308
|
+
function sectionBounds(token) {
|
309
|
+
var start = token[3];
|
310
|
+
var end = start;
|
311
|
+
|
312
|
+
var tokens;
|
313
|
+
while ((tokens = token[4]) && tokens.length) {
|
314
|
+
token = tokens[tokens.length - 1];
|
315
|
+
end = token[3];
|
316
|
+
}
|
317
|
+
|
318
|
+
return [start, end];
|
319
|
+
}
|
320
|
+
|
321
|
+
/**
|
322
|
+
* Low-level function that compiles the given `tokens` into a function
|
323
|
+
* that accepts three arguments: a Writer, a Context, and the template.
|
324
|
+
*/
|
325
|
+
function compileTokens(tokens) {
|
326
|
+
var subRenders = {};
|
327
|
+
|
328
|
+
function subRender(i, tokens, template) {
|
329
|
+
if (!subRenders[i]) {
|
330
|
+
var fn = compileTokens(tokens);
|
331
|
+
subRenders[i] = function (writer, context) {
|
332
|
+
return fn(writer, context, template);
|
333
|
+
};
|
316
334
|
}
|
317
335
|
|
318
|
-
|
319
|
-
}
|
336
|
+
return subRenders[i];
|
337
|
+
}
|
320
338
|
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
updateLine,
|
325
|
-
'\nbuffer += lookup("' + trim(source) + '",stack,"");',
|
326
|
-
'\nbuffer += "'
|
327
|
-
);
|
328
|
-
};
|
339
|
+
return function (writer, context, template) {
|
340
|
+
var buffer = "";
|
341
|
+
var token, sectionText;
|
329
342
|
|
330
|
-
|
331
|
-
|
332
|
-
'";',
|
333
|
-
updateLine,
|
334
|
-
'\nbuffer += escapeHTML(lookup("' + trim(source) + '",stack,""));',
|
335
|
-
'\nbuffer += "'
|
336
|
-
);
|
337
|
-
};
|
343
|
+
for (var i = 0, len = tokens.length; i < len; ++i) {
|
344
|
+
token = tokens[i];
|
338
345
|
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
c = template.substr(i, 1);
|
344
|
-
updateLine = '\nline = ' + line + ';';
|
345
|
-
nextOpenTag = openTag;
|
346
|
-
nextCloseTag = closeTag;
|
347
|
-
hasTag = true;
|
348
|
-
|
349
|
-
switch (c) {
|
350
|
-
case "!": // comment
|
351
|
-
i++;
|
352
|
-
callback = null;
|
353
|
-
break;
|
354
|
-
case "=": // change open/close tags, e.g. {{=<% %>=}}
|
355
|
-
i++;
|
356
|
-
closeTag = "=" + closeTag;
|
357
|
-
callback = setTags;
|
346
|
+
switch (token[0]) {
|
347
|
+
case "#":
|
348
|
+
sectionText = template.slice.apply(template, sectionBounds(token));
|
349
|
+
buffer += writer._section(token[1], context, sectionText, subRender(i, token[4], template));
|
358
350
|
break;
|
359
|
-
case "
|
360
|
-
i
|
361
|
-
callback = includePartial;
|
351
|
+
case "^":
|
352
|
+
buffer += writer._inverted(token[1], context, subRender(i, token[4], template));
|
362
353
|
break;
|
363
|
-
case "
|
364
|
-
|
365
|
-
callback = openSection;
|
354
|
+
case ">":
|
355
|
+
buffer += writer._partial(token[1], context);
|
366
356
|
break;
|
367
|
-
case "
|
368
|
-
|
369
|
-
callback = openInvertedSection;
|
357
|
+
case "&":
|
358
|
+
buffer += writer._name(token[1], context);
|
370
359
|
break;
|
371
|
-
case "
|
372
|
-
|
373
|
-
callback = closeSection;
|
360
|
+
case "name":
|
361
|
+
buffer += writer._escaped(token[1], context);
|
374
362
|
break;
|
375
|
-
case "
|
376
|
-
|
377
|
-
// fall through
|
378
|
-
case "&": // plain variable
|
379
|
-
i++;
|
380
|
-
nonSpace = true;
|
381
|
-
callback = sendPlain;
|
363
|
+
case "text":
|
364
|
+
buffer += token[1];
|
382
365
|
break;
|
383
|
-
default: // escaped variable
|
384
|
-
nonSpace = true;
|
385
|
-
callback = sendEscaped;
|
386
366
|
}
|
367
|
+
}
|
387
368
|
|
388
|
-
|
369
|
+
return buffer;
|
370
|
+
};
|
371
|
+
}
|
389
372
|
|
390
|
-
|
391
|
-
|
373
|
+
/**
|
374
|
+
* Forms the given array of `tokens` into a nested tree structure where
|
375
|
+
* tokens that represent a section have a fifth item: an array that contains
|
376
|
+
* all tokens in that section.
|
377
|
+
*/
|
378
|
+
function nestTokens(tokens) {
|
379
|
+
var tree = [];
|
380
|
+
var collector = tree;
|
381
|
+
var sections = [];
|
382
|
+
var token, section;
|
383
|
+
|
384
|
+
for (var i = 0; i < tokens.length; ++i) {
|
385
|
+
token = tokens[i];
|
386
|
+
|
387
|
+
switch (token[0]) {
|
388
|
+
case "#":
|
389
|
+
case "^":
|
390
|
+
token[4] = [];
|
391
|
+
sections.push(token);
|
392
|
+
collector.push(token);
|
393
|
+
collector = token[4];
|
394
|
+
break;
|
395
|
+
case "/":
|
396
|
+
if (sections.length === 0) {
|
397
|
+
throw new Error("Unopened section: " + token[1]);
|
392
398
|
}
|
393
399
|
|
394
|
-
|
400
|
+
section = sections.pop();
|
395
401
|
|
396
|
-
if (
|
397
|
-
|
402
|
+
if (section[1] !== token[1]) {
|
403
|
+
throw new Error("Unclosed section: " + section[1]);
|
398
404
|
}
|
399
405
|
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
n++;
|
406
|
+
if (sections.length > 0) {
|
407
|
+
collector = sections[sections.length - 1][4];
|
408
|
+
} else {
|
409
|
+
collector = tree;
|
405
410
|
}
|
411
|
+
break;
|
412
|
+
default:
|
413
|
+
collector.push(token);
|
414
|
+
}
|
415
|
+
}
|
416
|
+
|
417
|
+
// Make sure there were no open sections when we're done.
|
418
|
+
section = sections.pop();
|
406
419
|
|
407
|
-
|
408
|
-
|
409
|
-
|
420
|
+
if (section) {
|
421
|
+
throw new Error("Unclosed section: " + section[1]);
|
422
|
+
}
|
423
|
+
|
424
|
+
return tree;
|
425
|
+
}
|
426
|
+
|
427
|
+
/**
|
428
|
+
* Combines the values of consecutive text tokens in the given `tokens` array
|
429
|
+
* to a single token.
|
430
|
+
*/
|
431
|
+
function squashTokens(tokens) {
|
432
|
+
var token, lastToken;
|
433
|
+
|
434
|
+
for (var i = 0; i < tokens.length; ++i) {
|
435
|
+
token = tokens[i];
|
436
|
+
|
437
|
+
if (lastToken && lastToken[0] === "text" && token[0] === "text") {
|
438
|
+
lastToken[1] += token[1];
|
439
|
+
lastToken[3] = token[3];
|
440
|
+
tokens.splice(i--, 1); // Remove this token from the array.
|
410
441
|
} else {
|
411
|
-
|
442
|
+
lastToken = token;
|
443
|
+
}
|
444
|
+
}
|
445
|
+
}
|
412
446
|
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
447
|
+
function escapeTags(tags) {
|
448
|
+
if (tags.length !== 2) {
|
449
|
+
throw new Error("Invalid tags: " + tags.join(" "));
|
450
|
+
}
|
451
|
+
|
452
|
+
return [
|
453
|
+
new RegExp(escapeRe(tags[0]) + "\\s*"),
|
454
|
+
new RegExp("\\s*" + escapeRe(tags[1]))
|
455
|
+
];
|
456
|
+
}
|
457
|
+
|
458
|
+
/**
|
459
|
+
* Breaks up the given `template` string into a tree of token objects. If
|
460
|
+
* `tags` is given here it must be an array with two string values: the
|
461
|
+
* opening and closing tags used in the template (e.g. ["<%", "%>"]). Of
|
462
|
+
* course, the default is to use mustaches (i.e. Mustache.tags).
|
463
|
+
*/
|
464
|
+
exports.parse = function (template, tags) {
|
465
|
+
tags = tags || exports.tags;
|
466
|
+
|
467
|
+
var tagRes = escapeTags(tags);
|
468
|
+
var scanner = new Scanner(template);
|
469
|
+
|
470
|
+
var tokens = [], // Buffer to hold the tokens
|
471
|
+
spaces = [], // Indices of whitespace tokens on the current line
|
472
|
+
hasTag = false, // Is there a {{tag}} on the current line?
|
473
|
+
nonSpace = false; // Is there a non-space char on the current line?
|
474
|
+
|
475
|
+
// Strips all whitespace tokens array for the current line
|
476
|
+
// if there was a {{#tag}} on it and otherwise only space.
|
477
|
+
function stripSpace() {
|
478
|
+
if (hasTag && !nonSpace) {
|
479
|
+
while (spaces.length) {
|
480
|
+
tokens.splice(spaces.pop(), 1);
|
481
|
+
}
|
482
|
+
} else {
|
483
|
+
spaces = [];
|
484
|
+
}
|
485
|
+
|
486
|
+
hasTag = false;
|
487
|
+
nonSpace = false;
|
488
|
+
}
|
489
|
+
|
490
|
+
var start, type, value, chr;
|
491
|
+
|
492
|
+
while (!scanner.eos()) {
|
493
|
+
start = scanner.pos;
|
494
|
+
value = scanner.scanUntil(tagRes[0]);
|
495
|
+
|
496
|
+
if (value) {
|
497
|
+
for (var i = 0, len = value.length; i < len; ++i) {
|
498
|
+
chr = value.charAt(i);
|
499
|
+
|
500
|
+
if (isWhitespace(chr)) {
|
501
|
+
spaces.push(tokens.length);
|
431
502
|
} else {
|
432
503
|
nonSpace = true;
|
433
504
|
}
|
434
505
|
|
435
|
-
|
506
|
+
tokens.push(["text", chr, start, start + 1]);
|
507
|
+
start += 1;
|
508
|
+
|
509
|
+
if (chr === "\n") {
|
510
|
+
stripSpace(); // Check for whitespace on the current line.
|
511
|
+
}
|
436
512
|
}
|
437
513
|
}
|
438
|
-
}
|
439
514
|
|
440
|
-
|
441
|
-
throw debug(new Error('Section "' + sectionStack[sectionStack.length - 1].name + '" was not closed properly'), template, line, options.file);
|
442
|
-
}
|
515
|
+
start = scanner.pos;
|
443
516
|
|
444
|
-
|
445
|
-
|
446
|
-
|
517
|
+
// Match the opening tag.
|
518
|
+
if (!scanner.scan(tagRes[0])) {
|
519
|
+
break;
|
520
|
+
}
|
447
521
|
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
522
|
+
hasTag = true;
|
523
|
+
type = scanner.scan(tagRe) || "name";
|
524
|
+
|
525
|
+
// Skip any whitespace between tag and value.
|
526
|
+
scanner.scan(whiteRe);
|
527
|
+
|
528
|
+
// Extract the tag value.
|
529
|
+
if (type === "=") {
|
530
|
+
value = scanner.scanUntil(eqRe);
|
531
|
+
scanner.scan(eqRe);
|
532
|
+
scanner.scanUntil(tagRes[1]);
|
533
|
+
} else if (type === "{") {
|
534
|
+
var closeRe = new RegExp("\\s*" + escapeRe("}" + tags[1]));
|
535
|
+
value = scanner.scanUntil(closeRe);
|
536
|
+
scanner.scan(curlyRe);
|
537
|
+
scanner.scanUntil(tagRes[1]);
|
538
|
+
type = "&";
|
539
|
+
} else {
|
540
|
+
value = scanner.scanUntil(tagRes[1]);
|
541
|
+
}
|
453
542
|
|
454
|
-
|
455
|
-
|
543
|
+
// Match the closing tag.
|
544
|
+
if (!scanner.scan(tagRes[1])) {
|
545
|
+
throw new Error("Unclosed tag at " + scanner.pos);
|
546
|
+
}
|
547
|
+
|
548
|
+
tokens.push([type, value, start, scanner.pos]);
|
456
549
|
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
550
|
+
if (type === "name" || type === "{" || type === "&") {
|
551
|
+
nonSpace = true;
|
552
|
+
}
|
553
|
+
|
554
|
+
// Set the tags for the next time around.
|
555
|
+
if (type === "=") {
|
556
|
+
tags = value.split(spaceRe);
|
557
|
+
tagRes = escapeTags(tags);
|
462
558
|
}
|
463
559
|
}
|
464
560
|
|
465
|
-
|
466
|
-
|
561
|
+
squashTokens(tokens);
|
562
|
+
|
563
|
+
return nestTokens(tokens);
|
564
|
+
};
|
565
|
+
|
566
|
+
// The high-level clearCache, compile, compilePartial, and render functions
|
567
|
+
// use this default writer.
|
568
|
+
var _writer = new Writer();
|
467
569
|
|
468
570
|
/**
|
469
|
-
*
|
571
|
+
* Clears all cached templates and partials in the default writer.
|
470
572
|
*/
|
471
|
-
function
|
472
|
-
|
473
|
-
|
474
|
-
var fn = new Function(args, body);
|
475
|
-
|
476
|
-
// This anonymous function wraps the generated function so we can do
|
477
|
-
// argument coercion, setup some variables, and handle any errors
|
478
|
-
// encountered while executing it.
|
479
|
-
return function (view, partials) {
|
480
|
-
partials = partials || {};
|
481
|
-
|
482
|
-
var stack = [view]; // context stack
|
573
|
+
exports.clearCache = function () {
|
574
|
+
return _writer.clearCache();
|
575
|
+
};
|
483
576
|
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
}
|
577
|
+
/**
|
578
|
+
* Compiles the given `template` to a reusable function using the default
|
579
|
+
* writer.
|
580
|
+
*/
|
581
|
+
exports.compile = function (template, tags) {
|
582
|
+
return _writer.compile(template, tags);
|
583
|
+
};
|
491
584
|
|
492
|
-
|
493
|
-
|
585
|
+
/**
|
586
|
+
* Compiles the partial with the given `name` and `template` to a reusable
|
587
|
+
* function using the default writer.
|
588
|
+
*/
|
589
|
+
exports.compilePartial = function (name, template, tags) {
|
590
|
+
return _writer.compilePartial(name, template, tags);
|
591
|
+
};
|
494
592
|
|
495
593
|
/**
|
496
|
-
*
|
594
|
+
* Compiles the given array of tokens (the output of a parse) to a reusable
|
595
|
+
* function using the default writer.
|
497
596
|
*/
|
498
|
-
function
|
499
|
-
|
500
|
-
}
|
597
|
+
exports.compileTokens = function (tokens, template) {
|
598
|
+
return _writer.compileTokens(tokens, template);
|
599
|
+
};
|
501
600
|
|
502
601
|
/**
|
503
|
-
*
|
504
|
-
*
|
505
|
-
* recognized options include the following:
|
506
|
-
*
|
507
|
-
* - cache Set `false` to bypass any pre-compiled version of the given
|
508
|
-
* template. Otherwise, a given `template` string will be cached
|
509
|
-
* the first time it is parsed
|
602
|
+
* Renders the `template` with the given `view` and `partials` using the
|
603
|
+
* default writer.
|
510
604
|
*/
|
511
|
-
function
|
512
|
-
|
605
|
+
exports.render = function (template, view, partials) {
|
606
|
+
return _writer.render(template, view, partials);
|
607
|
+
};
|
513
608
|
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
_cache[template] = _compile(template, options);
|
518
|
-
}
|
609
|
+
// This is here for backwards compatibility with 0.4.x.
|
610
|
+
exports.to_html = function (template, view, partials, send) {
|
611
|
+
var result = exports.render(template, view, partials);
|
519
612
|
|
520
|
-
|
613
|
+
if (typeof send === "function") {
|
614
|
+
send(result);
|
615
|
+
} else {
|
616
|
+
return result;
|
521
617
|
}
|
618
|
+
};
|
522
619
|
|
523
|
-
|
524
|
-
}
|
525
|
-
|
526
|
-
/**
|
527
|
-
* High-level function that renders the given `template` using the given
|
528
|
-
* `view` and `partials`. If you need to use any of the template options (see
|
529
|
-
* `compile` above), you must compile in a separate step, and then call that
|
530
|
-
* compiled function.
|
531
|
-
*/
|
532
|
-
function render(template, view, partials) {
|
533
|
-
return compile(template)(view, partials);
|
534
|
-
}
|
620
|
+
return exports;
|
535
621
|
|
536
|
-
}
|
622
|
+
}())));
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smt_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-10-29 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rails
|
17
|
-
requirement: &
|
17
|
+
requirement: &70257902094220 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: 3.1.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *70257902094220
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: tilt
|
28
|
-
requirement: &
|
28
|
+
requirement: &70257902093340 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: 1.3.3
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *70257902093340
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: sprockets
|
39
|
-
requirement: &
|
39
|
+
requirement: &70257902130980 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: 2.0.3
|
45
45
|
type: :runtime
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *70257902130980
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: mustache
|
50
|
-
requirement: &
|
50
|
+
requirement: &70257902130440 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ! '>='
|
@@ -55,7 +55,7 @@ dependencies:
|
|
55
55
|
version: 0.99.4
|
56
56
|
type: :runtime
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *70257902130440
|
59
59
|
description: Shared mustache templates for rails 3
|
60
60
|
email:
|
61
61
|
- contacts@railsware.com
|
@@ -93,12 +93,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
93
93
|
- - ! '>='
|
94
94
|
- !ruby/object:Gem::Version
|
95
95
|
version: '0'
|
96
|
+
segments:
|
97
|
+
- 0
|
98
|
+
hash: 1538246288557208580
|
96
99
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
100
|
none: false
|
98
101
|
requirements:
|
99
102
|
- - ! '>='
|
100
103
|
- !ruby/object:Gem::Version
|
101
104
|
version: '0'
|
105
|
+
segments:
|
106
|
+
- 0
|
107
|
+
hash: 1538246288557208580
|
102
108
|
requirements: []
|
103
109
|
rubyforge_project:
|
104
110
|
rubygems_version: 1.8.16
|