All Downloads are FREE. Search and download functionalities are using the official Maven repository.

META-INF.resources.bower_components.datatables.net-buttons.js.buttons.html5.js Maven / Gradle / Ivy

There is a newer version: 0.66.0.1
Show newest version
/*!
 * HTML5 export buttons for Buttons and DataTables.
 * 2016 SpryMedia Ltd - datatables.net/license
 *
 * FileSaver.js (1.3.3) - MIT license
 * Copyright © 2016 Eli Grey - http://eligrey.com
 */

(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD
        define(['jquery', 'datatables.net', 'datatables.net-buttons'], function ($) {
            return factory($, window, document);
        });
    }
    else if (typeof exports === 'object') {
        // CommonJS
        module.exports = function (root, $, jszip, pdfmake) {
            if (!root) {
                root = window;
            }

            if (!$ || !$.fn.dataTable) {
                $ = require('datatables.net')(root, $).$;
            }

            if (!$.fn.dataTable.Buttons) {
                require('datatables.net-buttons')(root, $);
            }

            return factory($, root, root.document, jszip, pdfmake);
        };
    }
    else {
        // Browser
        factory(jQuery, window, document);
    }
}(function ($, window, document, jszip, pdfmake, undefined) {
    'use strict';
    var DataTable = $.fn.dataTable;

// Allow the constructor to pass in JSZip and PDFMake from external requires.
// Otherwise, use globally defined variables, if they are available.
    function _jsZip() {
        return jszip || window.JSZip;
    }

    function _pdfMake() {
        return pdfmake || window.pdfMake;
    }


    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     * FileSaver.js dependency
     */

    /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */

    var _saveAs = (function (view) {
        "use strict";
        // IE <10 is explicitly unsupported
        if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
            return;
        }
        var
            doc = view.document
            // only get URL when necessary in case Blob.js hasn't overridden it yet
            , get_URL = function () {
                return view.URL || view.webkitURL || view;
            }
            , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
            , can_use_save_link = "download" in save_link
            , click = function (node) {
                var event = new MouseEvent("click");
                node.dispatchEvent(event);
            }
            , is_safari = /constructor/i.test(view.HTMLElement) || view.safari
            , is_chrome_ios = /CriOS\/[\d]+/.test(navigator.userAgent)
            , throw_outside = function (ex) {
                (view.setImmediate || view.setTimeout)(function () {
                    throw ex;
                }, 0);
            }
            , force_saveable_type = "application/octet-stream"
            // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to
            , arbitrary_revoke_timeout = 1000 * 40 // in ms
            , revoke = function (file) {
                var revoker = function () {
                    if (typeof file === "string") { // file is an object URL
                        get_URL().revokeObjectURL(file);
                    } else { // file is a File
                        file.remove();
                    }
                };
                setTimeout(revoker, arbitrary_revoke_timeout);
            }
            , dispatch = function (filesaver, event_types, event) {
                event_types = [].concat(event_types);
                var i = event_types.length;
                while (i--) {
                    var listener = filesaver["on" + event_types[i]];
                    if (typeof listener === "function") {
                        try {
                            listener.call(filesaver, event || filesaver);
                        } catch (ex) {
                            throw_outside(ex);
                        }
                    }
                }
            }
            , auto_bom = function (blob) {
                // prepend BOM for UTF-8 XML and text/* types (including HTML)
                // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
                if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
                    return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});
                }
                return blob;
            }
            , FileSaver = function (blob, name, no_auto_bom) {
                if (!no_auto_bom) {
                    blob = auto_bom(blob);
                }
                // First try a.download, then web filesystem, then object URLs
                var
                    filesaver = this
                    , type = blob.type
                    , force = type === force_saveable_type
                    , object_url
                    , dispatch_all = function () {
                        dispatch(filesaver, "writestart progress write writeend".split(" "));
                    }
                    // on any filesys errors revert to saving with object URLs
                    , fs_error = function () {
                        if ((is_chrome_ios || (force && is_safari)) && view.FileReader) {
                            // Safari doesn't allow downloading of blob urls
                            var reader = new FileReader();
                            reader.onloadend = function () {
                                var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');
                                var popup = view.open(url, '_blank');
                                if (!popup) view.location.href = url;
                                url = undefined; // release reference before dispatching
                                filesaver.readyState = filesaver.DONE;
                                dispatch_all();
                            };
                            reader.readAsDataURL(blob);
                            filesaver.readyState = filesaver.INIT;
                            return;
                        }
                        // don't create more object URLs than needed
                        if (!object_url) {
                            object_url = get_URL().createObjectURL(blob);
                        }
                        if (force) {
                            view.location.href = object_url;
                        } else {
                            var opened = view.open(object_url, "_blank");
                            if (!opened) {
                                // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html
                                view.location.href = object_url;
                            }
                        }
                        filesaver.readyState = filesaver.DONE;
                        dispatch_all();
                        revoke(object_url);
                    }
                ;
                filesaver.readyState = filesaver.INIT;

                if (can_use_save_link) {
                    object_url = get_URL().createObjectURL(blob);
                    setTimeout(function () {
                        save_link.href = object_url;
                        save_link.download = name;
                        click(save_link);
                        dispatch_all();
                        revoke(object_url);
                        filesaver.readyState = filesaver.DONE;
                    });
                    return;
                }

                fs_error();
            }
            , FS_proto = FileSaver.prototype
            , saveAs = function (blob, name, no_auto_bom) {
                return new FileSaver(blob, name || blob.name || "download", no_auto_bom);
            }
        ;
        // IE 10+ (native saveAs)
        if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
            return function (blob, name, no_auto_bom) {
                name = name || blob.name || "download";

                if (!no_auto_bom) {
                    blob = auto_bom(blob);
                }
                return navigator.msSaveOrOpenBlob(blob, name);
            };
        }

        FS_proto.abort = function () {
        };
        FS_proto.readyState = FS_proto.INIT = 0;
        FS_proto.WRITING = 1;
        FS_proto.DONE = 2;

        FS_proto.error =
            FS_proto.onwritestart =
                FS_proto.onprogress =
                    FS_proto.onwrite =
                        FS_proto.onabort =
                            FS_proto.onerror =
                                FS_proto.onwriteend =
                                    null;

        return saveAs;
    }(
        typeof self !== "undefined" && self
        || typeof window !== "undefined" && window
        || this.content
    ));


