PageSourceSearch

https://letu.edu/_files/js/hogan-3.0.1.js

js letu.edu collected 2026-09-24 09:06:57 UTC 21,320 bytes, 750 lines download raw bytes

vendor: 21,320 bytes, lines 1-750
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 (codeObj, text, compiler, options) {
22    codeObj = codeObj || {};
23    this.r = codeObj.code || this.r;
24    this.c = compiler;
25    this.options = options || {};
26    this.text = text || '';
27    this.partials = codeObj.partials || {};
28    this.subs = codeObj.subs || {};
29    this.buf = '';
30  }
31
32  Hogan.Template.prototype = {
33    // render: replaced by generated code.
34    r: function (context, partials, indent) { return ''; },
35
36    // variable escaping
37    v: hoganEscape,
38
39    // triple stache
40    t: coerceToString,
41
42    render: function render(context, partials, indent) {
43      return this.ri([context], partials || {}, indent);
44    },
45
46    // render internal -- a hook for overrides that catches partials too
47    ri: function (context, partials, indent) {
48      return this.r(context, partials, indent);
49    },
50
51    // ensurePartial
52    ep: function(symbol, partials) {
53      var partial = this.partials[symbol];
54
55      // check to see that if we've instantiated this partial before
56      var template = partials[partial.name];
57      if (partial.instance && partial.base == template) {
58        return partial.instance;
59      }
60
61      if (typeof template == 'string') {
62        if (!this.c) {
63          throw new Error("No compiler available.");
64        }
65        template = this.c.compile(template, this.options);
66      }
67
68      if (!template) {
69        return null;
70      }
71
72      // We use this to check whether the partials dictionary has changed
73      this.partials[symbol].base = template;
74
75      if (partial.subs) {
76        // Make sure we consider parent template now
77        if (!partials.stackText) partials.stackText = {};
78        for (key in partial.subs) {
79          if (!partials.stackText[key]) {
80            partials.stackText[key] = (this.activeSub !== undefined && partials.stackText[this.activeSub]) ? partials.stackText[this.activeSub] : this.text;
81          }
82        }
83        template = createSpecializedPartial(template, partial.subs, partial.partials,
84          this.stackSubs, this.stackPartials, partials.stackText);
85      }
86      this.partials[symbol].instance = template;
87
88      return template;
89    },
90
91    // tries to find a partial in the current scope and render it
92    rp: function(symbol, context, partials, indent) {
93      var partial = this.ep(symbol, partials);
94      if (!partial) {
95        return '';
96      }
97
98      return partial.ri(context, partials, indent);
99    },
100
101    // render a section
102    rs: function(context, partials, section) {
103      var tail = context[context.length - 1];
104
105      if (!isArray(tail)) {
106        section(context, partials, this);
107        return;
108      }
109
110      for (var i = 0; i < tail.length; i++) {
111        context.push(tail[i]);
112        section(context, partials, this);
113        context.pop();
114      }
115    },
116
117    // maybe start a section
118    s: function(val, ctx, partials, inverted, start, end, tags) {
119      var pass;
120
121      if (isArray(val) && val.length === 0) {
122        return false;
123      }
124
125      if (typeof val == 'function') {
126        val = this.ms(val, ctx, partials, inverted, start, end, tags);
127      }
128
129      pass = !!val;
130
131      if (!inverted && pass && ctx) {
132        ctx.push((typeof val == 'object') ? val : ctx[ctx.length - 1]);
133      }
134
135      return pass;
136    },
137
138    // find values with dotted names
139    d: function(key, ctx, partials, returnFound) {
140      var found,
141          names = key.split('.'),
142          val = this.f(names[0], ctx, partials, returnFound),
143          doModelGet = this.options.modelGet,
144          cx = null;
145
146      if (key === '.' && isArray(ctx[ctx.length - 2])) {
147        val = ctx[ctx.length - 1];
148      } else {
149        for (var i = 1; i < names.length; i++) {
150          found = findInScope(names[i], val, doModelGet);
151          if (found != null) {
152            cx = val;
153            val = found;
154          } else {
155            val = '';
156          }
157        }
158      }
159
160      if (returnFound && !val) {
161        return false;
162      }
163
164      if (!returnFound && typeof val == 'function') {
165        ctx.push(cx);
166        val = this.mv(val, ctx, partials);
167        ctx.pop();
168      }
169
170      return val;
171    },
172
173    // find values with normal names
174    f: function(key, ctx, partials, returnFound) {
175      var val = false,
176          v = null,
177          found = false,
178          doModelGet = this.options.modelGet;
179
180      for (var i = ctx.length - 1; i >= 0; i--) {
181        v = ctx[i];
182        val = findInScope(key, v, doModelGet);
183        if (val != null) {
184          found = true;
185          break;
186        }
187      }
188
189      if (!found) {
190        return (returnFound) ? false : "";
191      }
192
193      if (!returnFound && typeof val == 'function') {
194        val = this.mv(val, ctx, partials);
195      }
196
197      return val;
198    },
199
200    // higher order templates
201    ls: function(func, cx, partials, text, tags) {
202      var oldTags = this.options.delimiters;
203
204      this.options.delimiters = tags;
205      this.b(this.ct(coerceToString(func.call(cx, text)), cx, partials));
206      this.options.delimiters = oldTags;
207
208      return false;
209    },
210
211    // compile text
212    ct: function(text, cx, partials) {
213      if (this.options.disableLambda) {
214        throw new Error('Lambda features disabled.');
215      }
216      return this.c.compile(text, this.options).render(cx, partials);
217    },
218
219    // template result buffering
220    b: function(s) { this.buf += s; },
221
222    fl: function() { var r = this.buf; this.buf = ''; return r; },
223
224    // method replace section
225    ms: function(func, ctx, partials, inverted, start, end, tags) {
226      var textSource,
227          cx = ctx[ctx.length - 1],
228          result = func.call(cx);
229
230      if (typeof result == 'function') {
231        if (inverted) {
232          return true;
233        } else {
234          textSource = (this.activeSub && this.subsText && this.subsText[this.activeSub]) ? this.subsText[this.activeSub] : this.text;
235          return this.ls(result, cx, partials, textSource.substring(start, end), tags);
236        }
237      }
238
239      return result;
240    },
241
242    // method replace variable
243    mv: function(func, ctx, partials) {
244      var cx = ctx[ctx.length - 1];
245      var result = func.call(cx);
246
247      if (typeof result == 'function') {
248        return this.ct(coerceToString(result.call(cx)), cx, partials);
249      }
250
251      return result;
252    },
253
254    sub: function(name, context, partials, indent) {
255      var f = this.subs[name];
256      if (f) {
257        this.activeSub = name;
258        f(context, partials, this, indent);
259        this.activeSub = false;
260      }
261    }
262
263  };
264
265  //Find a key in an object
266  function findInScope(key, scope, doModelGet) {
267    var val, checkVal;
268
269    if (scope && typeof scope == 'object') {
270
271      if (scope[key] != null) {
272        val = scope[key];
273
274      // try lookup with get for backbone or similar model data
275      } else if (doModelGet && scope.get && typeof scope.get == 'function') {
276        val = scope.get(key);
277      }
278    }
279
280    return val;
281  }
282
283  function createSpecializedPartial(instance, subs, partials, stackSubs, stackPartials, stackText) {
284    function PartialTemplate() {};
285    PartialTemplate.prototype = instance;
286    function Substitutions() {};
287    Substitutions.prototype = instance.subs;
288    var key;
289    var partial = new PartialTemplate();
290    partial.subs = new Substitutions();
291    partial.subsText = {};  //hehe. substext.
292    partial.buf = '';
293
294    stackSubs = stackSubs || {};
295    partial.stackSubs = stackSubs;
296    partial.subsText = stackText;
297    for (key in subs) {
298      if (!stackSubs[key]) stackSubs[key] = subs[key];
299    }
300    for (key in stackSubs) {
301      partial.subs[key] = stackSubs[key];
302    }
303
304    stackPartials = stackPartials || {};
305    partial.stackPartials = stackPartials;
306    for (key in partials) {
307      if (!stackPartials[key]) stackPartials[key] = partials[key];
308    }
309    for (key in stackPartials) {
310      partial.partials[key] = stackPartials[key];
311    }
312
313    return partial;
314  }
315
316  var rAmp = /&/g,
317      rLt = /</g,
318      rGt = />/g,
319      rApos = /\'/g,
320      rQuot = /\"/g,
321      hChars = /[&<>\"\']/;
322
323  function coerceToString(val) {
324    return String((val === null || val === undefined) ? '' : val);
325  }
326
327  function hoganEscape(str) {
328    str = coerceToString(str);
329    return hChars.test(str) ?
330      str
331        .replace(rAmp, '&amp;')
332        .replace(rLt, '&lt;')
333        .replace(rGt, '&gt;')
334        .replace(rApos, '&#39;')
335        .replace(rQuot, '&quot;') :
336      str;
337  }
338
339  var isArray = Array.isArray || function(a) {
340    return Object.prototype.toString.call(a) === '[object Array]';
341  };
342
343})(typeof exports !== 'undefined' ? exports : Hogan);
344
345
346
347(function (Hogan) {
348  // Setup regex  assignments
349  // remove whitespace according to Mustache spec
350  var rIsWhitespace = /\S/,
351      rQuot = /\"/g,
352      rNewline =  /\n/g,
353      rCr = /\r/g,
354      rSlash = /\\/g;
355
356  Hogan.tags = {
357    '#': 1, '^': 2, '<': 3, '$': 4,
358    '/': 5, '!': 6, '>': 7, '=': 8, '_v': 9,
359    '{': 10, '&': 11, '_t': 12
360  };
361
362  Hogan.scan = function scan(text, delimiters) {
363    var len = text.length,
364        IN_TEXT = 0,
365        IN_TAG_TYPE = 1,
366        IN_TAG = 2,
367        state = IN_TEXT,
368        tagType = null,
369        tag = null,
370        buf = '',
371        tokens = [],
372        seenTag = false,
373        i = 0,
374        lineStart = 0,
375        otag = '{{',
376        ctag = '}}';
377
378    function addBuf() {
379      if (buf.length > 0) {
380        tokens.push({tag: '_t', text: new String(buf)});
381        buf = '';
382      }
383    }
384
385    function lineIsWhitespace() {
386      var isAllWhitespace = true;
387      for (var j = lineStart; j < tokens.length; j++) {
388        isAllWhitespace =
389          (Hogan.tags[tokens[j].tag] < Hogan.tags['_v']) ||
390          (tokens[j].tag == '_t' && tokens[j].text.match(rIsWhitespace) === null);
391        if (!isAllWhitespace) {
392          return false;
393        }
394      }
395
396      return isAllWhitespace;
397    }
398
399    function filterLine(haveSeenTag, noNewLine) {
400      addBuf();
401
402      if (haveSeenTag && lineIsWhitespace()) {
403        for (var j = lineStart, next; j < tokens.length; j++) {
404          if (tokens[j].text) {
405            if ((next = tokens[j+1]) && next.tag == '>') {
406              // set indent to token value
407              next.indent = tokens[j].text.toString()
408            }
409            tokens.splice(j, 1);
410          }
411        }
412      } else if (!noNewLine) {
413        tokens.push({tag:'\n'});
414      }
415
416      seenTag = false;
417      lineStart = tokens.length;
418    }
419
420    function changeDelimiters(text, index) {
421      var close = '=' + ctag,
422          closeIndex = text.indexOf(close, index),
423          delimiters = trim(
424            text.substring(text.indexOf('=', index) + 1, closeIndex)
425          ).split(' ');
426
427      otag = delimiters[0];
428      ctag = delimiters[delimiters.length - 1];
429
430      return closeIndex + close.length - 1;
431    }
432
433    if (delimiters) {
434      delimiters = delimiters.split(' ');
435      otag = delimiters[0];
436      ctag = delimiters[1];
437    }
438
439    for (i = 0; i < len; i++) {
440      if (state == IN_TEXT) {
441        if (tagChange(otag, text, i)) {
442          --i;
443          addBuf();
444          state = IN_TAG_TYPE;
445        } else {
446          if (text.charAt(i) == '\n') {
447            filterLine(seenTag);
448          } else {
449            buf += text.charAt(i);
450          }
451        }
452      } else if (state == IN_TAG_TYPE) {
453        i += otag.length - 1;
454        tag = Hogan.tags[text.charAt(i + 1)];
455        tagType = tag ? text.charAt(i + 1) : '_v';
456        if (tagType == '=') {
457          i = changeDelimiters(text, i);
458          state = IN_TEXT;
459        } else {
460          if (tag) {
461            i++;
462          }
463          state = IN_TAG;
464        }
465        seenTag = i;
466      } else {
467        if (tagChange(ctag, text, i)) {
468          tokens.push({tag: tagType, n: trim(buf), otag: otag, ctag: ctag,
469                       i: (tagType == '/') ? seenTag - otag.length : i + ctag.length});
470          buf = '';
471          i += ctag.length - 1;
472          state = IN_TEXT;
473          if (tagType == '{') {
474            if (ctag == '}}') {
475              i++;
476            } else {
477              cleanTripleStache(tokens[tokens.length - 1]);
478            }
479          }
480        } else {
481          buf += text.charAt(i);
482        }
483      }
484    }
485
486    filterLine(seenTag, true);
487
488    return tokens;
489  }
490
491  function cleanTripleStache(token) {
492    if (token.n.substr(token.n.length - 1) === '}') {
493      token.n = token.n.substring(0, token.n.length - 1);
494    }
495  }
496
497  function trim(s) {
498    if (s.trim) {
499      return s.trim();
500    }
501
502    return s.replace(/^\s*|\s*$/g, '');
503  }
504
505  function tagChange(tag, text, index) {
506    if (text.charAt(index) != tag.charAt(0)) {
507      return false;
508    }
509
510    for (var i = 1, l = tag.length; i < l; i++) {
511      if (text.charAt(index + i) != tag.charAt(i)) {
512        return false;
513      }
514    }
515
516    return true;
517  }
518
519  // the tags allowed inside super templates
520  var allowedInSuper = {'_t': true, '\n': true, '$': true, '/': true};
521
522  function buildTree(tokens, kind, stack, customTags) {
523    var instructions = [],
524        opener = null,
525        tail = null,
526        token = null;
527
528    tail = stack[stack.length - 1];
529
530    while (tokens.length > 0) {
531      token = tokens.shift();
532
533      if (tail && tail.tag == '<' && !(token.tag in allowedInSuper)) {
534        throw new Error('Illegal content in < super tag.');
535      }
536
537      if (Hogan.tags[token.tag] <= Hogan.tags['$'] || isOpener(token, customTags)) {
538        stack.push(token);
539        token.nodes = buildTree(tokens, token.tag, stack, customTags);
540      } else if (token.tag == '/') {
541        if (stack.length === 0) {
542          throw new Error('Closing tag without opener: /' + token.n);
543        }
544        opener = stack.pop();
545        if (token.n != opener.n && !isCloser(token.n, opener.n, customTags)) {
546          throw new Error('Nesting error: ' + opener.n + ' vs. ' + token.n);
547        }
548        opener.end = token.i;
549        return instructions;
550      } else if (token.tag == '\n') {
551        token.last = (tokens.length == 0) || (tokens[0].tag == '\n');
552      }
553
554      instructions.push(token);
555    }
556
557    if (stack.length > 0) {
558      throw new Error('missing closing tag: ' + stack.pop().n);
559    }
560
561    return instructions;
562  }
563
564  function isOpener(token, tags) {
565    for (var i = 0, l = tags.length; i < l; i++) {
566      if (tags[i].o == token.n) {
567        token.tag = '#';
568        return true;
569      }
570    }
571  }
572
573  function isCloser(close, open, tags) {
574    for (var i = 0, l = tags.length; i < l; i++) {
575      if (tags[i].c == close && tags[i].o == open) {
576        return true;
577      }
578    }
579  }
580
581  function stringifySubstitutions(obj) {
582    var items = [];
583    for (var key in obj) {
584      items.push('"' + esc(key) + '": function(c,p,t,i) {' + obj[key] + '}');
585    }
586    return "{ " + items.join(",") + " }";
587  }
588
589  function stringifyPartials(codeObj) {
590    var partials = [];
591    for (var key in codeObj.partials) {
592      partials.push('"' + esc(key) + '":{name:"' + esc(codeObj.partials[key].name) + '", ' + stringifyPartials(codeObj.partials[key]) + "}");
593    }
594    return "partials: {" + partials.join(",") + "}, subs: " + stringifySubstitutions(codeObj.subs);
595  }
596
597  Hogan.stringify = function(codeObj, text, options) {
598    return "{code: function (c,p,i) { " + Hogan.wrapMain(codeObj.code) + " }," + stringifyPartials(codeObj) +  "}";
599  }
600
601  var serialNo = 0;
602  Hogan.generate = function(tree, text, options) {
603    serialNo = 0;
604    var context = { code: '', subs: {}, partials: {} };
605    Hogan.walk(tree, context);
606
607    if (options.asString) {
608      return this.stringify(context, text, options);
609    }
610
611    return this.makeTemplate(context, text, options);
612  }
613
614  Hogan.wrapMain = function(code) {
615    return 'var t=this;t.b(i=i||"");' + code + 'return t.fl();';
616  }
617
618  Hogan.template = Hogan.Template;
619
620  Hogan.makeTemplate = function(codeObj, text, options) {
621    var template = this.makePartials(codeObj);
622    template.code = new Function('c', 'p', 'i', this.wrapMain(codeObj.code));
623    return new this.template(template, text, this, options);
624  }
625
626  Hogan.makePartials = function(codeObj) {
627    var key, template = {subs: {}, partials: codeObj.partials, name: codeObj.name};
628    for (key in template.partials) {
629      template.partials[key] = this.makePartials(template.partials[key]);
630    }
631    for (key in codeObj.subs) {
632      template.subs[key] = new Function('c', 'p', 't', 'i', codeObj.subs[key]);
633    }
634    return template;
635  }
636
637  function esc(s) {
638    return s.replace(rSlash, '\\\\')
639            .replace(rQuot, '\\\"')
640            .replace(rNewline, '\\n')
641            .replace(rCr, '\\r');
642  }
643
644  function chooseMethod(s) {
645    return (~s.indexOf('.')) ? 'd' : 'f';
646  }
647
648  function createPartial(node, context) {
649    var prefix = "<" + (context.prefix || "");
650    var sym = prefix + node.n + serialNo++;
651    context.partials[sym] = {name: node.n, partials: {}};
652    context.code += 't.b(t.rp("' +  esc(sym) + '",c,p,"' + (node.indent || '') + '"));';
653    return sym;
654  }
655
656  Hogan.codegen = {
657    '#': function(node, context) {
658      context.code += 'if(t.s(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,1),' +
659                      'c,p,0,' + node.i + ',' + node.end + ',"' + node.otag + " " + node.ctag + '")){' +
660                      't.rs(c,p,' + 'function(c,p,t){';
661      Hogan.walk(node.nodes, context);
662      context.code += '});c.pop();}';
663    },
664
665    '^': function(node, context) {
666      context.code += 'if(!t.s(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,1),c,p,1,0,0,"")){';
667      Hogan.walk(node.nodes, context);
668      context.code += '};';
669    },
670
671    '>': createPartial,
672    '<': function(node, context) {
673      var ctx = {partials: {}, code: '', subs: {}, inPartial: true};
674      Hogan.walk(node.nodes, ctx);
675      var template = context.partials[createPartial(node, context)];
676      template.subs = ctx.subs;
677      template.partials = ctx.partials;
678    },
679
680    '$': function(node, context) {
681      var ctx = {subs: {}, code: '', partials: context.partials, prefix: node.n};
682      Hogan.walk(node.nodes, ctx);
683      context.subs[node.n] = ctx.code;
684      if (!context.inPartial) {
685        context.code += 't.sub("' + esc(node.n) + '",c,p,i);';
686      }
687    },
688
689    '\n': function(node, context) {
690      context.code += write('"\\n"' + (node.last ? '' : ' + i'));
691    },
692
693    '_v': function(node, context) {
694      context.code += 't.b(t.v(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,0)));';
695    },
696
697    '_t': function(node, context) {
698      context.code += write('"' + esc(node.text) + '"');
699    },
700
701    '{': tripleStache,
702
703    '&': tripleStache
704  }
705
706  function tripleStache(node, context) {
707    context.code += 't.b(t.t(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,0)));';
708  }
709
710  function write(s) {
711    return 't.b(' + s + ');';
712  }
713
714  Hogan.walk = function(nodelist, context) {
715    var func;
716    for (var i = 0, l = nodelist.length; i < l; i++) {
717      func = Hogan.codegen[nodelist[i].tag];
718      func && func(nodelist[i], context);
719    }
720    return context;
721  }
722
723  Hogan.parse = function(tokens, text, options) {
724    options = options || {};
725    return buildTree(tokens, '', [], options.sectionTags || []);
726  }
727
728  Hogan.cache = {};
729
730  Hogan.cacheKey = function(text, options) {
731    return [text, !!options.asString, !!options.disableLambda, options.delimiters, !!options.modelGet].join('||');
732  }
733
734  Hogan.compile = function(text, options) {
735    options = options || {};
736    var key = Hogan.cacheKey(text, options);
737    var template = this.cache[key];
738
739    if (template) {
740      var partials = template.partials;
741      for (var name in partials) {
742        delete partials[name].instance;
743      }
744      return template;
745    }
746
747    template = this.generate(this.parse(this.scan(text, options.delimiters), text, options), text, options);
748    return this.cache[key] = template;
749  }
750})(typeof exports !== 'undefined' ? exports : Hogan);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.