Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

buttons.html5.js 57KB

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