Jump To …

twig.lib.js

twig.lib.js

This file contains 3rd party libraries used within twig.

Copies of the licenses for the code included here can be found in the LICENSES.md file.

var Twig = (function(Twig) {

Namespace for libraries

    Twig.lib = { };

    /**
    sprintf() for JavaScript 0.7-beta1
    http://www.diveintojavascript.com/projects/javascript-sprintf
    **/
    var sprintf = (function() {
            function get_type(variable) {
                    return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
            }
            function str_repeat(input, multiplier) {
                    for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
                    return output.join('');
            }

            var str_format = function() {
                    if (!str_format.cache.hasOwnProperty(arguments[0])) {
                            str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
                    }
                    return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
            };

            str_format.format = function(parse_tree, argv) {
                    var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
                    for (i = 0; i < tree_length; i++) {
                            node_type = get_type(parse_tree[i]);
                            if (node_type === 'string') {
                                    output.push(parse_tree[i]);
                            }
                            else if (node_type === 'array') {
                                    match = parse_tree[i]; // convenience purposes only
                                    if (match[2]) { // keyword argument
                                            arg = argv[cursor];
                                            for (k = 0; k < match[2].length; k++) {
                                                    if (!arg.hasOwnProperty(match[2][k])) {
                                                            throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));
                                                    }
                                                    arg = arg[match[2][k]];
                                            }
                                    }
                                    else if (match[1]) { // positional argument (explicit)
                                            arg = argv[match[1]];
                                    }
                                    else { // positional argument (implicit)
                                            arg = argv[cursor++];
                                    }

                                    if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
                                            throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));
                                    }
                                    switch (match[8]) {
                                            case 'b': arg = arg.toString(2); break;
                                            case 'c': arg = String.fromCharCode(arg); break;
                                            case 'd': arg = parseInt(arg, 10); break;
                                            case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
                                            case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
                                            case 'o': arg = arg.toString(8); break;
                                            case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
                                            case 'u': arg = Math.abs(arg); break;
                                            case 'x': arg = arg.toString(16); break;
                                            case 'X': arg = arg.toString(16).toUpperCase(); break;
                                    }
                                    arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
                                    pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
                                    pad_length = match[6] - String(arg).length;
                                    pad = match[6] ? str_repeat(pad_character, pad_length) : '';
                                    output.push(match[5] ? arg + pad : pad + arg);
                            }
                    }
                    return output.join('');
            };

            str_format.cache = {};

            str_format.parse = function(fmt) {
                    var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
                    while (_fmt) {
                            if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
                                    parse_tree.push(match[0]);
                            }
                            else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
                                    parse_tree.push('%');
                            }
                            else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
                                    if (match[2]) {
                                            arg_names |= 1;
                                            var field_list = [], replacement_field = match[2], field_match = [];
                                            if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
                                                    field_list.push(field_match[1]);
                                                    while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
                                                            if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
                                                                    field_list.push(field_match[1]);
                                                            }
                                                            else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
                                                                    field_list.push(field_match[1]);
                                                            }
                                                            else {
                                                                    throw('[sprintf] huh?');
                                                            }
                                                    }
                                            }
                                            else {
                                                    throw('[sprintf] huh?');
                                            }
                                            match[2] = field_list;
                                    }
                                    else {
                                            arg_names |= 2;
                                    }
                                    if (arg_names === 3) {
                                            throw('[sprintf] mixing positional and named placeholders is not (yet) supported');
                                    }
                                    parse_tree.push(match);
                            }
                            else {
                                    throw('[sprintf] huh?');
                            }
                            _fmt = _fmt.substring(match[0].length);
                    }
                    return parse_tree;
            };

            return str_format;
    })();

    var vsprintf = function(fmt, argv) {
     	argv.unshift(fmt);
        return sprintf.apply(null, argv);
    };

