vue-carousel
Version:
A flexible, responsive, touch-friendly carousel for Vue.js
1,802 lines (1,649 loc) • 145 kB
JavaScript
/*! Swig v2.0.2 | https://node-swig.github.com/swig-templates | @license https://github.com/node-swig/swig-templates/blob/master/LICENSE */
/*! DateZ (c) 2011 Tomo Universalis | @license https://github.com/TomoUniversalis/DateZ/blob/master/LISENCE */
;(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var swig = require('../lib/swig');
if (typeof window.define === 'function' && typeof window.define.amd === 'object') {
window.define('swig', [], function () {
return swig;
});
} else {
window.swig = swig;
}
},{"../lib/swig":9}],2:[function(require,module,exports){
var utils = require('./utils');
var _months = {
full: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
abbr: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
},
_days = {
full: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
abbr: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
alt: {'-1': 'Yesterday', 0: 'Today', 1: 'Tomorrow'}
};
/*
DateZ is licensed under the MIT License:
Copyright (c) 2011 Tomo Universalis (http://tomouniversalis.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
exports.tzOffset = 0;
exports.DateZ = function () {
var members = {
'default': ['getUTCDate', 'getUTCDay', 'getUTCFullYear', 'getUTCHours', 'getUTCMilliseconds', 'getUTCMinutes', 'getUTCMonth', 'getUTCSeconds', 'toISOString', 'toGMTString', 'toUTCString', 'valueOf', 'getTime'],
z: ['getDate', 'getDay', 'getFullYear', 'getHours', 'getMilliseconds', 'getMinutes', 'getMonth', 'getSeconds', 'getYear', 'toDateString', 'toLocaleDateString', 'toLocaleTimeString']
},
d = this;
d.date = d.dateZ = (arguments.length > 1) ? new Date(Date.UTC.apply(Date, arguments) + ((new Date()).getTimezoneOffset() * 60000)) : (arguments.length === 1) ? new Date(new Date(arguments['0'])) : new Date();
d.timezoneOffset = d.dateZ.getTimezoneOffset();
utils.each(members.z, function (name) {
d[name] = function () {
return d.dateZ[name]();
};
});
utils.each(members['default'], function (name) {
d[name] = function () {
return d.date[name]();
};
});
this.setTimezoneOffset(exports.tzOffset);
};
exports.DateZ.prototype = {
getTimezoneOffset: function () {
return this.timezoneOffset;
},
setTimezoneOffset: function (offset) {
this.timezoneOffset = offset;
this.dateZ = new Date(this.date.getTime() + this.date.getTimezoneOffset() * 60000 - this.timezoneOffset * 60000);
return this;
}
};
// Day
exports.d = function (input) {
return (input.getDate() < 10 ? '0' : '') + input.getDate();
};
exports.D = function (input) {
return _days.abbr[input.getDay()];
};
exports.j = function (input) {
return input.getDate();
};
exports.l = function (input) {
return _days.full[input.getDay()];
};
exports.N = function (input) {
var d = input.getDay();
return (d >= 1) ? d : 7;
};
exports.S = function (input) {
var d = input.getDate();
return (d % 10 === 1 && d !== 11 ? 'st' : (d % 10 === 2 && d !== 12 ? 'nd' : (d % 10 === 3 && d !== 13 ? 'rd' : 'th')));
};
exports.w = function (input) {
return input.getDay();
};
exports.z = function (input, offset, abbr) {
var year = input.getFullYear(),
e = new exports.DateZ(year, input.getMonth(), input.getDate(), 12, 0, 0),
d = new exports.DateZ(year, 0, 1, 12, 0, 0);
e.setTimezoneOffset(offset, abbr);
d.setTimezoneOffset(offset, abbr);
return Math.round((e - d) / 86400000);
};
// Week
exports.W = function (input) {
var target = new Date(input.valueOf()),
dayNr = (input.getDay() + 6) % 7,
fThurs;
target.setDate(target.getDate() - dayNr + 3);
fThurs = target.valueOf();
target.setMonth(0, 1);
if (target.getDay() !== 4) {
target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
}
return 1 + Math.ceil((fThurs - target) / 604800000);
};
// Month
exports.F = function (input) {
return _months.full[input.getMonth()];
};
exports.m = function (input) {
return (input.getMonth() < 9 ? '0' : '') + (input.getMonth() + 1);
};
exports.M = function (input) {
return _months.abbr[input.getMonth()];
};
exports.n = function (input) {
return input.getMonth() + 1;
};
exports.t = function (input) {
return 32 - (new Date(input.getFullYear(), input.getMonth(), 32).getDate());
};
// Year
exports.L = function (input) {
return new Date(input.getFullYear(), 1, 29).getDate() === 29;
};
exports.o = function (input) {
var target = new Date(input.valueOf());
target.setDate(target.getDate() - ((input.getDay() + 6) % 7) + 3);
return target.getFullYear();
};
exports.Y = function (input) {
return input.getFullYear();
};
exports.y = function (input) {
return (input.getFullYear().toString()).substr(2);
};
// Time
exports.a = function (input) {
return input.getHours() < 12 ? 'am' : 'pm';
};
exports.A = function (input) {
return input.getHours() < 12 ? 'AM' : 'PM';
};
exports.B = function (input) {
var hours = input.getUTCHours(), beats;
hours = (hours === 23) ? 0 : hours + 1;
beats = Math.abs(((((hours * 60) + input.getUTCMinutes()) * 60) + input.getUTCSeconds()) / 86.4).toFixed(0);
return ('000'.concat(beats).slice(beats.length));
};
exports.g = function (input) {
var h = input.getHours();
return h === 0 ? 12 : (h > 12 ? h - 12 : h);
};
exports.G = function (input) {
return input.getHours();
};
exports.h = function (input) {
var h = input.getHours();
return ((h < 10 || (12 < h && 22 > h)) ? '0' : '') + ((h < 12) ? h : h - 12);
};
exports.H = function (input) {
var h = input.getHours();
return (h < 10 ? '0' : '') + h;
};
exports.i = function (input) {
var m = input.getMinutes();
return (m < 10 ? '0' : '') + m;
};
exports.s = function (input) {
var s = input.getSeconds();
return (s < 10 ? '0' : '') + s;
};
//u = function () { return ''; },
// Timezone
//e = function () { return ''; },
//I = function () { return ''; },
exports.O = function (input) {
var tz = input.getTimezoneOffset();
return (tz < 0 ? '-' : '+') + (tz / 60 < 10 ? '0' : '') + Math.abs((tz / 60)) + '00';
};
//T = function () { return ''; },
exports.Z = function (input) {
return input.getTimezoneOffset() * 60;
};
// Full Date/Time
exports.c = function (input) {
return input.toISOString();
};
exports.r = function (input) {
return input.toUTCString();
};
exports.U = function (input) {
return input.getTime() / 1000;
};
},{"./utils":26}],3:[function(require,module,exports){
var utils = require('./utils'),
dateFormatter = require('./dateformatter');
/**
* Helper method to recursively run a filter across an object/array and apply it to all of the object/array's values.
* @param {*} input
* @return {*}
* @private
*/
function iterateFilter(input) {
var self = this,
out = {};
if (utils.isArray(input)) {
return utils.map(input, function (value) {
return self.apply(null, arguments);
});
}
if (typeof input === 'object') {
utils.each(input, function (value, key) {
out[key] = self.apply(null, arguments);
});
return out;
}
return;
}
/**
* Backslash-escape characters that need to be escaped.
*
* @example
* {{ "\"quoted string\""|addslashes }}
* // => \"quoted string\"
*
* @param {*} input
* @return {*} Backslash-escaped string.
*/
exports.addslashes = function (input) {
var out = iterateFilter.apply(exports.addslashes, arguments);
if (out !== undefined) {
return out;
}
return input.replace(/\\/g, '\\\\').replace(/\'/g, "\\'").replace(/\"/g, '\\"');
};
/**
* Upper-case the first letter of the input and lower-case the rest.
*
* @example
* {{ "i like Burritos"|capitalize }}
* // => I like burritos
*
* @param {*} input If given an array or object, each string member will be run through the filter individually.
* @return {*} Returns the same type as the input.
*/
exports.capitalize = function (input) {
var out = iterateFilter.apply(exports.capitalize, arguments);
if (out !== undefined) {
return out;
}
return input.toString().charAt(0).toUpperCase() + input.toString().substr(1).toLowerCase();
};
/**
* Format a date or Date-compatible string.
*
* @example
* // now = new Date();
* {{ now|date('Y-m-d') }}
* // => 2013-08-14
* @example
* // now = new Date();
* {{ now|date('jS \o\f F') }}
* // => 4th of July
*
* @param {?(string|date)} input
* @param {string} format PHP-style date format compatible string. Escape characters with <code>\</code> for string literals.
* @param {number=} offset Timezone offset from GMT in minutes.
* @param {string=} abbr Timezone abbreviation. Used for output only.
* @return {string} Formatted date string.
*/
exports.date = function (input, format, offset, abbr) {
var l = format.length,
date = new dateFormatter.DateZ(input),
cur,
i = 0,
out = '';
if (offset) {
date.setTimezoneOffset(offset, abbr);
}
for (i; i < l; i += 1) {
cur = format.charAt(i);
if (cur === '\\') {
i += 1;
out += (i < l) ? format.charAt(i) : cur;
} else if (dateFormatter.hasOwnProperty(cur)) {
out += dateFormatter[cur](date, offset, abbr);
} else {
out += cur;
}
}
return out;
};
/**
* If the input is `undefined`, `null`, or `false`, a default return value can be specified.
*
* @example
* {{ null_value|default('Tacos') }}
* // => Tacos
*
* @example
* {{ "Burritos"|default("Tacos") }}
* // => Burritos
*
* @param {*} input
* @param {*} def Value to return if `input` is `undefined`, `null`, or `false`.
* @return {*} `input` or `def` value.
*/
exports["default"] = function (input, def) {
return (input !== undefined && (input || typeof input === 'number')) ? input : def;
};
/**
* Force escape the output of the variable. Optionally use `e` as a shortcut filter name. This filter will be applied by default if autoescape is turned on.
*
* @example
* {{ "<blah>"|escape }}
* // => <blah>
*
* @example
* {{ "<blah>"|e("js") }}
* // => \u003Cblah\u003E
*
* @param {*} input
* @param {string} [type='html'] If you pass the string js in as the type, output will be escaped so that it is safe for JavaScript execution.
* @return {string} Escaped string.
*/
exports.escape = function (input, type) {
var out = iterateFilter.apply(exports.escape, arguments),
inp = input,
i = 0,
code;
if (out !== undefined) {
return out;
}
if (typeof input !== 'string') {
return input;
}
out = '';
switch (type) {
case 'js':
inp = inp.replace(/\\/g, '\\u005C');
for (i; i < inp.length; i += 1) {
code = inp.charCodeAt(i);
if (code < 32) {
code = code.toString(16).toUpperCase();
code = (code.length < 2) ? '0' + code : code;
out += '\\u00' + code;
} else {
out += inp[i];
}
}
return out.replace(/&/g, '\\u0026')
.replace(/</g, '\\u003C')
.replace(/>/g, '\\u003E')
.replace(/\'/g, '\\u0027')
.replace(/"/g, '\\u0022')
.replace(/\=/g, '\\u003D')
.replace(/-/g, '\\u002D')
.replace(/;/g, '\\u003B');
default:
return inp.replace(/&(?!amp;|lt;|gt;|quot;|#39;)/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
};
exports.e = exports.escape;
/**
* Get the first item in an array or character in a string. All other objects will attempt to return the first value available.
*
* @example
* // my_arr = ['a', 'b', 'c']
* {{ my_arr|first }}
* // => a
*
* @example
* // my_val = 'Tacos'
* {{ my_val|first }}
* // T
*
* @param {*} input
* @return {*} The first item of the array or first character of the string input.
*/
exports.first = function (input) {
if (typeof input === 'object' && !utils.isArray(input)) {
var keys = utils.keys(input);
return input[keys[0]];
}
if (typeof input === 'string') {
return input.substr(0, 1);
}
return input[0];
};
/**
* Group an array of objects by a common key. If an array is not provided, the input value will be returned untouched.
*
* @example
* // people = [{ age: 23, name: 'Paul' }, { age: 26, name: 'Jane' }, { age: 23, name: 'Jim' }];
* {% for agegroup in people|groupBy('age') %}
* <h2>{{ loop.key }}</h2>
* <ul>
* {% for person in agegroup %}
* <li>{{ person.name }}</li>
* {% endfor %}
* </ul>
* {% endfor %}
*
* @param {*} input Input object.
* @param {string} key Key to group by.
* @return {object} Grouped arrays by given key.
*/
exports.groupBy = function (input, key) {
if (!utils.isArray(input)) {
return input;
}
var out = {};
utils.each(input, function (value) {
if (!value.hasOwnProperty(key)) {
return;
}
var keyname = value[key],
newValue = utils.extend({}, value);
delete newValue[key];
if (!out[keyname]) {
out[keyname] = [];
}
out[keyname].push(newValue);
});
return out;
};
/**
* Join the input with a string.
*
* @example
* // my_array = ['foo', 'bar', 'baz']
* {{ my_array|join(', ') }}
* // => foo, bar, baz
*
* @example
* // my_key_object = { a: 'foo', b: 'bar', c: 'baz' }
* {{ my_key_object|join(' and ') }}
* // => foo and bar and baz
*
* @param {*} input
* @param {string} glue String value to join items together.
* @return {string}
*/
exports.join = function (input, glue) {
if (utils.isArray(input)) {
return input.join(glue);
}
if (typeof input === 'object') {
var out = [];
utils.each(input, function (value) {
out.push(value);
});
return out.join(glue);
}
return input;
};
/**
* Return a string representation of an JavaScript object.
*
* Backwards compatible with swig@0.x.x using `json_encode`.
*
* @example
* // val = { a: 'b' }
* {{ val|json }}
* // => {"a":"b"}
*
* @example
* // val = { a: 'b' }
* {{ val|json(4) }}
* // => {
* // "a": "b"
* // }
*
* @param {*} input
* @param {number} [indent] Number of spaces to indent for pretty-formatting.
* @return {string} A valid JSON string.
*/
exports.json = function (input, indent) {
return JSON.stringify(input, null, indent || 0);
};
exports.json_encode = exports.json;
/**
* Get the last item in an array or character in a string. All other objects will attempt to return the last value available.
*
* @example
* // my_arr = ['a', 'b', 'c']
* {{ my_arr|last }}
* // => c
*
* @example
* // my_val = 'Tacos'
* {{ my_val|last }}
* // s
*
* @param {*} input
* @return {*} The last item of the array or last character of the string.input.
*/
exports.last = function (input) {
if (typeof input === 'object' && !utils.isArray(input)) {
var keys = utils.keys(input);
return input[keys[keys.length - 1]];
}
if (typeof input === 'string') {
return input.charAt(input.length - 1);
}
return input[input.length - 1];
};
/**
* Get the number of items in an array, string, or object.
*
* @example
* // my_arr = ['a', 'b', 'c']
* {{ my_arr|length }}
* // => 3
*
* @example
* // my_str = 'Tacos'
* {{ my_str|length }}
* // => 5
*
* @example
* // my_obj = {a: 5, b: 20}
* {{ my_obj|length }}
* // => 2
*
* @param {*} input
* @return {*} The length of the input
*/
exports.length = function (input) {
if (typeof input === 'object' && !utils.isArray(input)) {
var keys = utils.keys(input);
return keys.length;
}
if (input.hasOwnProperty('length')) {
return input.length;
}
return '';
};
/**
* Return the input in all lowercase letters.
*
* @example
* {{ "FOOBAR"|lower }}
* // => foobar
*
* @example
* // myObj = { a: 'FOO', b: 'BAR' }
* {{ myObj|lower|join('') }}
* // => foobar
*
* @param {*} input
* @return {*} Returns the same type as the input.
*/
exports.lower = function (input) {
var out = iterateFilter.apply(exports.lower, arguments);
if (out !== undefined) {
return out;
}
return input.toString().toLowerCase();
};
/**
* Deprecated in favor of <a href="#safe">safe</a>.
*/
exports.raw = function (input) {
return exports.safe(input);
};
exports.raw.safe = true;
/**
* Returns a new string with the matched search pattern replaced by the given replacement string. Uses JavaScript's built-in String.replace() method.
*
* @example
* // my_var = 'foobar';
* {{ my_var|replace('o', 'e', 'g') }}
* // => feebar
*
* @example
* // my_var = "farfegnugen";
* {{ my_var|replace('^f', 'p') }}
* // => parfegnugen
*
* @example
* // my_var = 'a1b2c3';
* {{ my_var|replace('\w', '0', 'g') }}
* // => 010203
*
* @param {string} input
* @param {string} search String or pattern to replace from the input.
* @param {string} replacement String to replace matched pattern.
* @param {string} [flags] Regular Expression flags. 'g': global match, 'i': ignore case, 'm': match over multiple lines
* @return {string} Replaced string.
*/
exports.replace = function (input, search, replacement, flags) {
var r = new RegExp(search, flags);
return input.replace(r, replacement);
};
/**
* Reverse sort the input. This is an alias for <code data-language="swig">{{ input|sort(true) }}</code>.
*
* @example
* // val = [1, 2, 3];
* {{ val|reverse }}
* // => 3,2,1
*
* @param {array} input
* @return {array} Reversed array. The original input object is returned if it was not an array.
*/
exports.reverse = function (input) {
return exports.sort(input, true);
};
/**
* Forces the input to not be auto-escaped. Use this only on content that you know is safe to be rendered on your page.
*
* @example
* // my_var = "<p>Stuff</p>";
* {{ my_var|safe }}
* // => <p>Stuff</p>
*
* @param {*} input
* @return {*} The input exactly how it was given, regardless of autoescaping status.
*/
exports.safe = function (input) {
// This is a magic filter. Its logic is hard-coded into Swig's parser.
return input;
};
exports.safe.safe = true;
/**
* Sort the input in an ascending direction.
* If given an object, will return the keys as a sorted array.
* If given a string, each character will be sorted individually.
*
* @example
* // val = [2, 6, 4];
* {{ val|sort }}
* // => 2,4,6
*
* @example
* // val = 'zaq';
* {{ val|sort }}
* // => aqz
*
* @example
* // val = { bar: 1, foo: 2 }
* {{ val|sort(true) }}
* // => foo,bar
*
* @param {*} input
* @param {boolean} [reverse=false] Output is given reverse-sorted if true.
* @return {*} Sorted array;
*/
exports.sort = function (input, reverse) {
var out, clone;
if (utils.isArray(input)) {
clone = utils.extend([], input);
out = clone.sort();
} else {
switch (typeof input) {
case 'object':
out = utils.keys(input).sort();
break;
case 'string':
out = input.split('');
if (reverse) {
return out.reverse().join('');
}
return out.sort().join('');
}
}
if (out && reverse) {
return out.reverse();
}
return out || input;
};
/**
* Strip HTML tags.
*
* @example
* // stuff = '<p>foobar</p>';
* {{ stuff|striptags }}
* // => foobar
*
* @param {*} input
* @return {*} Returns the same object as the input, but with all string values stripped of tags.
*/
exports.striptags = function (input) {
var out = iterateFilter.apply(exports.striptags, arguments);
if (out !== undefined) {
return out;
}
return input.toString().replace(/(<([^>]+)>)/ig, '');
};
/**
* Capitalizes every word given and lower-cases all other letters.
*
* @example
* // my_str = 'this is soMe text';
* {{ my_str|title }}
* // => This Is Some Text
*
* @example
* // my_arr = ['hi', 'this', 'is', 'an', 'array'];
* {{ my_arr|title|join(' ') }}
* // => Hi This Is An Array
*
* @param {*} input
* @return {*} Returns the same object as the input, but with all words in strings title-cased.
*/
exports.title = function (input) {
var out = iterateFilter.apply(exports.title, arguments);
if (out !== undefined) {
return out;
}
return input.toString().replace(/\w\S*/g, function (str) {
return str.charAt(0).toUpperCase() + str.substr(1).toLowerCase();
});
};
/**
* Remove all duplicate items from an array.
*
* @example
* // my_arr = [1, 2, 3, 4, 4, 3, 2, 1];
* {{ my_arr|uniq|join(',') }}
* // => 1,2,3,4
*
* @param {array} input
* @return {array} Array with unique items. If input was not an array, the original item is returned untouched.
*/
exports.uniq = function (input) {
var result;
if (!input || !utils.isArray(input)) {
return '';
}
result = [];
utils.each(input, function (v) {
if (result.indexOf(v) === -1) {
result.push(v);
}
});
return result;
};
/**
* Convert the input to all uppercase letters. If an object or array is provided, all values will be uppercased.
*
* @example
* // my_str = 'tacos';
* {{ my_str|upper }}
* // => TACOS
*
* @example
* // my_arr = ['tacos', 'burritos'];
* {{ my_arr|upper|join(' & ') }}
* // => TACOS & BURRITOS
*
* @param {*} input
* @return {*} Returns the same type as the input, with all strings upper-cased.
*/
exports.upper = function (input) {
var out = iterateFilter.apply(exports.upper, arguments);
if (out !== undefined) {
return out;
}
return input.toString().toUpperCase();
};
/**
* URL-encode a string. If an object or array is passed, all values will be URL-encoded.
*
* @example
* // my_str = 'param=1&anotherParam=2';
* {{ my_str|url_encode }}
* // => param%3D1%26anotherParam%3D2
*
* @param {*} input
* @return {*} URL-encoded string.
*/
exports.url_encode = function (input) {
var out = iterateFilter.apply(exports.url_encode, arguments);
if (out !== undefined) {
return out;
}
return encodeURIComponent(input);
};
/**
* URL-decode a string. If an object or array is passed, all values will be URL-decoded.
*
* @example
* // my_str = 'param%3D1%26anotherParam%3D2';
* {{ my_str|url_decode }}
* // => param=1&anotherParam=2
*
* @param {*} input
* @return {*} URL-decoded string.
*/
exports.url_decode = function (input) {
var out = iterateFilter.apply(exports.url_decode, arguments);
if (out !== undefined) {
return out;
}
return decodeURIComponent(input);
};
},{"./dateformatter":2,"./utils":26}],4:[function(require,module,exports){
var utils = require('./utils');
/**
* A lexer token.
* @typedef {object} LexerToken
* @property {string} match The string that was matched.
* @property {number} type Lexer type enum.
* @property {number} length Length of the original string processed.
*/
/**
* Enum for token types.
* @readonly
* @enum {number}
*/
var TYPES = {
/** Whitespace */
WHITESPACE: 0,
/** Plain string */
STRING: 1,
/** Variable filter */
FILTER: 2,
/** Empty variable filter */
FILTEREMPTY: 3,
/** Function */
FUNCTION: 4,
/** Function with no arguments */
FUNCTIONEMPTY: 5,
/** Open parenthesis */
PARENOPEN: 6,
/** Close parenthesis */
PARENCLOSE: 7,
/** Comma */
COMMA: 8,
/** Variable */
VAR: 9,
/** Number */
NUMBER: 10,
/** Math operator */
OPERATOR: 11,
/** Open square bracket */
BRACKETOPEN: 12,
/** Close square bracket */
BRACKETCLOSE: 13,
/** Key on an object using dot-notation */
DOTKEY: 14,
/** Start of an array */
ARRAYOPEN: 15,
/** End of an array
* Currently unused
ARRAYCLOSE: 16, */
/** Open curly brace */
CURLYOPEN: 17,
/** Close curly brace */
CURLYCLOSE: 18,
/** Colon (:) */
COLON: 19,
/** JavaScript-valid comparator */
COMPARATOR: 20,
/** Boolean logic */
LOGIC: 21,
/** Boolean logic "not" */
NOT: 22,
/** true or false */
BOOL: 23,
/** Variable assignment */
ASSIGNMENT: 24,
/** Start of a method */
METHODOPEN: 25,
/** End of a method
* Currently unused
METHODEND: 26, */
/** Unknown type */
UNKNOWN: 100
},
rules = [
{
type: TYPES.WHITESPACE,
regex: [
/^\s+/
]
},
{
type: TYPES.STRING,
regex: [
/^""/,
/^".*?[^\\]"/,
/^''/,
/^'.*?[^\\]'/
]
},
{
type: TYPES.FILTER,
regex: [
/^\|\s*(\w+)\(/
],
idx: 1
},
{
type: TYPES.FILTEREMPTY,
regex: [
/^\|\s*(\w+)/
],
idx: 1
},
{
type: TYPES.FUNCTIONEMPTY,
regex: [
/^\s*(\w+)\(\)/
],
idx: 1
},
{
type: TYPES.FUNCTION,
regex: [
/^\s*(\w+)\(/
],
idx: 1
},
{
type: TYPES.PARENOPEN,
regex: [
/^\(/
]
},
{
type: TYPES.PARENCLOSE,
regex: [
/^\)/
]
},
{
type: TYPES.COMMA,
regex: [
/^,/
]
},
{
type: TYPES.LOGIC,
regex: [
/^(&&|\|\|)\s*/,
/^(and|or)\s+/
],
idx: 1,
replace: {
'and': '&&',
'or': '||'
}
},
{
type: TYPES.COMPARATOR,
regex: [
/^(===|==|\!==|\!=|<=|<|>=|>|in\s|gte\s|gt\s|lte\s|lt\s)\s*/
],
idx: 1,
replace: {
'gte': '>=',
'gt': '>',
'lte': '<=',
'lt': '<'
}
},
{
type: TYPES.ASSIGNMENT,
regex: [
/^(=|\+=|-=|\*=|\/=)/
]
},
{
type: TYPES.NOT,
regex: [
/^\!\s*/,
/^not\s+/
],
replace: {
'not': '!'
}
},
{
type: TYPES.BOOL,
regex: [
/^(true|false)\s+/,
/^(true|false)$/
],
idx: 1
},
{
type: TYPES.VAR,
regex: [
/^[a-zA-Z_$]\w*((\.\$?\w*)+)?/,
/^[a-zA-Z_$]\w*/
]
},
{
type: TYPES.BRACKETOPEN,
regex: [
/^\[/
]
},
{
type: TYPES.BRACKETCLOSE,
regex: [
/^\]/
]
},
{
type: TYPES.CURLYOPEN,
regex: [
/^\{/
]
},
{
type: TYPES.COLON,
regex: [
/^\:/
]
},
{
type: TYPES.CURLYCLOSE,
regex: [
/^\}/
]
},
{
type: TYPES.DOTKEY,
regex: [
/^\.(\w+)/
],
idx: 1
},
{
type: TYPES.NUMBER,
regex: [
/^[+\-]?\d+(\.\d+)?/
]
},
{
type: TYPES.OPERATOR,
regex: [
/^(\+|\-|\/|\*|%)/
]
}
];
exports.types = TYPES;
/**
* Return the token type object for a single chunk of a string.
* @param {string} str String chunk.
* @return {LexerToken} Defined type, potentially stripped or replaced with more suitable content.
* @private
*/
function reader(str) {
var matched;
utils.some(rules, function (rule) {
return utils.some(rule.regex, function (regex) {
var match = str.match(regex),
normalized;
if (!match) {
return;
}
normalized = match[rule.idx || 0].replace(/\s*$/, '');
normalized = (rule.hasOwnProperty('replace') && rule.replace.hasOwnProperty(normalized)) ? rule.replace[normalized] : normalized;
matched = {
match: normalized,
type: rule.type,
length: match[0].length
};
return true;
});
});
if (!matched) {
matched = {
match: str,
type: TYPES.UNKNOWN,
length: str.length
};
}
return matched;
}
/**
* Read a string and break it into separate token types.
* @param {string} str
* @return {Array.LexerToken} Array of defined types, potentially stripped or replaced with more suitable content.
* @private
*/
exports.read = function (str) {
var offset = 0,
tokens = [],
substr,
match;
while (offset < str.length) {
substr = str.substring(offset);
match = reader(substr);
offset += match.length;
tokens.push(match);
}
return tokens;
};
},{"./utils":26}],5:[function(require,module,exports){
var process=require("__browserify_process");var fs = require('fs'),
path = require('path');
/**
* Loads templates from the file system.
* @alias swig.loaders.fs
* @example
* swig.setDefaults({ loader: swig.loaders.fs() });
* @example
* // Load Templates from a specific directory (does not require using relative paths in your templates)
* swig.setDefaults({ loader: swig.loaders.fs(__dirname + '/templates' )});
* @param {string} [basepath=''] Path to the templates as string. Assigning this value allows you to use semi-absolute paths to templates instead of relative paths.
* @param {string} [encoding='utf8'] Template encoding
*/
module.exports = function (basepath, encoding) {
var ret = {};
encoding = encoding || 'utf8';
basepath = basepath ? path.normalize(basepath) : null;
/**
* Resolves <var>to</var> to an absolute path or unique identifier. This is used for building correct, normalized, and absolute paths to a given template.
* @alias resolve
* @param {string} to Non-absolute identifier or pathname to a file.
* @param {string} [from] If given, should attempt to find the <var>to</var> path in relation to this given, known path.
* @return {string}
*/
ret.resolve = function (to, from) {
if (basepath) {
from = basepath;
} else {
from = from ? path.dirname(from) : process.cwd();
}
return path.resolve(from, to);
};
/**
* Loads a single template. Given a unique <var>identifier</var> found by the <var>resolve</var> method this should return the given template.
* @alias load
* @param {string} identifier Unique identifier of a template (possibly an absolute path).
* @param {function} [cb] Asynchronous callback function. If not provided, this method should run synchronously.
* @return {string} Template source string.
*/
ret.load = function (identifier, cb) {
if (!fs || (cb && !fs.readFile) || !fs.readFileSync) {
throw new Error('Unable to find file ' + identifier + ' because there is no filesystem to read from.');
}
identifier = ret.resolve(identifier);
if (cb) {
fs.readFile(identifier, encoding, cb);
return;
}
return fs.readFileSync(identifier, encoding);
};
return ret;
};
},{"__browserify_process":31,"fs":28,"path":29}],6:[function(require,module,exports){
/**
* @namespace TemplateLoader
* @description Swig is able to accept custom template loaders written by you, so that your templates can come from your favorite storage medium without needing to be part of the core library.
* A template loader consists of two methods: <var>resolve</var> and <var>load</var>. Each method is used internally by Swig to find and load the source of the template before attempting to parse and compile it.
* @example
* // A theoretical memcached loader
* var path = require('path'),
* Memcached = require('memcached');
* function memcachedLoader(locations, options) {
* var memcached = new Memcached(locations, options);
* return {
* resolve: function (to, from) {
* return path.resolve(from, to);
* },
* load: function (identifier, cb) {
* memcached.get(identifier, function (err, data) {
* // if (!data) { load from filesystem; }
* cb(err, data);
* });
* }
* };
* };
* // Tell swig about the loader:
* swig.setDefaults({ loader: memcachedLoader(['192.168.0.2']) });
*/
/**
* @function
* @name resolve
* @memberof TemplateLoader
* @description
* Resolves <var>to</var> to an absolute path or unique identifier. This is used for building correct, normalized, and absolute paths to a given template.
* @param {string} to Non-absolute identifier or pathname to a file.
* @param {string} [from] If given, should attempt to find the <var>to</var> path in relation to this given, known path.
* @return {string}
*/
/**
* @function
* @name load
* @memberof TemplateLoader
* @description
* Loads a single template. Given a unique <var>identifier</var> found by the <var>resolve</var> method this should return the given template.
* @param {string} identifier Unique identifier of a template (possibly an absolute path).
* @param {function} [cb] Asynchronous callback function. If not provided, this method should run synchronously.
* @return {string} Template source string.
*/
/**
* @private
*/
exports.fs = require('./filesystem');
exports.memory = require('./memory');
},{"./filesystem":5,"./memory":7}],7:[function(require,module,exports){
var path = require('path'),
utils = require('../utils');
/**
* Loads templates from a provided object mapping.
* @alias swig.loaders.memory
* @example
* var templates = {
* "layout": "{% block content %}{% endblock %}",
* "home.html": "{% extends 'layout.html' %}{% block content %}...{% endblock %}"
* };
* swig.setDefaults({ loader: swig.loaders.memory(templates) });
*
* @param {object} mapping Hash object with template paths as keys and template sources as values.
* @param {string} [basepath] Path to the templates as string. Assigning this value allows you to use semi-absolute paths to templates instead of relative paths.
*/
module.exports = function (mapping, basepath) {
var ret = {};
basepath = basepath ? path.normalize(basepath) : null;
/**
* Resolves <var>to</var> to an absolute path or unique identifier. This is used for building correct, normalized, and absolute paths to a given template.
* @alias resolve
* @param {string} to Non-absolute identifier or pathname to a file.
* @param {string} [from] If given, should attempt to find the <var>to</var> path in relation to this given, known path.
* @return {string}
*/
ret.resolve = function (to, from) {
if (basepath) {
from = basepath;
} else {
from = from ? path.dirname(from) : '/';
}
return path.resolve(from, to);
};
/**
* Loads a single template. Given a unique <var>identifier</var> found by the <var>resolve</var> method this should return the given template.
* @alias load
* @param {string} identifier Unique identifier of a template (possibly an absolute path).
* @param {function} [cb] Asynchronous callback function. If not provided, this method should run synchronously.
* @return {string} Template source string.
*/
ret.load = function (pathname, cb) {
var src, paths;
paths = [pathname, pathname.replace(/^(\/|\\)/, '')];
src = mapping[paths[0]] || mapping[paths[1]];
if (!src) {
utils.throwError('Unable to find template "' + pathname + '".');
}
if (cb) {
cb(null, src);
return;
}
return src;
};
return ret;
};
},{"../utils":26,"path":29}],8:[function(require,module,exports){
var utils = require('./utils'),
lexer = require('./lexer');
var _t = lexer.types,
_reserved = ['break', 'case', 'catch', 'continue', 'debugger', 'default', 'delete', 'do', 'else', 'finally', 'for', 'function', 'if', 'in', 'instanceof', 'new', 'return', 'switch', 'this', 'throw', 'try', 'typeof', 'var', 'void', 'while', 'with'];
/**
* Filters are simply functions that perform transformations on their first input argument.
* Filters are run at render time, so they may not directly modify the compiled template structure in any way.
* All of Swig's built-in filters are written in this same way. For more examples, reference the `filters.js` file in Swig's source.
*
* To disable auto-escaping on a custom filter, simply add a property to the filter method `safe = true;` and the output from this will not be escaped, no matter what the global settings are for Swig.
*
* @typedef {function} Filter
*
* @example
* // This filter will return 'bazbop' if the idx on the input is not 'foobar'
* swig.setFilter('foobar', function (input, idx) {
* return input[idx] === 'foobar' ? input[idx] : 'bazbop';
* });
* // myvar = ['foo', 'bar', 'baz', 'bop'];
* // => {{ myvar|foobar(3) }}
* // Since myvar[3] !== 'foobar', we render:
* // => bazbop
*
* @example
* // This filter will disable auto-escaping on its output:
* function bazbop (input) { return input; }
* bazbop.safe = true;
* swig.setFilter('bazbop', bazbop);
* // => {{ "<p>"|bazbop }}
* // => <p>
*
* @param {*} input Input argument, automatically sent from Swig's built-in parser.
* @param {...*} [args] All other arguments are defined by the Filter author.
* @return {*}
*/
/*!
* Makes a string safe for a regular expression.
* @param {string} str
* @return {string}
* @private
*/
function escapeRegExp(str) {
return str.replace(/[\-\/\\\^$*+?.()|\[\]{}]/g, '\\$&');
}
/**
* Parse strings of variables and tags into tokens for future compilation.
* @class
* @param {array} tokens Pre-split tokens read by the Lexer.
* @param {object} filters Keyed object of filters that may be applied to variables.
* @param {boolean} autoescape Whether or not this should be autoescaped.
* @param {number} line Beginning line number for the first token.
* @param {string} [filename] Name of the file being parsed.
* @private
*/
function TokenParser(tokens, filters, autoescape, line, filename) {
this.out = [];
this.state = [];
this.filterApplyIdx = [];
this._parsers = {};
this.line = line;
this.filename = filename;
this.filters = filters;
this.escape = autoescape;
this.parse = function () {
var self = this;
if (self._parsers.start) {
self._parsers.start.call(self);
}
utils.each(tokens, function (token, i) {
var prevToken = tokens[i - 1];
self.isLast = (i === tokens.length - 1);
if (prevToken) {
while (prevToken.type === _t.WHITESPACE) {
i -= 1;
prevToken = tokens[i - 1];
}
}
self.prevToken = prevToken;
self.parseToken(token);
});
if (self._parsers.end) {
self._parsers.end.call(self);
}
if (self.escape) {
self.filterApplyIdx = [0];
if (typeof self.escape === 'string') {
self.parseToken({ type: _t.FILTER, match: 'e' });
self.parseToken({ type: _t.COMMA, match: ',' });
self.parseToken({ type: _t.STRING, match: String(autoescape) });
self.parseToken({ type: _t.PARENCLOSE, match: ')'});
} else {
self.parseToken({ type: _t.FILTEREMPTY, match: 'e' });
}
}
return self.out;
};
}
TokenParser.prototype = {
/**
* Set a custom method to be called when a token type is found.
*
* @example
* parser.on(types.STRING, function (token) {
* this.out.push(token.match);
* });
* @example
* parser.on('start', function () {
* this.out.push('something at the beginning of your args')
* });
* parser.on('end', function () {
* this.out.push('something at the end of your args');
* });
*
* @param {number} type Token type ID. Found in the Lexer.
* @param {Function} fn Callback function. Return true to continue executing the default parsing function.
* @return {undefined}
*/
on: function (type, fn) {
this._parsers[type] = fn;
},
/**
* Parse a single token.
* @param {{match: string, type: number, line: number}} token Lexer token object.
* @return {undefined}
* @private
*/
parseToken: function (token) {
var self = this,
fn = self._parsers[token.type] || self._parsers['*'],
match = token.match,
prevToken = self.prevToken,
prevTokenType = prevToken ? prevToken.type : null,
lastState = (self.state.length) ? self.state[self.state.length - 1] : null,
temp;
if (fn && typeof fn === 'function') {
if (!fn.call(this, token)) {
return;
}
}
if (lastState && prevToken &&
lastState === _t.FILTER &&
prevTokenType === _t.FILTER &&
token.type !== _t.PARENCLOSE &&
token.type !== _t.COMMA &&
token.type !== _t.OPERATOR &&
token.type !== _t.FILTER &&
token.type !== _t.FILTEREMPTY) {
self.out.push(', ');
}
if (lastState && lastState === _t.METHODOPEN) {
self.state.pop();
if (token.type !== _t.PARENCLOSE) {
self.out.push(', ');
}
}
switch (token.type) {
case _t.WHITESPACE:
break;
case _t.STRING:
self.filterApplyIdx.push(self.out.length);
self.out.push(match.replace(/\\/g, '\\\\'));
break;
case _t.NUMBER:
case _t.BOOL:
self.filterApplyIdx.push(self.out.length);
self.out.push(match);
break;
case _t.FILTER:
if (!self.filters.hasOwnProperty(match) || typeof self.filters[match] !== "function") {
utils.throwError('Invalid filter "' + match + '"', self.line, self.filename);
}
self.escape = self.filters[match].safe ? false : self.escape;
self.out.splice(self.filterApplyIdx[self.filterApplyIdx.length - 1], 0, '_filters["' + match + '"](');
self.state.push(token.type);
break;
case _t.FILTEREMPTY:
if (!self.filters.hasOwnProperty(match) || typeof self.filters[match] !== "function") {
utils.throwError('Invalid filter "' + match + '"', self.line, self.filename);
}
self.escape = self.filters[match].safe ? false : self.escape;
self.out.splice(self.filterApplyIdx[self.filterApplyIdx.length - 1], 0, '_filters["' + match + '"](');
self.out.push(')');
break;
case _t.FUNCTION:
case _t.FUNCTIONEMPTY:
self.out.push('((typeof _ctx.' + match + ' !== "undefined") ? _ctx.' + match +
' : ((typeof ' + match + ' !== "undefined") ? ' + match +
' : _fn))(');
self.escape = false;
if (token.type === _t.FUNCTIONEMPTY) {
self.out[self.out.length - 1] = self.out[self.out.length - 1] + ')';
} else {
self.state.push(token.type);
}
self.filterApplyIdx.push(self.out.length - 1);
break;
case _t.PARENOPEN:
self.state.push(token.type);
if (self.filterApplyIdx.length) {
self.out.splice(self.filterApplyIdx[self.filterApplyIdx.length - 1], 0, '(');
if (prevToken && prevTokenType === _t.VAR) {
temp = prevToken.match.split('.').slice(0, -1);
self.out.push(' || _fn).call(' + self.checkMatch(temp));
self.state.push(_t.METHODOPEN);
self.escape = false;
} else {
self.out.push(' || _fn)(');
}
self.filterApplyIdx.push(self.out.length - 3);
} else {
self.out.push('(');
self.filterApplyIdx.push(self.out.length - 1);
}
break;
case _t.PARENCLOSE:
temp = self.state.pop();
if (temp !== _t.PARENOPEN && temp !== _t.FUNCTION && temp !== _t.FILTER) {
utils.throwError('Mismatched nesting state', self.line, self.filename);
}
self.out.push(')');
// Once off the previous entry
self.filterApplyIdx.pop();
if (temp !== _t.FILTER) {
// Once for the open paren
self.filterApplyIdx.pop();
}
break;
case _t.COMMA:
if (lastState !== _t.FUNCTION &&
lastState !== _t.FILTER &&
lastState !== _t.ARRAYOPEN &&
lastState !== _t.CURLYOPEN &&
lastState !== _t.PARENOPEN &&
lastState !== _t.COLON) {
utils.throwError('Unexpected comma', self.line, self.filename);
}
if (lastState === _t.COLON) {
self.state.pop();
}
self.out.push(', ');
self.filterApplyIdx.pop();
break;
case _t.LOGIC:
case _t.COMPARATOR:
if (!prevToken ||
prevTokenType === _t.COMMA ||
prevTokenType === token.type ||
prevTokenType === _t.BRACKETOPEN ||
prevTokenType === _t.CURLYOPEN ||
prevTokenType === _t.PARENOPEN ||
prevTokenType === _t.FUNCTION) {
utils.throwError('Unexpected logic', self.line, self.filename);
}
self.out.push(token.match);
break;
case _t.NOT:
self.out.push(token.match);
break;
case _t.VAR:
self.parseVar(token, match, lastState);
break;
case _t.BRACKETOPEN:
if (!prevToken ||
(prevTokenType !== _t.VAR &&
prevTokenType !== _t.BRACKETCLOSE &&
prevTokenType !== _t.PARENCLOSE)) {
self.state.push(_t.ARRAYOPEN);
self.filterApplyIdx.push(self.out.length);
} else {
self.state.push(token.type);
}
self.out.push('[');
break;
case _t.BRACKETCLOSE:
temp = self.state.pop();
if (temp !== _t.BRACKETOPEN && temp !== _t.ARRAYOPEN) {
utils.throwError('Unexpected closing square bracket', self.line, self.filename);
}
self.out.push(']');
self.filterApplyIdx.pop();
break;
case _t.CURLYOPEN:
self.state.push(token.type);
self.out.push('{');
self.filterApplyIdx.push(self.out.length - 1);
break;
case _t.COLON:
if (lastState !== _t.CURLYOPEN) {
utils.throwError('Unexpected colon', self.line, self.filename);
}
self.state.push(token.type);
self.out.push(':');
self.filterApplyIdx.pop();
break;
case _t.CURLYCLOSE:
if (lastState === _t.COLON) {
self.state.pop();
}
if (self.state.pop() !== _t.CURLYOPEN) {
utils.throwError('Unexpected closing curly brace', self.line, self.filename);
}
self.out.push('}');
self.filterApplyIdx.pop();
break;
case _t.DOTKEY:
if (!prevToken || (
prevTokenType !== _t.VAR &&
prevTokenType !== _t.BRACKETCLOSE &&
prevTokenType !== _t.DOTKEY &&
prevTokenType !== _t.PARENCLOSE &&
prevTokenType !== _t.FUNCTIONEMPTY &&
prevTokenType !== _t.FILTEREMPTY &&
prevTokenType !== _t.CURLYCLOSE
)) {
utils.throwError('Unexpected key "' + match + '"', self.line, self.filename);
}
self.out.push('.' + match);
break;
case _t.OPERATOR:
self.out.push(' ' + match + ' ');
self.filterApplyIdx.pop();
break;
}
},
/**
* Parse variable token
* @param {{match: string, type: number, line: number}} token Lexer token object.
* @param {string} match Shortcut for token.match
* @param {number} lastState Lexer token type state.
* @return {undefined}
* @private
*/
parseVar: function (token, match, lastState) {
var self = this;
match = match.split('.');
if (_reserved.indexOf(match[0]) !== -1) {
utils.throwError('Reserved keyword "' + match[0] + '" attempted to be used as a variable', self.line, self.filename);
}
self.filterApplyIdx.push(self.out.length);
if (lastState === _t.CURLYOPEN) {
if (match.length > 1) {
utils.throwError('Unexpected dot', self.line, self.filename);
}
self.out.push(match[0]);
return;
}
self.out.push(self.checkMatch(match));
},
/**
* Return contextual dot-check string for a match
* @param {string} match Shortcut for token.match
* @private
*/
checkMatch: function (match) {
var temp = match[0], result;
function checkDot(ctx) {
var c = ctx + temp,
m = match,
build = '';
build = '(typeof ' + c + ' !== "undefined" && ' + c + ' !== null';
utils.each(m, function (v, i) {
if (i === 0) {
return;
}
build += ' && ' + c + '.' + v + ' !== undefined && ' + c + '.' + v + ' !== null';
c += '.' + v;
});
build += ')';
return build;
}
function buildDot(ctx) {
return '(' + checkDot(ctx) + ' ? ' + ctx + match.join('.') + ' : "")';
}
result = '(' + checkDot('_ctx.') + ' ? ' + buildDot('_ctx.') + ' : ' + buildDot('') + ')';
return '(' + result + ' !== null ? ' + result + ' : ' + '"" )';
}
};
/**
* Parse a source string into tokens that are ready for compilation.
*
* @example
* exports.parse('{{ tacos }}', {}, tags, filters);
* // => [{ compile: [Function], ... }]
*
* @params {object} swig The current Swig instance
* @param {string} source Swig template source.
* @param {object} opts Swig options object.
* @param {object} tags Keyed object of tags that can be parsed and compiled.
* @param {object} filters Keyed objec