PageSourceSearch

https://www.cnv.org/CNV/Scripts/jQuery/Plugins/jquery.mustache.js

js cnv.org collected 2026-10-02 04:54:50 UTC 17,791 bytes, 552 lines download raw bytes

1/*!
2* mustache.js - Logic-less {{mustache}} templates with JavaScript
3* http://github.com/janl/mustache.js
4*/
5var Mustache = (typeof module !== "undefined" && module.exports) || {};
6
7(function (exports) {
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    };
27
28    var _toString = Object.prototype.toString;
29    var _isArray = Array.isArray;
30    var _forEach = Array.prototype.forEach;
31    var _trim = String.prototype.trim;
32
33    var isArray;
34    if (_isArray) {
35        isArray = _isArray;
36    } else {
37        isArray = function (obj) {
38            return _toString.call(obj) === "[object Array]";
39        };
40    }
41
42    var forEach;
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    }
54
55    var spaceRe = /^\s*$/;
56
57    function isWhitespace(string) {
58        return spaceRe.test(string);
59    }
60
61    var trim;
62    if (_trim) {
63        trim = function (string) {
64            return string == null ? "" : _trim.call(string);
65        };
66    } else {
67        var trimLeft, trimRight;
68
69        if (isWhitespace("\xA0")) {
70            trimLeft = /^\s+/;
71            trimRight = /\s+$/;
72        } else {
73            // IE doesn't match non-breaking spaces with \s, thanks jQuery.
74            trimLeft = /^[\s\xA0]+/;
75            trimRight = /[\s\xA0]+$/;
76        }
77
78        trim = function (string) {
79            return string == null ? "" :
80        String(string).replace(trimLeft, "").replace(trimRight, "");
81        };
82    }
83
84    var escapeMap = {
85        "&": "&amp;",
86        "<": "&lt;",
87        ">": "&gt;",
88        '"': '&quot;',
89        "'": '&#39;'
90    };
91
92    function escapeHTML(string) {
93        return String(string).replace(/&(?!\w+;)|[<>"']/g, function (s) {
94            return escapeMap[s] || s;
95        });
96    }
97
98    /**
99    * Adds the `template`, `line`, and `file` properties to the given error
100    * object and alters the message to provide more useful debugging information.
101    */
102    function debug(e, template, line, file) {
103        file = file || "<template>";
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        }
115
116        e.template = template;
117        e.line = line;
118        e.file = file;
119        e.message = [file + ":" + line, context.join("\n"), "", e.message].join("\n");
120
121        return e;
122    }
123
124    /**
125    * Looks up the value of the given `name` in the given context `stack`.
126    */
127    function lookup(name, stack, defaultValue) {
128        if (name === ".") {
129            return stack[stack.length - 1];
130        }
131
132        var names = name.split(".");
133        var lastIndex = names.length - 1;
134        var target = names[lastIndex];
135
136        var value, context, i = stack.length, j, localStack;
137        while (i) {
138            localStack = stack.slice(0);
139            context = stack[--i];
140
141            j = 0;
142            while (j < lastIndex) {
143                context = context[names[j++]];
144
145                if (context == null) {
146                    break;
147                }
148
149                localStack.push(context);
150            }
151
152            if (context && typeof context === "object" && target in context) {
153                value = context[target];
154                break;
155            }
156        }
157
158        // If the value is a function, call it in the current context.
159        if (typeof value === "function") {
160            value = value.call(localStack[localStack.length - 1]);
161        }
162
163        if (value == null) {
164            return defaultValue;
165        }
166
167        return value;
168    }
169
170    function renderSection(name, stack, callback, inverted) {
171        var buffer = "";
172        var value = lookup(name, stack);
173
174        if (inverted) {
175            // From the spec: inverted sections may render text once based on the
176            // inverse value of the key. That is, they will be rendered if the key
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();
199        }
200
201        return buffer;
202    }
203
204    /**
205    * Parses the given `template` and returns the source of a function that,
206    * with the proper arguments, will render the template. Recognized options
207    * include the following:
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    ];
231
232        var spaces = [],      // indices of whitespace in code on the current line
233        hasTag = false,   // is there a {{tag}} on the current line?
234        nonSpace = false; // is there a non-space char on the current line?
235
236        // Strips all space characters from the code array for the current line
237        // if there was a {{tag}} on it and otherwise only spaces.
238        var stripSpace = function () {
239            if (hasTag && !nonSpace && !options.space) {
240                while (spaces.length) {
241                    code.splice(spaces.pop(), 1);
242                }
243            } else {
244                spaces = [];
245            }
246
247            hasTag = false;
248            nonSpace = false;
249        };
250
251        var sectionStack = [], updateLine, nextOpenTag, nextCloseTag;
252
253        var setTags = function (source) {
254            tags = trim(source).split(/\s+/);
255            nextOpenTag = tags[0];
256            nextCloseTag = tags[tags.length - 1];
257        };
258
259        var includePartial = function (source) {
260            code.push(
261        '";',
262        updateLine,
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        };
270
271        var openSection = function (source, inverted) {
272            var name = trim(source);
273
274            if (name === "") {
275                throw debug(new Error("Section name may not be empty"), template, line, options.file);
276            }
277
278            sectionStack.push({ name: name, inverted: inverted });
279
280            code.push(
281        '";',
282        updateLine,
283        '\nvar name = "' + name + '";',
284        '\nvar callback = (function () {',
285        '\n  return function () {',
286        '\n    var buffer = "";',
287        '\nbuffer += "'
288      );
289        };
290
291        var openInvertedSection = function (source) {
292            openSection(source, true);
293        };
294
295        var closeSection = function (source) {
296            var name = trim(source);
297            var openName = sectionStack.length != 0 && sectionStack[sectionStack.length - 1].name;
298
299            if (!openName || name != openName) {
300                throw debug(new Error('Section named "' + name + '" was never opened'), template, line, options.file);
301            }
302
303            var section = sectionStack.pop();
304
305            code.push(
306        '";',
307        '\n    return buffer;',
308        '\n  };',
309        '\n})();'
310      );
311
312            if (section.inverted) {
313                code.push("\nbuffer += renderSection(name,stack,callback,true);");
314            } else {
315                code.push("\nbuffer += render
315Section(name,stack,callback);");
316            }
317
318            code.push('\nbuffer += "');
319        };
320
321        var sendPlain = function (source) {
322            code.push(
323        '";',
324        updateLine,
325        '\nbuffer += lookup("' + trim(source) + '",stack,"");',
326        '\nbuffer += "'
327      );
328        };
329
330        var sendEscaped = function (source) {
331            code.push(
332        '";',
333        updateLine,
334        '\nbuffer += escapeHTML(lookup("' + trim(source) + '",stack,""));',
335        '\nbuffer += "'
336      );
337        };
338
339        var line = 1, c, callback;
340        for (var i = 0, len = template.length; i < len; ++i) {
341            if (template.slice(i, i + openTag.length) === openTag) {
342                i += openTag.length;
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;
358                        break;
359                    case ">": // include partial
360                        i++;
361                        callback = includePartial;
362                        break;
363                    case "#": // start section
364                        i++;
365                        callback = openSection;
366                        break;
367                    case "^": // start inverted section
368                        i++;
369                        callback = openInvertedSection;
370                        break;
371                    case "/": // end section
372                        i++;
373                        callback = closeSection;
374                        break;
375                    case "{": // plain variable
376                        closeTag = "}" + closeTag;
377                        // fall through
378                    case "&": // plain variable
379                        i++;
380                        nonSpace = true;
381                        callback = sendPlain;
382                        break;
383                    default: // escaped variable
384                        nonSpace = true;
385                        callback = sendEscaped;
386                }
387
388                var end = template.indexOf(closeTag, i);
389
390                if (end === -1) {
391                    throw debug(new Error('Tag "' + openTag + '" was not closed properly'), template, line, options.file);
392                }
393
394                var source = template.substring(i, end);
395
396                if (callback) {
397                    callback(source);
398                }
399
400                // Maintain line count for \n in source.
401                var n = 0;
402                while (~(n = source.indexOf("\n", n))) {
403                    line++;
404                    n++;
405                }
406
407                i = end + closeTag.length - 1;
408                openTag = nextOpenTag;
409                closeTag = nextCloseTag;
410            } else {
411                c = template.substr(i, 1);
412
413                switch (c) {
414                    case '"':
415                    case "\\":
416                        nonSpace = true;
417                        code.push("\\" + c);
418                        break;
419                    case "\r":
420                        // Ignore carriage returns.
421                        break;
422                    case "\n":
423                        spaces.push(code.length);
424                        code.push("\\n");
425                        stripSpace(); // Check for whitespace on the current line.
426                        line++;
427                        break;
428                    default:
429                        if (isWhitespace(c)) {
430                            spaces.push(code.length);
431                        } else {
432                            nonSpace = true;
433                        }
434
435                        code.push(c);
436                }
437            }
438        }
439
440        if (sectionStack.length != 0) {
441            throw debug(new Error('Section "' + sectionStack[sectionStack.length - 1].name + '" was not closed properly'), template, line, options.file);
442        }
443
444        // Clean up any whitespace from a closing {{tag}} that was at the end
445        // of the template without a trailing \n.
446        stripSpace();
447
448        code.push(
449      '";',
450      "\nreturn buffer;",
451      "\n} catch (e) { throw {error: e, line: line}; }"
452    );
453
454        // Ignore `buffer += "";` statements.
455        var body = code.join("").replace(/buffer \+= "";\n/g, "");
456
457        if (options.debug) {
458            if (typeof console != "undefined" && console.log) {
459                console.log(body);
460            } else if (typeof print === "function") {
461                print(body);
462            }
463        }
464
465        return body;
466    }
467
468    /**
469    * Used by `compile` to generate a reusable function for the given `template`.
470    */
471    function _compile(template, options) {
472        var args = "view,partials,stack,lookup,escapeHTML,renderSection,render";
473        var body = parse(template, options);
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
483
484            try {
485                return fn(view, partials, stack, lookup, escapeHTML, renderSection, render);
486            } catch (e) {
487                throw debug(e.error, template, e.line, options.file);
488            }
489        };
490    }
491
492    // Cache of pre-compiled templates.
493    var _cache = {};
494
495    /**
496    * Clear the cache of compiled templates.
497    */
498    function clearCache() {
499        _cache = {};
500    }
501
502    /**
503    * Compiles the given `template` into a reusable function using the given
504    * `options`. In addition to the options accepted by Mustache.parse,
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
510    */
511    function compile(template, options) {
512        options = options || {};
513
514        // Use a pre-compiled version from the cache if we have one.
515        if (options.cache !== false) {
516            if (!_cache[template]) {
517                _cache[template] = _compile(template, options);
518            }
519
520            return _cache[template];
521        }
522
523        return _compile(template, options);
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    }
535
536})(Mustache);
537
538
539;(function($) {
540    $.mustache = function (template, view, partials) {
541        return Mustache.render(template, view, partials);
542    };
543
544    $.fn.mustache = function (view, partials) {
545        return $(this).map(function (i, elm) {
546            var template = $(elm).html().trim();
547            var output = $.mustache(template, view, partials);
548            return $(output).get();
549        });
550    };
551
552})(jQuery);

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.