Expose to Twig

    Twig.lib.sprintf = sprintf;
    Twig.lib.vsprintf = vsprintf;


    /**
     * jPaq - A fully customizable JavaScript/JScript library
     * http://jpaq.org/
     *
     * Copyright (c) 2011 Christopher West
     * Licensed under the MIT license.
     * http://jpaq.org/license/
     *
     * Version: 1.0.6.0000W
     * Revised: April 6, 2011
     */
    ; (function() {
        var shortDays = "Sun,Mon,Tue,Wed,Thu,Fri,Sat".split(",");
        var fullDays = "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday".split(",");
        var shortMonths = "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec".split(",");
        var fullMonths = "January,February,March,April,May,June,July,August,September,October,November,December".split(",");
        function getOrdinalFor(intNum) {
                return (((intNum = Math.abs(intNum) % 100) % 10 == 1 && intNum != 11) ? "st"
                        : (intNum % 10 == 2 && intNum != 12) ? "nd" : (intNum % 10 == 3
                        && intNum != 13) ? "rd" : "th");
        }
        function getISO8601Year(aDate) {
                var d = new Date(aDate.getFullYear() + 1, 0, 4);
                if((d - aDate) / 86400000 < 7 && (aDate.getDay() + 6) % 7 < (d.getDay() + 6) % 7)
                        return d.getFullYear();
                if(aDate.getMonth() > 0 || aDate.getDate() >= 4)
                        return aDate.getFullYear();
                return aDate.getFullYear() - (((aDate.getDay() + 6) % 7 - aDate.getDate() > 2) ? 1 : 0);
        }
        function getISO8601Week(aDate) {

Get a day during the first week of the year.

                var d = new Date(getISO8601Year(aDate), 0, 4);

Get the first monday of the year.

                d.setDate(d.getDate() - (d.getDay() + 6) % 7);
                return parseInt((aDate - d) / 604800000) + 1;
        }
        Twig.lib.formatDate = function(date, format) {

/

/ Gets a string for this date, formatted according to the given format / string. / / / The format of the output date string. The format string works in a / nearly identical way to the PHP date function which is highlighted here: / http://php.net/manual/en/function.date.php. / The only difference is the fact that "u" signifies milliseconds / instead of microseconds. The following characters are recognized in / the format parameter string: / d - Day of the month, 2 digits with leading zeros / D - A textual representation of a day, three letters / j - Day of the month without leading zeros / l (lowercase 'L') - A full textual representation of the day of the week / N - ISO-8601 numeric representation of the day of the week (starting from 1) / S - English ordinal suffix for the day of the month, 2 characters st, / nd, rd or th. Works well with j. / w - Numeric representation of the day of the week (starting from 0) / z - The day of the year (starting from 0) / W - ISO-8601 week number of year, weeks starting on Monday / F - A full textual representation of a month, such as January or March / m - Numeric representation of a month, with leading zeros / M - A short textual representation of a month, three letters / n - Numeric representation of a month, without leading zeros / t - Number of days in the given month / L - Whether it's a leap year / o - ISO-8601 year number. This has the same value as Y, except that if / the ISO week number (W) belongs to the previous or next year, that / year is used instead. / Y - A full numeric representation of a year, 4 digits / y - A two digit representation of a year / a - Lowercase Ante meridiem and Post meridiem / A - Uppercase Ante meridiem and Post meridiem / B - Swatch Internet time / g - 12-hour format of an hour without leading zeros / G - 24-hour format of an hour without leading zeros / h - 12-hour format of an hour with leading zeros / H - 24-hour format of an hour with leading zeros / i - Minutes with leading zeros / s - Seconds, with leading zeros / u - Milliseconds / / / Returns the string for this date, formatted according to the given / format string. / If the format was not passed, use the default toString method.

            if(typeof format !== "string" || /^\s*$/.test(format))
                    return date + "";
            var jan1st = new Date(date.getFullYear(), 0, 1);
            var me = date;
            return format.replace(/[dDjlNSwzWFmMntLoYyaABgGhHisu]/g, function(option) {
                switch(option) {

Day of the month, 2 digits with leading zeros

                    case "d": return ("0" + me.getDate()).replace(/^.+(..)$/, "$1");

A textual representation of a day, three letters

                    case "D": return shortDays[me.getDay()];

Day of the month without leading zeros

                    case "j": return me.getDate();

A full textual representation of the day of the week

                    case "l": return fullDays[me.getDay()];

ISO-8601 numeric representation of the day of the week

                    case "N": return (me.getDay() + 6) % 7 + 1;

English ordinal suffix for the day of the month, 2 characters

                    case "S": return getOrdinalFor(me.getDate());

Numeric representation of the day of the week

                    case "w": return me.getDay();

The day of the year (starting from 0)

                    case "z": return Math.ceil((jan1st - me) / 86400000);

ISO-8601 week number of year, weeks starting on Monday

                    case "W": return ("0" + getISO8601Week(me)).replace(/^.(..)$/, "$1");

A full textual representation of a month, such as January or March

                    case "F": return fullMonths[me.getMonth()];

Numeric representation of a month, with leading zeros

                    case "m": return ("0" + (me.getMonth() + 1)).replace(/^.+(..)$/, "$1");

A short textual representation of a month, three letters

                    case "M": return shortMonths[me.getMonth()];

Numeric representation of a month, without leading zeros

                    case "n": return me.getMonth() + 1;

Number of days in the given month

                    case "t": return new Date(me.getFullYear(), me.getMonth() + 1, -1).getDate();

Whether it's a leap year

                    case "L": return new Date(me.getFullYear(), 1, 29).getDate() == 29 ? 1 : 0;

ISO-8601 year number. This has the same value as Y, except that if the ISO week number (W) belongs to the previous or next year, that year is used instead.

                    case "o": return getISO8601Year(me);

A full numeric representation of a year, 4 digits

                    case "Y": return me.getFullYear();

A two digit representation of a year

                    case "y": return (me.getFullYear() + "").replace(/^.+(..)$/, "$1");

Lowercase Ante meridiem and Post meridiem

                    case "a": return me.getHours() < 12 ? "am" : "pm";

Uppercase Ante meridiem and Post meridiem

                    case "A": return me.getHours() < 12 ? "AM" : "PM";

Swatch Internet time

                    case "B": return Math.floor((((me.getUTCHours() + 1) % 24) + me.getUTCMinutes() / 60 + me.getUTCSeconds() / 3600) * 1000 / 24);

12-hour format of an hour without leading zeros

                    case "g": return me.getHours() % 12 != 0 ? me.getHours() % 12 : 12;

24-hour format of an hour without leading zeros

                    case "G": return me.getHours();

12-hour format of an hour with leading zeros

                    case "h": return ("0" + (me.getHours() % 12 != 0 ? me.getHours() % 12 : 12)).replace(/^.+(..)$/, "$1");

24-hour format of an hour with leading zeros

                    case "H": return ("0" + me.getHours()).replace(/^.+(..)$/, "$1");

Minutes with leading zeros

                    case "i": return ("0" + me.getMinutes()).replace(/^.+(..)$/, "$1");

Seconds, with leading zeros

                    case "s": return ("0" + me.getSeconds()).replace(/^.+(..)$/, "$1");

Milliseconds

                    case "u": return me.getMilliseconds();
                }
            });
        };
    })();

    Twig.lib.strip_tags = function(input, allowed) {

Strips HTML and PHP tags from a string

version: 1109.2015 discuss at: http://phpjs.org/functions/striptags + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + improved by: Luke Godfrey + input by: Pul + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + bugfixed by: Onno Marsman + input by: Alex + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + input by: Marc Palau + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + input by: Brett Zamir (http://brett-zamir.me) + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + bugfixed by: Eric Nagel + input by: Bobby Drake + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + bugfixed by: Tomasz Wesolowski + input by: Evertjan Garretsen + revised by: RafaƂ Kukawski (http://blog.kukawski.pl/) * example 1: striptags('

Kevin

van Zonneveld', ''); * returns 1: 'Kevin van Zonneveld' * example 2: striptags('

Kevin van Zonneveld

', '

'); * returns 2: '

Kevin van Zonneveld

' * example 3: strip
tags("Kevin van Zonneveld", ""); * returns 3: 'Kevin van Zonneveld' * example 4: striptags('1 < 5 5 > 1'); * returns 4: '1 < 5 5 > 1' * example 5: striptags('1
1'); * returns 5: '1 1' * example 6: striptags('1
1', '
'); * returns 6: '1 1' * example 7: strip
tags('1
1', '

'); * returns 7: '1
1'

        allowed = (((allowed || "") + "").toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join(''); // making sure the allowed arg is a string containing only tags in lowercase (<a><b><c>)
        var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
            commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
        return input.replace(commentsAndPhpTags, '').replace(tags, function ($0, $1) {
            return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
        });
    }
    
    Twig.lib.strtotime = function (str, now) {

http://kevin.vanzonneveld.net + original by: Caio Ariede (http://caioariede.com) + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + input by: David + improved by: Caio Ariede (http://caioariede.com) + improved by: Brett Zamir (http://brett-zamir.me) + bugfixed by: Wagner B. Soares + bugfixed by: Artur Tchernychev % note 1: Examples all have a fixed timestamp to prevent tests to fail because of variable time(zones) * example 1: strtotime('+1 day', 1129633200); * returns 1: 1129719600 * example 2: strtotime('+1 week 2 days 4 hours 2 seconds', 1129633200); * returns 2: 1130425202 * example 3: strtotime('last month', 1129633200); * returns 3: 1127041200 * example 4: strtotime('2009-05-04 08:30:00'); * returns 4: 1241418600

        var i, l, match, s, parse = '';

        str = str.replace(/\s{2,}|^\s|\s$/g, ' '); // unecessary spaces
        str = str.replace(/[\t\r\n]/g, ''); // unecessary chars
        if (str === 'now') {
            return now === null || isNaN(now) ? new Date().getTime() / 1000 | 0 : now | 0;
        } else if (!isNaN(parse = Date.parse(str))) {
            return parse / 1000 | 0;
        } else if (now) {
            now = new Date(now * 1000); // Accept PHP-style seconds
        } else {
            now = new Date();
        }

        str = str.toLowerCase();

        var __is = {
            day: {
                'sun': 0,
                'mon': 1,
                'tue': 2,
                'wed': 3,
                'thu': 4,
                'fri': 5,
                'sat': 6
            },
            mon: [
                'jan',
                'feb',
                'mar',
                'apr',
                'may',
                'jun',
                'jul',
                'aug',
                'sep',
                'oct',
                'nov',
                'dec'
            ]
        };

        var process = function (m) {
            var ago = (m[2] && m[2] === 'ago');
            var num = (num = m[0] === 'last' ? -1 : 1) * (ago ? -1 : 1);
        
            switch (m[0]) {
            case 'last':
            case 'next':
                switch (m[1].substring(0, 3)) {
                case 'yea':
                    now.setFullYear(now.getFullYear() + num);
                    break;
                case 'wee':
                    now.setDate(now.getDate() + (num * 7));
                    break;
                case 'day':
                    now.setDate(now.getDate() + num);
                    break;
                case 'hou':
                    now.setHours(now.getHours() + num);
                    break;
                case 'min':
                    now.setMinutes(now.getMinutes() + num);
                    break;
                case 'sec':
                    now.setSeconds(now.getSeconds() + num);
                    break;
                case 'mon':
                    if (m[1] === "month") {
                        now.setMonth(now.getMonth() + num);
                        break;
                    }

fall through

                default:
                    var day = __is.day[m[1].substring(0, 3)];
                    if (typeof day !== 'undefined') {
                        var diff = day - now.getDay();
                        if (diff === 0) {
                            diff = 7 * num;
                        } else if (diff > 0) {
                            if (m[0] === 'last') {
                                diff -= 7;
                            }
                        } else {
                            if (m[0] === 'next') {
                                diff += 7;
                            }
                        }
                        now.setDate(now.getDate() + diff);
                        now.setHours(0, 0, 0, 0); // when jumping to a specific last/previous day of week, PHP sets the time to 00:00:00
                    }
                }
                break;

            default:
                if (/\d+/.test(m[0])) {
                    num *= parseInt(m[0], 10);

                    switch (m[1].substring(0, 3)) {
                    case 'yea':
                        now.setFullYear(now.getFullYear() + num);
                        break;
                    case 'mon':
                        now.setMonth(now.getMonth() + num);
                        break;
                    case 'wee':
                        now.setDate(now.getDate() + (num * 7));
                        break;
                    case 'day':
                        now.setDate(now.getDate() + num);
                        break;
                    case 'hou':
                        now.setHours(now.getHours() + num);
                        break;
                    case 'min':
                        now.setMinutes(now.getMinutes() + num);
                        break;
                    case 'sec':
                        now.setSeconds(now.getSeconds() + num);
                        break;
                    }
                } else {
                    return false;
                }
                break;
            }
            return true;
        };

        match = str.match(/^(\d{2,4}-\d{2}-\d{2})(?:\s(\d{1,2}:\d{2}(:\d{2})?)?(?:\.(\d+))?)?$/);
        if (match !== null) {
            if (!match[2]) {
                match[2] = '00:00:00';
            } else if (!match[3]) {
                match[2] += ':00';
            }

            s = match[1].split(/-/g);

            s[1] = __is.mon[s[1] - 1] || s[1];
            s[0] = +s[0];

            s[0] = (s[0] >= 0 && s[0] <= 69) ? '20' + (s[0] < 10 ? '0' + s[0] : s[0] + '') : (s[0] >= 70 && s[0] <= 99) ? '19' + s[0] : s[0] + '';
            return parseInt(this.strtotime(s[2] + ' ' + s[1] + ' ' + s[0] + ' ' + match[2]) + (match[4] ? match[4] / 1000 : ''), 10);
        }

        var regex = '([+-]?\\d+\\s' + '(years?|months?|weeks?|days?|hours?|min|minutes?|sec|seconds?' + '|sun\\.?|sunday|mon\\.?|monday|tue\\.?|tuesday|wed\\.?|wednesday' + '|thu\\.?|thursday|fri\\.?|friday|sat\\.?|saturday)' + '|(last|next)\\s' + '(years?|months?|weeks?|days?|hours?|min|minutes?|sec|seconds?' + '|sun\\.?|sunday|mon\\.?|monday|tue\\.?|tuesday|wed\\.?|wednesday' + '|thu\\.?|thursday|fri\\.?|friday|sat\\.?|saturday))' + '(\\sago)?';

        match = str.match(new RegExp(regex, 'gi')); // Brett: seems should be case insensitive per docs, so added 'i'
        if (match === null) {
            return false;
        }

        for (i = 0, l = match.length; i < l; i++) {
            if (!process(match[i].split(' '))) {
                return false;
            }
        }

        return now.getTime() / 1000 | 0;
    };

    Twig.lib.is = function(type, obj) {
        var clas = Object.prototype.toString.call(obj).slice(8, -1);
        return obj !== undefined && obj !== null && clas === type;
    };
    

shallow-copy an object

    Twig.lib.copy = function(src) {
        var target = {},
            key;
        for (key in src)
            target[key] = src[key];
            
        return target;
    };

    return Twig;

})(Twig || { });