buttons.html5.js 41 KB

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