/src/honeynet_web/honeywall/static/twitter-bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.5/hogan-1.0.5.js
JavaScript | 572 lines | 434 code | 98 blank | 40 comment | 154 complexity | b4308bfebf8e9e58fac4c2605aaf0048 MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.1
1/*
2 * Copyright 2011 Twitter, Inc.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16
17
18var Hogan = {};
19
20(function (Hogan) {
21 Hogan.Template = function constructor(renderFunc, text, compiler) {
22 if (renderFunc) {
23 this.r = renderFunc;
24 }
25 this.c = compiler;
26 this.text = text || '';
27 }
28
29 Hogan.Template.prototype = {
30 // render: replaced by generated code.
31 r: function (context, partials, indent) { return ''; },
32
33 // variable escaping
34 v: hoganEscape,
35
36 render: function render(context, partials, indent) {
37 return this.ri([context], partials || {}, indent);
38 },
39
40 // render internal -- a hook for overrides that catches partials too
41 ri: function (context, partials, indent) {
42 return this.r(context, partials, indent);
43 },
44
45 // tries to find a partial in the curent scope and render it
46 rp: function(name, context, partials, indent) {
47 var partial = partials[name];
48
49 if (!partial) {
50 return '';
51 }
52
53 if (this.c && typeof partial == 'string') {
54 partial = this.c.compile(partial);
55 }
56
57 return partial.ri(context, partials, indent);
58 },
59
60 // render a section
61 rs: function(context, partials, section) {
62 var buf = '',
63 tail = context[context.length - 1];
64
65 if (!isArray(tail)) {
66 return buf = section(context, partials);
67 }
68
69 for (var i = 0; i < tail.length; i++) {
70 context.push(tail[i]);
71 buf += section(context, partials);
72 context.pop();
73 }
74
75 return buf;
76 },
77
78 // maybe start a section
79 s: function(val, ctx, partials, inverted, start, end, tags) {
80 var pass;
81
82 if (isArray(val) && val.length === 0) {
83 return false;
84 }
85
86 if (typeof val == 'function') {
87 val = this.ls(val, ctx, partials, inverted, start, end, tags);
88 }
89
90 pass = (val === '') || !!val;
91
92 if (!inverted && pass && ctx) {
93 ctx.push((typeof val == 'object') ? val : ctx[ctx.length - 1]);
94 }
95
96 return pass;
97 },
98
99 // find values with dotted names
100 d: function(key, ctx, partials, returnFound) {
101 var names = key.split('.'),
102 val = this.f(names[0], ctx, partials, returnFound),
103 cx = null;
104
105 if (key === '.' && isArray(ctx[ctx.length - 2])) {
106 return ctx[ctx.length - 1];
107 }
108
109 for (var i = 1; i < names.length; i++) {
110 if (val && typeof val == 'object' && names[i] in val) {
111 cx = val;
112 val = val[names[i]];
113 } else {
114 val = '';
115 }
116 }
117
118 if (returnFound && !val) {
119 return false;
120 }
121
122 if (!returnFound && typeof val == 'function') {
123 ctx.push(cx);
124 val = this.lv(val, ctx, partials);
125 ctx.pop();
126 }
127
128 return val;
129 },
130
131 // find values with normal names
132 f: function(key, ctx, partials, returnFound) {
133 var val = false,
134 v = null,
135 found = false;
136
137 for (var i = ctx.length - 1; i >= 0; i--) {
138 v = ctx[i];
139 if (v && typeof v == 'object' && key in v) {
140 val = v[key];
141 found = true;
142 break;
143 }
144 }
145
146 if (!found) {
147 return (returnFound) ? false : "";
148 }
149
150 if (!returnFound && typeof val == 'function') {
151 val = this.lv(val, ctx, partials);
152 }
153
154 return val;
155 },
156
157 // higher order templates
158 ho: function(val, cx, partials, text, tags) {
159 var compiler = this.c;
160 var t = val.call(cx, text, function(t) {
161 return compiler.compile(t, {delimiters: tags}).render(cx, partials);
162 });
163 var s = compiler.compile(t.toString(), {delimiters: tags}).render(cx, partials);
164 this.b = s;
165 return false;
166 },
167
168 // higher order template result buffer
169 b: '',
170
171 // lambda replace section
172 ls: function(val, ctx, partials, inverted, start, end, tags) {
173 var cx = ctx[ctx.length - 1],
174 t = null;
175
176 if (!inverted && this.c && val.length > 0) {
177 return this.ho(val, cx, partials, this.text.substring(start, end), tags);
178 }
179
180 t = val.call(cx);
181
182 if (typeof t == 'function') {
183 if (inverted) {
184 return true;
185 } else if (this.c) {
186 return this.ho(t, cx, partials, this.text.substring(start, end), tags);
187 }
188 }
189
190 return t;
191 },
192
193 // lambda replace variable
194 lv: function(val, ctx, partials) {
195 var cx = ctx[ctx.length - 1];
196 var result = val.call(cx);
197 if (typeof result == 'function') {
198 result = result.call(cx);
199 }
200 result = result.toString();
201
202 if (this.c && ~result.indexOf("{{")) {
203 return this.c.compile(result).render(cx, partials);
204 }
205
206 return result;
207 }
208
209 };
210
211 var rAmp = /&/g,
212 rLt = /</g,
213 rGt = />/g,
214 rApos =/\'/g,
215 rQuot = /\"/g,
216 hChars =/[&<>\"\']/;
217
218 function hoganEscape(str) {
219 str = String((str === null || str === undefined) ? '' : str);
220 return hChars.test(str) ?
221 str
222 .replace(rAmp,'&')
223 .replace(rLt,'<')
224 .replace(rGt,'>')
225 .replace(rApos,''')
226 .replace(rQuot, '"') :
227 str;
228 }
229
230 var isArray = Array.isArray || function(a) {
231 return Object.prototype.toString.call(a) === '[object Array]';
232 };
233
234})(typeof exports !== 'undefined' ? exports : Hogan);
235
236
237
238
239(function (Hogan) {
240 // Setup regex assignments
241 // remove whitespace according to Mustache spec
242 var rIsWhitespace = /\S/,
243 rQuot = /\"/g,
244 rNewline = /\n/g,
245 rCr = /\r/g,
246 rSlash = /\\/g,
247 tagTypes = {
248 '#': 1, '^': 2, '/': 3, '!': 4, '>': 5,
249 '<': 6, '=': 7, '_v': 8, '{': 9, '&': 10
250 };
251
252 Hogan.scan = function scan(text, delimiters) {
253 var len = text.length,
254 IN_TEXT = 0,
255 IN_TAG_TYPE = 1,
256 IN_TAG = 2,
257 state = IN_TEXT,
258 tagType = null,
259 tag = null,
260 buf = '',
261 tokens = [],
262 seenTag = false,
263 i = 0,
264 lineStart = 0,
265 otag = '{{',
266 ctag = '}}';
267
268 function addBuf() {
269 if (buf.length > 0) {
270 tokens.push(new String(buf));
271 buf = '';
272 }
273 }
274
275 function lineIsWhitespace() {
276 var isAllWhitespace = true;
277 for (var j = lineStart; j < tokens.length; j++) {
278 isAllWhitespace =
279 (tokens[j].tag && tagTypes[tokens[j].tag] < tagTypes['_v']) ||
280 (!tokens[j].tag && tokens[j].match(rIsWhitespace) === null);
281 if (!isAllWhitespace) {
282 return false;
283 }
284 }
285
286 return isAllWhitespace;
287 }
288
289 function filterLine(haveSeenTag, noNewLine) {
290 addBuf();
291
292 if (haveSeenTag && lineIsWhitespace()) {
293 for (var j = lineStart, next; j < tokens.length; j++) {
294 if (!tokens[j].tag) {
295 if ((next = tokens[j+1]) && next.tag == '>') {
296 // set indent to token value
297 next.indent = tokens[j].toString()
298 }
299 tokens.splice(j, 1);
300 }
301 }
302 } else if (!noNewLine) {
303 tokens.push({tag:'\n'});
304 }
305
306 seenTag = false;
307 lineStart = tokens.length;
308 }
309
310 function changeDelimiters(text, index) {
311 var close = '=' + ctag,
312 closeIndex = text.indexOf(close, index),
313 delimiters = trim(
314 text.substring(text.indexOf('=', index) + 1, closeIndex)
315 ).split(' ');
316
317 otag = delimiters[0];
318 ctag = delimiters[1];
319
320 return closeIndex + close.length - 1;
321 }
322
323 if (delimiters) {
324 delimiters = delimiters.split(' ');
325 otag = delimiters[0];
326 ctag = delimiters[1];
327 }
328
329 for (i = 0; i < len; i++) {
330 if (state == IN_TEXT) {
331 if (tagChange(otag, text, i)) {
332 --i;
333 addBuf();
334 state = IN_TAG_TYPE;
335 } else {
336 if (text.charAt(i) == '\n') {
337 filterLine(seenTag);
338 } else {
339 buf += text.charAt(i);
340 }
341 }
342 } else if (state == IN_TAG_TYPE) {
343 i += otag.length - 1;
344 tag = tagTypes[text.charAt(i + 1)];
345 tagType = tag ? text.charAt(i + 1) : '_v';
346 if (tagType == '=') {
347 i = changeDelimiters(text, i);
348 state = IN_TEXT;
349 } else {
350 if (tag) {
351 i++;
352 }
353 state = IN_TAG;
354 }
355 seenTag = i;
356 } else {
357 if (tagChange(ctag, text, i)) {
358 tokens.push({tag: tagType, n: trim(buf), otag: otag, ctag: ctag,
359 i: (tagType == '/') ? seenTag - ctag.length : i + otag.length});
360 buf = '';
361 i += ctag.length - 1;
362 state = IN_TEXT;
363 if (tagType == '{') {
364 if (ctag == '}}') {
365 i++;
366 } else {
367 cleanTripleStache(tokens[tokens.length - 1]);
368 }
369 }
370 } else {
371 buf += text.charAt(i);
372 }
373 }
374 }
375
376 filterLine(seenTag, true);
377
378 return tokens;
379 }
380
381 function cleanTripleStache(token) {
382 if (token.n.substr(token.n.length - 1) === '}') {
383 token.n = token.n.substring(0, token.n.length - 1);
384 }
385 }
386
387 function trim(s) {
388 if (s.trim) {
389 return s.trim();
390 }
391
392 return s.replace(/^\s*|\s*$/g, '');
393 }
394
395 function tagChange(tag, text, index) {
396 if (text.charAt(index) != tag.charAt(0)) {
397 return false;
398 }
399
400 for (var i = 1, l = tag.length; i < l; i++) {
401 if (text.charAt(index + i) != tag.charAt(i)) {
402 return false;
403 }
404 }
405
406 return true;
407 }
408
409 function buildTree(tokens, kind, stack, customTags) {
410 var instructions = [],
411 opener = null,
412 token = null;
413
414 while (tokens.length > 0) {
415 token = tokens.shift();
416 if (token.tag == '#' || token.tag == '^' || isOpener(token, customTags)) {
417 stack.push(token);
418 token.nodes = buildTree(tokens, token.tag, stack, customTags);
419 instructions.push(token);
420 } else if (token.tag == '/') {
421 if (stack.length === 0) {
422 throw new Error('Closing tag without opener: /' + token.n);
423 }
424 opener = stack.pop();
425 if (token.n != opener.n && !isCloser(token.n, opener.n, customTags)) {
426 throw new Error('Nesting error: ' + opener.n + ' vs. ' + token.n);
427 }
428 opener.end = token.i;
429 return instructions;
430 } else {
431 instructions.push(token);
432 }
433 }
434
435 if (stack.length > 0) {
436 throw new Error('missing closing tag: ' + stack.pop().n);
437 }
438
439 return instructions;
440 }
441
442 function isOpener(token, tags) {
443 for (var i = 0, l = tags.length; i < l; i++) {
444 if (tags[i].o == token.n) {
445 token.tag = '#';
446 return true;
447 }
448 }
449 }
450
451 function isCloser(close, open, tags) {
452 for (var i = 0, l = tags.length; i < l; i++) {
453 if (tags[i].c == close && tags[i].o == open) {
454 return true;
455 }
456 }
457 }
458
459 function writeCode(tree) {
460 return 'i = i || "";var b = i + "";var _ = this;' + walk(tree) + 'return b;';
461 }
462
463 Hogan.generate = function (code, text, options) {
464 if (options.asString) {
465 return 'function(c,p,i){' + code + ';}';
466 }
467
468 return new Hogan.Template(new Function('c', 'p', 'i', code), text, Hogan);
469 }
470
471 function esc(s) {
472 return s.replace(rSlash, '\\\\')
473 .replace(rQuot, '\\\"')
474 .replace(rNewline, '\\n')
475 .replace(rCr, '\\r');
476 }
477
478 function chooseMethod(s) {
479 return (~s.indexOf('.')) ? 'd' : 'f';
480 }
481
482 function walk(tree) {
483 var code = '';
484 for (var i = 0, l = tree.length; i < l; i++) {
485 var tag = tree[i].tag;
486 if (tag == '#') {
487 code += section(tree[i].nodes, tree[i].n, chooseMethod(tree[i].n),
488 tree[i].i, tree[i].end, tree[i].otag + " " + tree[i].ctag);
489 } else if (tag == '^') {
490 code += invertedSection(tree[i].nodes, tree[i].n,
491 chooseMethod(tree[i].n));
492 } else if (tag == '<' || tag == '>') {
493 code += partial(tree[i]);
494 } else if (tag == '{' || tag == '&') {
495 code += tripleStache(tree[i].n, chooseMethod(tree[i].n));
496 } else if (tag == '\n') {
497 code += text('"\\n"' + (tree.length-1 == i ? '' : ' + i'));
498 } else if (tag == '_v') {
499 code += variable(tree[i].n, chooseMethod(tree[i].n));
500 } else if (tag === undefined) {
501 code += text('"' + esc(tree[i]) + '"');
502 }
503 }
504 return code;
505 }
506
507 function section(nodes, id, method, start, end, tags) {
508 return 'if(_.s(_.' + method + '("' + esc(id) + '",c,p,1),' +
509 'c,p,0,' + start + ',' + end + ', "' + tags + '")){' +
510 'b += _.rs(c,p,' +
511 'function(c,p){ var b = "";' +
512 walk(nodes) +
513 'return b;});c.pop();}' +
514 'else{b += _.b; _.b = ""};';
515 }
516
517 function invertedSection(nodes, id, method) {
518 return 'if (!_.s(_.' + method + '("' + esc(id) + '",c,p,1),c,p,1,0,0,"")){' +
519 walk(nodes) +
520 '};';
521 }
522
523 function partial(tok) {
524 return 'b += _.rp("' + esc(tok.n) + '",c,p,"' + (tok.indent || '') + '");';
525 }
526
527 function tripleStache(id, method) {
528 return 'b += (_.' + method + '("' + esc(id) + '",c,p,0));';
529 }
530
531 function variable(id, method) {
532 return 'b += (_.v(_.' + method + '("' + esc(id) + '",c,p,0)));';
533 }
534
535 function text(id) {
536 return 'b += ' + id + ';';
537 }
538
539 Hogan.parse = function(tokens, options) {
540 options = options || {};
541 return buildTree(tokens, '', [], options.sectionTags || []);
542 },
543
544 Hogan.cache = {};
545
546 Hogan.compile = function(text, options) {
547 // options
548 //
549 // asString: false (default)
550 //
551 // sectionTags: [{o: '_foo', c: 'foo'}]
552 // An array of object with o and c fields that indicate names for custom
553 // section tags. The example above allows parsing of {{_foo}}{{/foo}}.
554 //
555 // delimiters: A string that overrides the default delimiters.
556 // Example: "<% %>"
557 //
558 options = options || {};
559
560 var key = text + '||' + !!options.asString;
561
562 var t = this.cache[key];
563
564 if (t) {
565 return t;
566 }
567
568 t = this.generate(writeCode(this.parse(this.scan(text, options.delimiters), options)), text, options);
569 return this.cache[key] = t;
570 };
571})(typeof exports !== 'undefined' ? exports : Hogan);
572