UNPKG

tableexport

Version:

The simple, easy-to-implement library to export HTML tables to xlsx, xls, csv, and txt files

1,133 lines (1,055 loc) 39.6 kB
/*! * TableExport.js v5.2.0 (https://www.travismclarke.com) * * Copyright (c) 2018 - Travis Clarke - https://www.travismclarke.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ (function(root, factory) { if (typeof define === "function" && define.amd) { // AMD define(function(require) { var $; try { $ = require("jquery"); } catch (e) {} return factory($, require("blobjs"), require("file-saverjs"), require("xlsx")); }); } else if (typeof exports === "object" && typeof exports.nodeName !== "string") { // CommonJS var $; try { $ = require("jquery"); } catch (e) {} module.exports = factory($, require("blobjs"), require("file-saverjs"), require("xlsx")); } else { // Browser globals root.TableExport = factory(root.jQuery, root.Blob, root.saveAs, root.XLSX); } })(this, function($, Blob, saveAs, XLSX) { "use strict"; /** * TableExport main library constructor * @param selectors {jQuery} jQuery selector(s) * @param options {Object} TableExport configuration options * @constructor */ var TableExport = function(selectors, options) { var self = this; if (!selectors) return _handleError('"selectors" is required. \nUsage: TableExport(selectors, options)'); if (!self) return new TableExport(selectors, options); /** * TableExport configuration options (user-defined w/ default fallback) */ self.settings = _extend({}, self.defaults, options); /** * Selectors (tables) to apply the library to */ self.selectors = _nodesArray(selectors); var settings = self.settings; settings.ignoreRows = settings.ignoreRows instanceof Array ? settings.ignoreRows : [settings.ignoreRows]; settings.ignoreCols = settings.ignoreCols instanceof Array ? settings.ignoreCols : [settings.ignoreCols]; settings.ignoreCSS = self.ignoreCSS instanceof Array ? self.ignoreCSS : [self.ignoreCSS]; settings.emptyCSS = self.emptyCSS instanceof Array ? self.emptyCSS : [self.emptyCSS]; settings.formatValue = self.formatValue.bind(this, settings.trimWhitespace); settings.bootstrapSettings = _getBootstrapSettings(settings.bootstrap, self.bootstrapConfig, self.defaultButton); var _exportData = {}; self.getExportData = function() { return _exportData; }; self.selectors.forEach(function(el) { var context = {}; context.rows = _nodesArray(el.querySelectorAll("tbody > tr")); context.rows = settings.headers ? _nodesArray(el.querySelectorAll("thead > tr")).concat(context.rows) : context.rows; context.rows = settings.footers ? context.rows.concat(_nodesArray(el.querySelectorAll("tfoot > tr"))) : context.rows; context.thAdj = settings.headers ? el.querySelectorAll("thead > tr").length : 0; context.filename = settings.filename === "id" ? el.getAttribute("id") || self.defaultFilename : settings.filename || self.defaultFilename; context.sheetname = settings.sheetname === "id" ? el.getAttribute("id") || self.defaultSheetname : settings.sheetname || self.defaultSheetname; context.uuid = _uuid(el); /** * Initializes table caption with export buttons * @param exportButton {HTMLButtonElement} */ context.checkCaption = function(exportButton) { var caption = el.querySelectorAll("caption." + self.defaultCaptionClass); if (caption.length) { caption[0].appendChild(exportButton); } else { caption = document.createElement("caption"); caption.className = settings.bootstrapSettings.bootstrapSpacing + self.defaultCaptionClass; caption.style.cssText = "caption-side: " + settings.position; caption.appendChild(exportButton); el.insertBefore(caption, el.firstChild); } }; context.setExportData = (function() { return function(exporter) { var data = Storage.getInstance().getItem(exporter); var type = exporter.substring(exporter.indexOf("-") + 1); _exportData[context.uuid] = _exportData[context.uuid] || {}; _exportData[context.uuid][type] = JSON.parse(data); }; })(); context.rcMap = new RowColMap().build(context, settings); var formatMap = _FORMAT_LIST.reduce(function(acc, cur) { acc[cur] = 0; return acc; }, {}); settings.formats.forEach(function(key) { if (!_isValidFormat(key)) { return _handleError('"' + key + '" is not a valid format. \nFormats: ' + _FORMAT_LIST.join(", ")); } else if (!_hasDependencies(key)) { // TODO: provide a fallback option to XLS? return _handleError('"' + key + '" requires "js-xlsx".'); } else if (!formatMap[key]) { context.setExportData(self.exporters.build.call(self, context, key)); formatMap[key]++; } }); }); var exportButton = document.querySelectorAll("button[" + self.storageKey + "]"); _on(exportButton, "click", self.downloadHandler, self); return self; }; TableExport.prototype = { /** * Version. * @memberof TableExport.prototype */ version: "5.2.0", /** * Default library options. * @memberof TableExport.prototype */ defaults: { headers: true, // (Boolean), display table headers (th or td elements) in the <thead>, (default: true) footers: true, // (Boolean), display table footers (th or td elements) in the <tfoot>, (default: false) formats: ["xlsx", "csv", "txt"], // (String[]), filetype(s) for the export, (default: ['xlsx', 'csv', 'txt']) filename: "id", // (id, String), filename for the downloaded file, (default: 'id') bootstrap: false, // (Boolean), style buttons using bootstrap, (default: true) exportButtons: true, // (Boolean), automatically generate the built-in export buttons for each of the specified formats (default: true) position: "bottom", // (top, bottom), position of the caption element relative to table, (default: 'bottom') ignoreRows: null, // (Number, Number[]), row indices to exclude from the exported file(s) (default: null) ignoreCols: null, // (Number, Number[]), column indices to exclude from the exported file(s) (default: null) trimWhitespace: true, // (Boolean), remove all leading/trailing newlines, spaces, and tabs from cell text in the exported file(s) (default: false) RTL: false, // (Boolean), set direction of the worksheet to right-to-left (default: false) sheetname: "id" // (id, String), sheet name for the exported spreadsheet, (default: 'id') }, /** * Constants * @memberof TableExport.prototype */ CONSTANTS: { FORMAT: { XLSX: "xlsx", XLSM: "xlsm", XLSB: "xlsb", BIFF2: "biff2", XLS: "xls", CSV: "csv", TXT: "txt" }, TYPE: { STRING: "s", NUMBER: "n", BOOLEAN: "b", DATE: "d" } }, /** * Character set (character encoding) of the HTML. * @memberof TableExport.prototype */ charset: "charset=utf-8", /** * Filename fallback for exported files. * @memberof TableExport.prototype */ defaultFilename: "myDownload", /** * Sheetname fallback for exported files. * @memberof TableExport.prototype */ defaultSheetname: "myWorksheet", /** * Class applied to each export button element. * @memberof TableExport.prototype */ defaultButton: "button-default", /** * Class applied to each table caption. * @memberof TableExport.prototype */ defaultCaptionClass: "tableexport-caption", /** * Namespace (i.e. prefix) applied to each table UUID and Storage key. * @memberof TableExport.prototype */ defaultNamespace: "tableexport-", /** * Attribute applied to each table element used to generate each Storage key. * @memberof TableExport.prototype */ tableKey: "tableexport-key", /** * Attribute applied to each export button element used to reference a Storage key. * @memberof TableExport.prototype */ storageKey: "tableexport-id", /** * CSS selector or selector[] to exclude/remove cells from the exported file(s). * @type {selector|selector[]} * @memberof TableExport.prototype */ ignoreCSS: ".tableexport-ignore", /** * CSS selector or selector[] to replace cells with an empty string in the exported file(s). * @type {selector|selector[]} * @memberof TableExport.prototype */ emptyCSS: ".tableexport-empty", /** * Bootstrap configuration classes ['base', 'theme', 'container']. * @memberof TableExport.prototype */ bootstrapConfig: ["btn", "btn-default", "btn-toolbar"], /** * Row delimeter * @memberof TableExport.prototype */ rowDel: "\r\n", /** * HTML entity mapping for special characters. * @memberof TableExport.prototype */ entityMap: { "&": "&#38;", "<": "&#60;", ">": "&#62;", "'": "&#39;", "/": "&#47;" }, /** * Format configuration * @memberof TableExport.prototype */ formatConfig: { /** * XLSX (Open XML spreadsheet) file extension configuration * @memberof TableExport.prototype */ xlsx: { defaultClass: "xlsx", buttonContent: "Export to xlsx", mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileExtension: ".xlsx" }, xlsm: { defaultClass: "xlsm", buttonContent: "Export to xlsm", mimeType: "application/vnd.ms-excel.sheet.macroEnabled.main+xml", fileExtension: ".xlsm" }, xlsb: { defaultClass: "xlsb", buttonContent: "Export to xlsb", mimeType: "application/vnd.ms-excel.sheet.binary.macroEnabled.main", fileExtension: ".xlsb" }, /** * XLS (Binary spreadsheet) file extension configuration * @memberof TableExport.prototype */ xls: { defaultClass: "xls", buttonContent: "Export to xls", separator: "\t", mimeType: "application/vnd.ms-excel", fileExtension: ".xls", enforceStrictRFC4180: false }, /** * CSV (Comma Separated Values) file extension configuration * @memberof TableExport.prototype */ csv: { defaultClass: "csv", buttonContent: "Export to csv", separator: ",", mimeType: "text/csv", fileExtension: ".csv", enforceStrictRFC4180: true }, /** * TXT (Plain Text) file extension configuration * @memberof TableExport.prototype */ txt: { defaultClass: "txt", buttonContent: "Export to txt", separator: " ", mimeType: "text/plain", fileExtension: ".txt", enforceStrictRFC4180: true } }, /** * Cell-types override and assertion configuration * @memberof TableExport.prototype */ typeConfig: { string: { defaultClass: "tableexport-string" }, number: { defaultClass: "tableexport-number", assert: function(v) { return !isNaN(v); } }, boolean: { defaultClass: "tableexport-boolean", assert: function(v) { return v.toLowerCase() === "true" || v.toLowerCase() === "false"; } }, date: { defaultClass: "tableexport-date", assert: function(v) { return !/.*%/.test(v) && !isNaN(Date.parse(v)); } } }, exporters: { build: function(context, key) { var self = this; var settings = self.settings; var format = self.formatConfig[key]; var colDel = format.separator; var rcMap = context.rcMap; var getReturn = function(val) { if (_isEnhanced(key)) { return { v: settings.formatValue(val.textContent), t: self.getType(val.className) }; } switch (key) { case _FORMAT.CSV: return '"' + settings.formatValue(val.textContent.replace(/"/g, '""')) + '"'; default: return settings.formatValue(val.textContent); } }; var dataURI = _nodesArray(context.rows) .map(function(val, ir) { if (rcMap.isIgnore(ir)) { return rcMap.handleRowColMapProp(rcMap.TYPE.IGNORE); } else if (rcMap.isEmpty(ir)) { return rcMap.handleRowColMapProp(rcMap.TYPE.EMPTY); } var cols = val.querySelectorAll("th, td"); return _nodesArray(cols) .map(function(val, ic) { var _return = getReturn(val); if (rcMap.isIgnore(ir, ic)) { return rcMap.handleRowColMapProp(rcMap.TYPE.IGNORE); } else if (rcMap.isEmpty(ir, ic)) { return rcMap.handleRowColMapProp(rcMap.TYPE.EMPTY); } else { return rcMap.handleRowColMapProp(rcMap.TYPE.DEFAULT, ir, ic, key, _return, colDel); } }) .processCols(key, colDel); }) .processRows(key, self.rowDel); var dataObject = JSON.stringify({ data: dataURI, filename: context.filename, mimeType: format.mimeType, fileExtension: format.fileExtension, merges: rcMap.merges, RTL: settings.RTL, sheetname: settings.sheetname }); var hashKey = _hashCode({ uuid: context.uuid, type: key }); settings.exportButtons && context.checkCaption(self.createObjButton(hashKey, dataObject, format.buttonContent, format.defaultClass, settings.bootstrapSettings)); return Storage.getInstance().setItem(hashKey, dataObject, true); } }, /** * Creates file export buttons * @param hashKey {String} * @param dataObject {String} * @param myContent {String} * @param myClass {String} * @param bootstrapSettings {Object} * @returns Element */ createObjButton: function(hashKey, dataObject, myContent, myClass, bootstrapSettings) { var exportButton = document.createElement("button"); exportButton.setAttribute("type", "button"); exportButton.setAttribute(this.storageKey, hashKey); exportButton.className = bootstrapSettings.bootstrapClass + bootstrapSettings.bootstrapTheme + myClass; exportButton.textContent = myContent; return exportButton; }, /** * Escapes special characters with HTML entities * @memberof TableExport.prototype * @param string {String} * @returns {String} escaped string */ escapeHtml: function(string) { var self = this; return String(string).replace(/[&<>'\/]/g, function(s) { return self.entityMap[s]; }); }, /** * Unescapes HTML entities to special characters * @memberof TableExport.prototype * @param string {String} * @returns {String} unescaped string */ unescapeHtml: function(string) { var str = String(string); for (var key in this.entityMap) { str = str.replace(RegExp(this.entityMap[key], "g"), key); } return str; }, /** * Removes leading/trailing whitespace from cell string * @param isTrimWhitespace {Boolean} * @param string {String} * @returns {String} trimmed string */ formatValue: function(isTrimWhitespace, string) { return isTrimWhitespace ? string.trim() : string; }, /** * Get cell data-type * @param string {String} * @returns {String} data-type */ getType: function(string) { if (!string) return ""; var types = this.typeConfig; if (~string.indexOf(types.string.defaultClass)) { return _TYPE.STRING; } else if (~string.indexOf(types.number.defaultClass)) { return _TYPE.NUMBER; } else if (~string.indexOf(types.boolean.defaultClass)) { return _TYPE.BOOLEAN; } else if (~string.indexOf(types.date.defaultClass)) { return _TYPE.DATE; } else { return ""; } }, /** * Formats datetimes for compatibility with Excel * @memberof TableExport.prototype * @param v {Number} * @param date1904 {Date} * @returns {Number} epoch time */ dateNum: function(v, date1904) { if (date1904) v += 1462; var epoch = Date.parse(v); var result = (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000); return Math.floor(result); }, /** * Creates an Excel spreadsheet from a data string * @memberof TableExport.prototype * @param data {String} * @param merges {Object[]} */ createSheet: function(data, merges) { var ws = {}; var range = { s: { c: 10000000, r: 10000000 }, e: { c: 0, r: 0 } }; var types = this.typeConfig; for (var R = 0; R !== data.length; ++R) { for (var C = 0; C !== data[R].length; ++C) { if (range.s.r > R) range.s.r = R; if (range.s.c > C) range.s.c = C; if (range.e.r < R) range.e.r = R; if (range.e.c < C) range.e.c = C; var cell = data[R][C]; if (!cell || !cell.v) continue; var cell_ref = XLSX.utils.encode_cell({ c: C, r: R }); if (!cell.t) { if (types.number.assert(cell.v)) cell.t = _TYPE.NUMBER; else if (types.boolean.assert(cell.v)) cell.t = _TYPE.BOOLEAN; else if (types.date.assert(cell.v)) cell.t = _TYPE.DATE; else cell.t = _TYPE.STRING; } if (cell.t === _TYPE.DATE) { cell.t = _TYPE.NUMBER; cell.z = XLSX.SSF._table[14]; cell.v = this.dateNum(cell.v); } ws[cell_ref] = cell; } } ws["!merges"] = merges; if (range.s.c < 10000000) ws["!ref"] = XLSX.utils.encode_range(range); return ws; }, /** * Click handler for export button "download" * @memberof TableExport.prototype */ downloadHandler: function(event) { var target = event.target; var object = JSON.parse(Storage.getInstance().getItem(target.getAttribute(this.storageKey))), data = object.data, filename = object.filename, mimeType = object.mimeType, fileExtension = object.fileExtension, merges = object.merges, RTL = object.RTL, sheetname = object.sheetname; this.export2file(data, mimeType, filename, fileExtension, merges, RTL, sheetname); }, /** * Excel Workbook constructor * @memberof TableExport.prototype * @constructor */ Workbook: function() { this.Workbook = { Views: [] }; this.SheetNames = []; this.Sheets = {}; }, /** * Converts a string to an arraybuffer * @param s {String} * @memberof TableExport.prototype * @returns {ArrayBuffer} */ string2ArrayBuffer: function(s) { var buf = new ArrayBuffer(s.length); var view = new Uint8Array(buf); for (var i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xff; return buf; }, /** * Exports and downloads the file * @memberof TableExport.prototype * @param data {String} * @param mime {String} mime type * @param name {String} filename * @param extension {String} file extension * @param merges {Object[]} * @param RTL {Boolean} */ export2file: function(data, mime, name, extension, merges, RTL, sheetname) { var format = extension.slice(1); data = this.getRawData(data, extension, name, merges, RTL, sheetname); if (_isMobile && (format === _FORMAT.CSV || format === _FORMAT.TXT)) { var dataURI = "data:" + mime + ";" + this.charset + "," + data; this.downloadDataURI(dataURI, name, extension); } else { // TODO: error and fallback when `saveAs` not available saveAs(new Blob([data], { type: mime + ";" + this.charset }), name + extension, true); } }, downloadDataURI: function(dataURI, name, extension) { var encodedUri = encodeURI(dataURI); var link = document.createElement("a"); link.setAttribute("href", encodedUri); link.setAttribute("download", name + extension); document.body.appendChild(link); link.click(); }, getBookType: function(key) { switch (key) { case _FORMAT.XLS: return _FORMAT.BIFF2; default: return key; } }, getRawData: function(data, extension, name, merges, RTL, sheetname) { var key = extension.substring(1); if (_isEnhanced(key)) { var wb = new this.Workbook(), ws = this.createSheet(data, merges), bookType = this.getBookType(key); sheetname = sheetname || ""; wb.SheetNames.push(sheetname); wb.Sheets[sheetname] = ws; wb.Workbook.Views[0] = { RTL: RTL }; var wopts = { bookType: bookType, bookSST: false, type: "binary" }, wbout = XLSX.write(wb, wopts); data = this.string2ArrayBuffer(wbout); } return data; }, getFileSize: function(data, extension) { var binary = this.getRawData(data, extension); return binary instanceof ArrayBuffer ? binary.byteLength : this.string2ArrayBuffer(binary).byteLength; }, /** * Updates the library instance with new/updated options * @param options {Object} TableExport configuration options * @returns {TableExport} updated TableExport instance */ update: function(options) { this.remove(); return new TableExport(this.selectors, _extend({}, this.defaults, options)); }, /** * Reset the library instance to its original state * @returns {TableExport} original TableExport instance */ reset: function() { this.remove(); return new TableExport(this.selectors, this.settings); }, /** * Remove the instance (i.e. caption containing the export buttons) */ remove: function() { var self = this; this.selectors.forEach(function(el) { var caption = el.querySelector("caption." + self.defaultCaptionClass); caption && el.removeChild(caption); }); } }; /** * Storage main interface constructor * @memberof TableExport.prototype * @constructor */ var Storage = function() { this._instance = null; this.store = sessionStorage; this.namespace = TableExport.prototype.defaultNamespace; this.getKey = function(key) { return this.namespace + key; }; this.setItem = function(_key, value, overwrite) { var key = this.getKey(_key); if (this.exists(_key) && !overwrite) { return; } if (typeof value !== "string") return _handleError('"value" must be a string.'); this.store.setItem(key, value); return _key; }; this.getItem = function(_key) { var key = this.getKey(_key); return this.store.getItem(key); }; this.exists = function(_key) { var key = this.getKey(_key); return this.store.getItem(key) !== null; }; this.removeItem = function(_key) { var key = this.getKey(_key); return this.store.removeItem(key); }; }; Storage.getInstance = function() { if (!this._instance) { this._instance = new Storage(); } return this._instance; }; /** * RowColMap main interface constructor * @memberof TableExport.prototype * @constructor */ var RowColMap = function() { this.rcMap = []; this.merges = []; this.isIgnore = function(ir, ic) { var _ignore = RowColMap.prototype.TYPE.IGNORE; return this.getRowColMapProp(ir, ic, _ignore); }; this.isEmpty = function(ir, ic) { var _empty = RowColMap.prototype.TYPE.EMPTY; return this.getRowColMapProp(ir, ic, _empty); }; this.isRowSpan = function(ir) { var _rowspan = RowColMap.prototype.TYPE.ROWSPAN; return this.getRowColMapProp(ir, undefined, _rowspan); }; this.isColSpan = function(ir) { var _colspan = RowColMap.prototype.TYPE.COLSPAN; return this.getRowColMapProp(ir, undefined, _colspan); }; this.isSpan = function(ir) { return this.isRowSpan(ir) || this.isColSpan(ir); }; this.isMerge = function(ir) { return this.merges.length > 0; }; this.addMerge = function(ir, mergeObj) { var _merge = RowColMap.prototype.TYPE.MERGE; this.merges.push(mergeObj); this.setRowColMapProp(ir, undefined, _merge, this.merges); }; this.getRowColMapProp = function(ir, ic, key) { if (this.rcMap[ir]) { if (typeof key === "undefined") { return this.rcMap[ir][ic]; } else if (typeof ic === "undefined") { return this.rcMap[ir][key]; } else if (this.rcMap[ir][ic]) { return this.rcMap[ir][ic][key]; } } return undefined; }; this.setRowColMapProp = function(ir, ic, key, value) { this.rcMap[ir] = this.rcMap[ir] || []; if (typeof key === "undefined") { return (this.rcMap[ir][ic] = value); } else if (typeof ic === "undefined") { return (this.rcMap[ir][key] = value); } else { this.rcMap[ir][ic] = this.rcMap[ir][ic] || []; return (this.rcMap[ir][ic][key] = value); } }; this.generateTotal = function(ir, ic) { var VALUE = RowColMap.prototype.TYPE.VALUE; var _total = 0; if (this.isRowSpan(ir) && this.isColSpan(ir)) { _total = this.getRowColMapProp(ir, ic, VALUE) || 0; } else if (this.getRowColMapProp(ir, ic, VALUE)) { _total = this.getRowColMapProp(ir, ic, VALUE); } return _total; }; this.convertSpanToArray = function(ir, ic, key, _return, colDel) { if (this.rcMap[ir] && this.isSpan(ir)) { var total = this.generateTotal(ir, ic); if (_isEnhanced(key)) { return new Array(total).concat(_return); } else { return new Array(total).concat(_return).join(colDel); } } return _return; }; this.handleRowColMapProp = function(type, ir, ic, key, _return, colDel) { switch (type) { case RowColMap.prototype.TYPE.IGNORE: return; case RowColMap.prototype.TYPE.EMPTY: return " "; case RowColMap.prototype.TYPE.DEFAULT: default: return this.convertSpanToArray(ir, ic, key, _return, colDel); } }; }; RowColMap.prototype = { OFFSET: 1, TYPE: { IGNORE: "ignore", EMPTY: "empty", MERGE: "merge", ROWSPAN: "rowspan", ROWSPANTOTAL: "rowspantotal", COLSPAN: "colspan", COLSPANTOTAL: "colspantotal", DEFAULT: "default", VALUE: "value" }, build: function(context, settings) { var self = this; var OFFSET = self.OFFSET; var rowLength = (self.rowLength = context.rows.length); // var colLength = self.colLength = Math.max.apply(null, // _nodesArray(context.rows).map(function (val) { // return val.querySelectorAll('th, td').length // })); var handleIgnore = function(ir, ic) { self.setRowColMapProp(ir, ic, self.TYPE.IGNORE, true); }; var handleEmpty = function(ir, ic) { self.setRowColMapProp(ir, ic, self.TYPE.EMPTY, true); }; var handleRowSpan = function(val, ir, ic) { var rowSpan = +val.getAttribute("rowspan"); var colSpan = +val.getAttribute("colspan"); var handledByColSpan, countRowSpan, countColSpan, totalRowSpan, totalColSpan, irStart, irEnd, icStart, icEnd; for (var _row = 0; _row < rowSpan; _row++) { if (_row + ir >= rowLength) { return; } colSpan && (handledByColSpan = handleColSpan(val, _row + ir, ic, _row > 0, rowSpan)); if (rowSpan <= 1) { return false; } var cur = self.rcMap["c" + (ic - 1)] ? self.rcMap["c" + (ic - 1)][_row + ir] : 0; if (cur) { self.rcMap["c" + ic] = self.rcMap["c" + ic] || []; self.rcMap["c" + ic][_row + ir] = (self.rcMap["c" + ic][_row + ir] || 0) + cur; } if (rowSpan && _row === 0 && colSpan > 1) { for (var i = 0; i < rowSpan; i++) { self.rcMap["c" + (ic + 1)] = self.rcMap["c" + (ic + 1)] || []; self.rcMap["c" + (ic + 1)][_row + ir + i] = (self.rcMap["c" + (ic + 1)][_row + ir + i] || 0) + Math.max(1, colSpan); } } if (_row >= 1) { countRowSpan = self.getRowColMapProp(_row + ir, undefined, self.TYPE.ROWSPAN) || 0; self.setRowColMapProp(_row + ir, undefined, self.TYPE.ROWSPAN, countRowSpan + 1); if (!handledByColSpan) { totalRowSpan = self.getRowColMapProp(_row + ir, ic - countRowSpan, self.TYPE.VALUE) || 0; self.setRowColMapProp(_row + ir, ic - countRowSpan, self.TYPE.VALUE, totalRowSpan + 1); if (rowSpan > 1 && _row === 1) { var _re = self.rcMap["c" + ic] && self.rcMap["c" + ic][_row + ir]; totalColSpan = self.getRowColMapProp(ir, undefined, self.TYPE.COLSPANTOTAL) || 0; countColSpan = self.getRowColMapProp(ir, undefined, self.TYPE.COLSPAN) || 0; irStart = ir; irEnd = ir + rowSpan - 1; icStart = ic + totalColSpan - countColSpan + (_re || 0); icEnd = icStart + Math.max(1, colSpan) - 1; handleMerge(irStart, icStart, irEnd, icEnd); } } } } }; var handleColSpan = function(val, ir, ic, isRowSpan, rowSpan) { var irStart, irEnd, icStart, icEnd; var colSpan = +val.getAttribute("colspan"); var countColSpan = self.getRowColMapProp(ir, undefined, self.TYPE.COLSPAN) || 0; var totalColSpan = self.getRowColMapProp(ir, undefined, self.TYPE.COLSPANTOTAL) || 0; if (colSpan <= 1) { return false; } self.setRowColMapProp(ir, undefined, self.TYPE.COLSPAN, countColSpan + 1); self.setRowColMapProp(ir, undefined, self.TYPE.COLSPANTOTAL, totalColSpan + colSpan); if (isRowSpan) { self.setRowColMapProp(ir, ic - countColSpan, self.TYPE.VALUE, colSpan); return true; } else { irStart = ir; irEnd = ir + (rowSpan || 1) - OFFSET; icStart = ic + totalColSpan - countColSpan; icEnd = ic + totalColSpan - countColSpan + (colSpan - OFFSET); self.setRowColMapProp(ir, ic + OFFSET, self.TYPE.VALUE, colSpan - OFFSET); handleMerge(irStart, icStart, irEnd, icEnd); } }; var handleMerge = function(irs, ics, ire, ice) { var merge = { s: { r: irs, c: ics }, e: { r: ire, c: ice } }; return self.addMerge(irs, merge); }; _nodesArray(context.rows).map(function(val, ir) { if (!!~settings.ignoreRows.indexOf(ir - context.thAdj) || _matches(val, settings.ignoreCSS)) { handleIgnore(ir); } if (_matches(val, settings.emptyCSS)) { handleEmpty(ir); } var cols = val.querySelectorAll("th, td"); return _nodesArray(cols).map(function(val, ic) { if (!!~settings.ignoreCols.indexOf(ic) || _matches(val, settings.ignoreCSS)) { handleIgnore(ir, ic); } if (_matches(val, settings.emptyCSS)) { handleEmpty(ir, ic); } if (val.hasAttribute("rowspan")) { handleRowSpan(val, ir, ic); } else if (val.hasAttribute("colspan")) { handleColSpan(val, ir, ic); } }); }); return self; } }; var _isMobile = (function isMobile(ua) { return ( /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test( ua ) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test( ua.substring(0, 4) ) ); })(navigator.userAgent || navigator.vendor || window.opera); var _isEnhanced = (function() { return function(key) { return XLSX && !TableExport.prototype.formatConfig[key].enforceStrictRFC4180; }; })(); var _FORMAT = (function() { return TableExport.prototype.CONSTANTS.FORMAT; })(); var _FORMAT_LIST = (function() { return Object.keys(_FORMAT).map(function(key) { return _FORMAT[key]; }); })(); var _TYPE = (function() { return TableExport.prototype.CONSTANTS.TYPE; })(); Object.defineProperty(Array.prototype, "processRows", { enumerable: false, value: function(key, rowDel) { if (_isEnhanced(key)) { return this.map(_toArray).filter(_defined); } else { return this.filter(_defined).join(rowDel); } } }); Object.defineProperty(Array.prototype, "processCols", { enumerable: false, value: function(key, colDel) { if (_isEnhanced(key)) { return this.filter(_defined); } else { return this.filter(_defined).join(colDel); } } }); var _uuid = (function() { var uuid = 0; return function(el) { var tableKey = el.getAttribute(TableExport.prototype.tableKey); if (!tableKey) { tableKey = el.id ? el.id : TableExport.prototype.defaultNamespace + ++uuid; el.setAttribute(TableExport.prototype.tableKey, tableKey); } return tableKey; }; })(); var _hashCode = (function() { return function(hashKey) { var hash = 0, i, char; var type = hashKey.type; hashKey = JSON.stringify(hashKey); if (hashKey.length === 0) return hash; for (i = 0; i < hashKey.length; i++) { char = hashKey.charCodeAt(i); hash = (hash << 5) - hash + char; hash |= 0; } return hash.toString(16).substring(1) + "-" + type; }; })(); var _on = (function() { var prevFn = null; return function(el, event, fn, context) { // , args var curFn = fn.bind(context); // var curFn = fn.bind.apply(fn, [context].concat(args)); // OR [].slice.call(arguments[4])) for (var i = 0; i < el.length; ++i) { prevFn && el[i].removeEventListener(event, prevFn, false); el[i].addEventListener(event, curFn, false); } prevFn = curFn; }; })(); function _extend() { var args = arguments; for (var i = 1; i < args.length; i++) for (var key in args[i]) if (args[i].hasOwnProperty(key)) args[0][key] = args[i][key]; return args[0]; } function _nodesArray(els) { return typeof els.length === "undefined" ? [].concat(els) : [].slice.call(els); } function _hasClass(el, cls) { return el.classList ? el.classList.contains(cls) : new RegExp("(^| )" + cls + "( |$)", "gi").test(el.cls); } function _matches(el, selectors) { return ( selectors.filter(function(selector) { return [].indexOf.call(document.querySelectorAll(selector), el) !== -1; }).length > 0 ); } function _numeric(val) { return !isNaN(val); } function _defined(val) { return typeof val !== "undefined"; } function _toArray(val) { return val instanceof Array ? [].concat.apply([], val) : val; } function _isValidFormat(key) { return ~_FORMAT_LIST.indexOf(key); } function _hasDependencies(key) { var hasDependencies; switch (key) { case _FORMAT.TXT: case _FORMAT.CSV: case _FORMAT.XLS: hasDependencies = true; break; default: hasDependencies = _isEnhanced(key); } return hasDependencies; } function _handleError(msg) { console.error(msg); return new Error(msg); } function _getBootstrapSettings(bootstrap, bootstrapConfig, defaultButton) { var config = {}; if (bootstrap) { config.bootstrapClass = bootstrapConfig[0] + " "; config.bootstrapTheme = bootstrapConfig[1] + " "; config.bootstrapSpacing = bootstrapConfig[2] + " "; } else { config.bootstrapClass = defaultButton + " "; config.bootstrapTheme = ""; config.bootstrapSpacing = ""; } return config; } if ($) { /** * jQuery TableExport wrapper * @param options {Object} TableExport configuration options * @returns {TableExport} TableExport instance */ $.fn.tableExport = function(options) { return TableExport.call(_extend({}, TableExport.prototype, $.fn.tableExport), this, options); }; // alias the TableExport prototype for (var prop in TableExport.prototype) { $.fn.tableExport[prop] = TableExport.prototype[prop]; } } TableExport.TableExport = TableExport; return TableExport; });