Instantly share code, notes, and snippets.
Created
February 20, 2020 15:23
-
Star
6
(6)
You must be signed in to star a gist -
Fork
1
(1)
You must be signed in to fork a gist
-
Save emersonmoretto/41993309f74a4b09f8e90c0a541de342 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* 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=""£"#,##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; | |
}; |
Yeah, it does not worked also from my case... I was looking for a solution on this.
For me it works exactly as expected, thanks a lot. Great work.
I use it with DataTables Buttons v.1.5.2
it works for me fine.
thanks
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?
Thank a lot, for solution. :)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey Emerson! Thanks for the code. For me it doesn't seem to be working. Is there any other files I would need to modify for this one to take effect?