/*! Browser bundle of nunjucks 3.0.0 */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["nunjucks"] = factory(); else root["nunjucks"] = factory(); })(this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ exports: {}, /******/ id: moduleId, /******/ loaded: false /******/ }; /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ // Flag the module as loaded /******/ module.loaded = true; /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ // Load entry module and return exports /******/ return __webpack_require__(0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var lib = __webpack_require__(1); var env = __webpack_require__(2); var Loader = __webpack_require__(15); var loaders = __webpack_require__(14); var precompile = __webpack_require__(3); module.exports = {}; module.exports.Environment = env.Environment; module.exports.Template = env.Template; module.exports.Loader = Loader; module.exports.FileSystemLoader = loaders.FileSystemLoader; module.exports.PrecompiledLoader = loaders.PrecompiledLoader; module.exports.WebLoader = loaders.WebLoader; module.exports.compiler = __webpack_require__(7); module.exports.parser = __webpack_require__(8); module.exports.lexer = __webpack_require__(9); module.exports.runtime = __webpack_require__(12); module.exports.lib = lib; module.exports.nodes = __webpack_require__(10); module.exports.installJinjaCompat = __webpack_require__(21); // A single instance of an environment, since this is so commonly used var e; module.exports.configure = function(templatesPath, opts) { opts = opts || {}; if(lib.isObject(templatesPath)) { opts = templatesPath; templatesPath = null; } var TemplateLoader; if(loaders.FileSystemLoader) { TemplateLoader = new loaders.FileSystemLoader(templatesPath, { watch: opts.watch, noCache: opts.noCache }); } else if(loaders.WebLoader) { TemplateLoader = new loaders.WebLoader(templatesPath, { useCache: opts.web && opts.web.useCache, async: opts.web && opts.web.async }); } e = new env.Environment(TemplateLoader, opts); if(opts && opts.express) { e.express(opts.express); } return e; }; module.exports.compile = function(src, env, path, eagerCompile) { if(!e) { module.exports.configure(); } return new module.exports.Template(src, env, path, eagerCompile); }; module.exports.render = function(name, ctx, cb) { if(!e) { module.exports.configure(); } return e.render(name, ctx, cb); }; module.exports.renderString = function(src, ctx, cb) { if(!e) { module.exports.configure(); } return e.renderString(src, ctx, cb); }; if(precompile) { module.exports.precompile = precompile.precompile; module.exports.precompileString = precompile.precompileString; } /***/ }, /* 1 */ /***/ function(module, exports) { 'use strict'; var ArrayProto = Array.prototype; var ObjProto = Object.prototype; var escapeMap = { '&': '&', '"': '"', '\'': ''', '<': '<', '>': '>' }; var escapeRegex = /[&"'<>]/g; var lookupEscape = function(ch) { return escapeMap[ch]; }; var exports = module.exports = {}; exports.prettifyError = function(path, withInternals, err) { // jshint -W022 // http://jslinterrors.com/do-not-assign-to-the-exception-parameter if (!err.Update) { // not one of ours, cast it err = new exports.TemplateError(err); } err.Update(path); // Unless they marked the dev flag, show them a trace from here if (!withInternals) { var old = err; err = new Error(old.message); err.name = old.name; } return err; }; 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; try { if(err.name = '') {} } catch(e) { // If we can't set the name of the error object in this // environment, don't use it err = this; } } 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(escapeRegex, 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 ObjProto.toString.call(obj) === '[object Object]'; }; exports.groupBy = function(obj, val) { var result = {}; var iterator = exports.isFunction(val) ? val : function(obj) { return obj[val]; }; for(var i=0; i>> 0; // Hack to convert object.length to a UInt32 fromIndex = +fromIndex || 0; if(Math.abs(fromIndex) === Infinity) { fromIndex = 0; } if(fromIndex < 0) { fromIndex += length; if (fromIndex < 0) { fromIndex = 0; } } for(;fromIndex < length; fromIndex++) { if (arr[fromIndex] === searchElement) { return fromIndex; } } 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; } }; exports.inOperator = function (key, val) { if (exports.isArray(val)) { return exports.indexOf(val, key) !== -1; } else if (exports.isObject(val)) { return key in val; } else if (exports.isString(val)) { return val.indexOf(key) !== -1; } else { throw new Error('Cannot use "in" operator to search for "' + key + '" in unexpected types.'); } }; /***/ }, /* 2 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var path = __webpack_require__(3); var asap = __webpack_require__(4); var lib = __webpack_require__(1); var Obj = __webpack_require__(6); var compiler = __webpack_require__(7); var builtin_filters = __webpack_require__(13); var builtin_loaders = __webpack_require__(14); var runtime = __webpack_require__(12); var globals = __webpack_require__(17); var waterfall = __webpack_require__(18); var Frame = runtime.Frame; var Template; // Unconditionally load in this loader, even if no other ones are // included (possible in the slim browser build) builtin_loaders.PrecompiledLoader = __webpack_require__(16); // If the user is using the async API, *always* call it // asynchronously even if the template was synchronous. function callbackAsap(cb, err, res) { asap(function() { cb(err, res); }); } var Environment = Obj.extend({ init: function(loaders, opts) { // The dev flag determines the trace that'll be shown on errors. // If set to true, returns the full trace from the error point, // otherwise will return trace starting from Template.render // (the full trace from within nunjucks may confuse developers using // the library) // defaults to false opts = this.opts = opts || {}; this.opts.dev = !!opts.dev; // The autoescape flag sets global autoescaping. If true, // every string variable will be escaped by default. // If false, strings can be manually escaped using the `escape` filter. // defaults to true this.opts.autoescape = opts.autoescape != null ? opts.autoescape : true; // If true, this will make the system throw errors if trying // to output a null or undefined value this.opts.throwOnUndefined = !!opts.throwOnUndefined; this.opts.trimBlocks = !!opts.trimBlocks; this.opts.lstripBlocks = !!opts.lstripBlocks; this.loaders = []; if(!loaders) { // The filesystem loader is only available server-side if(builtin_loaders.FileSystemLoader) { this.loaders = [new builtin_loaders.FileSystemLoader('views')]; } else if(builtin_loaders.WebLoader) { this.loaders = [new builtin_loaders.WebLoader('/views')]; } } else { this.loaders = lib.isArray(loaders) ? loaders : [loaders]; } // It's easy to use precompiled templates: just include them // before you configure nunjucks and this will automatically // pick it up and use it if((true) && window.nunjucksPrecompiled) { this.loaders.unshift( new builtin_loaders.PrecompiledLoader(window.nunjucksPrecompiled) ); } this.initCache(); this.globals = globals(); this.filters = {}; this.asyncFilters = []; this.extensions = {}; this.extensionsList = []; for(var name in builtin_filters) { this.addFilter(name, builtin_filters[name]); } }, initCache: function() { // Caching and cache busting lib.each(this.loaders, function(loader) { loader.cache = {}; if(typeof loader.on === 'function') { loader.on('update', function(template) { loader.cache[template] = null; }); } }); }, addExtension: function(name, extension) { extension._name = name; this.extensions[name] = extension; this.extensionsList.push(extension); return this; }, removeExtension: function(name) { var extension = this.getExtension(name); if (!extension) return; this.extensionsList = lib.without(this.extensionsList, extension); delete this.extensions[name]; }, getExtension: function(name) { return this.extensions[name]; }, hasExtension: function(name) { return !!this.extensions[name]; }, addGlobal: function(name, value) { this.globals[name] = value; return this; }, getGlobal: function(name) { if(typeof this.globals[name] === 'undefined') { throw new Error('global not found: ' + name); } return this.globals[name]; }, addFilter: function(name, func, async) { var wrapped = func; if(async) { this.asyncFilters.push(name); } this.filters[name] = wrapped; return this; }, getFilter: function(name) { if(!this.filters[name]) { throw new Error('filter not found: ' + name); } return this.filters[name]; }, resolveTemplate: function(loader, parentName, filename) { var isRelative = (loader.isRelative && parentName)? loader.isRelative(filename) : false; return (isRelative && loader.resolve)? loader.resolve(parentName, filename) : filename; }, getTemplate: function(name, eagerCompile, parentName, ignoreMissing, cb) { var that = this; var tmpl = null; if(name && name.raw) { // this fixes autoescape for templates referenced in symbols name = name.raw; } if(lib.isFunction(parentName)) { cb = parentName; parentName = null; eagerCompile = eagerCompile || false; } if(lib.isFunction(eagerCompile)) { cb = eagerCompile; eagerCompile = false; } if (name instanceof Template) { tmpl = name; } else if(typeof name !== 'string') { throw new Error('template names must be a string: ' + name); } else { for (var i = 0; i < this.loaders.length; i++) { var _name = this.resolveTemplate(this.loaders[i], parentName, name); tmpl = this.loaders[i].cache[_name]; if (tmpl) break; } } if(tmpl) { if(eagerCompile) { tmpl.compile(); } if(cb) { cb(null, tmpl); } else { return tmpl; } } else { var syncResult; var _this = this; var createTemplate = function(err, info) { if(!info && !err) { if(!ignoreMissing) { err = new Error('template not found: ' + name); } } if (err) { if(cb) { cb(err); } else { throw err; } } else { var tmpl; if(info) { tmpl = new Template(info.src, _this, info.path, eagerCompile); if(!info.noCache) { info.loader.cache[name] = tmpl; } } else { tmpl = new Template('', _this, '', eagerCompile); } if(cb) { cb(null, tmpl); } else { syncResult = tmpl; } } }; lib.asyncIter(this.loaders, function(loader, i, next, done) { function handle(err, src) { if(err) { done(err); } else if(src) { src.loader = loader; done(null, src); } else { next(); } } // Resolve name relative to parentName name = that.resolveTemplate(loader, parentName, name); if(loader.async) { loader.getSource(name, handle); } else { handle(null, loader.getSource(name)); } }, createTemplate); return syncResult; } }, express: function(app) { var env = this; function NunjucksView(name, opts) { this.name = name; this.path = name; this.defaultEngine = opts.defaultEngine; this.ext = path.extname(name); if (!this.ext && !this.defaultEngine) throw new Error('No default engine was specified and no extension was provided.'); if (!this.ext) this.name += (this.ext = ('.' !== this.defaultEngine[0] ? '.' : '') + this.defaultEngine); } NunjucksView.prototype.render = function(opts, cb) { env.render(this.name, opts, cb); }; app.set('view', NunjucksView); app.set('nunjucksEnv', this); return this; }, render: function(name, ctx, cb) { if(lib.isFunction(ctx)) { cb = ctx; ctx = null; } // We support a synchronous API to make it easier to migrate // existing code to async. This works because if you don't do // anything async work, the whole thing is actually run // synchronously. var syncResult = null; this.getTemplate(name, function(err, tmpl) { if(err && cb) { callbackAsap(cb, err); } else if(err) { throw err; } else { syncResult = tmpl.render(ctx, cb); } }); return syncResult; }, renderString: function(src, ctx, opts, cb) { if(lib.isFunction(opts)) { cb = opts; opts = {}; } opts = opts || {}; var tmpl = new Template(src, this, opts.path); return tmpl.render(ctx, cb); }, waterfall: waterfall }); var Context = Obj.extend({ init: function(ctx, blocks, env) { // Has to be tied to an environment so we can tap into its globals. this.env = env || new Environment(); // Make a duplicate of ctx this.ctx = {}; for(var k in ctx) { if(ctx.hasOwnProperty(k)) { this.ctx[k] = ctx[k]; } } this.blocks = {}; this.exported = []; for(var name in blocks) { this.addBlock(name, blocks[name]); } }, lookup: function(name) { // This is one of the most called functions, so optimize for // the typical case where the name isn't in the globals if(name in this.env.globals && !(name in this.ctx)) { return this.env.globals[name]; } else { return this.ctx[name]; } }, setVariable: function(name, val) { this.ctx[name] = val; }, getVariables: function() { return this.ctx; }, addBlock: function(name, block) { this.blocks[name] = this.blocks[name] || []; this.blocks[name].push(block); return this; }, getBlock: function(name) { if(!this.blocks[name]) { throw new Error('unknown block "' + name + '"'); } return this.blocks[name][0]; }, getSuper: function(env, name, block, frame, runtime, cb) { var idx = lib.indexOf(this.blocks[name] || [], block); var blk = this.blocks[name][idx + 1]; var context = this; if(idx === -1 || !blk) { throw new Error('no super block available for "' + name + '"'); } blk(env, context, frame, runtime, cb); }, addExport: function(name) { this.exported.push(name); }, getExported: function() { var exported = {}; for(var i=0; i capacity) { // Manually shift all values starting at the index back to the // beginning of the queue. for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) { queue[scan] = queue[scan + index]; } queue.length -= index; index = 0; } } queue.length = 0; index = 0; flushing = false; } // `requestFlush` is implemented using a strategy based on data collected from // every available SauceLabs Selenium web driver worker at time of writing. // https://docs.google.com/spreadsheets/d/1mG-5UYGup5qxGdEMWkhP6BWCz053NUb2E1QoUTU16uA/edit#gid=783724593 // Safari 6 and 6.1 for desktop, iPad, and iPhone are the only browsers that // have WebKitMutationObserver but not un-prefixed MutationObserver. // Must use `global` instead of `window` to work in both frames and web // workers. `global` is a provision of Browserify, Mr, Mrs, or Mop. var BrowserMutationObserver = global.MutationObserver || global.WebKitMutationObserver; // MutationObservers are desirable because they have high priority and work // reliably everywhere they are implemented. // They are implemented in all modern browsers. // // - Android 4-4.3 // - Chrome 26-34 // - Firefox 14-29 // - Internet Explorer 11 // - iPad Safari 6-7.1 // - iPhone Safari 7-7.1 // - Safari 6-7 if (typeof BrowserMutationObserver === "function") { requestFlush = makeRequestCallFromMutationObserver(flush); // MessageChannels are desirable because they give direct access to the HTML // task queue, are implemented in Internet Explorer 10, Safari 5.0-1, and Opera // 11-12, and in web workers in many engines. // Although message channels yield to any queued rendering and IO tasks, they // would be better than imposing the 4ms delay of timers. // However, they do not work reliably in Internet Explorer or Safari. // Internet Explorer 10 is the only browser that has setImmediate but does // not have MutationObservers. // Although setImmediate yields to the browser's renderer, it would be // preferrable to falling back to setTimeout since it does not have // the minimum 4ms penalty. // Unfortunately there appears to be a bug in Internet Explorer 10 Mobile (and // Desktop to a lesser extent) that renders both setImmediate and // MessageChannel useless for the purposes of ASAP. // https://github.com/kriskowal/q/issues/396 // Timers are implemented universally. // We fall back to timers in workers in most engines, and in foreground // contexts in the following browsers. // However, note that even this simple case requires nuances to operate in a // broad spectrum of browsers. // // - Firefox 3-13 // - Internet Explorer 6-9 // - iPad Safari 4.3 // - Lynx 2.8.7 } else { requestFlush = makeRequestCallFromTimer(flush); } // `requestFlush` requests that the high priority event queue be flushed as // soon as possible. // This is useful to prevent an error thrown in a task from stalling the event // queue if the exception handled by Node.js’s // `process.on("uncaughtException")` or by a domain. rawAsap.requestFlush = requestFlush; // To request a high priority event, we induce a mutation observer by toggling // the text of a text node between "1" and "-1". function makeRequestCallFromMutationObserver(callback) { var toggle = 1; var observer = new BrowserMutationObserver(callback); var node = document.createTextNode(""); observer.observe(node, {characterData: true}); return function requestCall() { toggle = -toggle; node.data = toggle; }; } // The message channel technique was discovered by Malte Ubl and was the // original foundation for this library. // http://www.nonblocking.io/2011/06/windownexttick.html // Safari 6.0.5 (at least) intermittently fails to create message ports on a // page's first load. Thankfully, this version of Safari supports // MutationObservers, so we don't need to fall back in that case. // function makeRequestCallFromMessageChannel(callback) { // var channel = new MessageChannel(); // channel.port1.onmessage = callback; // return function requestCall() { // channel.port2.postMessage(0); // }; // } // For reasons explained above, we are also unable to use `setImmediate` // under any circumstances. // Even if we were, there is another bug in Internet Explorer 10. // It is not sufficient to assign `setImmediate` to `requestFlush` because // `setImmediate` must be called *by name* and therefore must be wrapped in a // closure. // Never forget. // function makeRequestCallFromSetImmediate(callback) { // return function requestCall() { // setImmediate(callback); // }; // } // Safari 6.0 has a problem where timers will get lost while the user is // scrolling. This problem does not impact ASAP because Safari 6.0 supports // mutation observers, so that implementation is used instead. // However, if we ever elect to use timers in Safari, the prevalent work-around // is to add a scroll event listener that calls for a flush. // `setTimeout` does not call the passed callback if the delay is less than // approximately 7 in web workers in Firefox 8 through 18, and sometimes not // even then. function makeRequestCallFromTimer(callback) { return function requestCall() { // We dispatch a timeout with a specified delay of 0 for engines that // can reliably accommodate that request. This will usually be snapped // to a 4 milisecond delay, but once we're flushing, there's no delay // between events. var timeoutHandle = setTimeout(handleTimer, 0); // However, since this timer gets frequently dropped in Firefox // workers, we enlist an interval handle that will try to fire // an event 20 times per second until it succeeds. var intervalHandle = setInterval(handleTimer, 50); function handleTimer() { // Whichever timer succeeds will cancel both timers and // execute the callback. clearTimeout(timeoutHandle); clearInterval(intervalHandle); callback(); } }; } // This is for `asap.js` only. // Its name will be periodically randomized to break any code that depends on // its existence. rawAsap.makeRequestCallFromTimer = makeRequestCallFromTimer; // ASAP was originally a nextTick shim included in Q. This was factored out // into this ASAP package. It was later adapted to RSVP which made further // amendments. These decisions, particularly to marginalize MessageChannel and // to capture the MutationObserver implementation in a closure, were integrated // back into ASAP proper. // https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) /***/ }, /* 6 */ /***/ function(module, exports) { 'use strict'; // 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(); // jshint undef: false 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)) { /*jshint -W083 */ 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; } module.exports = extend(Object, 'Object', {}); /***/ }, /* 7 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var lib = __webpack_require__(1); var parser = __webpack_require__(8); var transformer = __webpack_require__(11); var nodes = __webpack_require__(10); // jshint -W079 var Object = __webpack_require__(6); var Frame = __webpack_require__(12).Frame; // These are all the same for now, but shouldn't be passed straight // through var compareOps = { '==': '==', '===': '===', '!=': '!=', '!==': '!==', '<': '<', '>': '>', '<=': '<=', '>=': '>=' }; // A common pattern is to emit binary operators function binOpEmitter(str) { return function(node, frame) { this.compile(node.left, frame); this.emit(str); this.compile(node.right, frame); }; } var Compiler = Object.extend({ init: function(templateName, throwOnUndefined) { this.templateName = templateName; this.codebuf = []; this.lastId = 0; this.buffer = null; this.bufferStack = []; this.scopeClosers = ''; this.inBlock = false; this.throwOnUndefined = throwOnUndefined; }, fail: function (msg, lineno, colno) { if (lineno !== undefined) lineno += 1; if (colno !== undefined) colno += 1; throw new lib.TemplateError(msg, lineno, colno); }, pushBufferId: function(id) { this.bufferStack.push(this.buffer); this.buffer = id; this.emit('var ' + this.buffer + ' = "";'); }, popBufferId: function() { this.buffer = this.bufferStack.pop(); }, emit: function(code) { this.codebuf.push(code); }, emitLine: function(code) { this.emit(code + '\n'); }, emitLines: function() { lib.each(lib.toArray(arguments), function(line) { this.emitLine(line); }, this); }, emitFuncBegin: function(name) { this.buffer = 'output'; this.scopeClosers = ''; this.emitLine('function ' + name + '(env, context, frame, runtime, cb) {'); this.emitLine('var lineno = null;'); this.emitLine('var colno = null;'); this.emitLine('var ' + this.buffer + ' = "";'); this.emitLine('try {'); }, emitFuncEnd: function(noReturn) { if(!noReturn) { this.emitLine('cb(null, ' + this.buffer +');'); } this.closeScopeLevels(); this.emitLine('} catch (e) {'); this.emitLine(' cb(runtime.handleError(e, lineno, colno));'); this.emitLine('}'); this.emitLine('}'); this.buffer = null; }, addScopeLevel: function() { this.scopeClosers += '})'; }, closeScopeLevels: function() { this.emitLine(this.scopeClosers + ';'); this.scopeClosers = ''; }, withScopedSyntax: function(func) { var scopeClosers = this.scopeClosers; this.scopeClosers = ''; func.call(this); this.closeScopeLevels(); this.scopeClosers = scopeClosers; }, makeCallback: function(res) { var err = this.tmpid(); return 'function(' + err + (res ? ',' + res : '') + ') {\n' + 'if(' + err + ') { cb(' + err + '); return; }'; }, tmpid: function() { this.lastId++; return 't_' + this.lastId; }, _templateName: function() { return this.templateName == null? 'undefined' : JSON.stringify(this.templateName); }, _compileChildren: function(node, frame) { var children = node.children; for(var i=0, l=children.length; i 0) { this.emit(','); } this.compile(node.children[i], frame); } if(endChar) { this.emit(endChar); } }, _compileExpression: function(node, frame) { // TODO: I'm not really sure if this type check is worth it or // not. this.assertType( node, nodes.Literal, nodes.Symbol, nodes.Group, nodes.Array, nodes.Dict, nodes.FunCall, nodes.Caller, nodes.Filter, nodes.LookupVal, nodes.Compare, nodes.InlineIf, nodes.In, nodes.And, nodes.Or, nodes.Not, nodes.Add, nodes.Concat, nodes.Sub, nodes.Mul, nodes.Div, nodes.FloorDiv, nodes.Mod, nodes.Pow, nodes.Neg, nodes.Pos, nodes.Compare, nodes.NodeList ); this.compile(node, frame); }, assertType: function(node /*, types */) { var types = lib.toArray(arguments).slice(1); var success = false; for(var i=0; i 0) { this.emit(','); } if(arg) { var id = this.tmpid(); this.emitLine('function(cb) {'); this.emitLine('if(!cb) { cb = function(err) { if(err) { throw err; }}}'); this.pushBufferId(id); this.withScopedSyntax(function() { this.compile(arg, frame); this.emitLine('cb(null, ' + id + ');'); }); this.popBufferId(); this.emitLine('return ' + id + ';'); this.emitLine('}'); } else { this.emit('null'); } }, this); } if(async) { var res = this.tmpid(); this.emitLine(', ' + this.makeCallback(res)); this.emitLine(this.buffer + ' += runtime.suppressValue(' + res + ', ' + autoescape + ' && env.opts.autoescape);'); this.addScopeLevel(); } else { this.emit(')'); this.emit(', ' + autoescape + ' && env.opts.autoescape);\n'); } }, compileCallExtensionAsync: function(node, frame) { this.compileCallExtension(node, frame, true); }, compileNodeList: function(node, frame) { this._compileChildren(node, frame); }, compileLiteral: function(node) { if(typeof node.value === 'string') { var val = node.value.replace(/\\/g, '\\\\'); val = val.replace(/"/g, '\\"'); val = val.replace(/\n/g, '\\n'); val = val.replace(/\r/g, '\\r'); val = val.replace(/\t/g, '\\t'); this.emit('"' + val + '"'); } else if (node.value === null) { this.emit('null'); } else { this.emit(node.value.toString()); } }, compileSymbol: function(node, frame) { var name = node.value; var v; if((v = frame.lookup(name))) { this.emit(v); } else { this.emit('runtime.contextOrFrameLookup(' + 'context, frame, "' + name + '")'); } }, compileGroup: function(node, frame) { this._compileAggregate(node, frame, '(', ')'); }, compileArray: function(node, frame) { this._compileAggregate(node, frame, '[', ']'); }, compileDict: function(node, frame) { this._compileAggregate(node, frame, '{', '}'); }, compilePair: function(node, frame) { var key = node.key; var val = node.value; if(key instanceof nodes.Symbol) { key = new nodes.Literal(key.lineno, key.colno, key.value); } else if(!(key instanceof nodes.Literal && typeof key.value === 'string')) { this.fail('compilePair: Dict keys must be strings or names', key.lineno, key.colno); } this.compile(key, frame); this.emit(': '); this._compileExpression(val, frame); }, compileInlineIf: function(node, frame) { this.emit('('); this.compile(node.cond, frame); this.emit('?'); this.compile(node.body, frame); this.emit(':'); if(node.else_ !== null) this.compile(node.else_, frame); else this.emit('""'); this.emit(')'); }, compileIn: function(node, frame) { this.emit('runtime.inOperator('); this.compile(node.left, frame); this.emit(','); this.compile(node.right, frame); this.emit(')'); }, compileOr: binOpEmitter(' || '), compileAnd: binOpEmitter(' && '), compileAdd: binOpEmitter(' + '), // ensure concatenation instead of addition // by adding empty string in between compileConcat: binOpEmitter(' + "" + '), compileSub: binOpEmitter(' - '), compileMul: binOpEmitter(' * '), compileDiv: binOpEmitter(' / '), compileMod: binOpEmitter(' % '), compileNot: function(node, frame) { this.emit('!'); this.compile(node.target, frame); }, compileFloorDiv: function(node, frame) { this.emit('Math.floor('); this.compile(node.left, frame); this.emit(' / '); this.compile(node.right, frame); this.emit(')'); }, compilePow: function(node, frame) { this.emit('Math.pow('); this.compile(node.left, frame); this.emit(', '); this.compile(node.right, frame); this.emit(')'); }, compileNeg: function(node, frame) { this.emit('-'); this.compile(node.target, frame); }, compilePos: function(node, frame) { this.emit('+'); this.compile(node.target, frame); }, compileCompare: function(node, frame) { this.compile(node.expr, frame); for(var i=0; i 0 && !this.skip(lexer.TOKEN_COMMA)) { this.fail('parseFrom: expected comma', fromTok.lineno, fromTok.colno); } var name = this.parsePrimary(); if(name.value.charAt(0) === '_') { this.fail('parseFrom: names starting with an underscore ' + 'cannot be imported', name.lineno, name.colno); } if(this.skipSymbol('as')) { var alias = this.parsePrimary(); names.addChild(new nodes.Pair(name.lineno, name.colno, name, alias)); } else { names.addChild(name); } withContext = this.parseWithContext(); } return new nodes.FromImport(fromTok.lineno, fromTok.colno, template, names, withContext); }, parseBlock: function() { var tag = this.peekToken(); if(!this.skipSymbol('block')) { this.fail('parseBlock: expected block', tag.lineno, tag.colno); } var node = new nodes.Block(tag.lineno, tag.colno); node.name = this.parsePrimary(); if(!(node.name instanceof nodes.Symbol)) { this.fail('parseBlock: variable name expected', tag.lineno, tag.colno); } this.advanceAfterBlockEnd(tag.value); node.body = this.parseUntilBlocks('endblock'); this.skipSymbol('endblock'); this.skipSymbol(node.name.value); var tok = this.peekToken(); if(!tok) { this.fail('parseBlock: expected endblock, got end of file'); } this.advanceAfterBlockEnd(tok.value); return node; }, parseExtends: function() { var tagName = 'extends'; var tag = this.peekToken(); if(!this.skipSymbol(tagName)) { this.fail('parseTemplateRef: expected '+ tagName); } var node = new nodes.Extends(tag.lineno, tag.colno); node.template = this.parseExpression(); this.advanceAfterBlockEnd(tag.value); return node; }, parseInclude: function() { var tagName = 'include'; var tag = this.peekToken(); if(!this.skipSymbol(tagName)) { this.fail('parseInclude: expected '+ tagName); } var node = new nodes.Include(tag.lineno, tag.colno); node.template = this.parseExpression(); if(this.skipSymbol('ignore') && this.skipSymbol('missing')) { node.ignoreMissing = true; } this.advanceAfterBlockEnd(tag.value); return node; }, parseIf: function() { var tag = this.peekToken(); var node; if(this.skipSymbol('if') || this.skipSymbol('elif') || this.skipSymbol('elseif')) { node = new nodes.If(tag.lineno, tag.colno); } else if(this.skipSymbol('ifAsync')) { node = new nodes.IfAsync(tag.lineno, tag.colno); } else { this.fail('parseIf: expected if, elif, or elseif', tag.lineno, tag.colno); } node.cond = this.parseExpression(); this.advanceAfterBlockEnd(tag.value); node.body = this.parseUntilBlocks('elif', 'elseif', 'else', 'endif'); var tok = this.peekToken(); switch(tok && tok.value) { case 'elseif': case 'elif': node.else_ = this.parseIf(); break; case 'else': this.advanceAfterBlockEnd(); node.else_ = this.parseUntilBlocks('endif'); this.advanceAfterBlockEnd(); break; case 'endif': node.else_ = null; this.advanceAfterBlockEnd(); break; default: this.fail('parseIf: expected elif, else, or endif, ' + 'got end of file'); } return node; }, parseSet: function() { var tag = this.peekToken(); if(!this.skipSymbol('set')) { this.fail('parseSet: expected set', tag.lineno, tag.colno); } var node = new nodes.Set(tag.lineno, tag.colno, []); var target; while((target = this.parsePrimary())) { node.targets.push(target); if(!this.skip(lexer.TOKEN_COMMA)) { break; } } if(!this.skipValue(lexer.TOKEN_OPERATOR, '=')) { if (!this.skip(lexer.TOKEN_BLOCK_END)) { this.fail('parseSet: expected = or block end in set tag', tag.lineno, tag.colno); } else { node.body = new nodes.Capture( tag.lineno, tag.colno, this.parseUntilBlocks('endset') ); node.value = null; this.advanceAfterBlockEnd(); } } else { node.value = this.parseExpression(); this.advanceAfterBlockEnd(tag.value); } return node; }, parseStatement: function () { var tok = this.peekToken(); var node; if(tok.type !== lexer.TOKEN_SYMBOL) { this.fail('tag name expected', tok.lineno, tok.colno); } if(this.breakOnBlocks && lib.indexOf(this.breakOnBlocks, tok.value) !== -1) { return null; } switch(tok.value) { case 'raw': return this.parseRaw(); case 'verbatim': return this.parseRaw('verbatim'); case 'if': case 'ifAsync': return this.parseIf(); case 'for': case 'asyncEach': case 'asyncAll': return this.parseFor(); case 'block': return this.parseBlock(); case 'extends': return this.parseExtends(); case 'include': return this.parseInclude(); case 'set': return this.parseSet(); case 'macro': return this.parseMacro(); case 'call': return this.parseCall(); case 'import': return this.parseImport(); case 'from': return this.parseFrom(); case 'filter': return this.parseFilterStatement(); default: if (this.extensions.length) { for (var i = 0; i < this.extensions.length; i++) { var ext = this.extensions[i]; if (lib.indexOf(ext.tags || [], tok.value) !== -1) { return ext.parse(this, nodes, lexer); } } } this.fail('unknown block tag: ' + tok.value, tok.lineno, tok.colno); } return node; }, parseRaw: function(tagName) { tagName = tagName || 'raw'; var endTagName = 'end' + tagName; // Look for upcoming raw blocks (ignore all other kinds of blocks) var rawBlockRegex = new RegExp('([\\s\\S]*?){%\\s*(' + tagName + '|' + endTagName + ')\\s*(?=%})%}'); var rawLevel = 1; var str = ''; var matches = null; // Skip opening raw token // Keep this token to track line and column numbers var begun = this.advanceAfterBlockEnd(); // Exit when there's nothing to match // or when we've found the matching "endraw" block while((matches = this.tokens._extractRegex(rawBlockRegex)) && rawLevel > 0) { var all = matches[0]; var pre = matches[1]; var blockName = matches[2]; // Adjust rawlevel if(blockName === tagName) { rawLevel += 1; } else if(blockName === endTagName) { rawLevel -= 1; } // Add to str if(rawLevel === 0) { // We want to exclude the last "endraw" str += pre; // Move tokenizer to beginning of endraw block this.tokens.backN(all.length - pre.length); } else { str += all; } } return new nodes.Output( begun.lineno, begun.colno, [new nodes.TemplateData(begun.lineno, begun.colno, str)] ); }, parsePostfix: function(node) { var lookup, tok = this.peekToken(); while(tok) { if(tok.type === lexer.TOKEN_LEFT_PAREN) { // Function call node = new nodes.FunCall(tok.lineno, tok.colno, node, this.parseSignature()); } else if(tok.type === lexer.TOKEN_LEFT_BRACKET) { // Reference lookup = this.parseAggregate(); if(lookup.children.length > 1) { this.fail('invalid index'); } node = new nodes.LookupVal(tok.lineno, tok.colno, node, lookup.children[0]); } else if(tok.type === lexer.TOKEN_OPERATOR && tok.value === '.') { // Reference this.nextToken(); var val = this.nextToken(); if(val.type !== lexer.TOKEN_SYMBOL) { this.fail('expected name as lookup value, got ' + val.value, val.lineno, val.colno); } // Make a literal string because it's not a variable // reference lookup = new nodes.Literal(val.lineno, val.colno, val.value); node = new nodes.LookupVal(tok.lineno, tok.colno, node, lookup); } else { break; } tok = this.peekToken(); } return node; }, parseExpression: function() { var node = this.parseInlineIf(); return node; }, parseInlineIf: function() { var node = this.parseOr(); if(this.skipSymbol('if')) { var cond_node = this.parseOr(); var body_node = node; node = new nodes.InlineIf(node.lineno, node.colno); node.body = body_node; node.cond = cond_node; if(this.skipSymbol('else')) { node.else_ = this.parseOr(); } else { node.else_ = null; } } return node; }, parseOr: function() { var node = this.parseAnd(); while(this.skipSymbol('or')) { var node2 = this.parseAnd(); node = new nodes.Or(node.lineno, node.colno, node, node2); } return node; }, parseAnd: function() { var node = this.parseNot(); while(this.skipSymbol('and')) { var node2 = this.parseNot(); node = new nodes.And(node.lineno, node.colno, node, node2); } return node; }, parseNot: function() { var tok = this.peekToken(); if(this.skipSymbol('not')) { return new nodes.Not(tok.lineno, tok.colno, this.parseNot()); } return this.parseIn(); }, parseIn: function() { var node = this.parseCompare(); while(1) { // check if the next token is 'not' var tok = this.nextToken(); if (!tok) { break; } var invert = tok.type === lexer.TOKEN_SYMBOL && tok.value === 'not'; // if it wasn't 'not', put it back if (!invert) { this.pushToken(tok); } if (this.skipSymbol('in')) { var node2 = this.parseCompare(); node = new nodes.In(node.lineno, node.colno, node, node2); if (invert) { node = new nodes.Not(node.lineno, node.colno, node); } } else { // if we'd found a 'not' but this wasn't an 'in', put back the 'not' if (invert) { this.pushToken(tok); } break; } } return node; }, parseCompare: function() { var compareOps = ['==', '===', '!=', '!==', '<', '>', '<=', '>=']; var expr = this.parseConcat(); var ops = []; while(1) { var tok = this.nextToken(); if(!tok) { break; } else if(lib.indexOf(compareOps, tok.value) !== -1) { ops.push(new nodes.CompareOperand(tok.lineno, tok.colno, this.parseConcat(), tok.value)); } else { this.pushToken(tok); break; } } if(ops.length) { return new nodes.Compare(ops[0].lineno, ops[0].colno, expr, ops); } else { return expr; } }, // finds the '~' for string concatenation parseConcat: function(){ var node = this.parseAdd(); while(this.skipValue(lexer.TOKEN_TILDE, '~')) { var node2 = this.parseAdd(); node = new nodes.Concat(node.lineno, node.colno, node, node2); } return node; }, parseAdd: function() { var node = this.parseSub(); while(this.skipValue(lexer.TOKEN_OPERATOR, '+')) { var node2 = this.parseSub(); node = new nodes.Add(node.lineno, node.colno, node, node2); } return node; }, parseSub: function() { var node = this.parseMul(); while(this.skipValue(lexer.TOKEN_OPERATOR, '-')) { var node2 = this.parseMul(); node = new nodes.Sub(node.lineno, node.colno, node, node2); } return node; }, parseMul: function() { var node = this.parseDiv(); while(this.skipValue(lexer.TOKEN_OPERATOR, '*')) { var node2 = this.parseDiv(); node = new nodes.Mul(node.lineno, node.colno, node, node2); } return node; }, parseDiv: function() { var node = this.parseFloorDiv(); while(this.skipValue(lexer.TOKEN_OPERATOR, '/')) { var node2 = this.parseFloorDiv(); node = new nodes.Div(node.lineno, node.colno, node, node2); } return node; }, parseFloorDiv: function() { var node = this.parseMod(); while(this.skipValue(lexer.TOKEN_OPERATOR, '//')) { var node2 = this.parseMod(); node = new nodes.FloorDiv(node.lineno, node.colno, node, node2); } return node; }, parseMod: function() { var node = this.parsePow(); while(this.skipValue(lexer.TOKEN_OPERATOR, '%')) { var node2 = this.parsePow(); node = new nodes.Mod(node.lineno, node.colno, node, node2); } return node; }, parsePow: function() { var node = this.parseUnary(); while(this.skipValue(lexer.TOKEN_OPERATOR, '**')) { var node2 = this.parseUnary(); node = new nodes.Pow(node.lineno, node.colno, node, node2); } return node; }, parseUnary: function(noFilters) { var tok = this.peekToken(); var node; if(this.skipValue(lexer.TOKEN_OPERATOR, '-')) { node = new nodes.Neg(tok.lineno, tok.colno, this.parseUnary(true)); } else if(this.skipValue(lexer.TOKEN_OPERATOR, '+')) { node = new nodes.Pos(tok.lineno, tok.colno, this.parseUnary(true)); } else { node = this.parsePrimary(); } if(!noFilters) { node = this.parseFilter(node); } return node; }, parsePrimary: function (noPostfix) { var tok = this.nextToken(); var val; var node = null; if(!tok) { this.fail('expected expression, got end of file'); } else if(tok.type === lexer.TOKEN_STRING) { val = tok.value; } else if(tok.type === lexer.TOKEN_INT) { val = parseInt(tok.value, 10); } else if(tok.type === lexer.TOKEN_FLOAT) { val = parseFloat(tok.value); } else if(tok.type === lexer.TOKEN_BOOLEAN) { if(tok.value === 'true') { val = true; } else if(tok.value === 'false') { val = false; } else { this.fail('invalid boolean: ' + tok.value, tok.lineno, tok.colno); } } else if(tok.type === lexer.TOKEN_NONE) { val = null; } else if (tok.type === lexer.TOKEN_REGEX) { val = new RegExp(tok.value.body, tok.value.flags); } if(val !== undefined) { node = new nodes.Literal(tok.lineno, tok.colno, val); } else if(tok.type === lexer.TOKEN_SYMBOL) { node = new nodes.Symbol(tok.lineno, tok.colno, tok.value); if(!noPostfix) { node = this.parsePostfix(node); } } else { // See if it's an aggregate type, we need to push the // current delimiter token back on this.pushToken(tok); node = this.parseAggregate(); } if(node) { return node; } else { this.fail('unexpected token: ' + tok.value, tok.lineno, tok.colno); } }, parseFilterName: function() { var tok = this.expect(lexer.TOKEN_SYMBOL); var name = tok.value; while(this.skipValue(lexer.TOKEN_OPERATOR, '.')) { name += '.' + this.expect(lexer.TOKEN_SYMBOL).value; } return new nodes.Symbol(tok.lineno, tok.colno, name); }, parseFilterArgs: function(node) { if(this.peekToken().type === lexer.TOKEN_LEFT_PAREN) { // Get a FunCall node and add the parameters to the // filter var call = this.parsePostfix(node); return call.args.children; } return []; }, parseFilter: function(node) { while(this.skip(lexer.TOKEN_PIPE)) { var name = this.parseFilterName(); node = new nodes.Filter( name.lineno, name.colno, name, new nodes.NodeList( name.lineno, name.colno, [node].concat(this.parseFilterArgs(node)) ) ); } return node; }, parseFilterStatement: function() { var filterTok = this.peekToken(); if(!this.skipSymbol('filter')) { this.fail('parseFilterStatement: expected filter'); } var name = this.parseFilterName(); var args = this.parseFilterArgs(name); this.advanceAfterBlockEnd(filterTok.value); var body = new nodes.Capture( name.lineno, name.colno, this.parseUntilBlocks('endfilter') ); this.advanceAfterBlockEnd(); var node = new nodes.Filter( name.lineno, name.colno, name, new nodes.NodeList( name.lineno, name.colno, [body].concat(args) ) ); return new nodes.Output( name.lineno, name.colno, [node] ); }, parseAggregate: function() { var tok = this.nextToken(); var node; switch(tok.type) { case lexer.TOKEN_LEFT_PAREN: node = new nodes.Group(tok.lineno, tok.colno); break; case lexer.TOKEN_LEFT_BRACKET: node = new nodes.Array(tok.lineno, tok.colno); break; case lexer.TOKEN_LEFT_CURLY: node = new nodes.Dict(tok.lineno, tok.colno); break; default: return null; } while(1) { var type = this.peekToken().type; if(type === lexer.TOKEN_RIGHT_PAREN || type === lexer.TOKEN_RIGHT_BRACKET || type === lexer.TOKEN_RIGHT_CURLY) { this.nextToken(); break; } if(node.children.length > 0) { if(!this.skip(lexer.TOKEN_COMMA)) { this.fail('parseAggregate: expected comma after expression', tok.lineno, tok.colno); } } if(node instanceof nodes.Dict) { // TODO: check for errors var key = this.parsePrimary(); // We expect a key/value pair for dicts, separated by a // colon if(!this.skip(lexer.TOKEN_COLON)) { this.fail('parseAggregate: expected colon after dict key', tok.lineno, tok.colno); } // TODO: check for errors var value = this.parseExpression(); node.addChild(new nodes.Pair(key.lineno, key.colno, key, value)); } else { // TODO: check for errors var expr = this.parseExpression(); node.addChild(expr); } } return node; }, parseSignature: function(tolerant, noParens) { var tok = this.peekToken(); if(!noParens && tok.type !== lexer.TOKEN_LEFT_PAREN) { if(tolerant) { return null; } else { this.fail('expected arguments', tok.lineno, tok.colno); } } if(tok.type === lexer.TOKEN_LEFT_PAREN) { tok = this.nextToken(); } var args = new nodes.NodeList(tok.lineno, tok.colno); var kwargs = new nodes.KeywordArgs(tok.lineno, tok.colno); var checkComma = false; while(1) { tok = this.peekToken(); if(!noParens && tok.type === lexer.TOKEN_RIGHT_PAREN) { this.nextToken(); break; } else if(noParens && tok.type === lexer.TOKEN_BLOCK_END) { break; } if(checkComma && !this.skip(lexer.TOKEN_COMMA)) { this.fail('parseSignature: expected comma after expression', tok.lineno, tok.colno); } else { var arg = this.parseExpression(); if(this.skipValue(lexer.TOKEN_OPERATOR, '=')) { kwargs.addChild( new nodes.Pair(arg.lineno, arg.colno, arg, this.parseExpression()) ); } else { args.addChild(arg); } } checkComma = true; } if(kwargs.children.length) { args.addChild(kwargs); } return args; }, parseUntilBlocks: function(/* blockNames */) { var prev = this.breakOnBlocks; this.breakOnBlocks = lib.toArray(arguments); var ret = this.parse(); this.breakOnBlocks = prev; return ret; }, parseNodes: function () { var tok; var buf = []; while((tok = this.nextToken())) { if(tok.type === lexer.TOKEN_DATA) { var data = tok.value; var nextToken = this.peekToken(); var nextVal = nextToken && nextToken.value; // If the last token has "-" we need to trim the // leading whitespace of the data. This is marked with // the `dropLeadingWhitespace` variable. if(this.dropLeadingWhitespace) { // TODO: this could be optimized (don't use regex) data = data.replace(/^\s*/, ''); this.dropLeadingWhitespace = false; } // Same for the succeeding block start token if(nextToken && ((nextToken.type === lexer.TOKEN_BLOCK_START && nextVal.charAt(nextVal.length - 1) === '-') || (nextToken.type === lexer.TOKEN_VARIABLE_START && nextVal.charAt(this.tokens.tags.VARIABLE_START.length) === '-') || (nextToken.type === lexer.TOKEN_COMMENT && nextVal.charAt(this.tokens.tags.COMMENT_START.length) === '-'))) { // TODO: this could be optimized (don't use regex) data = data.replace(/\s*$/, ''); } buf.push(new nodes.Output(tok.lineno, tok.colno, [new nodes.TemplateData(tok.lineno, tok.colno, data)])); } else if(tok.type === lexer.TOKEN_BLOCK_START) { this.dropLeadingWhitespace = false; var n = this.parseStatement(); if(!n) { break; } buf.push(n); } else if(tok.type === lexer.TOKEN_VARIABLE_START) { var e = this.parseExpression(); this.dropLeadingWhitespace = false; this.advanceAfterVariableEnd(); buf.push(new nodes.Output(tok.lineno, tok.colno, [e])); } else if(tok.type === lexer.TOKEN_COMMENT) { this.dropLeadingWhitespace = tok.value.charAt( tok.value.length - this.tokens.tags.COMMENT_END.length - 1 ) === '-'; } else { // Ignore comments, otherwise this should be an error this.fail('Unexpected token at top-level: ' + tok.type, tok.lineno, tok.colno); } } return buf; }, parse: function() { return new nodes.NodeList(0, 0, this.parseNodes()); }, parseAsRoot: function() { return new nodes.Root(0, 0, this.parseNodes()); } }); // var util = require('util'); // var l = lexer.lex('{%- if x -%}\n hello {% endif %}'); // var t; // while((t = l.nextToken())) { // console.log(util.inspect(t)); // } // var p = new Parser(lexer.lex('hello {% filter title %}' + // 'Hello madam how are you' + // '{% endfilter %}')); // var n = p.parseAsRoot(); // nodes.printNodes(n); module.exports = { parse: function(src, extensions, opts) { var p = new Parser(lexer.lex(src, opts)); if (extensions !== undefined) { p.extensions = extensions; } return p.parseAsRoot(); } }; /***/ }, /* 9 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var lib = __webpack_require__(1); var whitespaceChars = ' \n\t\r\u00A0'; var delimChars = '()[]{}%*-+~/#,:|.<>=!'; var intChars = '0123456789'; var BLOCK_START = '{%'; var BLOCK_END = '%}'; var VARIABLE_START = '{{'; var VARIABLE_END = '}}'; var COMMENT_START = '{#'; var COMMENT_END = '#}'; var TOKEN_STRING = 'string'; var TOKEN_WHITESPACE = 'whitespace'; var TOKEN_DATA = 'data'; var TOKEN_BLOCK_START = 'block-start'; var TOKEN_BLOCK_END = 'block-end'; var TOKEN_VARIABLE_START = 'variable-start'; var TOKEN_VARIABLE_END = 'variable-end'; var TOKEN_COMMENT = 'comment'; var TOKEN_LEFT_PAREN = 'left-paren'; var TOKEN_RIGHT_PAREN = 'right-paren'; var TOKEN_LEFT_BRACKET = 'left-bracket'; var TOKEN_RIGHT_BRACKET = 'right-bracket'; var TOKEN_LEFT_CURLY = 'left-curly'; var TOKEN_RIGHT_CURLY = 'right-curly'; var TOKEN_OPERATOR = 'operator'; var TOKEN_COMMA = 'comma'; var TOKEN_COLON = 'colon'; var TOKEN_TILDE = 'tilde'; var TOKEN_PIPE = 'pipe'; var TOKEN_INT = 'int'; var TOKEN_FLOAT = 'float'; var TOKEN_BOOLEAN = 'boolean'; var TOKEN_NONE = 'none'; var TOKEN_SYMBOL = 'symbol'; var TOKEN_SPECIAL = 'special'; var TOKEN_REGEX = 'regex'; function token(type, value, lineno, colno) { return { type: type, value: value, lineno: lineno, colno: colno }; } function Tokenizer(str, opts) { this.str = str; this.index = 0; this.len = str.length; this.lineno = 0; this.colno = 0; this.in_code = false; opts = opts || {}; var tags = opts.tags || {}; this.tags = { BLOCK_START: tags.blockStart || BLOCK_START, BLOCK_END: tags.blockEnd || BLOCK_END, VARIABLE_START: tags.variableStart || VARIABLE_START, VARIABLE_END: tags.variableEnd || VARIABLE_END, COMMENT_START: tags.commentStart || COMMENT_START, COMMENT_END: tags.commentEnd || COMMENT_END }; this.trimBlocks = !!opts.trimBlocks; this.lstripBlocks = !!opts.lstripBlocks; } Tokenizer.prototype.nextToken = function() { var lineno = this.lineno; var colno = this.colno; var tok; if(this.in_code) { // Otherwise, if we are in a block parse it as code var cur = this.current(); if(this.is_finished()) { // We have nothing else to parse return null; } else if(cur === '"' || cur === '\'') { // We've hit a string return token(TOKEN_STRING, this.parseString(cur), lineno, colno); } else if((tok = this._extract(whitespaceChars))) { // We hit some whitespace return token(TOKEN_WHITESPACE, tok, lineno, colno); } else if((tok = this._extractString(this.tags.BLOCK_END)) || (tok = this._extractString('-' + this.tags.BLOCK_END))) { // Special check for the block end tag // // It is a requirement that start and end tags are composed of // delimiter characters (%{}[] etc), and our code always // breaks on delimiters so we can assume the token parsing // doesn't consume these elsewhere this.in_code = false; if(this.trimBlocks) { cur = this.current(); if(cur === '\n') { // Skip newline this.forward(); }else if(cur === '\r'){ // Skip CRLF newline this.forward(); cur = this.current(); if(cur === '\n'){ this.forward(); }else{ // Was not a CRLF, so go back this.back(); } } } return token(TOKEN_BLOCK_END, tok, lineno, colno); } else if((tok = this._extractString(this.tags.VARIABLE_END)) || (tok = this._extractString('-' + this.tags.VARIABLE_END))) { // Special check for variable end tag (see above) this.in_code = false; return token(TOKEN_VARIABLE_END, tok, lineno, colno); } else if (cur === 'r' && this.str.charAt(this.index + 1) === '/') { // Skip past 'r/'. this.forwardN(2); // Extract until the end of the regex -- / ends it, \/ does not. var regexBody = ''; while (!this.is_finished()) { if (this.current() === '/' && this.previous() !== '\\') { this.forward(); break; } else { regexBody += this.current(); this.forward(); } } // Check for flags. // The possible flags are according to https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/RegExp) var POSSIBLE_FLAGS = ['g', 'i', 'm', 'y']; var regexFlags = ''; while (!this.is_finished()) { var isCurrentAFlag = POSSIBLE_FLAGS.indexOf(this.current()) !== -1; if (isCurrentAFlag) { regexFlags += this.current(); this.forward(); } else { break; } } return token(TOKEN_REGEX, {body: regexBody, flags: regexFlags}, lineno, colno); } else if(delimChars.indexOf(cur) !== -1) { // We've hit a delimiter (a special char like a bracket) this.forward(); var complexOps = ['==', '===', '!=', '!==', '<=', '>=', '//', '**']; var curComplex = cur + this.current(); var type; if(lib.indexOf(complexOps, curComplex) !== -1) { this.forward(); cur = curComplex; // See if this is a strict equality/inequality comparator if(lib.indexOf(complexOps, curComplex + this.current()) !== -1) { cur = curComplex + this.current(); this.forward(); } } switch(cur) { case '(': type = TOKEN_LEFT_PAREN; break; case ')': type = TOKEN_RIGHT_PAREN; break; case '[': type = TOKEN_LEFT_BRACKET; break; case ']': type = TOKEN_RIGHT_BRACKET; break; case '{': type = TOKEN_LEFT_CURLY; break; case '}': type = TOKEN_RIGHT_CURLY; break; case ',': type = TOKEN_COMMA; break; case ':': type = TOKEN_COLON; break; case '~': type = TOKEN_TILDE; break; case '|': type = TOKEN_PIPE; break; default: type = TOKEN_OPERATOR; } return token(type, cur, lineno, colno); } else { // We are not at whitespace or a delimiter, so extract the // text and parse it tok = this._extractUntil(whitespaceChars + delimChars); if(tok.match(/^[-+]?[0-9]+$/)) { if(this.current() === '.') { this.forward(); var dec = this._extract(intChars); return token(TOKEN_FLOAT, tok + '.' + dec, lineno, colno); } else { return token(TOKEN_INT, tok, lineno, colno); } } else if(tok.match(/^(true|false)$/)) { return token(TOKEN_BOOLEAN, tok, lineno, colno); } else if(tok === 'none') { return token(TOKEN_NONE, tok, lineno, colno); } else if(tok) { return token(TOKEN_SYMBOL, tok, lineno, colno); } else { throw new Error('Unexpected value while parsing: ' + tok); } } } else { // Parse out the template text, breaking on tag // delimiters because we need to look for block/variable start // tags (don't use the full delimChars for optimization) var beginChars = (this.tags.BLOCK_START.charAt(0) + this.tags.VARIABLE_START.charAt(0) + this.tags.COMMENT_START.charAt(0) + this.tags.COMMENT_END.charAt(0)); if(this.is_finished()) { return null; } else if((tok = this._extractString(this.tags.BLOCK_START + '-')) || (tok = this._extractString(this.tags.BLOCK_START))) { this.in_code = true; return token(TOKEN_BLOCK_START, tok, lineno, colno); } else if((tok = this._extractString(this.tags.VARIABLE_START + '-')) || (tok = this._extractString(this.tags.VARIABLE_START))) { this.in_code = true; return token(TOKEN_VARIABLE_START, tok, lineno, colno); } else { tok = ''; var data; var in_comment = false; if(this._matches(this.tags.COMMENT_START)) { in_comment = true; tok = this._extractString(this.tags.COMMENT_START); } // Continually consume text, breaking on the tag delimiter // characters and checking to see if it's a start tag. // // We could hit the end of the template in the middle of // our looping, so check for the null return value from // _extractUntil while((data = this._extractUntil(beginChars)) !== null) { tok += data; if((this._matches(this.tags.BLOCK_START) || this._matches(this.tags.VARIABLE_START) || this._matches(this.tags.COMMENT_START)) && !in_comment) { if(this.lstripBlocks && this._matches(this.tags.BLOCK_START) && this.colno > 0 && this.colno <= tok.length) { var lastLine = tok.slice(-this.colno); if(/^\s+$/.test(lastLine)) { // Remove block leading whitespace from beginning of the string tok = tok.slice(0, -this.colno); if(!tok.length) { // All data removed, collapse to avoid unnecessary nodes // by returning next token (block start) return this.nextToken(); } } } // If it is a start tag, stop looping break; } else if(this._matches(this.tags.COMMENT_END)) { if(!in_comment) { throw new Error('unexpected end of comment'); } tok += this._extractString(this.tags.COMMENT_END); break; } else { // It does not match any tag, so add the character and // carry on tok += this.current(); this.forward(); } } if(data === null && in_comment) { throw new Error('expected end of comment, got end of file'); } return token(in_comment ? TOKEN_COMMENT : TOKEN_DATA, tok, lineno, colno); } } throw new Error('Could not parse text'); }; Tokenizer.prototype.parseString = function(delimiter) { this.forward(); var str = ''; while(!this.is_finished() && this.current() !== delimiter) { var cur = this.current(); if(cur === '\\') { this.forward(); switch(this.current()) { case 'n': str += '\n'; break; case 't': str += '\t'; break; case 'r': str += '\r'; break; default: str += this.current(); } this.forward(); } else { str += cur; this.forward(); } } this.forward(); return str; }; Tokenizer.prototype._matches = function(str) { if(this.index + str.length > this.len) { return null; } var m = this.str.slice(this.index, this.index + str.length); return m === str; }; Tokenizer.prototype._extractString = function(str) { if(this._matches(str)) { this.index += str.length; return str; } return null; }; Tokenizer.prototype._extractUntil = function(charString) { // Extract all non-matching chars, with the default matching set // to everything return this._extractMatching(true, charString || ''); }; Tokenizer.prototype._extract = function(charString) { // Extract all matching chars (no default, so charString must be // explicit) return this._extractMatching(false, charString); }; Tokenizer.prototype._extractMatching = function (breakOnMatch, charString) { // Pull out characters until a breaking char is hit. // If breakOnMatch is false, a non-matching char stops it. // If breakOnMatch is true, a matching char stops it. if(this.is_finished()) { return null; } var first = charString.indexOf(this.current()); // Only proceed if the first character doesn't meet our condition if((breakOnMatch && first === -1) || (!breakOnMatch && first !== -1)) { var t = this.current(); this.forward(); // And pull out all the chars one at a time until we hit a // breaking char var idx = charString.indexOf(this.current()); while(((breakOnMatch && idx === -1) || (!breakOnMatch && idx !== -1)) && !this.is_finished()) { t += this.current(); this.forward(); idx = charString.indexOf(this.current()); } return t; } return ''; }; Tokenizer.prototype._extractRegex = function(regex) { var matches = this.currentStr().match(regex); if(!matches) { return null; } // Move forward whatever was matched this.forwardN(matches[0].length); return matches; }; Tokenizer.prototype.is_finished = function() { return this.index >= this.len; }; Tokenizer.prototype.forwardN = function(n) { for(var i=0; i 0) || !inline) { for(var j=0; j 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 < vals.length; i++) { if(i < kwargNames.length) { kwargs[kwargNames[i]] = vals[i]; } } args.push(kwargs); } else if(argCount < argNames.length) { args = Array.prototype.slice.call(arguments, 0, argCount); for(i = argCount; i < argNames.length; i++) { var arg = argNames[i]; // Keyword arguments that should be passed as // positional arguments, i.e. the caller explicitly // used the name of a positional arg args.push(kwargs[arg]); delete kwargs[arg]; } args.push(kwargs); } else { args = arguments; } return func.apply(this, args); }; } function makeKeywordArgs(obj) { obj.__keywords = true; return obj; } function getKeywordArgs(args) { var len = args.length; if(len) { var lastArg = args[len - 1]; if(lastArg && lastArg.hasOwnProperty('__keywords')) { return lastArg; } } return {}; } function numArgs(args) { var len = args.length; if(len === 0) { return 0; } var lastArg = args[len - 1]; if(lastArg && lastArg.hasOwnProperty('__keywords')) { return len - 1; } else { return len; } } // A SafeString object indicates that the string should not be // autoescaped. This happens magically because autoescaping only // occurs on primitive string objects. function SafeString(val) { if(typeof val !== 'string') { return val; } this.val = val; this.length = val.length; } SafeString.prototype = Object.create(String.prototype, { length: { writable: true, configurable: true, value: 0 } }); SafeString.prototype.valueOf = function() { return this.val; }; SafeString.prototype.toString = function() { return this.val; }; function copySafeness(dest, target) { if(dest instanceof SafeString) { return new SafeString(target); } return target.toString(); } function markSafe(val) { var type = typeof val; if(type === 'string') { return new SafeString(val); } else if(type !== 'function') { return val; } else { return function() { var ret = val.apply(this, arguments); if(typeof ret === 'string') { return new SafeString(ret); } return ret; }; } } function suppressValue(val, autoescape) { val = (val !== undefined && val !== null) ? val : ''; if(autoescape && !(val instanceof SafeString)) { val = lib.escape(val.toString()); } return val; } function ensureDefined(val, lineno, colno) { if(val === null || val === undefined) { throw new lib.TemplateError( 'attempted to output null or undefined value', lineno + 1, colno + 1 ); } return val; } function memberLookup(obj, val) { obj = obj || {}; if(typeof obj[val] === 'function') { return function() { return obj[val].apply(obj, arguments); }; } return obj[val]; } function callWrap(obj, name, context, args) { if(!obj) { throw new Error('Unable to call `' + name + '`, which is undefined or falsey'); } else if(typeof obj !== 'function') { throw new Error('Unable to call `' + name + '`, which is not a function'); } // jshint validthis: true return obj.apply(context, args); } function contextOrFrameLookup(context, frame, name) { var val = frame.lookup(name); return (val !== undefined) ? val : context.lookup(name); } function handleError(error, lineno, colno) { if(error.lineno) { return error; } else { return new lib.TemplateError(error, lineno, colno); } } function asyncEach(arr, dimen, iter, cb) { if(lib.isArray(arr)) { var len = arr.length; lib.asyncIter(arr, function(item, i, next) { switch(dimen) { case 1: iter(item, i, len, next); break; case 2: iter(item[0], item[1], i, len, next); break; case 3: iter(item[0], item[1], item[2], i, len, next); break; default: item.push(i, next); iter.apply(this, item); } }, cb); } else { lib.asyncFor(arr, function(key, val, i, len, next) { iter(key, val, i, len, next); }, cb); } } function asyncAll(arr, dimen, func, cb) { var finished = 0; var len, i; var outputArr; function done(i, output) { finished++; outputArr[i] = output; if(finished === len) { cb(null, outputArr.join('')); } } if(lib.isArray(arr)) { len = arr.length; outputArr = new Array(len); if(len === 0) { cb(null, ''); } else { for(i = 0; i < arr.length; i++) { var item = arr[i]; switch(dimen) { case 1: func(item, i, len, done); break; case 2: func(item[0], item[1], i, len, done); break; case 3: func(item[0], item[1], item[2], i, len, done); break; default: item.push(i, done); // jshint validthis: true func.apply(this, item); } } } } else { var keys = lib.keys(arr); len = keys.length; outputArr = new Array(len); if(len === 0) { cb(null, ''); } else { for(i = 0; i < keys.length; i++) { var k = keys[i]; func(k, arr[k], i, len, done); } } } } module.exports = { Frame: Frame, makeMacro: makeMacro, makeKeywordArgs: makeKeywordArgs, numArgs: numArgs, suppressValue: suppressValue, ensureDefined: ensureDefined, memberLookup: memberLookup, contextOrFrameLookup: contextOrFrameLookup, callWrap: callWrap, handleError: handleError, isArray: lib.isArray, keys: lib.keys, SafeString: SafeString, copySafeness: copySafeness, markSafe: markSafe, asyncEach: asyncEach, asyncAll: asyncAll, inOperator: lib.inOperator }; /***/ }, /* 13 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var lib = __webpack_require__(1); var r = __webpack_require__(12); function normalize(value, defaultValue) { if(value === null || value === undefined || value === false) { return defaultValue; } return value; } var filters = { abs: function(n) { return Math.abs(n); }, batch: function(arr, linecount, fill_with) { var i; var res = []; var tmp = []; for(i = 0; i < arr.length; i++) { if(i % linecount === 0 && tmp.length) { res.push(tmp); tmp = []; } tmp.push(arr[i]); } if(tmp.length) { if(fill_with) { for(i = tmp.length; i < linecount; i++) { tmp.push(fill_with); } } res.push(tmp); } return res; }, capitalize: function(str) { str = normalize(str, ''); var ret = str.toLowerCase(); return r.copySafeness(str, ret.charAt(0).toUpperCase() + ret.slice(1)); }, center: function(str, width) { str = normalize(str, ''); width = width || 80; if(str.length >= 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, bool) { if(bool) { return val ? val : def; } else { return (val !== undefined) ? 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; }, dump: function(obj, spaces) { return JSON.stringify(obj, null, spaces); }, escape: function(str) { if(str instanceof r.SafeString) { return str; } str = (str === null || str === undefined) ? '' : str; return r.markSafe(lib.escape(str.toString())); }, safe: function(str) { if (str instanceof r.SafeString) { return str; } str = (str === null || str === undefined) ? '' : str; return r.markSafe(str.toString()); }, first: function(arr) { return arr[0]; }, groupby: function(arr, attr) { return lib.groupBy(arr, attr); }, indent: function(str, width, indentfirst) { str = normalize(str, ''); if (str === '') return ''; width = width || 4; var res = ''; var lines = str.split('\n'); var sp = lib.repeat(' ', width); for(var i=0; i\n')); }, random: function(arr) { return arr[Math.floor(Math.random() * arr.length)]; }, rejectattr: function(arr, attr) { return arr.filter(function (item) { return !item[attr]; }); }, selectattr: function(arr, attr) { return arr.filter(function (item) { return !!item[attr]; }); }, replace: function(str, old, new_, maxCount) { var originalStr = str; if (old instanceof RegExp) { return str.replace(old, new_); } if(typeof maxCount === 'undefined'){ maxCount = -1; } var res = ''; // Output // Cast Numbers in the search term to string if(typeof old === 'number'){ old = old + ''; } else if(typeof old !== 'string') { // If it is something other than number or string, // return the original string return str; } // Cast numbers in the replacement to string if(typeof str === 'number'){ str = str + ''; } // If by now, we don't have a string, throw it back if(typeof str !== 'string' && !(str instanceof r.SafeString)){ return str; } // ShortCircuits if(old === ''){ // Mimic the python behaviour: empty string is replaced // by replacement e.g. "abc"|replace("", ".") -> .a.b.c. res = new_ + str.split('').join(new_) + new_; return r.copySafeness(str, res); } var nextIndex = str.indexOf(old); // if # of replacements to perform is 0, or the string to does // not contain the old value, return the string if(maxCount === 0 || nextIndex === -1){ return str; } var pos = 0; var count = 0; // # of replacements made while(nextIndex > -1 && (maxCount === -1 || count < maxCount)){ // Grab the next chunk of src string and add it with the // replacement, to the result res += str.substring(pos, nextIndex) + new_; // Increment our pointer in the src string pos = nextIndex + old.length; count++; // See if there are any more replacements to be made nextIndex = str.indexOf(old, pos); } // We've either reached the end, or done the max # of // replacements, tack on any remaining string if(pos < str.length) { res += str.substring(pos); } return r.copySafeness(originalStr, 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; }, sum: function(arr, attr, start) { var sum = 0; if(typeof start === 'number'){ sum += start; } if(attr) { arr = lib.map(arr, function(v) { return v[attr]; }); } for(var i = 0; i < arr.length; i++) { sum += arr[i]; } return sum; }, sort: r.makeMacro(['value', 'reverse', 'case_sensitive', 'attribute'], [], 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); }, striptags: function(input, preserve_linebreaks) { input = normalize(input, ''); preserve_linebreaks = preserve_linebreaks || false; var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>|/gi; var trimmedInput = filters.trim(input.replace(tags, '')); var res = ''; if (preserve_linebreaks) { res = trimmedInput .replace(/^ +| +$/gm, '') // remove leading and trailing spaces .replace(/ +/g, ' ') // squash adjacent spaces .replace(/(\r\n)/g, '\n') // normalize linebreaks (CRLF -> LF) .replace(/\n\n\n+/g, '\n\n'); // squash abnormal adjacent linebreaks } else { res = trimmedInput.replace(/\s+/gi, ' '); } return r.copySafeness(input, res); }, title: function(str) { str = normalize(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; input = normalize(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) { str = normalize(str, ''); return str.toUpperCase(); }, urlencode: function(obj) { var enc = encodeURIComponent; if (lib.isString(obj)) { return enc(obj); } else { var parts; if (lib.isArray(obj)) { parts = obj.map(function(item) { return enc(item[0]) + '=' + enc(item[1]); }); } else { parts = []; for (var k in obj) { if (obj.hasOwnProperty(k)) { parts.push(enc(k) + '=' + enc(obj[k])); } } } return parts.join('&'); } }, 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 word; }); return words.join(''); }, wordcount: function(str) { str = normalize(str, ''); var words = (str) ? str.match(/\w+/g) : null; return (words) ? words.length : null; }, // CUSTOM FILTER dateFormater:function(data){ return moment(data,"YYYY-mm-DD").format("mm-DD-YYYY"); }, dateFormatertextbox:function(data){ return moment(data,"DD/mm/YYYY").format("mm-DD-YYYY"); }, timestampConvert:function(datas){ // TIMESTAMP TO DATE if(datas != undefined || datas!= null){ return moment.unix(datas/1000).format("MM-DD-YYYY"); } }, timestampToTime:function(data){ // TIMESTAMP TO TIME CONVERTION return moment.unix(data/1000).format("HH:mm"); }, '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; module.exports = filters; /***/ }, /* 14 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var Loader = __webpack_require__(15); var PrecompiledLoader = __webpack_require__(16); var WebLoader = Loader.extend({ init: function(baseURL, opts) { this.baseURL = baseURL || '.'; opts = opts || {}; // By default, the cache is turned off because there's no way // to "watch" templates over HTTP, so they are re-downloaded // and compiled each time. (Remember, PRECOMPILE YOUR // TEMPLATES in production!) this.useCache = !!opts.useCache; // We default `async` to false so that the simple synchronous // API can be used when you aren't doing anything async in // your templates (which is most of the time). This performs a // sync ajax request, but that's ok because it should *only* // happen in development. PRECOMPILE YOUR TEMPLATES. this.async = !!opts.async; }, resolve: function(from, to) { // jshint ignore:line throw new Error('relative templates not support in the browser yet'); }, getSource: function(name, cb) { var useCache = this.useCache; var result; this.fetch(this.baseURL + '/' + name, function(err, src) { if(err) { if(cb) { cb(err.content); } else { if (err.status === 404) { result = null; } else { throw err.content; } } } else { result = { src: src, path: name, noCache: !useCache }; if(cb) { cb(null, result); } } }); // if this WebLoader isn't running asynchronously, the // fetch above would actually run sync and we'll have a // result here return result; }, fetch: function(url, cb) { // Only in the browser please var ajax; var loading = true; if(window.XMLHttpRequest) { // Mozilla, Safari, ... ajax = new XMLHttpRequest(); } else if(window.ActiveXObject) { // IE 8 and older /* global ActiveXObject */ ajax = new ActiveXObject('Microsoft.XMLHTTP'); } ajax.onreadystatechange = function() { if(ajax.readyState === 4 && loading) { loading = false; if(ajax.status === 0 || ajax.status === 200) { cb(null, ajax.responseText); } else { cb({ status: ajax.status, content: ajax.responseText }); } } }; url += (url.indexOf('?') === -1 ? '?' : '&') + 's=' + (new Date().getTime()); ajax.open('GET', url, this.async); ajax.send(); } }); module.exports = { WebLoader: WebLoader, PrecompiledLoader: PrecompiledLoader }; /***/ }, /* 15 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var path = __webpack_require__(3); var Obj = __webpack_require__(6); var lib = __webpack_require__(1); var Loader = Obj.extend({ on: function(name, func) { this.listeners = this.listeners || {}; this.listeners[name] = this.listeners[name] || []; this.listeners[name].push(func); }, emit: function(name /*, arg1, arg2, ...*/) { var args = Array.prototype.slice.call(arguments, 1); if(this.listeners && this.listeners[name]) { lib.each(this.listeners[name], function(listener) { listener.apply(null, args); }); } }, resolve: function(from, to) { return path.resolve(path.dirname(from), to); }, isRelative: function(filename) { return (filename.indexOf('./') === 0 || filename.indexOf('../') === 0); } }); module.exports = Loader; /***/ }, /* 16 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var Loader = __webpack_require__(15); var PrecompiledLoader = Loader.extend({ init: function(compiledTemplates) { this.precompiled = compiledTemplates || {}; }, getSource: function(name) { if (this.precompiled[name]) { return { src: { type: 'code', obj: this.precompiled[name] }, path: name }; } return null; } }); module.exports = PrecompiledLoader; /***/ }, /* 17 */ /***/ function(module, exports) { 'use strict'; function cycler(items) { var index = -1; return { current: null, reset: function() { index = -1; this.current = null; }, next: function() { index++; if(index >= items.length) { index = 0; } this.current = items[index]; return this.current; }, }; } function joiner(sep) { sep = sep || ','; var first = true; return function() { var val = first ? '' : sep; first = false; return val; }; } // Making this a function instead so it returns a new object // each time it's called. That way, if something like an environment // uses it, they will each have their own copy. function globals() { return { range: function(start, stop, step) { if(typeof stop === 'undefined') { stop = start; start = 0; step = 1; } else if(!step) { step = 1; } var arr = []; var i; if (step > 0) { for (i=start; istop; i+=step) { arr.push(i); } } return arr; }, // lipsum: function(n, html, min, max) { // }, cycler: function() { return cycler(Array.prototype.slice.call(arguments)); }, joiner: function(sep) { return joiner(sep); } }; } module.exports = globals; /***/ }, /* 18 */ /***/ function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(setImmediate, process) {// MIT license (by Elan Shanker). (function(globals) { 'use strict'; var executeSync = function(){ var args = Array.prototype.slice.call(arguments); if (typeof args[0] === 'function'){ args[0].apply(null, args.splice(1)); } }; var executeAsync = function(fn){ if (typeof setImmediate === 'function') { setImmediate(fn); } else if (typeof process !== 'undefined' && process.nextTick) { process.nextTick(fn); } else { setTimeout(fn, 0); } }; var makeIterator = function (tasks) { var makeCallback = function (index) { var fn = function () { if (tasks.length) { tasks[index].apply(null, arguments); } return fn.next(); }; fn.next = function () { return (index < tasks.length - 1) ? makeCallback(index + 1): null; }; return fn; }; return makeCallback(0); }; var _isArray = Array.isArray || function(maybeArray){ return Object.prototype.toString.call(maybeArray) === '[object Array]'; }; var waterfall = function (tasks, callback, forceAsync) { var nextTick = forceAsync ? executeAsync : executeSync; callback = callback || function () {}; if (!_isArray(tasks)) { var err = new Error('First argument to waterfall must be an array of functions'); return callback(err); } if (!tasks.length) { return callback(); } var wrapIterator = function (iterator) { return function (err) { if (err) { callback.apply(null, arguments); callback = function () {}; } else { var args = Array.prototype.slice.call(arguments, 1); var next = iterator.next(); if (next) { args.push(wrapIterator(next)); } else { args.push(callback); } nextTick(function () { iterator.apply(null, args); }); } }; }; wrapIterator(makeIterator(tasks))(); }; if (true) { !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return waterfall; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); // RequireJS } else if (typeof module !== 'undefined' && module.exports) { module.exports = waterfall; // CommonJS } else { globals.waterfall = waterfall; //