// Expose file saver on the DataTables API. Can't attach to `DataTables.Buttons`
// since this file can be loaded before Button's core!
    DataTable.fileSave = _saveAs;


    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     * Local (private) functions
     */

    /**
     * Get the sheet name for Excel exports.
     *
     * @param {object}    config Button configuration
     */
    var _sheetname = function (config) {
        var sheetName = 'Sheet1';

        if (config.sheetName) {
            sheetName = config.sheetName.replace(/[\[\]\*\/\\\?\:]/g, '');
        }

        return sheetName;
    };

    /**
     * Get the newline character(s)
     *
     * @param {object}    config Button configuration
     * @return {string}                Newline character
     */
    var _newLine = function (config) {
        return config.newline ?
            config.newline :
            navigator.userAgent.match(/Windows/) ?
                '\r\n' :
                '\n';
    };

    /**
     * Combine the data from the `buttons.exportData` method into a string that
     * will be used in the export file.
     *
     * @param    {DataTable.Api} dt         DataTables API instance
     * @param    {object}                config Button configuration
     * @return {object}                             The data to export
     */
    var _exportData = function (dt, config) {
        var newLine = _newLine(config);
        var data = dt.buttons.exportData(config.exportOptions);
        var boundary = config.fieldBoundary;
        var separator = config.fieldSeparator;
        var reBoundary = new RegExp(boundary, 'g');
        var escapeChar = config.escapeChar !== undefined ?
            config.escapeChar :
            '\\';
        var join = function (a) {
            var s = '';

            // If there is a field boundary, then we might need to escape it in
            // the source data
            for (var i = 0, ien = a.length; i < ien; i++) {
                if (i > 0) {
                    s += separator;
                }

                s += boundary ?
                    boundary + ('' + a[i]).replace(reBoundary, escapeChar + boundary) + boundary :
                    a[i];
            }

            return s;
        };

        var header = config.header ? join(data.header) + newLine : '';
        var footer = config.footer && data.footer ? newLine + join(data.footer) : '';
        var body = [];

        for (var i = 0, ien = data.body.length; i < ien; i++) {
            body.push(join(data.body[i]));
        }

        return {
            str: header + body.join(newLine) + footer,
            rows: body.length
        };
    };

    /**
     * Older versions of Safari (prior to tech preview 18) don't support the
     * download option required.
     *
     * @return {Boolean} `true` if old Safari
     */
    var _isDuffSafari = function () {
        var safari = navigator.userAgent.indexOf('Safari') !== -1 &&
            navigator.userAgent.indexOf('Chrome') === -1 &&
            navigator.userAgent.indexOf('Opera') === -1;

        if (!safari) {
            return false;
        }

        var version = navigator.userAgent.match(/AppleWebKit\/(\d+\.\d+)/);
        if (version && version.length > 1 && version[1] * 1 < 603.1) {
            return true;
        }

        return false;
    };

    /**
     * Convert from numeric position to letter for column names in Excel
     * @param  {int} n Column number
     * @return {string} Column letter(s) name
     */
    function createCellPos(n) {
        var ordA = 'A'.charCodeAt(0);
        var ordZ = 'Z'.charCodeAt(0);
        var len = ordZ - ordA + 1;
        var s = "";

        while (n >= 0) {
            s = String.fromCharCode(n % len + ordA) + s;
            n = Math.floor(n / len) - 1;
        }

        return s;
    }

    try {
        var _serialiser = new XMLSerializer();
        var _ieExcel;
    }
    catch (t) {
    }

    /**
     * Recursively add XML files from an object's structure to a ZIP file. This
     * allows the XSLX file to be easily defined with an object's structure matching
     * the files structure.
     *
     * @param {JSZip} zip ZIP package
     * @param {object} obj Object to add (recursive)
     */
    function _addToZip(zip, obj) {
        if (_ieExcel === undefined) {
            // Detect if we are dealing with IE's _awful_ serialiser by seeing if it
            // drop attributes
            _ieExcel = _serialiser
                .serializeToString(
                    $.parseXML(excelStrings['xl/worksheets/sheet1.xml'])
                )
                .indexOf('xmlns:r') === -1;
        }

        $.each(obj, function (name, val) {
            if ($.isPlainObject(val)) {
                var newDir = zip.folder(name);
                _addToZip(newDir, val);
            }
            else {
                if (_ieExcel) {
                    // IE's XML serialiser will drop some name space attributes from
                    // from the root node, so we need to save them. Do this by
                    // replacing the namespace nodes with a regular attribute that
                    // we convert back when serialised. Edge does not have this
                    // issue
                    var worksheet = val.childNodes[0];
                    var i, ien;
                    var attrs = [];

                    for (i = worksheet.attributes.length - 1; i >= 0; i--) {
                        var attrName = worksheet.attributes[i].nodeName;
                        var attrValue = worksheet.attributes[i].nodeValue;

                        if (attrName.indexOf(':') !== -1) {
                            attrs.push({name: attrName, value: attrValue});

                            worksheet.removeAttribute(attrName);
                        }
                    }

                    for (i = 0, ien = attrs.length; i < ien; i++) {
                        var attr = val.createAttribute(attrs[i].name.replace(':', '_dt_b_namespace_token_'));
                        attr.value = attrs[i].value;
                        worksheet.setAttributeNode(attr);
                    }
                }

                var str = _serialiser.serializeToString(val);

                // Fix IE's XML
                if (_ieExcel) {
                    // IE doesn't include the XML declaration
                    if (str.indexOf('' + str;
                    }

                    // Return namespace attributes to being as such
                    str = str.replace(/_dt_b_namespace_token_/g, ':');
                }

                // Safari, IE and Edge will put empty name space attributes onto
                // various elements making them useless. This strips them out
                str = str.replace(/<([^<>]*?) xmlns=""([^<>]*?)>/g, '<$1 $2>');

                zip.file(name, str);
            }
        });
    }

    /**
     * Create an XML node and add any children, attributes, etc without needing to
     * be verbose in the DOM.
     *
     * @param  {object} doc      XML document
     * @param  {string} nodeName Node name
     * @param  {object} opts     Options - can be `attr` (attributes), `children`
     *   (child nodes) and `text` (text content)
     * @return {node}            Created node
     */
    function _createNode(doc, nodeName, opts) {
        var tempNode = doc.createElement(nodeName);

        if (opts) {
            if (opts.attr) {
                $(tempNode).attr(opts.attr);
            }

            if (opts.children) {
                $.each(opts.children, function (key, value) {
                    tempNode.appendChild(value);
                });
            }

            if (opts.text !== null && opts.text !== undefined) {
                tempNode.appendChild(doc.createTextNode(opts.text));
            }
        }

        return tempNode;
    }

    /**
     * Get the width for an Excel column based on the contents of that column
     * @param  {object} data Data for export
     * @param  {int}    col  Column index
     * @return {int}         Column width
     */
    function _excelColWidth(data, col) {
        var max = data.header[col].length;
        var len, lineSplit, str;

        if (data.footer && data.footer[col].length > max) {
            max = data.footer[col].length;
        }

        for (var i = 0, ien = data.body.length; i < ien; i++) {
            var point = data.body[i][col];
            str = point !== null && point !== undefined ?
                point.toString() :
                '';

            // If there is a newline character, workout the width of the column
            // based on the longest line in the string
            if (str.indexOf('\n') !== -1) {
                lineSplit = str.split('\n');
                lineSplit.sort(function (a, b) {
                    return b.length - a.length;
                });

                len = lineSplit[0].length;
            }
            else {
                len = str.length;
            }

            if (len > max) {
                max = len;
            }

            // Max width rather than having potentially massive column widths
            if (max > 40) {
                return 52; // 40 * 1.3
            }
        }

        max *= 1.3;

        // And a min width
        return max > 6 ? max : 6;
    }

// Excel - Pre-defined strings to build a basic XLSX file
    var excelStrings = {
        "_rels/.rels":
            '' +
            '' +
            '' +
            '',

        "xl/_rels/workbook.xml.rels":
            '' +
            '' +
            '' +
            '' +
            '',

        "[Content_Types].xml":
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '',

        "xl/workbook.xml":
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '',

        "xl/worksheets/sheet1.xml":
            '' +
            '' +
            '' +
            '' +
            '',

        "xl/styles.xml":
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' + // Excel appears to use this as a dotted background regardless of values but
            '' + // to be valid to the schema, use a patternFill
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            '' +
            ''
    };
// Note we could use 3 `for` loops for the styles, but when gzipped there is
// virtually no difference in size, since the above can be easily compressed

// Pattern matching for special number formats. Perhaps this should be exposed
// via an API in future?
// Ref: section 3.8.30 - built in formatters in open spreadsheet
//   https://www.ecma-international.org/news/TC45_current_work/Office%20Open%20XML%20Part%204%20-%20Markup%20Language%20Reference.pdf
    var _excelSpecials = [
        {
            match: /^\-?\d+\.\d%$/, style: 60, fmt: function (d) {
                return d / 100;
            }
        }, // Precent with d.p.
        {
            match: /^\-?\d+\.?\d*%$/, style: 56, fmt: function (d) {
                return d / 100;
            }
        }, // Percent
        {match: /^\-?\$[\d,]+.?\d*$/, style: 57}, // Dollars
        {match: /^\-?£[\d,]+.?\d*$/, style: 58}, // Pounds
        {match: /^\-?€[\d,]+.?\d*$/, style: 59}, // Euros
        {match: /^\-?\d+$/, style: 65}, // Numbers without thousand separators
        {match: /^\-?\d+\.\d{2}$/, style: 66}, // Numbers 2 d.p. without thousands separators
        {
            match: /^\([\d,]+\)$/, style: 61, fmt: function (d) {
                return -1 * d.replace(/[\(\)]/g, '');
            }
        },  // Negative numbers indicated by brackets
        {
            match: /^\([\d,]+\.\d{2}\)$/, style: 62, fmt: function (d) {
                return -1 * d.replace(/[\(\)]/g, '');
            }
        },  // Negative numbers indicated by brackets - 2d.p.
        {match: /^\-?[\d,]+$/, style: 63}, // Numbers with thousand separators
        {match: /^\-?[\d,]+\.\d{2}$/, style: 64}  // Numbers with 2 d.p. and thousands separators
    ];


    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     * Buttons
     */

//
// Copy to clipboard
//
    DataTable.ext.buttons.copyHtml5 = {
        className: 'buttons-copy buttons-html5',

        text: function (dt) {
            return dt.i18n('buttons.copy', 'Copy');
        },

        action: function (e, dt, button, config) {
            this.processing(true);

            var that = this;
            var exportData = _exportData(dt, config);
            var info = dt.buttons.exportInfo(config);
            var newline = _newLine(config);
            var output = exportData.str;
            var hiddenDiv = $('
') .css({ height: 1, width: 1, overflow: 'hidden', position: 'fixed', top: 0, left: 0 }); if (info.title) { output = info.title + newline + newline + output; } if (info.messageTop) { output = info.messageTop + newline + newline + output; } if (info.messageBottom) { output = output + newline + newline + info.messageBottom; } if (config.customize) { output = config.customize(output, config, dt); } var textarea = $('