// Browser bundle of nunjucks 1.0.0 (slim, only works with precompiled templates) (function() { var modules = {}; (function() { // A simple class system, more documentation to come function extend(cls, name, props) { // This does that same thing as Object.create, but with support for IE8 var F = function() {}; F.prototype = cls.prototype; var prototype = new F(); var fnTest = /xyz/.test(function(){ xyz; }) ? /\bparent\b/ : /.*/; props = props || {}; for(var k in props) { var src = props[k]; var parent = prototype[k]; if(typeof parent == "function" && typeof src == "function" && fnTest.test(src)) { prototype[k] = (function (src, parent) { return function() { // Save the current parent method var tmp = this.parent; // Set parent to the previous method, call, and restore this.parent = parent; var res = src.apply(this, arguments); this.parent = tmp; return res; }; })(src, parent); } else { prototype[k] = src; } } prototype.typename = name; var new_cls = function() { if(prototype.init) { prototype.init.apply(this, arguments); } }; new_cls.prototype = prototype; new_cls.prototype.constructor = new_cls; new_cls.extend = function(name, props) { if(typeof name == "object") { props = name; name = "anonymous"; } return extend(new_cls, name, props); }; return new_cls; } modules.object = extend(Object, "Object", {}); })(); (function() { var ArrayProto = Array.prototype; var ObjProto = Object.prototype; var escapeMap = { '&': '&', '"': '"', "'": ''', "<": '<', ">": '>' }; var lookupEscape = function(ch) { return escapeMap[ch]; }; var exports = modules.lib = {}; exports.withPrettyErrors = function(path, withInternals, func) { // try { return func(); // } catch (e) { // if (!e.Update) { // // not one of ours, cast it // e = new exports.TemplateError(e); // } // e.Update(path); // // Unless they marked the dev flag, show them a trace from here // if (!withInternals) { // var old = e; // e = new Error(old.message); // e.name = old.name; // } // throw e; // } }; exports.TemplateError = function(message, lineno, colno) { var err = this; if (message instanceof Error) { // for casting regular js errors err = message; message = message.name + ": " + message.message; } else { if(Error.captureStackTrace) { Error.captureStackTrace(err); } } err.name = 'Template render error'; err.message = message; err.lineno = lineno; err.colno = colno; err.firstUpdate = true; err.Update = function(path) { var message = "(" + (path || "unknown path") + ")"; // only show lineno + colno next to path of template // where error occurred if (this.firstUpdate) { if(this.lineno && this.colno) { message += ' [Line ' + this.lineno + ', Column ' + this.colno + ']'; } else if(this.lineno) { message += ' [Line ' + this.lineno + ']'; } } message += '\n '; if (this.firstUpdate) { message += ' '; } this.message = message + (this.message || ''); this.firstUpdate = false; return this; }; return err; }; exports.TemplateError.prototype = Error.prototype; exports.escape = function(val) { return val.replace(/[&"'<>]/g, lookupEscape); }; exports.isFunction = function(obj) { return ObjProto.toString.call(obj) == '[object Function]'; }; exports.isArray = Array.isArray || function(obj) { return ObjProto.toString.call(obj) == '[object Array]'; }; exports.isString = function(obj) { return ObjProto.toString.call(obj) == '[object String]'; }; exports.isObject = function(obj) { return obj === Object(obj); }; exports.groupBy = function(obj, val) { var result = {}; var iterator = exports.isFunction(val) ? val : function(obj) { return obj[val]; }; for(var i=0; i>> 0; if (len === 0) { return -1; } var n = 0; if (arguments.length > 2) { n = Number(arguments[2]); if (n != n) { // shortcut for verifying if it's NaN n = 0; } else if (n !== 0 && n !== Infinity && n !== -Infinity) { n = (n > 0 || -1) * Math.floor(Math.abs(n)); } } if (n >= len) { return -1; } var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); for (; k < len; k++) { if (k in t && t[k] === searchElement) { return k; } } return -1; }; } if(!Array.prototype.map) { Array.prototype.map = function() { throw new Error("map is unimplemented for this js engine"); }; } exports.keys = function(obj) { if(Object.prototype.keys) { return obj.keys(); } else { var keys = []; for(var k in obj) { if(obj.hasOwnProperty(k)) { keys.push(k); } } return keys; } }; })(); (function() { var lib = modules.lib; var Object = modules.object; // Frames keep track of scoping both at compile-time and run-time so // we know how to access variables. Block tags can introduce special // variables, for example. var Frame = Object.extend({ init: function(parent) { this.variables = {}; this.parent = parent; }, set: function(name, val) { // Allow variables with dots by automatically creating the // nested structure var parts = name.split('.'); var obj = this.variables; for(var i=0; i argNames.length) { args = Array.prototype.slice.call(arguments, 0, argNames.length); // Positional arguments that should be passed in as // keyword arguments (essentially default values) var vals = Array.prototype.slice.call(arguments, args.length, argCount); for(i=0; i= width) { return str; } var spaces = width - str.length; var pre = lib.repeat(" ", spaces/2 - spaces % 2); var post = lib.repeat(" ", spaces/2); return r.copySafeness(str, pre + str + post); }, 'default': function(val, def) { return val ? val : def; }, dictsort: function(val, case_sensitive, by) { if (!lib.isObject(val)) { throw new lib.TemplateError("dictsort filter: val must be an object"); } var array = []; for (var k in val) { // deliberately include properties from the object's prototype array.push([k,val[k]]); } var si; if (by === undefined || by === "key") { si = 0; } else if (by === "value") { si = 1; } else { throw new lib.TemplateError( "dictsort filter: You can only sort by either key or value"); } array.sort(function(t1, t2) { var a = t1[si]; var b = t2[si]; if (!case_sensitive) { if (lib.isString(a)) { a = a.toUpperCase(); } if (lib.isString(b)) { b = b.toUpperCase(); } } return a > b ? 1 : (a == b ? 0 : -1); }); return array; }, escape: function(str) { if(typeof str == 'string' || str instanceof r.SafeString) { return lib.escape(str); } return str; }, safe: r.markSafe, first: function(arr) { return arr[0]; }, groupby: function(arr, attr) { return lib.groupBy(arr, attr); }, indent: function(str, width, indentfirst) { width = width || 4; var res = ''; var lines = str.split('\n'); var sp = lib.repeat(' ', width); for(var i=0; i= maxCount) { break; } last = res; res = res.replace(old, new_); count++; } return r.copySafeness(str, res); }, reverse: function(val) { var arr; if(lib.isString(val)) { arr = filters.list(val); } else { // Copy it arr = lib.map(val, function(v) { return v; }); } arr.reverse(); if(lib.isString(val)) { return r.copySafeness(val, arr.join('')); } return arr; }, round: function(val, precision, method) { precision = precision || 0; var factor = Math.pow(10, precision); var rounder; if(method == 'ceil') { rounder = Math.ceil; } else if(method == 'floor') { rounder = Math.floor; } else { rounder = Math.round; } return rounder(val * factor) / factor; }, slice: function(arr, slices, fillWith) { var sliceLength = Math.floor(arr.length / slices); var extra = arr.length % slices; var offset = 0; var res = []; for(var i=0; i= extra) { slice.push(fillWith); } res.push(slice); } return res; }, sort: function(arr, reverse, caseSens, attr) { // Copy it arr = lib.map(arr, function(v) { return v; }); arr.sort(function(a, b) { var x, y; if(attr) { x = a[attr]; y = b[attr]; } else { x = a; y = b; } if(!caseSens && lib.isString(x) && lib.isString(y)) { x = x.toLowerCase(); y = y.toLowerCase(); } if(x < y) { return reverse ? 1 : -1; } else if(x > y) { return reverse ? -1: 1; } else { return 0; } }); return arr; }, string: function(obj) { return r.copySafeness(obj, obj); }, title: function(str) { var words = str.split(' '); for(var i = 0; i < words.length; i++) { words[i] = filters.capitalize(words[i]); } return r.copySafeness(str, words.join(' ')); }, trim: function(str) { return r.copySafeness(str, str.replace(/^\s*|\s*$/g, '')); }, truncate: function(input, length, killwords, end) { var orig = input; length = length || 255; if (input.length <= length) return input; if (killwords) { input = input.substring(0, length); } else { var idx = input.lastIndexOf(' ', length); if(idx === -1) { idx = length; } input = input.substring(0, idx); } input += (end !== undefined && end !== null) ? end : '...'; return r.copySafeness(orig, input); }, upper: function(str) { return str.toUpperCase(); }, urlize: function(str, length, nofollow) { if (isNaN(length)) length = Infinity; var noFollowAttr = (nofollow === true ? ' rel="nofollow"' : ''); // For the jinja regexp, see // https://github.com/mitsuhiko/jinja2/blob/f15b814dcba6aa12bc74d1f7d0c881d55f7126be/jinja2/utils.py#L20-L23 var puncRE = /^(?:\(|<|<)?(.*?)(?:\.|,|\)|\n|>)?$/; // from http://blog.gerv.net/2011/05/html5_email_address_regexp/ var emailRE = /^[\w.!#$%&'*+\-\/=?\^`{|}~]+@[a-z\d\-]+(\.[a-z\d\-]+)+$/i; var httpHttpsRE = /^https?:\/\/.*$/; var wwwRE = /^www\./; var tldRE = /\.(?:org|net|com)(?:\:|\/|$)/; var words = str.split(/\s+/).filter(function(word) { // If the word has no length, bail. This can happen for str with // trailing whitespace. return word && word.length; }).map(function(word) { var matches = word.match(puncRE); var possibleUrl = matches && matches[1] || word; // url that starts with http or https if (httpHttpsRE.test(possibleUrl)) return '' + possibleUrl.substr(0, length) + ''; // url that starts with www. if (wwwRE.test(possibleUrl)) return '' + possibleUrl.substr(0, length) + ''; // an email address of the form username@domain.tld if (emailRE.test(possibleUrl)) return '' + possibleUrl + ''; // url that ends in .com, .org or .net that is not an email address if (tldRE.test(possibleUrl)) return '' + possibleUrl.substr(0, length) + ''; return possibleUrl; }); return words.join(' '); }, wordcount: function(str) { return str.match(/\w+/g).length; }, 'float': function(val, def) { var res = parseFloat(val); return isNaN(res) ? def : res; }, 'int': function(val, def) { var res = parseInt(val, 10); return isNaN(res) ? def : res; } }; // Aliases filters.d = filters['default']; filters.e = filters.escape; modules.filters = filters; })(); (function() { function cycler(items) { var index = -1; var current = null; return { reset: function() { index = -1; current = null; }, next: function() { index++; if(index >= items.length) { index = 0; } current = items[index]; return current; } }; } function joiner(sep) { sep = sep || ','; var first = true; return function() { var val = first ? '' : sep; first = false; return val; }; } var globals = { range: function(start, stop, step) { if(!stop) { stop = start; start = 0; step = 1; } else if(!step) { step = 1; } var arr = []; for(var i=start; i