Skip to content

Instantly share code, notes, and snippets.

@emersonmoretto
Created February 20, 2020 15:23
Show Gist options
  • Save emersonmoretto/41993309f74a4b09f8e90c0a541de342 to your computer and use it in GitHub Desktop.
Save emersonmoretto/41993309f74a4b09f8e90c0a541de342 to your computer and use it in GitHub Desktop.
/*!
* 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;
}
DataTable.Buttons.pdfMake = function (_) {
if ( ! _ ) {
return _pdfMake();
}
pdfmake = m_ake;
}
DataTable.Buttons.jszip = function (_) {
if ( ! _ ) {
return _jsZip();
}
jszip = _;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* 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( '<?xml' ) === -1 ) {
str = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+str;
}
// Return namespace attributes to being as such
str = str.replace( /_dt_b_namespace_token_/g, ':' );
// Remove testing name space that IE puts into the space preserve attr
str = str.replace( /xmlns:NS[\d]+="" NS[\d]+:/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 54; // 40 * 1.35
}
}
max *= 1.35;
// And a min width
return max > 6 ? max : 6;
}
// Excel - Pre-defined strings to build a basic XLSX file
var excelStrings = {
"_rels/.rels":
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'+
'<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>'+
'</Relationships>',
"xl/_rels/workbook.xml.rels":
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'+
'<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>'+
'<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>'+
'</Relationships>',
"[Content_Types].xml":
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
'<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">'+
'<Default Extension="xml" ContentType="application/xml" />'+
'<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" />'+
'<Default Extension="jpeg" ContentType="image/jpeg" />'+
'<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" />'+
'<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" />'+
'<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml" />'+
'</Types>',
"xl/workbook.xml":
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
'<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">'+
'<fileVersion appName="xl" lastEdited="5" lowestEdited="5" rupBuild="24816"/>'+
'<workbookPr showInkAnnotation="0" autoCompressPictures="0"/>'+
'<bookViews>'+
'<workbookView xWindow="0" yWindow="0" windowWidth="25600" windowHeight="19020" tabRatio="500"/>'+
'</bookViews>'+
'<sheets>'+
'<sheet name="Sheet1" sheetId="1" r:id="rId1"/>'+
'</sheets>'+
'<definedNames/>'+
'</workbook>',
"xl/worksheets/sheet1.xml":
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
'<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">'+
'<sheetData/>'+
'<mergeCells count="0"/>'+
'</worksheet>',
"xl/styles.xml":
'<?xml version="1.0" encoding="UTF-8"?>'+
'<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">'+
'<numFmts count="6">'+
'<numFmt numFmtId="164" formatCode="#,##0.00_-\ [$$-45C]"/>'+
'<numFmt numFmtId="165" formatCode="&quot;£&quot;#,##0.00"/>'+
'<numFmt numFmtId="166" formatCode="[$€-2]\ #,##0.00"/>'+
'<numFmt numFmtId="167" formatCode="0.0%"/>'+
'<numFmt numFmtId="168" formatCode="#,##0;(#,##0)"/>'+
'<numFmt numFmtId="169" formatCode="#,##0.00;(#,##0.00)"/>'+
'</numFmts>'+
'<fonts count="5" x14ac:knownFonts="1">'+
'<font>'+
'<sz val="11" />'+
'<name val="Calibri" />'+
'</font>'+
'<font>'+
'<sz val="11" />'+
'<name val="Calibri" />'+
'<color rgb="FFFFFFFF" />'+
'</font>'+
'<font>'+
'<sz val="11" />'+
'<name val="Calibri" />'+
'<b />'+
'</font>'+
'<font>'+
'<sz val="11" />'+
'<name val="Calibri" />'+
'<i />'+
'</font>'+
'<font>'+
'<sz val="11" />'+
'<name val="Calibri" />'+
'<u />'+
'</font>'+
'</fonts>'+
'<fills count="6">'+
'<fill>'+
'<patternFill patternType="none" />'+
'</fill>'+
'<fill>'+ // Excel appears to use this as a dotted background regardless of values but
'<patternFill patternType="none" />'+ // to be valid to the schema, use a patternFill
'</fill>'+
'<fill>'+
'<patternFill patternType="solid">'+
'<fgColor rgb="FFD9D9D9" />'+
'<bgColor indexed="64" />'+
'</patternFill>'+
'</fill>'+
'<fill>'+
'<patternFill patternType="solid">'+
'<fgColor rgb="FFD99795" />'+
'<bgColor indexed="64" />'+
'</patternFill>'+
'</fill>'+
'<fill>'+
'<patternFill patternType="solid">'+
'<fgColor rgb="ffc6efce" />'+
'<bgColor indexed="64" />'+
'</patternFill>'+
'</fill>'+
'<fill>'+
'<patternFill patternType="solid">'+
'<fgColor rgb="ffc6cfef" />'+
'<bgColor indexed="64" />'+
'</patternFill>'+
'</fill>'+
'</fills>'+
'<borders count="2">'+
'<border>'+
'<left />'+
'<right />'+
'<top />'+
'<bottom />'+
'<diagonal />'+
'</border>'+
'<border diagonalUp="false" diagonalDown="false">'+
'<left style="thin">'+
'<color auto="1" />'+
'</left>'+
'<right style="thin">'+
'<color auto="1" />'+
'</right>'+
'<top style="thin">'+
'<color auto="1" />'+
'</top>'+
'<bottom style="thin">'+
'<color auto="1" />'+
'</bottom>'+
'<diagonal />'+
'</border>'+
'</borders>'+
'<cellStyleXfs count="1">'+
'<xf numFmtId="0" fontId="0" fillId="0" borderId="0" />'+
'</cellStyleXfs>'+
'<cellXfs count="67">'+
'<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="1" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="2" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="3" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="4" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="0" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="1" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="2" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="3" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="4" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="0" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="1" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="2" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="3" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="4" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="0" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="1" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="2" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="3" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="4" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="0" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="1" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="2" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="3" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="4" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="0" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="1" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="2" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="3" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="4" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="0" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="1" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="2" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="3" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="4" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="0" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="1" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="2" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="3" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="4" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="0" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="1" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="2" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="3" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="4" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="0" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="1" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="2" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="3" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="4" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
'<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
'<alignment horizontal="left"/>'+
'</xf>'+
'<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
'<alignment horizontal="center"/>'+
'</xf>'+
'<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
'<alignment horizontal="right"/>'+
'</xf>'+
'<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
'<alignment horizontal="fill"/>'+
'</xf>'+
'<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
'<alignment textRotation="90"/>'+
'</xf>'+
'<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
'<alignment wrapText="1"/>'+
'</xf>'+
'<xf numFmtId="9" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
'<xf numFmtId="164" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
'<xf numFmtId="165" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
'<xf numFmtId="166" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
'<xf numFmtId="167" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
'<xf numFmtId="168" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
'<xf numFmtId="169" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
'<xf numFmtId="3" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
'<xf numFmtId="4" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
'<xf numFmtId="1" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
'<xf numFmtId="2" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
'</cellXfs>'+
'<cellStyles count="1">'+
'<cellStyle name="Normal" xfId="0" builtinId="0" />'+
'</cellStyles>'+
'<dxfs count="0" />'+
'<tableStyles count="0" defaultTableStyle="TableStyleMedium9" defaultPivotStyle="PivotStyleMedium4" />'+
'</styleSheet>'
};
// 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 = $('<div/>')
.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 = $('<textarea readonly/>')
.val( output )
.appendTo( hiddenDiv );
// For browsers that support the copy execCommand, try to use it
if ( document.queryCommandSupported('copy') ) {
hiddenDiv.appendTo( dt.table().container() );
textarea[0].focus();
textarea[0].select();
try {
var successful = document.execCommand( 'copy' );
hiddenDiv.remove();
if (successful) {
dt.buttons.info(
dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ),
dt.i18n( 'buttons.copySuccess', {
1: 'Copied one row to clipboard',
_: 'Copied %d rows to clipboard'
}, exportData.rows ),
2000
);
this.processing( false );
return;
}
}
catch (t) {}
}
// Otherwise we show the text box and instruct the user to use it
var message = $('<span>'+dt.i18n( 'buttons.copyKeys',
'Press <i>ctrl</i> or <i>\u2318</i> + <i>C</i> to copy the table data<br>to your system clipboard.<br><br>'+
'To cancel, click this message or press escape.' )+'</span>'
)
.append( hiddenDiv );
dt.buttons.info( dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ), message, 0 );
// Select the text so when the user activates their system clipboard
// it will copy that text
textarea[0].focus();
textarea[0].select();
// Event to hide the message when the user is done
var container = $(message).closest('.dt-button-info');
var close = function () {
container.off( 'click.buttons-copy' );
$(document).off( '.buttons-copy' );
dt.buttons.info( false );
};
container.on( 'click.buttons-copy', close );
$(document)
.on( 'keydown.buttons-copy', function (e) {
if ( e.keyCode === 27 ) { // esc
close();
that.processing( false );
}
} )
.on( 'copy.buttons-copy cut.buttons-copy', function () {
close();
that.processing( false );
} );
},
exportOptions: {},
fieldSeparator: '\t',
fieldBoundary: '',
header: true,
footer: false,
title: '*',
messageTop: '*',
messageBottom: '*'
};
//
// CSV export
//
DataTable.ext.buttons.csvHtml5 = {
bom: false,
className: 'buttons-csv buttons-html5',
available: function () {
return window.FileReader !== undefined && window.Blob;
},
text: function ( dt ) {
return dt.i18n( 'buttons.csv', 'CSV' );
},
action: function ( e, dt, button, config ) {
this.processing( true );
// Set the text
var output = _exportData( dt, config ).str;
var info = dt.buttons.exportInfo(config);
var charset = config.charset;
if ( config.customize ) {
output = config.customize( output, config, dt );
}
if ( charset !== false ) {
if ( ! charset ) {
charset = document.characterSet || document.charset;
}
if ( charset ) {
charset = ';charset='+charset;
}
}
else {
charset = '';
}
if ( config.bom ) {
output = '\ufeff' + output;
}
_saveAs(
new Blob( [output], {type: 'text/csv'+charset} ),
info.filename,
true
);
this.processing( false );
},
filename: '*',
extension: '.csv',
exportOptions: {},
fieldSeparator: ',',
fieldBoundary: '"',
escapeChar: '"',
charset: null,
header: true,
footer: false
};
//
// Excel (xlsx) export
//
DataTable.ext.buttons.excelHtml5 = {
className: 'buttons-excel buttons-html5',
available: function () {
return window.FileReader !== undefined && _jsZip() !== undefined && ! _isDuffSafari() && _serialiser;
},
text: function ( dt ) {
return dt.i18n( 'buttons.excel', 'Excel' );
},
action: function ( e, dt, button, config ) {
this.processing( true );
var that = this;
var rowPos = 0;
var dataStartRow, dataEndRow;
var getXml = function ( type ) {
var str = excelStrings[ type ];
//str = str.replace( /xmlns:/g, 'xmlns_' ).replace( /mc:/g, 'mc_' );
return $.parseXML( str );
};
var rels = getXml('xl/worksheets/sheet1.xml');
var relsGet = rels.getElementsByTagName( "sheetData" )[0];
var xlsx = {
_rels: {
".rels": getXml('_rels/.rels')
},
xl: {
_rels: {
"workbook.xml.rels": getXml('xl/_rels/workbook.xml.rels')
},
"workbook.xml": getXml('xl/workbook.xml'),
"styles.xml": getXml('xl/styles.xml'),
"worksheets": {
"sheet1.xml": rels
}
},
"[Content_Types].xml": getXml('[Content_Types].xml')
};
var data = dt.buttons.exportData( config.exportOptions );
var currentRow, rowNode;
var addRow = function ( row ) {
currentRow = rowPos+1;
rowNode = _createNode( rels, "row", { attr: {r:currentRow} } );
for ( var i=0, ien=row.length ; i<ien ; i++ ) {
// Concat both the Cell Columns as a letter and the Row of the cell.
var cellId = createCellPos(i) + '' + currentRow;
var cell = null;
// For null, undefined of blank cell, continue so it doesn't create the _createNode
if ( row[i] === null || row[i] === undefined || row[i] === '' ) {
if ( config.createEmptyCells === true ) {
row[i] = '';
}
else {
continue;
}
}
var originalContent = row[i];
row[i] = $.trim( row[i] );
// Special number formatting options
for ( var j=0, jen=_excelSpecials.length ; j<jen ; j++ ) {
var special = _excelSpecials[j];
// TODO Need to provide the ability for the specials to say
// if they are returning a string, since at the moment it is
// assumed to be a number
if ( row[i].match && ! row[i].match(/^0\d+/) && row[i].match( special.match ) ) {
var val = row[i].replace(/[^\d\.\-]/g, '');
if ( special.fmt ) {
val = special.fmt( val );
}
cell = _createNode( rels, 'c', {
attr: {
r: cellId,
s: special.style
},
children: [
_createNode( rels, 'v', { text: val } )
]
} );
break;
}
}
if ( ! cell ) {
if ( typeof row[i] === 'number' || (
row[i].match &&
row[i].match(/^-?\d+(\.\d+)?$/) &&
! row[i].match(/^0\d+/) )
) {
// Detect numbers - don't match numbers with leading zeros
// or a negative anywhere but the start
cell = _createNode( rels, 'c', {
attr: {
t: 'n',
r: cellId
},
children: [
_createNode( rels, 'v', { text: row[i] } )
]
} );
}
else {
// String output - replace non standard characters for text output
var text = ! originalContent.replace ?
originalContent :
originalContent.replace(/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, '');
cell = _createNode( rels, 'c', {
attr: {
t: 'inlineStr',
r: cellId
},
children:{
row: _createNode( rels, 'is', {
children: {
row: _createNode( rels, 't', {
text: text,
attr: {
'xml:space': 'preserve'
}
} )
}
} )
}
} );
}
}
rowNode.appendChild( cell );
}
relsGet.appendChild(rowNode);
rowPos++;
};
if ( config.customizeData ) {
config.customizeData( data );
}
var mergeCells = function ( row, colspan ) {
var mergeCells = $('mergeCells', rels);
mergeCells[0].appendChild( _createNode( rels, 'mergeCell', {
attr: {
ref: 'A'+row+':'+createCellPos(colspan)+row
}
} ) );
mergeCells.attr( 'count', parseFloat(mergeCells.attr( 'count' ))+1 );
$('row:eq('+(row-1)+') c', rels).attr( 's', '51' ); // centre
};
// Title and top messages
var exportInfo = dt.buttons.exportInfo( config );
if ( exportInfo.title ) {
addRow( [exportInfo.title], rowPos );
mergeCells( rowPos, data.header.length-1 );
}
if ( exportInfo.messageTop ) {
addRow( [exportInfo.messageTop], rowPos );
mergeCells( rowPos, data.header.length-1 );
}
// Table itself
if ( config.header ) {
/* ----- BEGIN changed Code ----- */
var headerMatrix = _fnGetHeaders(dt);
for ( var rowIdx = 0; rowIdx < headerMatrix.length; rowIdx++ ) {
addRow( headerMatrix[rowIdx], rowPos );
}
/* ----- OLD Code that is replaced: ----- */
//addRow( data.header, rowPos );
/* ----- END changed Code ----- */
//addRow( data.header, rowPos );
$('row:last c', rels).attr( 's', '2' ); // bold
}
dataStartRow = rowPos;
for ( var n=0, ie=data.body.length ; n<ie ; n++ ) {
addRow( data.body[n], rowPos );
}
dataEndRow = rowPos;
if ( config.footer && data.footer ) {
/* ----- BEGIN changed Code ----- */
var footerMatrix = _fnGetFooters(dt);
for ( var rowIdx = 0; rowIdx < footerMatrix.length; rowIdx++ ) {
addRow( footerMatrix[rowIdx], rowPos );
}
/* ----- OLD Code that is replaced: ----- */
//addRow( data.footer, rowPos);
/* ----- END changed Code ----- */
$('row:last c', rels).attr( 's', '2' ); // bold
}
// Below the table
if ( exportInfo.messageBottom ) {
addRow( [exportInfo.messageBottom], rowPos );
mergeCells( rowPos, data.header.length-1 );
}
// Set column widths
var cols = _createNode( rels, 'cols' );
$('worksheet', rels).prepend( cols );
for ( var i=0, ien=data.header.length ; i<ien ; i++ ) {
cols.appendChild( _createNode( rels, 'col', {
attr: {
min: i+1,
max: i+1,
width: _excelColWidth( data, i ),
customWidth: 1
}
} ) );
}
// Workbook modifications
var workbook = xlsx.xl['workbook.xml'];
$( 'sheets sheet', workbook ).attr( 'name', _sheetname( config ) );
// Auto filter for columns
if ( config.autoFilter ) {
$('mergeCells', rels).before( _createNode( rels, 'autoFilter', {
attr: {
ref: 'A'+dataStartRow+':'+createCellPos(data.header.length-1)+dataEndRow
}
} ) );
$('definedNames', workbook).append( _createNode( workbook, 'definedName', {
attr: {
name: '_xlnm._FilterDatabase',
localSheetId: '0',
hidden: 1
},
text: _sheetname(config)+'!$A$'+dataStartRow+':'+createCellPos(data.header.length-1)+dataEndRow
} ) );
}
// Let the developer customise the document if they want to
if ( config.customize ) {
config.customize( xlsx, config, dt );
}
// Excel doesn't like an empty mergeCells tag
if ( $('mergeCells', rels).children().length === 0 ) {
$('mergeCells', rels).remove();
}
var jszip = _jsZip();
var zip = new jszip();
var zipConfig = {
type: 'blob',
mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
};
_addToZip( zip, xlsx );
if ( zip.generateAsync ) {
// JSZip 3+
zip
.generateAsync( zipConfig )
.then( function ( blob ) {
_saveAs( blob, exportInfo.filename );
that.processing( false );
} );
}
else {
// JSZip 2.5
_saveAs(
zip.generate( zipConfig ),
exportInfo.filename
);
this.processing( false );
}
},
filename: '*',
extension: '.xlsx',
exportOptions: {},
header: true,
footer: false,
title: '*',
messageTop: '*',
messageBottom: '*',
createEmptyCells: false,
autoFilter: false,
sheetName: ''
};
//
// PDF export - using pdfMake - http://pdfmake.org
//
DataTable.ext.buttons.pdfHtml5 = {
className: 'buttons-pdf buttons-html5',
available: function () {
return window.FileReader !== undefined && _pdfMake();
},
text: function ( dt ) {
return dt.i18n( 'buttons.pdf', 'PDF' );
},
action: function ( e, dt, button, config ) {
this.processing( true );
var that = this;
var data = dt.buttons.exportData( config.exportOptions );
var info = dt.buttons.exportInfo( config );
var rows = [];
if ( config.header ) {
rows.push( $.map( data.header, function ( d ) {
return {
text: typeof d === 'string' ? d : d+'',
style: 'tableHeader'
};
} ) );
}
for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
rows.push( $.map( data.body[i], function ( d ) {
if ( d === null || d === undefined ) {
d = '';
}
return {
text: typeof d === 'string' ? d : d+'',
style: i % 2 ? 'tableBodyEven' : 'tableBodyOdd'
};
} ) );
}
if ( config.footer && data.footer) {
rows.push( $.map( data.footer, function ( d ) {
return {
text: typeof d === 'string' ? d : d+'',
style: 'tableFooter'
};
} ) );
}
var doc = {
pageSize: config.pageSize,
pageOrientation: config.orientation,
content: [
{
table: {
headerRows: 1,
body: rows
},
layout: 'noBorders'
}
],
styles: {
tableHeader: {
bold: true,
fontSize: 11,
color: 'white',
fillColor: '#2d4154',
alignment: 'center'
},
tableBodyEven: {},
tableBodyOdd: {
fillColor: '#f3f3f3'
},
tableFooter: {
bold: true,
fontSize: 11,
color: 'white',
fillColor: '#2d4154'
},
title: {
alignment: 'center',
fontSize: 15
},
message: {}
},
defaultStyle: {
fontSize: 10
}
};
if ( info.messageTop ) {
doc.content.unshift( {
text: info.messageTop,
style: 'message',
margin: [ 0, 0, 0, 12 ]
} );
}
if ( info.messageBottom ) {
doc.content.push( {
text: info.messageBottom,
style: 'message',
margin: [ 0, 0, 0, 12 ]
} );
}
if ( info.title ) {
doc.content.unshift( {
text: info.title,
style: 'title',
margin: [ 0, 0, 0, 12 ]
} );
}
if ( config.customize ) {
config.customize( doc, config, dt );
}
var pdf = _pdfMake().createPdf( doc );
if ( config.download === 'open' && ! _isDuffSafari() ) {
pdf.open();
}
else {
pdf.download( info.filename );
}
this.processing( false );
},
title: '*',
filename: '*',
extension: '.pdf',
exportOptions: {},
orientation: 'portrait',
pageSize: 'A4',
header: true,
footer: false,
messageTop: '*',
messageBottom: '*',
customize: null,
download: 'download'
};
return DataTable.Buttons;
}));
var _fnGetHeaders = function(dt) {
var thRows = $(dt.header()[0]).children();
var numRows = thRows.length;
var matrix = [];
// Iterate over each row of the header and add information to matrix.
for ( var rowIdx = 0; rowIdx < numRows; rowIdx++ ) {
var $row = $(thRows[rowIdx]);
// Iterate over actual columns specified in this row.
var $ths = $row.children("th");
for ( var colIdx = 0; colIdx < $ths.length; colIdx++ )
{
var $th = $($ths.get(colIdx));
var colspan = $th.attr("colspan") || 1;
var rowspan = $th.attr("rowspan") || 1;
var colCount = 0;
// ----- add this cell's title to the matrix
if (matrix[rowIdx] === undefined) {
matrix[rowIdx] = []; // create array for this row
}
// find 1st empty cell
for ( var j = 0; j < (matrix[rowIdx]).length; j++, colCount++ ) {
if ( matrix[rowIdx][j] === "PLACEHOLDER" ) {
break;
}
}
var myColCount = colCount;
matrix[rowIdx][colCount++] = $th.text();
// ----- If title cell has colspan, add empty titles for extra cell width.
for ( var j = 1; j < colspan; j++ ) {
matrix[rowIdx][colCount++] = "";
}
// ----- If title cell has rowspan, add empty titles for extra cell height.
for ( var i = 1; i < rowspan; i++ ) {
var thisRow = rowIdx+i;
if ( matrix[thisRow] === undefined ) {
matrix[thisRow] = [];
}
// First add placeholder text for any previous columns.
for ( var j = (matrix[thisRow]).length; j < myColCount; j++ ) {
matrix[thisRow][j] = "PLACEHOLDER";
}
for ( var j = 0; j < colspan; j++ ) { // and empty for my columns
matrix[thisRow][myColCount+j] = "";
}
}
}
}
return matrix;
};
var _fnGetFooters = function(dt) {
var thRows = $(dt.footer()[0]).children();
var numRows = thRows.length;
var matrix = [];
// Iterate over each row of the header and add information to matrix.
for ( var rowIdx = 0; rowIdx < numRows; rowIdx++ ) {
var $row = $(thRows[rowIdx]);
// Iterate over actual columns specified in this row.
var $ths = $row.children("th");
for ( var colIdx = 0; colIdx < $ths.length; colIdx++ )
{
var $th = $($ths.get(colIdx));
var colspan = $th.attr("colspan") || 1;
var rowspan = $th.attr("rowspan") || 1;
var colCount = 0;
// ----- add this cell's title to the matrix
if (matrix[rowIdx] === undefined) {
matrix[rowIdx] = []; // create array for this row
}
// find 1st empty cell
for ( var j = 0; j < (matrix[rowIdx]).length; j++, colCount++ ) {
if ( matrix[rowIdx][j] === "PLACEHOLDER" ) {
break;
}
}
var myColCount = colCount;
matrix[rowIdx][colCount++] = $th.text();
// ----- If title cell has colspan, add empty titles for extra cell width.
for ( var j = 1; j < colspan; j++ ) {
matrix[rowIdx][colCount++] = "";
}
// ----- If title cell has rowspan, add empty titles for extra cell height.
for ( var i = 1; i < rowspan; i++ ) {
var thisRow = rowIdx+i;
if ( matrix[thisRow] === undefined ) {
matrix[thisRow] = [];
}
// First add placeholder text for any previous columns.
for ( var j = (matrix[thisRow]).length; j < myColCount; j++ ) {
matrix[thisRow][j] = "PLACEHOLDER";
}
for ( var j = 0; j < colspan; j++ ) { // and empty for my columns
matrix[thisRow][myColCount+j] = "";
}
}
}
}
return matrix;
};
@findsomeoneyys
Copy link

it works for me fine.
thanks

@chalamministries
Copy link

I get “We found a problem with some content in ‘filename.xlsx’. Do you want us to try to recover as much as we can? If you trust the source of this workbook, click Yes". I'm using multiple headers and some have a rowspan on them. Any ideas?

@apisitp61
Copy link

Thank a lot, for solution. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment