buttons.html5.js 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345
  1. /*!
  2. * HTML5 export buttons for Buttons and DataTables.
  3. * 2016 SpryMedia Ltd - datatables.net/license
  4. *
  5. * FileSaver.js (1.1.20160328) - MIT license
  6. * Copyright © 2016 Eli Grey - http://eligrey.com
  7. */
  8. (function( factory ){
  9. if ( typeof define === 'function' && define.amd ) {
  10. // AMD
  11. define( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) {
  12. return factory( $, window, document );
  13. } );
  14. }
  15. else if ( typeof exports === 'object' ) {
  16. // CommonJS
  17. module.exports = function (root, $, jszip, pdfmake) {
  18. if ( ! root ) {
  19. root = window;
  20. }
  21. if ( ! $ || ! $.fn.dataTable ) {
  22. $ = require('datatables.net')(root, $).$;
  23. }
  24. if ( ! $.fn.dataTable.Buttons ) {
  25. require('datatables.net-buttons')(root, $);
  26. }
  27. return factory( $, root, root.document, jszip, pdfmake );
  28. };
  29. }
  30. else {
  31. // Browser
  32. factory( jQuery, window, document );
  33. }
  34. }(function( $, window, document, jszip, pdfmake, undefined ) {
  35. 'use strict';
  36. var DataTable = $.fn.dataTable;
  37. // Allow the constructor to pass in JSZip and PDFMake from external requires.
  38. // Otherwise, use globally defined variables, if they are available.
  39. function _jsZip () {
  40. return jszip || window.JSZip;
  41. }
  42. function _pdfMake () {
  43. return pdfmake || window.pdfMake;
  44. }
  45. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  46. * FileSaver.js dependency
  47. */
  48. /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
  49. var _saveAs = (function(view) {
  50. "use strict";
  51. // IE <10 is explicitly unsupported
  52. if (typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
  53. return;
  54. }
  55. var
  56. doc = view.document
  57. // only get URL when necessary in case Blob.js hasn't overridden it yet
  58. , get_URL = function() {
  59. return view.URL || view.webkitURL || view;
  60. }
  61. , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
  62. , can_use_save_link = "download" in save_link
  63. , click = function(node) {
  64. var event = new MouseEvent("click");
  65. node.dispatchEvent(event);
  66. }
  67. , is_safari = /Version\/[\d\.]+.*Safari/.test(navigator.userAgent)
  68. , webkit_req_fs = view.webkitRequestFileSystem
  69. , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
  70. , throw_outside = function(ex) {
  71. (view.setImmediate || view.setTimeout)(function() {
  72. throw ex;
  73. }, 0);
  74. }
  75. , force_saveable_type = "application/octet-stream"
  76. , fs_min_size = 0
  77. // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to
  78. , arbitrary_revoke_timeout = 1000 * 40 // in ms
  79. , revoke = function(file) {
  80. var revoker = function() {
  81. if (typeof file === "string") { // file is an object URL
  82. get_URL().revokeObjectURL(file);
  83. } else { // file is a File
  84. file.remove();
  85. }
  86. };
  87. /* // Take note W3C:
  88. var
  89. uri = typeof file === "string" ? file : file.toURL()
  90. , revoker = function(evt) {
  91. // idealy DownloadFinishedEvent.data would be the URL requested
  92. if (evt.data === uri) {
  93. if (typeof file === "string") { // file is an object URL
  94. get_URL().revokeObjectURL(file);
  95. } else { // file is a File
  96. file.remove();
  97. }
  98. }
  99. }
  100. ;
  101. view.addEventListener("downloadfinished", revoker);
  102. */
  103. setTimeout(revoker, arbitrary_revoke_timeout);
  104. }
  105. , dispatch = function(filesaver, event_types, event) {
  106. event_types = [].concat(event_types);
  107. var i = event_types.length;
  108. while (i--) {
  109. var listener = filesaver["on" + event_types[i]];
  110. if (typeof listener === "function") {
  111. try {
  112. listener.call(filesaver, event || filesaver);
  113. } catch (ex) {
  114. throw_outside(ex);
  115. }
  116. }
  117. }
  118. }
  119. , auto_bom = function(blob) {
  120. // prepend BOM for UTF-8 XML and text/* types (including HTML)
  121. if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
  122. return new Blob(["\ufeff", blob], {type: blob.type});
  123. }
  124. return blob;
  125. }
  126. , FileSaver = function(blob, name, no_auto_bom) {
  127. if (!no_auto_bom) {
  128. blob = auto_bom(blob);
  129. }
  130. // First try a.download, then web filesystem, then object URLs
  131. var
  132. filesaver = this
  133. , type = blob.type
  134. , blob_changed = false
  135. , object_url
  136. , target_view
  137. , dispatch_all = function() {
  138. dispatch(filesaver, "writestart progress write writeend".split(" "));
  139. }
  140. // on any filesys errors revert to saving with object URLs
  141. , fs_error = function() {
  142. if (target_view && is_safari && typeof FileReader !== "undefined") {
  143. // Safari doesn't allow downloading of blob urls
  144. var reader = new FileReader();
  145. reader.onloadend = function() {
  146. var base64Data = reader.result;
  147. target_view.location.href = "data:attachment/file" + base64Data.slice(base64Data.search(/[,;]/));
  148. filesaver.readyState = filesaver.DONE;
  149. dispatch_all();
  150. };
  151. reader.readAsDataURL(blob);
  152. filesaver.readyState = filesaver.INIT;
  153. return;
  154. }
  155. // don't create more object URLs than needed
  156. if (blob_changed || !object_url) {
  157. object_url = get_URL().createObjectURL(blob);
  158. }
  159. if (target_view) {
  160. target_view.location.href = object_url;
  161. } else {
  162. var new_tab = view.open(object_url, "_blank");
  163. if (new_tab === undefined && is_safari) {
  164. //Apple do not allow window.open, see http://bit.ly/1kZffRI
  165. view.location.href = object_url
  166. }
  167. }
  168. filesaver.readyState = filesaver.DONE;
  169. dispatch_all();
  170. revoke(object_url);
  171. }
  172. , abortable = function(func) {
  173. return function() {
  174. if (filesaver.readyState !== filesaver.DONE) {
  175. return func.apply(this, arguments);
  176. }
  177. };
  178. }
  179. , create_if_not_found = {create: true, exclusive: false}
  180. , slice
  181. ;
  182. filesaver.readyState = filesaver.INIT;
  183. if (!name) {
  184. name = "download";
  185. }
  186. if (can_use_save_link) {
  187. object_url = get_URL().createObjectURL(blob);
  188. setTimeout(function() {
  189. save_link.href = object_url;
  190. save_link.download = name;
  191. click(save_link);
  192. dispatch_all();
  193. revoke(object_url);
  194. filesaver.readyState = filesaver.DONE;
  195. });
  196. return;
  197. }
  198. // Object and web filesystem URLs have a problem saving in Google Chrome when
  199. // viewed in a tab, so I force save with application/octet-stream
  200. // http://code.google.com/p/chromium/issues/detail?id=91158
  201. // Update: Google errantly closed 91158, I submitted it again:
  202. // https://code.google.com/p/chromium/issues/detail?id=389642
  203. if (view.chrome && type && type !== force_saveable_type) {
  204. slice = blob.slice || blob.webkitSlice;
  205. blob = slice.call(blob, 0, blob.size, force_saveable_type);
  206. blob_changed = true;
  207. }
  208. // Since I can't be sure that the guessed media type will trigger a download
  209. // in WebKit, I append .download to the filename.
  210. // https://bugs.webkit.org/show_bug.cgi?id=65440
  211. if (webkit_req_fs && name !== "download") {
  212. name += ".download";
  213. }
  214. if (type === force_saveable_type || webkit_req_fs) {
  215. target_view = view;
  216. }
  217. if (!req_fs) {
  218. fs_error();
  219. return;
  220. }
  221. fs_min_size += blob.size;
  222. req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
  223. fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
  224. var save = function() {
  225. dir.getFile(name, create_if_not_found, abortable(function(file) {
  226. file.createWriter(abortable(function(writer) {
  227. writer.onwriteend = function(event) {
  228. target_view.location.href = file.toURL();
  229. filesaver.readyState = filesaver.DONE;
  230. dispatch(filesaver, "writeend", event);
  231. revoke(file);
  232. };
  233. writer.onerror = function() {
  234. var error = writer.error;
  235. if (error.code !== error.ABORT_ERR) {
  236. fs_error();
  237. }
  238. };
  239. "writestart progress write abort".split(" ").forEach(function(event) {
  240. writer["on" + event] = filesaver["on" + event];
  241. });
  242. writer.write(blob);
  243. filesaver.abort = function() {
  244. writer.abort();
  245. filesaver.readyState = filesaver.DONE;
  246. };
  247. filesaver.readyState = filesaver.WRITING;
  248. }), fs_error);
  249. }), fs_error);
  250. };
  251. dir.getFile(name, {create: false}, abortable(function(file) {
  252. // delete file if it already exists
  253. file.remove();
  254. save();
  255. }), abortable(function(ex) {
  256. if (ex.code === ex.NOT_FOUND_ERR) {
  257. save();
  258. } else {
  259. fs_error();
  260. }
  261. }));
  262. }), fs_error);
  263. }), fs_error);
  264. }
  265. , FS_proto = FileSaver.prototype
  266. , saveAs = function(blob, name, no_auto_bom) {
  267. return new FileSaver(blob, name, no_auto_bom);
  268. }
  269. ;
  270. // IE 10+ (native saveAs)
  271. if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
  272. return function(blob, name, no_auto_bom) {
  273. if (!no_auto_bom) {
  274. blob = auto_bom(blob);
  275. }
  276. return navigator.msSaveOrOpenBlob(blob, name || "download");
  277. };
  278. }
  279. FS_proto.abort = function() {
  280. var filesaver = this;
  281. filesaver.readyState = filesaver.DONE;
  282. dispatch(filesaver, "abort");
  283. };
  284. FS_proto.readyState = FS_proto.INIT = 0;
  285. FS_proto.WRITING = 1;
  286. FS_proto.DONE = 2;
  287. FS_proto.error =
  288. FS_proto.onwritestart =
  289. FS_proto.onprogress =
  290. FS_proto.onwrite =
  291. FS_proto.onabort =
  292. FS_proto.onerror =
  293. FS_proto.onwriteend =
  294. null;
  295. return saveAs;
  296. }(
  297. typeof self !== "undefined" && self
  298. || typeof window !== "undefined" && window
  299. || this.content
  300. ));
  301. // Expose file saver on the DataTables API. Can't attach to `DataTables.Buttons`
  302. // since this file can be loaded before Button's core!
  303. DataTable.fileSave = _saveAs;
  304. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  305. * Local (private) functions
  306. */
  307. /**
  308. * Get the file name for an exported file.
  309. *
  310. * @param {object} config Button configuration
  311. * @param {boolean} incExtension Include the file name extension
  312. */
  313. var _filename = function ( config, incExtension )
  314. {
  315. // Backwards compatibility
  316. var filename = config.filename === '*' && config.title !== '*' && config.title !== undefined ?
  317. config.title :
  318. config.filename;
  319. if ( typeof filename === 'function' ) {
  320. filename = filename();
  321. }
  322. if ( filename.indexOf( '*' ) !== -1 ) {
  323. filename = $.trim( filename.replace( '*', $('title').text() ) );
  324. }
  325. // Strip characters which the OS will object to
  326. filename = filename.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g, "");
  327. return incExtension === undefined || incExtension === true ?
  328. filename+config.extension :
  329. filename;
  330. };
  331. /**
  332. * Get the sheet name for Excel exports.
  333. *
  334. * @param {object} config Button configuration
  335. */
  336. var _sheetname = function ( config )
  337. {
  338. var sheetName = 'Sheet1';
  339. if ( config.sheetName ) {
  340. sheetName = config.sheetName.replace(/[\[\]\*\/\\\?\:]/g, '');
  341. }
  342. return sheetName;
  343. };
  344. /**
  345. * Get the title for an exported file.
  346. *
  347. * @param {object} config Button configuration
  348. */
  349. var _title = function ( config )
  350. {
  351. var title = config.title;
  352. if ( typeof title === 'function' ) {
  353. title = title();
  354. }
  355. return title.indexOf( '*' ) !== -1 ?
  356. title.replace( '*', $('title').text() || 'Exported data' ) :
  357. title;
  358. };
  359. /**
  360. * Get the newline character(s)
  361. *
  362. * @param {object} config Button configuration
  363. * @return {string} Newline character
  364. */
  365. var _newLine = function ( config )
  366. {
  367. return config.newline ?
  368. config.newline :
  369. navigator.userAgent.match(/Windows/) ?
  370. '\r\n' :
  371. '\n';
  372. };
  373. /**
  374. * Combine the data from the `buttons.exportData` method into a string that
  375. * will be used in the export file.
  376. *
  377. * @param {DataTable.Api} dt DataTables API instance
  378. * @param {object} config Button configuration
  379. * @return {object} The data to export
  380. */
  381. var _exportData = function ( dt, config )
  382. {
  383. var newLine = _newLine( config );
  384. var data = dt.buttons.exportData( config.exportOptions );
  385. var boundary = config.fieldBoundary;
  386. var separator = config.fieldSeparator;
  387. var reBoundary = new RegExp( boundary, 'g' );
  388. var escapeChar = config.escapeChar !== undefined ?
  389. config.escapeChar :
  390. '\\';
  391. var join = function ( a ) {
  392. var s = '';
  393. // If there is a field boundary, then we might need to escape it in
  394. // the source data
  395. for ( var i=0, ien=a.length ; i<ien ; i++ ) {
  396. if ( i > 0 ) {
  397. s += separator;
  398. }
  399. s += boundary ?
  400. boundary + ('' + a[i]).replace( reBoundary, escapeChar+boundary ) + boundary :
  401. a[i];
  402. }
  403. return s;
  404. };
  405. var header = config.header ? join( data.header )+newLine : '';
  406. var footer = config.footer && data.footer ? newLine+join( data.footer ) : '';
  407. var body = [];
  408. for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
  409. body.push( join( data.body[i] ) );
  410. }
  411. return {
  412. str: header + body.join( newLine ) + footer,
  413. rows: body.length
  414. };
  415. };
  416. /**
  417. * Safari's data: support for creating and downloading files is really poor, so
  418. * various options need to be disabled in it. See
  419. * https://bugs.webkit.org/show_bug.cgi?id=102914
  420. *
  421. * @return {Boolean} `true` if Safari
  422. */
  423. var _isSafari = function ()
  424. {
  425. return navigator.userAgent.indexOf('Safari') !== -1 &&
  426. navigator.userAgent.indexOf('Chrome') === -1 &&
  427. navigator.userAgent.indexOf('Opera') === -1;
  428. };
  429. /**
  430. * Convert from numeric position to letter for column names in Excel
  431. * @param {int} n Column number
  432. * @return {string} Column letter(s) name
  433. */
  434. function createCellPos( n ){
  435. var ordA = 'A'.charCodeAt(0);
  436. var ordZ = 'Z'.charCodeAt(0);
  437. var len = ordZ - ordA + 1;
  438. var s = "";
  439. while( n >= 0 ) {
  440. s = String.fromCharCode(n % len + ordA) + s;
  441. n = Math.floor(n / len) - 1;
  442. }
  443. return s;
  444. }
  445. try {
  446. var _serialiser = new XMLSerializer();
  447. var _ieExcel;
  448. }
  449. catch (t) {}
  450. /**
  451. * Recursively add XML files from an object's structure to a ZIP file. This
  452. * allows the XSLX file to be easily defined with an object's structure matching
  453. * the files structure.
  454. *
  455. * @param {JSZip} zip ZIP package
  456. * @param {object} obj Object to add (recursive)
  457. */
  458. function _addToZip( zip, obj ) {
  459. if ( _ieExcel === undefined ) {
  460. // Detect if we are dealing with IE's _awful_ serialiser by seeing if it
  461. // drop attributes
  462. _ieExcel = _serialiser
  463. .serializeToString(
  464. $.parseXML( excelStrings['xl/worksheets/sheet1.xml'] )
  465. )
  466. .indexOf( 'xmlns:r' ) === -1;
  467. }
  468. $.each( obj, function ( name, val ) {
  469. if ( $.isPlainObject( val ) ) {
  470. var newDir = zip.folder( name );
  471. _addToZip( newDir, val );
  472. }
  473. else {
  474. if ( _ieExcel ) {
  475. // IE's XML serialiser will drop some name space attributes from
  476. // from the root node, so we need to save them. Do this by
  477. // replacing the namespace nodes with a regular attribute that
  478. // we convert back when serialised. Edge does not have this
  479. // issue
  480. var worksheet = val.childNodes[0];
  481. var i, ien;
  482. var attrs = [];
  483. for ( i=worksheet.attributes.length-1 ; i>=0 ; i-- ) {
  484. var attrName = worksheet.attributes[i].nodeName;
  485. var attrValue = worksheet.attributes[i].nodeValue;
  486. if ( attrName.indexOf( ':' ) !== -1 ) {
  487. attrs.push( { name: attrName, value: attrValue } );
  488. worksheet.removeAttribute( attrName );
  489. }
  490. }
  491. for ( i=0, ien=attrs.length ; i<ien ; i++ ) {
  492. var attr = val.createAttribute( attrs[i].name.replace( ':', '_dt_b_namespace_token_' ) );
  493. attr.value = attrs[i].value;
  494. worksheet.setAttributeNode( attr );
  495. }
  496. }
  497. var str = _serialiser.serializeToString(val);
  498. // Fix IE's XML
  499. if ( _ieExcel ) {
  500. // IE doesn't include the XML declaration
  501. if ( str.indexOf( '<?xml' ) === -1 ) {
  502. str = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+str;
  503. }
  504. // Return namespace attributes to being as such
  505. str = str.replace( /_dt_b_namespace_token_/g, ':' );
  506. }
  507. // Both IE and Edge will put empty name space attributes onto the
  508. // rows and columns making them useless
  509. str = str
  510. .replace( /<row xmlns="" /g, '<row ' )
  511. .replace( /<cols xmlns="">/g, '<cols>' );
  512. zip.file( name, str );
  513. }
  514. } );
  515. }
  516. /**
  517. * Create an XML node and add any children, attributes, etc without needing to
  518. * be verbose in the DOM.
  519. *
  520. * @param {object} doc XML document
  521. * @param {string} nodeName Node name
  522. * @param {object} opts Options - can be `attr` (attributes), `children`
  523. * (child nodes) and `text` (text content)
  524. * @return {node} Created node
  525. */
  526. function _createNode( doc, nodeName, opts ) {
  527. var tempNode = doc.createElement( nodeName );
  528. if ( opts ) {
  529. if ( opts.attr ) {
  530. $(tempNode).attr( opts.attr );
  531. }
  532. if( opts.children ) {
  533. $.each( opts.children, function ( key, value ) {
  534. tempNode.appendChild( value );
  535. });
  536. }
  537. if( opts.text ) {
  538. tempNode.appendChild( doc.createTextNode( opts.text ) );
  539. }
  540. }
  541. return tempNode;
  542. }
  543. /**
  544. * Get the width for an Excel column based on the contents of that column
  545. * @param {object} data Data for export
  546. * @param {int} col Column index
  547. * @return {int} Column width
  548. */
  549. function _excelColWidth( data, col ) {
  550. var max = data.header[col].length;
  551. var len;
  552. if ( data.footer && data.footer[col].length > max ) {
  553. max = data.footer[col].length;
  554. }
  555. for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
  556. len = data.body[i][col].toString().length;
  557. if ( len > max ) {
  558. max = len;
  559. }
  560. // Max width rather than having potentially massive column widths
  561. if ( max > 40 ) {
  562. break;
  563. }
  564. }
  565. // And a min width
  566. return max > 5 ? max : 5;
  567. }
  568. // Excel - Pre-defined strings to build a basic XLSX file
  569. var excelStrings = {
  570. "_rels/.rels":
  571. '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
  572. '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'+
  573. '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>'+
  574. '</Relationships>',
  575. "xl/_rels/workbook.xml.rels":
  576. '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
  577. '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'+
  578. '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>'+
  579. '<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>'+
  580. '</Relationships>',
  581. "[Content_Types].xml":
  582. '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
  583. '<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">'+
  584. '<Default Extension="xml" ContentType="application/xml" />'+
  585. '<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" />'+
  586. '<Default Extension="jpeg" ContentType="image/jpeg" />'+
  587. '<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" />'+
  588. '<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" />'+
  589. '<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml" />'+
  590. '</Types>',
  591. "xl/workbook.xml":
  592. '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
  593. '<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">'+
  594. '<fileVersion appName="xl" lastEdited="5" lowestEdited="5" rupBuild="24816"/>'+
  595. '<workbookPr showInkAnnotation="0" autoCompressPictures="0"/>'+
  596. '<bookViews>'+
  597. '<workbookView xWindow="0" yWindow="0" windowWidth="25600" windowHeight="19020" tabRatio="500"/>'+
  598. '</bookViews>'+
  599. '<sheets>'+
  600. '<sheet name="" sheetId="1" r:id="rId1"/>'+
  601. '</sheets>'+
  602. '</workbook>',
  603. "xl/worksheets/sheet1.xml":
  604. '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
  605. '<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">'+
  606. '<sheetData/>'+
  607. '</worksheet>',
  608. "xl/styles.xml":
  609. '<?xml version="1.0" encoding="UTF-8"?>'+
  610. '<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">'+
  611. '<fonts count="5" x14ac:knownFonts="1">'+
  612. '<font>'+
  613. '<sz val="11" />'+
  614. '<name val="Calibri" />'+
  615. '</font>'+
  616. '<font>'+
  617. '<sz val="11" />'+
  618. '<name val="Calibri" />'+
  619. '<color rgb="FFFFFFFF" />'+
  620. '</font>'+
  621. '<font>'+
  622. '<sz val="11" />'+
  623. '<name val="Calibri" />'+
  624. '<b />'+
  625. '</font>'+
  626. '<font>'+
  627. '<sz val="11" />'+
  628. '<name val="Calibri" />'+
  629. '<i />'+
  630. '</font>'+
  631. '<font>'+
  632. '<sz val="11" />'+
  633. '<name val="Calibri" />'+
  634. '<u />'+
  635. '</font>'+
  636. '</fonts>'+
  637. '<fills count="6">'+
  638. '<fill>'+
  639. '<patternFill patternType="none" />'+
  640. '</fill>'+
  641. '<fill/>'+ // Excel appears to use this as a dotted background regardless of values
  642. '<fill>'+
  643. '<patternFill patternType="solid">'+
  644. '<fgColor rgb="FFD9D9D9" />'+
  645. '<bgColor indexed="64" />'+
  646. '</patternFill>'+
  647. '</fill>'+
  648. '<fill>'+
  649. '<patternFill patternType="solid">'+
  650. '<fgColor rgb="FFD99795" />'+
  651. '<bgColor indexed="64" />'+
  652. '</patternFill>'+
  653. '</fill>'+
  654. '<fill>'+
  655. '<patternFill patternType="solid">'+
  656. '<fgColor rgb="ffc6efce" />'+
  657. '<bgColor indexed="64" />'+
  658. '</patternFill>'+
  659. '</fill>'+
  660. '<fill>'+
  661. '<patternFill patternType="solid">'+
  662. '<fgColor rgb="ffc6cfef" />'+
  663. '<bgColor indexed="64" />'+
  664. '</patternFill>'+
  665. '</fill>'+
  666. '</fills>'+
  667. '<borders count="2">'+
  668. '<border>'+
  669. '<left />'+
  670. '<right />'+
  671. '<top />'+
  672. '<bottom />'+
  673. '<diagonal />'+
  674. '</border>'+
  675. '<border diagonalUp="false" diagonalDown="false">'+
  676. '<left style="thin">'+
  677. '<color auto="1" />'+
  678. '</left>'+
  679. '<right style="thin">'+
  680. '<color auto="1" />'+
  681. '</right>'+
  682. '<top style="thin">'+
  683. '<color auto="1" />'+
  684. '</top>'+
  685. '<bottom style="thin">'+
  686. '<color auto="1" />'+
  687. '</bottom>'+
  688. '<diagonal />'+
  689. '</border>'+
  690. '</borders>'+
  691. '<cellStyleXfs count="1">'+
  692. '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" />'+
  693. '</cellStyleXfs>'+
  694. '<cellXfs count="56">'+
  695. '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  696. '<xf numFmtId="0" fontId="1" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  697. '<xf numFmtId="0" fontId="2" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  698. '<xf numFmtId="0" fontId="3" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  699. '<xf numFmtId="0" fontId="4" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  700. '<xf numFmtId="0" fontId="0" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  701. '<xf numFmtId="0" fontId="1" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  702. '<xf numFmtId="0" fontId="2" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  703. '<xf numFmtId="0" fontId="3" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  704. '<xf numFmtId="0" fontId="4" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  705. '<xf numFmtId="0" fontId="0" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  706. '<xf numFmtId="0" fontId="1" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  707. '<xf numFmtId="0" fontId="2" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  708. '<xf numFmtId="0" fontId="3" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  709. '<xf numFmtId="0" fontId="4" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  710. '<xf numFmtId="0" fontId="0" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  711. '<xf numFmtId="0" fontId="1" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  712. '<xf numFmtId="0" fontId="2" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  713. '<xf numFmtId="0" fontId="3" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  714. '<xf numFmtId="0" fontId="4" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  715. '<xf numFmtId="0" fontId="0" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  716. '<xf numFmtId="0" fontId="1" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  717. '<xf numFmtId="0" fontId="2" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  718. '<xf numFmtId="0" fontId="3" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  719. '<xf numFmtId="0" fontId="4" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
  720. '<xf numFmtId="0" fontId="0" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  721. '<xf numFmtId="0" fontId="1" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  722. '<xf numFmtId="0" fontId="2" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  723. '<xf numFmtId="0" fontId="3" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  724. '<xf numFmtId="0" fontId="4" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  725. '<xf numFmtId="0" fontId="0" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  726. '<xf numFmtId="0" fontId="1" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  727. '<xf numFmtId="0" fontId="2" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  728. '<xf numFmtId="0" fontId="3" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  729. '<xf numFmtId="0" fontId="4" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  730. '<xf numFmtId="0" fontId="0" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  731. '<xf numFmtId="0" fontId="1" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  732. '<xf numFmtId="0" fontId="2" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  733. '<xf numFmtId="0" fontId="3" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  734. '<xf numFmtId="0" fontId="4" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  735. '<xf numFmtId="0" fontId="0" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  736. '<xf numFmtId="0" fontId="1" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  737. '<xf numFmtId="0" fontId="2" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  738. '<xf numFmtId="0" fontId="3" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  739. '<xf numFmtId="0" fontId="4" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  740. '<xf numFmtId="0" fontId="0" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  741. '<xf numFmtId="0" fontId="1" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  742. '<xf numFmtId="0" fontId="2" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  743. '<xf numFmtId="0" fontId="3" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  744. '<xf numFmtId="0" fontId="4" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
  745. '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
  746. '<alignment horizontal="left"/>'+
  747. '</xf>'+
  748. '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
  749. '<alignment horizontal="center"/>'+
  750. '</xf>'+
  751. '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
  752. '<alignment horizontal="right"/>'+
  753. '</xf>'+
  754. '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
  755. '<alignment horizontal="fill"/>'+
  756. '</xf>'+
  757. '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
  758. '<alignment textRotation="90"/>'+
  759. '</xf>'+
  760. '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
  761. '<alignment wrapText="1"/>'+
  762. '</xf>'+
  763. '</cellXfs>'+
  764. '<cellStyles count="1">'+
  765. '<cellStyle name="Normal" xfId="0" builtinId="0" />'+
  766. '</cellStyles>'+
  767. '<dxfs count="0" />'+
  768. '<tableStyles count="0" defaultTableStyle="TableStyleMedium9" defaultPivotStyle="PivotStyleMedium4" />'+
  769. '</styleSheet>'
  770. };
  771. // Note we could use 3 `for` loops for the styles, but when gzipped there is
  772. // virtually no difference in size, since the above can be easily compressed
  773. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  774. * Buttons
  775. */
  776. //
  777. // Copy to clipboard
  778. //
  779. DataTable.ext.buttons.copyHtml5 = {
  780. className: 'buttons-copy buttons-html5',
  781. text: function ( dt ) {
  782. return dt.i18n( 'buttons.copy', 'Copy' );
  783. },
  784. action: function ( e, dt, button, config ) {
  785. var exportData = _exportData( dt, config );
  786. var output = exportData.str;
  787. var hiddenDiv = $('<div/>')
  788. .css( {
  789. height: 1,
  790. width: 1,
  791. overflow: 'hidden',
  792. position: 'fixed',
  793. top: 0,
  794. left: 0
  795. } );
  796. if ( config.customize ) {
  797. output = config.customize( output, config );
  798. }
  799. var textarea = $('<textarea readonly/>')
  800. .val( output )
  801. .appendTo( hiddenDiv );
  802. // For browsers that support the copy execCommand, try to use it
  803. if ( document.queryCommandSupported('copy') ) {
  804. hiddenDiv.appendTo( dt.table().container() );
  805. textarea[0].focus();
  806. textarea[0].select();
  807. try {
  808. var successful = document.execCommand( 'copy' );
  809. hiddenDiv.remove();
  810. if (successful) {
  811. dt.buttons.info(
  812. dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ),
  813. dt.i18n( 'buttons.copySuccess', {
  814. 1: 'Copied one row to clipboard',
  815. _: 'Copied %d rows to clipboard'
  816. }, exportData.rows ),
  817. 2000
  818. );
  819. return;
  820. }
  821. }
  822. catch (t) {}
  823. }
  824. // Otherwise we show the text box and instruct the user to use it
  825. var message = $('<span>'+dt.i18n( 'buttons.copyKeys',
  826. 'Press <i>ctrl</i> or <i>\u2318</i> + <i>C</i> to copy the table data<br>to your system clipboard.<br><br>'+
  827. 'To cancel, click this message or press escape.' )+'</span>'
  828. )
  829. .append( hiddenDiv );
  830. dt.buttons.info( dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ), message, 0 );
  831. // Select the text so when the user activates their system clipboard
  832. // it will copy that text
  833. textarea[0].focus();
  834. textarea[0].select();
  835. // Event to hide the message when the user is done
  836. var container = $(message).closest('.dt-button-info');
  837. var close = function () {
  838. container.off( 'click.buttons-copy' );
  839. $(document).off( '.buttons-copy' );
  840. dt.buttons.info( false );
  841. };
  842. container.on( 'click.buttons-copy', close );
  843. $(document)
  844. .on( 'keydown.buttons-copy', function (e) {
  845. if ( e.keyCode === 27 ) { // esc
  846. close();
  847. }
  848. } )
  849. .on( 'copy.buttons-copy cut.buttons-copy', function () {
  850. close();
  851. } );
  852. },
  853. exportOptions: {},
  854. fieldSeparator: '\t',
  855. fieldBoundary: '',
  856. header: true,
  857. footer: false
  858. };
  859. //
  860. // CSV export
  861. //
  862. DataTable.ext.buttons.csvHtml5 = {
  863. bom: false,
  864. className: 'buttons-csv buttons-html5',
  865. available: function () {
  866. return window.FileReader !== undefined && window.Blob;
  867. },
  868. text: function ( dt ) {
  869. return dt.i18n( 'buttons.csv', 'CSV' );
  870. },
  871. action: function ( e, dt, button, config ) {
  872. // Set the text
  873. var output = _exportData( dt, config ).str;
  874. var charset = config.charset;
  875. if ( config.customize ) {
  876. output = config.customize( output, config );
  877. }
  878. if ( charset !== false ) {
  879. if ( ! charset ) {
  880. charset = document.characterSet || document.charset;
  881. }
  882. if ( charset ) {
  883. charset = ';charset='+charset;
  884. }
  885. }
  886. else {
  887. charset = '';
  888. }
  889. if ( config.bom ) {
  890. output = '\ufeff' + output;
  891. }
  892. _saveAs(
  893. new Blob( [output], {type: 'text/csv'+charset} ),
  894. _filename( config ),
  895. true
  896. );
  897. },
  898. filename: '*',
  899. extension: '.csv',
  900. exportOptions: {},
  901. fieldSeparator: ',',
  902. fieldBoundary: '"',
  903. escapeChar: '"',
  904. charset: null,
  905. header: true,
  906. footer: false
  907. };
  908. //
  909. // Excel (xlsx) export
  910. //
  911. DataTable.ext.buttons.excelHtml5 = {
  912. className: 'buttons-excel buttons-html5',
  913. available: function () {
  914. return window.FileReader !== undefined && _jsZip() !== undefined && ! _isSafari() && _serialiser;
  915. },
  916. text: function ( dt ) {
  917. return dt.i18n( 'buttons.excel', 'Excel' );
  918. },
  919. action: function ( e, dt, button, config ) {
  920. var rowPos = 0;
  921. var getXml = function ( type ) {
  922. var str = excelStrings[ type ];
  923. //str = str.replace( /xmlns:/g, 'xmlns_' ).replace( /mc:/g, 'mc_' );
  924. return $.parseXML( str );
  925. };
  926. var rels = getXml('xl/worksheets/sheet1.xml');
  927. var relsGet = rels.getElementsByTagName( "sheetData" )[0];
  928. var xlsx = {
  929. _rels: {
  930. ".rels": getXml('_rels/.rels')
  931. },
  932. xl: {
  933. _rels: {
  934. "workbook.xml.rels": getXml('xl/_rels/workbook.xml.rels')
  935. },
  936. "workbook.xml": getXml('xl/workbook.xml'),
  937. "styles.xml": getXml('xl/styles.xml'),
  938. "worksheets": {
  939. "sheet1.xml": rels
  940. }
  941. },
  942. "[Content_Types].xml": getXml('[Content_Types].xml')
  943. };
  944. var data = dt.buttons.exportData( config.exportOptions );
  945. var currentRow, rowNode;
  946. var addRow = function ( row ) {
  947. currentRow = rowPos+1;
  948. rowNode = _createNode( rels, "row", { attr: {r:currentRow} } );
  949. for ( var i=0, ien=row.length ; i<ien ; i++ ) {
  950. // Concat both the Cell Columns as a letter and the Row of the cell.
  951. var cellId = createCellPos(i) + '' + currentRow;
  952. var cell;
  953. if ( row[i] === null || row[i] === undefined ) {
  954. row[i] = '';
  955. }
  956. // Detect numbers - don't match numbers with leading zeros or a negative
  957. // anywhere but the start
  958. if ( typeof row[i] === 'number' || (
  959. row[i].match &&
  960. $.trim(row[i]).match(/^-?\d+(\.\d+)?$/) &&
  961. ! $.trim(row[i]).match(/^0\d+/) )
  962. ) {
  963. cell = _createNode( rels, 'c', {
  964. attr: {
  965. t: 'n',
  966. r: cellId
  967. },
  968. children: [
  969. _createNode( rels, 'v', { text: row[i] } )
  970. ]
  971. } );
  972. }
  973. else {
  974. // Replace non standard characters for text output
  975. var text = ! row[i].replace ?
  976. row[i] :
  977. row[i].replace(/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, '');
  978. cell = _createNode( rels, 'c', {
  979. attr: {
  980. t: 'inlineStr',
  981. r: cellId
  982. },
  983. children:{
  984. row: _createNode( rels, 'is', {
  985. children: {
  986. row: _createNode( rels, 't', {
  987. text: text
  988. } )
  989. }
  990. } )
  991. }
  992. } );
  993. }
  994. rowNode.appendChild( cell );
  995. }
  996. relsGet.appendChild(rowNode);
  997. rowPos++;
  998. };
  999. $( 'sheets sheet', xlsx.xl['workbook.xml'] ).attr( 'name', _sheetname( config ) );
  1000. if ( config.customizeData ) {
  1001. config.customizeData( data );
  1002. }
  1003. if ( config.header ) {
  1004. addRow( data.header, rowPos );
  1005. $('row c', rels).attr( 's', '2' ); // bold
  1006. }
  1007. for ( var n=0, ie=data.body.length ; n<ie ; n++ ) {
  1008. addRow( data.body[n], rowPos );
  1009. }
  1010. if ( config.footer && data.footer ) {
  1011. addRow( data.footer, rowPos);
  1012. $('row:last c', rels).attr( 's', '2' ); // bold
  1013. }
  1014. // Set column widths
  1015. var cols = _createNode( rels, 'cols' );
  1016. $('worksheet', rels).prepend( cols );
  1017. for ( var i=0, ien=data.header.length ; i<ien ; i++ ) {
  1018. cols.appendChild( _createNode( rels, 'col', {
  1019. attr: {
  1020. min: i+1,
  1021. max: i+1,
  1022. width: _excelColWidth( data, i ),
  1023. customWidth: 1
  1024. }
  1025. } ) );
  1026. }
  1027. // Let the developer customise the document if they want to
  1028. if ( config.customize ) {
  1029. config.customize( xlsx );
  1030. }
  1031. var jszip = _jsZip();
  1032. var zip = new jszip();
  1033. var zipConfig = {
  1034. type: 'blob',
  1035. mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
  1036. };
  1037. _addToZip( zip, xlsx );
  1038. if ( zip.generateAsync ) {
  1039. // JSZip 3+
  1040. zip
  1041. .generateAsync( zipConfig )
  1042. .then( function ( blob ) {
  1043. _saveAs( blob, _filename( config ) );
  1044. } );
  1045. }
  1046. else {
  1047. // JSZip 2.5
  1048. _saveAs(
  1049. zip.generate( zipConfig ),
  1050. _filename( config )
  1051. );
  1052. }
  1053. },
  1054. filename: '*',
  1055. extension: '.xlsx',
  1056. exportOptions: {},
  1057. header: true,
  1058. footer: false
  1059. };
  1060. //
  1061. // PDF export - using pdfMake - http://pdfmake.org
  1062. //
  1063. DataTable.ext.buttons.pdfHtml5 = {
  1064. className: 'buttons-pdf buttons-html5',
  1065. available: function () {
  1066. return window.FileReader !== undefined && _pdfMake();
  1067. },
  1068. text: function ( dt ) {
  1069. return dt.i18n( 'buttons.pdf', 'PDF' );
  1070. },
  1071. action: function ( e, dt, button, config ) {
  1072. var newLine = _newLine( config );
  1073. var data = dt.buttons.exportData( config.exportOptions );
  1074. var rows = [];
  1075. if ( config.header ) {
  1076. rows.push( $.map( data.header, function ( d ) {
  1077. return {
  1078. text: typeof d === 'string' ? d : d+'',
  1079. style: 'tableHeader'
  1080. };
  1081. } ) );
  1082. }
  1083. for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
  1084. rows.push( $.map( data.body[i], function ( d ) {
  1085. return {
  1086. text: typeof d === 'string' ? d : d+'',
  1087. style: i % 2 ? 'tableBodyEven' : 'tableBodyOdd'
  1088. };
  1089. } ) );
  1090. }
  1091. if ( config.footer && data.footer) {
  1092. rows.push( $.map( data.footer, function ( d ) {
  1093. return {
  1094. text: typeof d === 'string' ? d : d+'',
  1095. style: 'tableFooter'
  1096. };
  1097. } ) );
  1098. }
  1099. var doc = {
  1100. pageSize: config.pageSize,
  1101. pageOrientation: config.orientation,
  1102. content: [
  1103. {
  1104. table: {
  1105. headerRows: 1,
  1106. body: rows
  1107. },
  1108. layout: 'noBorders'
  1109. }
  1110. ],
  1111. styles: {
  1112. tableHeader: {
  1113. bold: true,
  1114. fontSize: 11,
  1115. color: 'white',
  1116. fillColor: '#2d4154',
  1117. alignment: 'center'
  1118. },
  1119. tableBodyEven: {},
  1120. tableBodyOdd: {
  1121. fillColor: '#f3f3f3'
  1122. },
  1123. tableFooter: {
  1124. bold: true,
  1125. fontSize: 11,
  1126. color: 'white',
  1127. fillColor: '#2d4154'
  1128. },
  1129. title: {
  1130. alignment: 'center',
  1131. fontSize: 15
  1132. },
  1133. message: {}
  1134. },
  1135. defaultStyle: {
  1136. fontSize: 10
  1137. }
  1138. };
  1139. if ( config.message ) {
  1140. doc.content.unshift( {
  1141. text: typeof config.message == 'function' ? config.message(dt, button, config) : config.message,
  1142. style: 'message',
  1143. margin: [ 0, 0, 0, 12 ]
  1144. } );
  1145. }
  1146. if ( config.title ) {
  1147. doc.content.unshift( {
  1148. text: _title( config, false ),
  1149. style: 'title',
  1150. margin: [ 0, 0, 0, 12 ]
  1151. } );
  1152. }
  1153. if ( config.customize ) {
  1154. config.customize( doc, config );
  1155. }
  1156. var pdf = _pdfMake().createPdf( doc );
  1157. if ( config.download === 'open' && ! _isSafari() ) {
  1158. pdf.open();
  1159. }
  1160. else {
  1161. pdf.getBuffer( function (buffer) {
  1162. var blob = new Blob( [buffer], {type:'application/pdf'} );
  1163. _saveAs( blob, _filename( config ) );
  1164. } );
  1165. }
  1166. },
  1167. title: '*',
  1168. filename: '*',
  1169. extension: '.pdf',
  1170. exportOptions: {},
  1171. orientation: 'portrait',
  1172. pageSize: 'A4',
  1173. header: true,
  1174. footer: false,
  1175. message: null,
  1176. customize: null,
  1177. download: 'download'
  1178. };
  1179. return DataTable.Buttons;
  1180. }));