tableExport.js 86 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267
  1. /**
  2. * @preserve tableExport.jquery.plugin
  3. *
  4. * Version 1.9.9
  5. *
  6. * Copyright (c) 2015-2018 hhurz, https://github.com/hhurz
  7. *
  8. * Original Work Copyright (c) 2014 Giri Raj
  9. *
  10. * Licensed under the MIT License
  11. **/
  12. 'use strict';
  13. (function ($) {
  14. $.fn.tableExport = function (options) {
  15. var defaults = {
  16. consoleLog: false,
  17. csvEnclosure: '"',
  18. csvSeparator: ',',
  19. csvUseBOM: true,
  20. displayTableName: false,
  21. escape: false,
  22. excelFileFormat: 'xlshtml', // xmlss = XML Spreadsheet 2003 file format (XMLSS), xlshtml = Excel 2000 html format
  23. excelRTL: false, // true = Set Excel option 'DisplayRightToLeft'
  24. excelstyles: [], // e.g. ['border-bottom', 'border-top', 'border-left', 'border-right']
  25. exportHiddenCells: false, // true = speed up export of large tables with hidden cells (hidden cells will be exported !)
  26. fileName: 'tableExport',
  27. htmlContent: false,
  28. ignoreColumn: [],
  29. ignoreRow: [],
  30. jsonScope: 'all', // head, data, all
  31. jspdf: {
  32. orientation: 'p',
  33. unit: 'pt',
  34. format: 'a4', // jspdf page format or 'bestfit' for autmatic paper format selection
  35. margins: {left: 20, right: 10, top: 10, bottom: 10},
  36. onDocCreated: null,
  37. autotable: {
  38. styles: {
  39. cellPadding: 2,
  40. rowHeight: 12,
  41. fontSize: 8,
  42. fillColor: 255, // color value or 'inherit' to use css background-color from html table
  43. textColor: 50, // color value or 'inherit' to use css color from html table
  44. fontStyle: 'normal', // normal, bold, italic, bolditalic or 'inherit' to use css font-weight and fonst-style from html table
  45. overflow: 'ellipsize', // visible, hidden, ellipsize or linebreak
  46. halign: 'left', // left, center, right
  47. valign: 'middle' // top, middle, bottom
  48. },
  49. headerStyles: {
  50. fillColor: [52, 73, 94],
  51. textColor: 255,
  52. fontStyle: 'bold',
  53. halign: 'center'
  54. },
  55. alternateRowStyles: {
  56. fillColor: 245
  57. },
  58. tableExport: {
  59. doc: null, // jsPDF doc object. If set, an already created doc will be used to export to
  60. onAfterAutotable: null,
  61. onBeforeAutotable: null,
  62. onAutotableText: null,
  63. onTable: null,
  64. outputImages: true
  65. }
  66. }
  67. },
  68. numbers: {
  69. html: {
  70. decimalMark: '.',
  71. thousandsSeparator: ','
  72. },
  73. output: { // set output: false to keep number format in exported output
  74. decimalMark: '.',
  75. thousandsSeparator: ','
  76. }
  77. },
  78. onCellData: null,
  79. onCellHtmlData: null,
  80. onIgnoreRow: null, // onIgnoreRow($tr, rowIndex): function should return true to not export a row
  81. onMsoNumberFormat: null, // Excel 2000 html format only. See readme.md for more information about msonumberformat
  82. outputMode: 'file', // 'file', 'string', 'base64' or 'window' (experimental)
  83. pdfmake: {
  84. enabled: false, // true: use pdfmake instead of jspdf and jspdf-autotable (experimental)
  85. docDefinition: {
  86. pageOrientation: 'portrait', // 'portrait' or 'landscape'
  87. defaultStyle: {
  88. font: 'Roboto' // default is 'Roboto', for arabic font set this option to 'Mirza' and include mirza_fonts.js
  89. }
  90. },
  91. fonts: {}
  92. },
  93. tbodySelector: 'tr',
  94. tfootSelector: 'tr', // set empty ('') to prevent export of tfoot rows
  95. theadSelector: 'tr',
  96. tableName: 'Table',
  97. type: 'csv', // 'csv', 'tsv', 'txt', 'sql', 'json', 'xml', 'excel', 'doc', 'png' or 'pdf'
  98. worksheetName: ''
  99. };
  100. var FONT_ROW_RATIO = 1.15;
  101. var el = this;
  102. var DownloadEvt = null;
  103. var $hrows = [];
  104. var $rows = [];
  105. var rowIndex = 0;
  106. var trData = '';
  107. var colNames = [];
  108. var ranges = [];
  109. var blob;
  110. var $hiddenTableElements = [];
  111. var checkCellVisibilty = false;
  112. $.extend(true, defaults, options);
  113. colNames = GetColumnNames(el);
  114. if ( defaults.type == 'csv' || defaults.type == 'tsv' || defaults.type == 'txt' ) {
  115. var csvData = "";
  116. var rowlength = 0;
  117. ranges = [];
  118. rowIndex = 0;
  119. var csvString = function (cell, rowIndex, colIndex) {
  120. var result = '';
  121. if ( cell !== null ) {
  122. var dataString = parseString(cell, rowIndex, colIndex);
  123. var csvValue = (dataString === null || dataString === '') ? '' : dataString.toString();
  124. if ( defaults.type == 'tsv' ) {
  125. if ( dataString instanceof Date )
  126. dataString.toLocaleString();
  127. // According to http://www.iana.org/assignments/media-types/text/tab-separated-values
  128. // are fields that contain tabs not allowable in tsv encoding
  129. result = replaceAll(csvValue, '\t', ' ');
  130. }
  131. else {
  132. // Takes a string and encapsulates it (by default in double-quotes) if it
  133. // contains the csv field separator, spaces, or linebreaks.
  134. if ( dataString instanceof Date )
  135. result = defaults.csvEnclosure + dataString.toLocaleString() + defaults.csvEnclosure;
  136. else {
  137. result = replaceAll(csvValue, defaults.csvEnclosure, defaults.csvEnclosure + defaults.csvEnclosure);
  138. if ( result.indexOf(defaults.csvSeparator) >= 0 || /[\r\n ]/g.test(result) )
  139. result = defaults.csvEnclosure + result + defaults.csvEnclosure;
  140. }
  141. }
  142. }
  143. return result;
  144. };
  145. var CollectCsvData = function ($rows, rowselector, length) {
  146. $rows.each(function () {
  147. trData = "";
  148. ForEachVisibleCell(this, rowselector, rowIndex, length + $rows.length,
  149. function (cell, row, col) {
  150. trData += csvString(cell, row, col) + (defaults.type == 'tsv' ? '\t' : defaults.csvSeparator);
  151. });
  152. trData = $.trim(trData).substring(0, trData.length - 1);
  153. if ( trData.length > 0 ) {
  154. if ( csvData.length > 0 )
  155. csvData += "\n";
  156. csvData += trData;
  157. }
  158. rowIndex++;
  159. });
  160. return $rows.length;
  161. };
  162. rowlength += CollectCsvData($(el).find('thead').first().find(defaults.theadSelector), 'th,td', rowlength);
  163. findTablePart($(el),'tbody').each(function () {
  164. rowlength += CollectCsvData(findRows($(this), defaults.tbodySelector), 'td,th', rowlength);
  165. });
  166. if ( defaults.tfootSelector.length )
  167. CollectCsvData($(el).find('tfoot').first().find(defaults.tfootSelector), 'td,th', rowlength);
  168. csvData += "\n";
  169. //output
  170. if ( defaults.consoleLog === true )
  171. console.log(csvData);
  172. if ( defaults.outputMode === 'string' )
  173. return csvData;
  174. if ( defaults.outputMode === 'base64' )
  175. return base64encode(csvData);
  176. if ( defaults.outputMode === 'window' ) {
  177. downloadFile(false, 'data:text/' + (defaults.type == 'csv' ? 'csv' : 'plain') + ';charset=utf-8,', csvData);
  178. return;
  179. }
  180. try {
  181. blob = new Blob([csvData], {type: "text/" + (defaults.type == 'csv' ? 'csv' : 'plain') + ";charset=utf-8"});
  182. saveAs(blob, defaults.fileName + '.' + defaults.type, (defaults.type != 'csv' || defaults.csvUseBOM === false));
  183. }
  184. catch (e) {
  185. downloadFile(defaults.fileName + '.' + defaults.type,
  186. 'data:text/' + (defaults.type == 'csv' ? 'csv' : 'plain') + ';charset=utf-8,' + ((defaults.type == 'csv' && defaults.csvUseBOM) ? '\ufeff' : ''),
  187. csvData);
  188. }
  189. } else if ( defaults.type == 'sql' ) {
  190. // Header
  191. rowIndex = 0;
  192. ranges = [];
  193. var tdData = "INSERT INTO `" + defaults.tableName + "` (";
  194. $hrows = $(el).find('thead').first().find(defaults.theadSelector);
  195. $hrows.each(function () {
  196. ForEachVisibleCell(this, 'th,td', rowIndex, $hrows.length,
  197. function (cell, row, col) {
  198. tdData += "'" + parseString(cell, row, col) + "',";
  199. });
  200. rowIndex++;
  201. tdData = $.trim(tdData).substring(0, tdData.length - 1);
  202. });
  203. tdData += ") VALUES ";
  204. // Data
  205. $rows = collectRows ($(el));
  206. $($rows).each(function () {
  207. trData = "";
  208. ForEachVisibleCell(this, 'td,th', rowIndex, $hrows.length + $rows.length,
  209. function (cell, row, col) {
  210. trData += "'" + parseString(cell, row, col) + "',";
  211. });
  212. if ( trData.length > 3 ) {
  213. tdData += "(" + trData;
  214. tdData = $.trim(tdData).substring(0, tdData.length - 1);
  215. tdData += "),";
  216. }
  217. rowIndex++;
  218. });
  219. tdData = $.trim(tdData).substring(0, tdData.length - 1);
  220. tdData += ";";
  221. // Output
  222. if ( defaults.consoleLog === true )
  223. console.log(tdData);
  224. if ( defaults.outputMode === 'string' )
  225. return tdData;
  226. if ( defaults.outputMode === 'base64' )
  227. return base64encode(tdData);
  228. try {
  229. blob = new Blob([tdData], {type: "text/plain;charset=utf-8"});
  230. saveAs(blob, defaults.fileName + '.sql');
  231. }
  232. catch (e) {
  233. downloadFile(defaults.fileName + '.sql',
  234. 'data:application/sql;charset=utf-8,',
  235. tdData);
  236. }
  237. } else if ( defaults.type == 'json' ) {
  238. var jsonHeaderArray = [];
  239. ranges = [];
  240. $hrows = $(el).find('thead').first().find(defaults.theadSelector);
  241. $hrows.each(function () {
  242. var jsonArrayTd = [];
  243. ForEachVisibleCell(this, 'th,td', rowIndex, $hrows.length,
  244. function (cell, row, col) {
  245. jsonArrayTd.push(parseString(cell, row, col));
  246. });
  247. jsonHeaderArray.push(jsonArrayTd);
  248. });
  249. // Data
  250. var jsonArray = [];
  251. $rows = collectRows ($(el));
  252. $($rows).each(function () {
  253. var jsonObjectTd = {};
  254. var colIndex = 0;
  255. ForEachVisibleCell(this, 'td,th', rowIndex, $hrows.length + $rows.length,
  256. function (cell, row, col) {
  257. if ( jsonHeaderArray.length ) {
  258. jsonObjectTd[jsonHeaderArray[jsonHeaderArray.length - 1][colIndex]] = parseString(cell, row, col);
  259. } else {
  260. jsonObjectTd[colIndex] = parseString(cell, row, col);
  261. }
  262. colIndex++;
  263. });
  264. if ( $.isEmptyObject(jsonObjectTd) === false )
  265. jsonArray.push(jsonObjectTd);
  266. rowIndex++;
  267. });
  268. var sdata = "";
  269. if ( defaults.jsonScope == 'head' )
  270. sdata = JSON.stringify(jsonHeaderArray);
  271. else if ( defaults.jsonScope == 'data' )
  272. sdata = JSON.stringify(jsonArray);
  273. else // all
  274. sdata = JSON.stringify({header: jsonHeaderArray, data: jsonArray});
  275. if ( defaults.consoleLog === true )
  276. console.log(sdata);
  277. if ( defaults.outputMode === 'string' )
  278. return sdata;
  279. if ( defaults.outputMode === 'base64' )
  280. return base64encode(sdata);
  281. try {
  282. blob = new Blob([sdata], {type: "application/json;charset=utf-8"});
  283. saveAs(blob, defaults.fileName + '.json');
  284. }
  285. catch (e) {
  286. downloadFile(defaults.fileName + '.json',
  287. 'data:application/json;charset=utf-8;base64,',
  288. sdata);
  289. }
  290. } else if ( defaults.type === 'xml' ) {
  291. rowIndex = 0;
  292. ranges = [];
  293. var xml = '<?xml version="1.0" encoding="utf-8"?>';
  294. xml += '<tabledata><fields>';
  295. // Header
  296. $hrows = $(el).find('thead').first().find(defaults.theadSelector);
  297. $hrows.each(function () {
  298. ForEachVisibleCell(this, 'th,td', rowIndex, $hrows.length,
  299. function (cell, row, col) {
  300. xml += "<field>" + parseString(cell, row, col) + "</field>";
  301. });
  302. rowIndex++;
  303. });
  304. xml += '</fields><data>';
  305. // Data
  306. var rowCount = 1;
  307. $rows = collectRows ($(el));
  308. $($rows).each(function () {
  309. var colCount = 1;
  310. trData = "";
  311. ForEachVisibleCell(this, 'td,th', rowIndex, $hrows.length + $rows.length,
  312. function (cell, row, col) {
  313. trData += "<column-" + colCount + ">" + parseString(cell, row, col) + "</column-" + colCount + ">";
  314. colCount++;
  315. });
  316. if ( trData.length > 0 && trData != "<column-1></column-1>" ) {
  317. xml += '<row id="' + rowCount + '">' + trData + '</row>';
  318. rowCount++;
  319. }
  320. rowIndex++;
  321. });
  322. xml += '</data></tabledata>';
  323. // Output
  324. if ( defaults.consoleLog === true )
  325. console.log(xml);
  326. if ( defaults.outputMode === 'string' )
  327. return xml;
  328. if ( defaults.outputMode === 'base64' )
  329. return base64encode(xml);
  330. try {
  331. blob = new Blob([xml], {type: "application/xml;charset=utf-8"});
  332. saveAs(blob, defaults.fileName + '.xml');
  333. }
  334. catch (e) {
  335. downloadFile(defaults.fileName + '.xml',
  336. 'data:application/xml;charset=utf-8;base64,',
  337. xml);
  338. }
  339. }
  340. else if ( defaults.type === 'excel' && defaults.excelFileFormat === 'xmlss' ) {
  341. var docDatas = [];
  342. var docNames = [];
  343. $(el).filter(function () {
  344. return isVisible($(this));
  345. }).each(function () {
  346. var $table = $(this);
  347. var ssName = '';
  348. if ( typeof defaults.worksheetName === 'string' && defaults.worksheetName.length )
  349. ssName = defaults.worksheetName + ' ' + (docNames.length + 1);
  350. else if ( typeof defaults.worksheetName[docNames.length] !== 'undefined' )
  351. ssName = defaults.worksheetName[docNames.length];
  352. if ( ! ssName.length )
  353. ssName = $table.find('caption').text() || '';
  354. if ( ! ssName.length )
  355. ssName = 'Table ' + (docNames.length + 1);
  356. ssName = $.trim(ssName.replace(/[\\\/[\]*:?'"]/g,'').substring(0,31));
  357. docNames.push($('<div />').text(ssName).html());
  358. if ( defaults.exportHiddenCells === false ) {
  359. $hiddenTableElements = $table.find("tr, th, td").filter(":hidden");
  360. checkCellVisibilty = $hiddenTableElements.length > 0;
  361. }
  362. rowIndex = 0;
  363. colNames = GetColumnNames(this);
  364. docData = '<Table>\r';
  365. function CollectXmlssData ($rows, rowselector, length) {
  366. var spans = [];
  367. $($rows).each(function () {
  368. var ssIndex = 0;
  369. var nCols = 0;
  370. trData = "";
  371. ForEachVisibleCell(this, 'td,th', rowIndex, length + $rows.length,
  372. function (cell, row, col) {
  373. if ( cell !== null ) {
  374. var style = "";
  375. var data = parseString(cell, row, col);
  376. var type = "String";
  377. if ( jQuery.isNumeric(data) !== false ) {
  378. type = "Number";
  379. }
  380. else {
  381. var number = parsePercent(data);
  382. if ( number !== false ) {
  383. data = number;
  384. type = "Number";
  385. style += ' ss:StyleID="pct1"';
  386. }
  387. }
  388. if ( type !== "Number" )
  389. data = data.replace(/\n/g, '<br>');
  390. var colspan = getColspan (cell);
  391. var rowspan = getRowspan (cell);
  392. // Skip spans
  393. $.each(spans, function () {
  394. var range = this;
  395. if ( rowIndex >= range.s.r && rowIndex <= range.e.r && nCols >= range.s.c && nCols <= range.e.c ) {
  396. for ( var i = 0; i <= range.e.c - range.s.c; ++i ) {
  397. nCols++;
  398. ssIndex++;
  399. }
  400. }
  401. });
  402. // Handle Row Span
  403. if ( rowspan || colspan ) {
  404. rowspan = rowspan || 1;
  405. colspan = colspan || 1;
  406. spans.push({
  407. s: {r: rowIndex, c: nCols},
  408. e: {r: rowIndex + rowspan - 1, c: nCols + colspan - 1}
  409. });
  410. }
  411. // Handle Colspan
  412. if ( colspan > 1 ) {
  413. style += ' ss:MergeAcross="' + (colspan-1) + '"';
  414. nCols += (colspan - 1);
  415. }
  416. if ( rowspan > 1 ) {
  417. style += ' ss:MergeDown="' + (rowspan-1) + '" ss:StyleID="rsp1"';
  418. }
  419. if ( ssIndex > 0 ) {
  420. style += ' ss:Index="' + (nCols+1) + '"';
  421. ssIndex = 0;
  422. }
  423. trData += '<Cell' + style + '><Data ss:Type="' + type + '">' +
  424. $('<div />').text(data).html() +
  425. '</Data></Cell>\r';
  426. nCols++;
  427. }
  428. });
  429. if ( trData.length > 0 )
  430. docData += '<Row ss:AutoFitHeight="0">\r' + trData + '</Row>\r';
  431. rowIndex++;
  432. });
  433. return $rows.length;
  434. }
  435. var rowLength = 0;
  436. rowLength += CollectXmlssData ($table.find('thead').first().find(defaults.theadSelector), 'th,td', rowLength);
  437. CollectXmlssData (collectRows ($table), 'td,th', rowLength);
  438. docData += '</Table>\r';
  439. docDatas.push(docData);
  440. if ( defaults.consoleLog === true )
  441. console.log(docData);
  442. });
  443. var count = {};
  444. var firstOccurences = {};
  445. var item, itemCount;
  446. for (var n = 0, c = docNames.length; n < c; n++)
  447. {
  448. item = docNames[n];
  449. itemCount = count[item];
  450. itemCount = count[item] = (itemCount == null ? 1 : itemCount + 1);
  451. if( itemCount == 2 )
  452. docNames[firstOccurences[item]] = docNames[firstOccurences[item]].substring(0,29) + "-1";
  453. if( count[ item ] > 1 )
  454. docNames[n] = docNames[n].substring(0,29) + "-" + count[item];
  455. else
  456. firstOccurences[item] = n;
  457. }
  458. var CreationDate = new Date().toISOString();
  459. var xmlssDocFile = '<?xml version="1.0" encoding="UTF-8"?>\r' +
  460. '<?mso-application progid="Excel.Sheet"?>\r' +
  461. '<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"\r' +
  462. ' xmlns:o="urn:schemas-microsoft-com:office:office"\r' +
  463. ' xmlns:x="urn:schemas-microsoft-com:office:excel"\r' +
  464. ' xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"\r' +
  465. ' xmlns:html="http://www.w3.org/TR/REC-html40">\r' +
  466. '<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">\r' +
  467. ' <Created>' + CreationDate + '</Created>\r' +
  468. '</DocumentProperties>\r' +
  469. '<OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">\r' +
  470. ' <AllowPNG/>\r' +
  471. '</OfficeDocumentSettings>\r' +
  472. '<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">\r' +
  473. ' <WindowHeight>9000</WindowHeight>\r' +
  474. ' <WindowWidth>13860</WindowWidth>\r' +
  475. ' <WindowTopX>0</WindowTopX>\r' +
  476. ' <WindowTopY>0</WindowTopY>\r' +
  477. ' <ProtectStructure>False</ProtectStructure>\r' +
  478. ' <ProtectWindows>False</ProtectWindows>\r' +
  479. '</ExcelWorkbook>\r' +
  480. '<Styles>\r' +
  481. ' <Style ss:ID="Default" ss:Name="Normal">\r' +
  482. ' <Alignment ss:Vertical="Bottom"/>\r' +
  483. ' <Borders/>\r' +
  484. ' <Font/>\r' +
  485. ' <Interior/>\r' +
  486. ' <NumberFormat/>\r' +
  487. ' <Protection/>\r' +
  488. ' </Style>\r' +
  489. ' <Style ss:ID="rsp1">\r' +
  490. ' <Alignment ss:Vertical="Center"/>\r' +
  491. ' </Style>\r' +
  492. ' <Style ss:ID="pct1">\r' +
  493. ' <NumberFormat ss:Format="Percent"/>\r' +
  494. ' </Style>\r' +
  495. '</Styles>\r';
  496. for ( var j = 0; j < docDatas.length; j++ ) {
  497. xmlssDocFile += '<Worksheet ss:Name="' + docNames[j] + '" ss:RightToLeft="' + (defaults.excelRTL ? '1' : '0') + '">\r' +
  498. docDatas[j];
  499. if (defaults.excelRTL) {
  500. xmlssDocFile += '<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">\r' +
  501. '<DisplayRightToLeft/>\r' +
  502. '</WorksheetOptions>\r';
  503. }
  504. else
  505. xmlssDocFile += '<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel"/>\r';
  506. xmlssDocFile += '</Worksheet>\r';
  507. }
  508. xmlssDocFile += '</Workbook>\r';
  509. if ( defaults.consoleLog === true )
  510. console.log(xmlssDocFile);
  511. if ( defaults.outputMode === 'string' )
  512. return xmlssDocFile;
  513. if ( defaults.outputMode === 'base64' )
  514. return base64encode(xmlssDocFile);
  515. try {
  516. blob = new Blob([xmlssDocFile], {type: "application/xml;charset=utf-8"});
  517. saveAs(blob, defaults.fileName + '.xml');
  518. }
  519. catch (e) {
  520. downloadFile(defaults.fileName + '.xml',
  521. 'data:application/xml;charset=utf-8;base64,',
  522. xmlssDocFile);
  523. }
  524. }
  525. else if ( defaults.type == 'excel' || defaults.type == 'xls' || defaults.type == 'word' || defaults.type == 'doc' ) {
  526. var MSDocType = (defaults.type == 'excel' || defaults.type == 'xls') ? 'excel' : 'word';
  527. var MSDocExt = (MSDocType == 'excel') ? 'xls' : 'doc';
  528. var MSDocSchema = 'xmlns:x="urn:schemas-microsoft-com:office:' + MSDocType + '"';
  529. var docData = '';
  530. var docName = '';
  531. $(el).filter(function () {
  532. return isVisible($(this));
  533. }).each(function () {
  534. var $table = $(this);
  535. if (docName === '') {
  536. docName = defaults.worksheetName || $table.find('caption').text() || 'Table';
  537. docName = $.trim(docName.replace(/[\\\/[\]*:?'"]/g, '').substring(0, 31));
  538. }
  539. if ( defaults.exportHiddenCells === false ) {
  540. $hiddenTableElements = $table.find("tr, th, td").filter(":hidden");
  541. checkCellVisibilty = $hiddenTableElements.length > 0;
  542. }
  543. rowIndex = 0;
  544. ranges = [];
  545. colNames = GetColumnNames(this);
  546. // Header
  547. docData += '<table><thead>';
  548. $hrows = $table.find('thead').first().find(defaults.theadSelector);
  549. $hrows.each(function () {
  550. trData = "";
  551. ForEachVisibleCell(this, 'th,td', rowIndex, $hrows.length,
  552. function (cell, row, col) {
  553. if ( cell !== null ) {
  554. var thstyle = '';
  555. trData += '<th';
  556. for ( var styles in defaults.excelstyles ) {
  557. if ( defaults.excelstyles.hasOwnProperty(styles) ) {
  558. var thcss = $(cell).css(defaults.excelstyles[styles]);
  559. if ( thcss !== '' && thcss != '0px none rgb(0, 0, 0)' && thcss != 'rgba(0, 0, 0, 0)' ) {
  560. thstyle += (thstyle === '') ? 'style="' : ';';
  561. thstyle += defaults.excelstyles[styles] + ':' + thcss;
  562. }
  563. }
  564. }
  565. if ( thstyle !== '' )
  566. trData += ' ' + thstyle + '"';
  567. var tdcolspan = getColspan (cell);
  568. if ( tdcolspan > 0 )
  569. trData += ' colspan="' + tdcolspan + '"';
  570. var tdrowspan = getRowspan (cell);
  571. if ( tdrowspan > 0 )
  572. trData += ' rowspan="' + tdrowspan + '"';
  573. trData += '>' + parseString(cell, row, col) + '</th>';
  574. }
  575. });
  576. if ( trData.length > 0 )
  577. docData += '<tr>' + trData + '</tr>';
  578. rowIndex++;
  579. });
  580. docData += '</thead><tbody>';
  581. // Data
  582. $rows = collectRows ($table);
  583. $($rows).each(function () {
  584. var $row = $(this);
  585. trData = "";
  586. ForEachVisibleCell(this, 'td,th', rowIndex, $hrows.length + $rows.length,
  587. function (cell, row, col) {
  588. if ( cell !== null ) {
  589. var tdvalue = parseString(cell, row, col);
  590. var tdstyle = '';
  591. var tdcss = $(cell).data("tableexport-msonumberformat");
  592. if ( typeof tdcss == 'undefined' && typeof defaults.onMsoNumberFormat === 'function' )
  593. tdcss = defaults.onMsoNumberFormat(cell, row, col);
  594. if ( typeof tdcss != 'undefined' && tdcss !== '' )
  595. tdstyle = 'style="mso-number-format:\'' + tdcss + '\'';
  596. for ( var cssStyle in defaults.excelstyles ) {
  597. if ( defaults.excelstyles.hasOwnProperty(cssStyle) ) {
  598. tdcss = $(cell).css(defaults.excelstyles[cssStyle]);
  599. if ( tdcss === '' )
  600. tdcss = $row.css(defaults.excelstyles[cssStyle]);
  601. if ( tdcss !== '' && tdcss != '0px none rgb(0, 0, 0)' && tdcss != 'rgba(0, 0, 0, 0)' ) {
  602. tdstyle += (tdstyle === '') ? 'style="' : ';';
  603. tdstyle += defaults.excelstyles[cssStyle] + ':' + tdcss;
  604. }
  605. }
  606. }
  607. trData += '<td';
  608. if ( tdstyle !== '' )
  609. trData += ' ' + tdstyle + '"';
  610. var tdcolspan = getColspan (cell);
  611. if ( tdcolspan > 0 )
  612. trData += ' colspan="' + tdcolspan + '"';
  613. var tdrowspan = getRowspan (cell);
  614. if ( tdrowspan > 0 )
  615. trData += ' rowspan="' + tdrowspan + '"';
  616. if ( typeof tdvalue === 'string' && tdvalue != '' )
  617. tdvalue = tdvalue.replace(/\n/g, '<br>');
  618. trData += '>' + tdvalue + '</td>';
  619. }
  620. });
  621. if ( trData.length > 0 )
  622. docData += '<tr>' + trData + '</tr>';
  623. rowIndex++;
  624. });
  625. if ( defaults.displayTableName )
  626. docData += '<tr><td></td></tr><tr><td></td></tr><tr><td>' + parseString($('<p>' + defaults.tableName + '</p>')) + '</td></tr>';
  627. docData += '</tbody></table>';
  628. if ( defaults.consoleLog === true )
  629. console.log(docData);
  630. });
  631. //noinspection XmlUnusedNamespaceDeclaration
  632. var docFile = '<html xmlns:o="urn:schemas-microsoft-com:office:office" ' + MSDocSchema + ' xmlns="http://www.w3.org/TR/REC-html40">';
  633. docFile += '<meta http-equiv="content-type" content="application/vnd.ms-' + MSDocType + '; charset=UTF-8">';
  634. docFile += "<head>";
  635. if (MSDocType === 'excel') {
  636. docFile += "<!--[if gte mso 9]>";
  637. docFile += "<xml>";
  638. docFile += "<x:ExcelWorkbook>";
  639. docFile += "<x:ExcelWorksheets>";
  640. docFile += "<x:ExcelWorksheet>";
  641. docFile += "<x:Name>";
  642. docFile += docName;
  643. docFile += "</x:Name>";
  644. docFile += "<x:WorksheetOptions>";
  645. docFile += "<x:DisplayGridlines/>";
  646. if (defaults.excelRTL)
  647. docFile += "<x:DisplayRightToLeft/>";
  648. docFile += "</x:WorksheetOptions>";
  649. docFile += "</x:ExcelWorksheet>";
  650. docFile += "</x:ExcelWorksheets>";
  651. docFile += "</x:ExcelWorkbook>";
  652. docFile += "</xml>";
  653. docFile += "<![endif]-->";
  654. }
  655. docFile += "<style>br {mso-data-placement:same-cell;}</style>";
  656. docFile += "</head>";
  657. docFile += "<body>";
  658. docFile += docData;
  659. docFile += "</body>";
  660. docFile += "</html>";
  661. if ( defaults.consoleLog === true )
  662. console.log(docFile);
  663. if ( defaults.outputMode === 'string' )
  664. return docFile;
  665. if ( defaults.outputMode === 'base64' )
  666. return base64encode(docFile);
  667. try {
  668. blob = new Blob([docFile], {type: 'application/vnd.ms-' + defaults.type});
  669. saveAs(blob, defaults.fileName + '.' + MSDocExt);
  670. }
  671. catch (e) {
  672. downloadFile(defaults.fileName + '.' + MSDocExt,
  673. 'data:application/vnd.ms-' + MSDocType + ';base64,',
  674. docFile);
  675. }
  676. } else if ( defaults.type == 'xlsx' ) {
  677. var data = [];
  678. var spans = [];
  679. rowIndex = 0;
  680. $rows = $(el).find('thead').first().find(defaults.theadSelector).toArray();
  681. $rows.push.apply($rows, collectRows ($(el)));
  682. $($rows).each(function () {
  683. var cols = [];
  684. ForEachVisibleCell(this, 'th,td', rowIndex, $rows.length,
  685. function (cell, row, col) {
  686. if ( typeof cell !== 'undefined' && cell !== null ) {
  687. var cellValue = parseString(cell, row, col);
  688. var colspan = getColspan (cell);
  689. var rowspan = getRowspan (cell);
  690. // Skip span ranges
  691. $.each(spans, function () {
  692. var range = this;
  693. if ( rowIndex >= range.s.r && rowIndex <= range.e.r && cols.length >= range.s.c && cols.length <= range.e.c ) {
  694. for ( var i = 0; i <= range.e.c - range.s.c; ++i )
  695. cols.push(null);
  696. }
  697. });
  698. // Handle Row Span
  699. if ( rowspan || colspan ) {
  700. rowspan = rowspan || 1;
  701. colspan = colspan || 1;
  702. spans.push({
  703. s: {r: rowIndex, c: cols.length},
  704. e: {r: rowIndex + rowspan - 1, c: cols.length + colspan - 1}
  705. });
  706. }
  707. // Handle Value
  708. if ( typeof defaults.onCellData !== 'function' ) {
  709. // Type conversion
  710. if ( cellValue !== "" && cellValue == +cellValue )
  711. cellValue = +cellValue;
  712. }
  713. cols.push(cellValue !== "" ? cellValue : null);
  714. // Handle Colspan
  715. if ( colspan )
  716. for ( var k = 0; k < colspan - 1; ++k )
  717. cols.push(null);
  718. }
  719. });
  720. data.push(cols);
  721. rowIndex++;
  722. });
  723. //noinspection JSPotentiallyInvalidConstructorUsage
  724. var wb = new jx_Workbook(),
  725. ws = jx_createSheet(data);
  726. // add span ranges to worksheet
  727. ws['!merges'] = spans;
  728. // add worksheet to workbook
  729. wb.SheetNames.push(defaults.worksheetName);
  730. wb.Sheets[defaults.worksheetName] = ws;
  731. var wbout = XLSX.write(wb, {bookType: defaults.type, bookSST: false, type: 'binary'});
  732. try {
  733. blob = new Blob([jx_s2ab(wbout)], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8'});
  734. saveAs(blob, defaults.fileName + '.' + defaults.type);
  735. }
  736. catch (e) {
  737. downloadFile(defaults.fileName + '.' + defaults.type,
  738. 'data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8,',
  739. jx_s2ab(wbout));
  740. }
  741. } else if ( defaults.type == 'png' ) {
  742. //html2canvas($(el)[0], {
  743. // onrendered: function (canvas) {
  744. html2canvas($(el)[0]).then(
  745. function (canvas) {
  746. var image = canvas.toDataURL();
  747. var byteString = atob(image.substring(22)); // remove data stuff
  748. var buffer = new ArrayBuffer(byteString.length);
  749. var intArray = new Uint8Array(buffer);
  750. for ( var i = 0; i < byteString.length; i++ )
  751. intArray[i] = byteString.charCodeAt(i);
  752. if ( defaults.consoleLog === true )
  753. console.log(byteString);
  754. if ( defaults.outputMode === 'string' )
  755. return byteString;
  756. if ( defaults.outputMode === 'base64' )
  757. return base64encode(image);
  758. if ( defaults.outputMode === 'window' ) {
  759. window.open(image);
  760. return;
  761. }
  762. try {
  763. blob = new Blob([buffer], {type: "image/png"});
  764. saveAs(blob, defaults.fileName + '.png');
  765. }
  766. catch (e) {
  767. downloadFile(defaults.fileName + '.png', 'data:image/png,', blob);
  768. }
  769. //}
  770. });
  771. } else if ( defaults.type == 'pdf' ) {
  772. if ( defaults.pdfmake.enabled === true ) {
  773. // pdf output using pdfmake
  774. // https://github.com/bpampuch/pdfmake
  775. var widths = [];
  776. var body = [];
  777. rowIndex = 0;
  778. ranges = [];
  779. var CollectPdfmakeData = function ($rows, colselector, length) {
  780. var rlength = 0;
  781. $($rows).each(function () {
  782. var r = [];
  783. ForEachVisibleCell(this, colselector, rowIndex, length,
  784. function (cell, row, col) {
  785. if ( typeof cell !== 'undefined' && cell !== null ) {
  786. var colspan = getColspan (cell);
  787. var rowspan = getRowspan (cell);
  788. var cellValue = parseString(cell, row, col) || " ";
  789. if ( colspan > 1 || rowspan > 1 ) {
  790. colspan = colspan || 1;
  791. rowspan = rowspan || 1;
  792. r.push({colSpan: colspan, rowSpan: rowspan, text: cellValue});
  793. }
  794. else
  795. r.push(cellValue);
  796. }
  797. else
  798. r.push(" ");
  799. });
  800. if ( r.length )
  801. body.push(r);
  802. if ( rlength < r.length )
  803. rlength = r.length;
  804. rowIndex++;
  805. });
  806. return rlength;
  807. };
  808. $hrows = $(this).find('thead').first().find(defaults.theadSelector);
  809. var colcount = CollectPdfmakeData($hrows, 'th,td', $hrows.length);
  810. for ( var i = widths.length; i < colcount; i++ )
  811. widths.push("*");
  812. // Data
  813. $rows = collectRows ($(this));
  814. CollectPdfmakeData($rows, 'th,td', $hrows.length + $rows.length);
  815. var docDefinition = {
  816. content: [{
  817. table: {
  818. headerRows: $hrows.length,
  819. widths: widths,
  820. body: body
  821. }
  822. }]
  823. };
  824. $.extend(true, docDefinition, defaults.pdfmake.docDefinition);
  825. pdfMake.fonts = {
  826. Roboto: {
  827. normal: 'Roboto-Regular.ttf',
  828. bold: 'Roboto-Medium.ttf',
  829. italics: 'Roboto-Italic.ttf',
  830. bolditalics: 'Roboto-MediumItalic.ttf'
  831. }
  832. };
  833. $.extend(true, pdfMake.fonts, defaults.pdfmake.fonts);
  834. pdfMake.createPdf(docDefinition).getBuffer(function (buffer) {
  835. try {
  836. var blob = new Blob([buffer], {type: "application/pdf"});
  837. saveAs(blob, defaults.fileName + '.pdf');
  838. }
  839. catch (e) {
  840. downloadFile(defaults.fileName + '.pdf',
  841. 'data:application/pdf;base64,',
  842. buffer);
  843. }
  844. });
  845. }
  846. else if ( defaults.jspdf.autotable === false ) {
  847. // pdf output using jsPDF's core html support
  848. var addHtmlOptions = {
  849. dim: {
  850. w: getPropertyUnitValue($(el).first().get(0), 'width', 'mm'),
  851. h: getPropertyUnitValue($(el).first().get(0), 'height', 'mm')
  852. },
  853. pagesplit: false
  854. };
  855. var doc = new jsPDF(defaults.jspdf.orientation, defaults.jspdf.unit, defaults.jspdf.format);
  856. doc.addHTML($(el).first(),
  857. defaults.jspdf.margins.left,
  858. defaults.jspdf.margins.top,
  859. addHtmlOptions,
  860. function () {
  861. jsPdfOutput(doc, false);
  862. });
  863. //delete doc;
  864. }
  865. else {
  866. // pdf output using jsPDF AutoTable plugin
  867. // https://github.com/simonbengtsson/jsPDF-AutoTable
  868. var teOptions = defaults.jspdf.autotable.tableExport;
  869. // When setting jspdf.format to 'bestfit' tableExport tries to choose
  870. // the minimum required paper format and orientation in which the table
  871. // (or tables in multitable mode) completely fits without column adjustment
  872. if ( typeof defaults.jspdf.format === 'string' && defaults.jspdf.format.toLowerCase() === 'bestfit' ) {
  873. var pageFormats = {
  874. 'a0': [2383.94, 3370.39], 'a1': [1683.78, 2383.94],
  875. 'a2': [1190.55, 1683.78], 'a3': [841.89, 1190.55],
  876. 'a4': [595.28, 841.89]
  877. };
  878. var rk = '', ro = '';
  879. var mw = 0;
  880. $(el).each(function () {
  881. if ( isVisible($(this)) ) {
  882. var w = getPropertyUnitValue($(this).get(0), 'width', 'pt');
  883. if ( w > mw ) {
  884. if ( w > pageFormats.a0[0] ) {
  885. rk = 'a0';
  886. ro = 'l';
  887. }
  888. for ( var key in pageFormats ) {
  889. if ( pageFormats.hasOwnProperty(key) ) {
  890. if ( pageFormats[key][1] > w ) {
  891. rk = key;
  892. ro = 'l';
  893. if ( pageFormats[key][0] > w )
  894. ro = 'p';
  895. }
  896. }
  897. }
  898. mw = w;
  899. }
  900. }
  901. });
  902. defaults.jspdf.format = (rk === '' ? 'a4' : rk);
  903. defaults.jspdf.orientation = (ro === '' ? 'w' : ro);
  904. }
  905. // The jsPDF doc object is stored in defaults.jspdf.autotable.tableExport,
  906. // thus it can be accessed from any callback function
  907. if ( teOptions.doc == null ) {
  908. teOptions.doc = new jsPDF(defaults.jspdf.orientation,
  909. defaults.jspdf.unit,
  910. defaults.jspdf.format);
  911. if ( typeof defaults.jspdf.onDocCreated === 'function' )
  912. defaults.jspdf.onDocCreated(teOptions.doc);
  913. }
  914. if ( teOptions.outputImages === true )
  915. teOptions.images = {};
  916. if ( typeof teOptions.images != 'undefined' ) {
  917. $(el).filter(function () {
  918. return isVisible($(this));
  919. }).each(function () {
  920. var rowCount = 0;
  921. ranges = [];
  922. if ( defaults.exportHiddenCells === false ) {
  923. $hiddenTableElements = $(this).find("tr, th, td").filter(":hidden");
  924. checkCellVisibilty = $hiddenTableElements.length > 0;
  925. }
  926. $hrows = $(this).find('thead').find(defaults.theadSelector);
  927. $rows = collectRows ($(this));
  928. $($rows).each(function () {
  929. ForEachVisibleCell(this, 'td,th', $hrows.length + rowCount, $hrows.length + $rows.length,
  930. function (cell) {
  931. if ( typeof cell !== 'undefined' && cell !== null ) {
  932. var kids = $(cell).children();
  933. if ( typeof kids != 'undefined' && kids.length > 0 )
  934. collectImages(cell, kids, teOptions);
  935. }
  936. });
  937. rowCount++;
  938. });
  939. });
  940. $hrows = [];
  941. $rows = [];
  942. }
  943. loadImages(teOptions, function () {
  944. $(el).filter(function () {
  945. return isVisible($(this));
  946. }).each(function () {
  947. var colKey;
  948. rowIndex = 0;
  949. ranges = [];
  950. if ( defaults.exportHiddenCells === false ) {
  951. $hiddenTableElements = $(this).find("tr, th, td").filter(":hidden");
  952. checkCellVisibilty = $hiddenTableElements.length > 0;
  953. }
  954. colNames = GetColumnNames(this);
  955. teOptions.columns = [];
  956. teOptions.rows = [];
  957. teOptions.rowoptions = {};
  958. // onTable: optional callback function for every matching table that can be used
  959. // to modify the tableExport options or to skip the output of a particular table
  960. // if the table selector targets multiple tables
  961. if ( typeof teOptions.onTable === 'function' )
  962. if ( teOptions.onTable($(this), defaults) === false )
  963. return true; // continue to next iteration step (table)
  964. // each table works with an own copy of AutoTable options
  965. defaults.jspdf.autotable.tableExport = null; // avoid deep recursion error
  966. var atOptions = $.extend(true, {}, defaults.jspdf.autotable);
  967. defaults.jspdf.autotable.tableExport = teOptions;
  968. atOptions.margin = {};
  969. $.extend(true, atOptions.margin, defaults.jspdf.margins);
  970. atOptions.tableExport = teOptions;
  971. // Fix jsPDF Autotable's row height calculation
  972. if ( typeof atOptions.beforePageContent !== 'function' ) {
  973. atOptions.beforePageContent = function (data) {
  974. if ( data.pageCount == 1 ) {
  975. var all = data.table.rows.concat(data.table.headerRow);
  976. $.each(all, function () {
  977. var row = this;
  978. if ( row.height > 0 ) {
  979. row.height += (2 - FONT_ROW_RATIO) / 2 * row.styles.fontSize;
  980. data.table.height += (2 - FONT_ROW_RATIO) / 2 * row.styles.fontSize;
  981. }
  982. });
  983. }
  984. };
  985. }
  986. if ( typeof atOptions.createdHeaderCell !== 'function' ) {
  987. // apply some original css styles to pdf header cells
  988. atOptions.createdHeaderCell = function (cell, data) {
  989. // jsPDF AutoTable plugin v2.0.14 fix: each cell needs its own styles object
  990. cell.styles = $.extend({}, data.row.styles);
  991. if ( typeof teOptions.columns [data.column.dataKey] != 'undefined' ) {
  992. var col = teOptions.columns [data.column.dataKey];
  993. if ( typeof col.rect != 'undefined' ) {
  994. var rh;
  995. cell.contentWidth = col.rect.width;
  996. if ( typeof teOptions.heightRatio == 'undefined' || teOptions.heightRatio === 0 ) {
  997. if ( data.row.raw [data.column.dataKey].rowspan )
  998. rh = data.row.raw [data.column.dataKey].rect.height / data.row.raw [data.column.dataKey].rowspan;
  999. else
  1000. rh = data.row.raw [data.column.dataKey].rect.height;
  1001. teOptions.heightRatio = cell.styles.rowHeight / rh;
  1002. }
  1003. rh = data.row.raw [data.column.dataKey].rect.height * teOptions.heightRatio;
  1004. if ( rh > cell.styles.rowHeight )
  1005. cell.styles.rowHeight = rh;
  1006. }
  1007. if ( typeof col.style != 'undefined' && col.style.hidden !== true ) {
  1008. cell.styles.halign = col.style.align;
  1009. if ( atOptions.styles.fillColor === 'inherit' )
  1010. cell.styles.fillColor = col.style.bcolor;
  1011. if ( atOptions.styles.textColor === 'inherit' )
  1012. cell.styles.textColor = col.style.color;
  1013. if ( atOptions.styles.fontStyle === 'inherit' )
  1014. cell.styles.fontStyle = col.style.fstyle;
  1015. }
  1016. }
  1017. };
  1018. }
  1019. if ( typeof atOptions.createdCell !== 'function' ) {
  1020. // apply some original css styles to pdf table cells
  1021. atOptions.createdCell = function (cell, data) {
  1022. var rowopt = teOptions.rowoptions [data.row.index + ":" + data.column.dataKey];
  1023. if ( typeof rowopt != 'undefined' &&
  1024. typeof rowopt.style != 'undefined' &&
  1025. rowopt.style.hidden !== true ) {
  1026. cell.styles.halign = rowopt.style.align;
  1027. if ( atOptions.styles.fillColor === 'inherit' )
  1028. cell.styles.fillColor = rowopt.style.bcolor;
  1029. if ( atOptions.styles.textColor === 'inherit' )
  1030. cell.styles.textColor = rowopt.style.color;
  1031. if ( atOptions.styles.fontStyle === 'inherit' )
  1032. cell.styles.fontStyle = rowopt.style.fstyle;
  1033. }
  1034. };
  1035. }
  1036. if ( typeof atOptions.drawHeaderCell !== 'function' ) {
  1037. atOptions.drawHeaderCell = function (cell, data) {
  1038. var colopt = teOptions.columns [data.column.dataKey];
  1039. if ( (colopt.style.hasOwnProperty("hidden") !== true || colopt.style.hidden !== true) &&
  1040. colopt.rowIndex >= 0 )
  1041. return prepareAutoTableText(cell, data, colopt);
  1042. else
  1043. return false; // cell is hidden
  1044. };
  1045. }
  1046. if ( typeof atOptions.drawCell !== 'function' ) {
  1047. atOptions.drawCell = function (cell, data) {
  1048. var rowopt = teOptions.rowoptions [data.row.index + ":" + data.column.dataKey];
  1049. if ( prepareAutoTableText(cell, data, rowopt) ) {
  1050. teOptions.doc.rect(cell.x, cell.y, cell.width, cell.height, cell.styles.fillStyle);
  1051. if ( typeof rowopt != 'undefined' && typeof rowopt.kids != 'undefined' && rowopt.kids.length > 0 ) {
  1052. var dh = cell.height / rowopt.rect.height;
  1053. if ( dh > teOptions.dh || typeof teOptions.dh == 'undefined' )
  1054. teOptions.dh = dh;
  1055. teOptions.dw = cell.width / rowopt.rect.width;
  1056. var y = cell.textPos.y;
  1057. drawAutotableElements(cell, rowopt.kids, teOptions);
  1058. cell.textPos.y = y;
  1059. drawAutotableText(cell, rowopt.kids, teOptions);
  1060. }
  1061. else
  1062. drawAutotableText(cell, {}, teOptions);
  1063. }
  1064. return false;
  1065. };
  1066. }
  1067. // collect header and data rows
  1068. teOptions.headerrows = [];
  1069. $hrows = $(this).find('thead').find(defaults.theadSelector);
  1070. $hrows.each(function () {
  1071. colKey = 0;
  1072. teOptions.headerrows[rowIndex] = [];
  1073. ForEachVisibleCell(this, 'th,td', rowIndex, $hrows.length,
  1074. function (cell, row, col) {
  1075. var obj = getCellStyles(cell);
  1076. obj.title = parseString(cell, row, col);
  1077. obj.key = colKey++;
  1078. obj.rowIndex = rowIndex;
  1079. teOptions.headerrows[rowIndex].push(obj);
  1080. });
  1081. rowIndex++;
  1082. });
  1083. if ( rowIndex > 0 ) {
  1084. // iterate through last row
  1085. var lastrow = rowIndex - 1;
  1086. while ( lastrow >= 0 ) {
  1087. $.each(teOptions.headerrows[lastrow], function () {
  1088. var obj = this;
  1089. if ( lastrow > 0 && this.rect === null )
  1090. obj = teOptions.headerrows[lastrow - 1][this.key];
  1091. if ( obj !== null && obj.rowIndex >= 0 &&
  1092. (obj.style.hasOwnProperty("hidden") !== true || obj.style.hidden !== true) )
  1093. teOptions.columns.push(obj);
  1094. });
  1095. lastrow = (teOptions.columns.length > 0) ? -1 : lastrow - 1;
  1096. }
  1097. }
  1098. var rowCount = 0;
  1099. $rows = [];
  1100. $rows = collectRows ($(this));
  1101. $($rows).each(function () {
  1102. var rowData = [];
  1103. colKey = 0;
  1104. ForEachVisibleCell(this, 'td,th', rowIndex, $hrows.length + $rows.length,
  1105. function (cell, row, col) {
  1106. var obj;
  1107. if ( typeof teOptions.columns[colKey] === 'undefined' ) {
  1108. // jsPDF-Autotable needs columns. Thus define hidden ones for tables without thead
  1109. obj = {
  1110. title: '',
  1111. key: colKey,
  1112. style: {
  1113. hidden: true
  1114. }
  1115. };
  1116. teOptions.columns.push(obj);
  1117. }
  1118. if ( typeof cell !== 'undefined' && cell !== null ) {
  1119. obj = getCellStyles(cell);
  1120. obj.kids = $(cell).children();
  1121. teOptions.rowoptions [rowCount + ":" + colKey++] = obj;
  1122. }
  1123. else {
  1124. obj = $.extend(true, {}, teOptions.rowoptions [rowCount + ":" + (colKey - 1)]);
  1125. obj.colspan = -1;
  1126. teOptions.rowoptions [rowCount + ":" + colKey++] = obj;
  1127. }
  1128. rowData.push(parseString(cell, row, col));
  1129. });
  1130. if ( rowData.length ) {
  1131. teOptions.rows.push(rowData);
  1132. rowCount++;
  1133. }
  1134. rowIndex++;
  1135. });
  1136. // onBeforeAutotable: optional callback function before calling
  1137. // jsPDF AutoTable that can be used to modify the AutoTable options
  1138. if ( typeof teOptions.onBeforeAutotable === 'function' )
  1139. teOptions.onBeforeAutotable($(this), teOptions.columns, teOptions.rows, atOptions);
  1140. teOptions.doc.autoTable(teOptions.columns, teOptions.rows, atOptions);
  1141. // onAfterAutotable: optional callback function after returning
  1142. // from jsPDF AutoTable that can be used to modify the AutoTable options
  1143. if ( typeof teOptions.onAfterAutotable === 'function' )
  1144. teOptions.onAfterAutotable($(this), atOptions);
  1145. // set the start position for the next table (in case there is one)
  1146. defaults.jspdf.autotable.startY = teOptions.doc.autoTableEndPosY() + atOptions.margin.top;
  1147. });
  1148. jsPdfOutput(teOptions.doc, (typeof teOptions.images != 'undefined' && jQuery.isEmptyObject(teOptions.images) === false));
  1149. if ( typeof teOptions.headerrows != 'undefined' )
  1150. teOptions.headerrows.length = 0;
  1151. if ( typeof teOptions.columns != 'undefined' )
  1152. teOptions.columns.length = 0;
  1153. if ( typeof teOptions.rows != 'undefined' )
  1154. teOptions.rows.length = 0;
  1155. delete teOptions.doc;
  1156. teOptions.doc = null;
  1157. });
  1158. }
  1159. }
  1160. /*
  1161. function FindColObject (objects, colIndex, rowIndex) {
  1162. var result = null;
  1163. $.each(objects, function () {
  1164. if ( this.rowIndex == rowIndex && this.key == colIndex ) {
  1165. result = this;
  1166. return false;
  1167. }
  1168. });
  1169. return result;
  1170. }
  1171. */
  1172. function collectRows ($table) {
  1173. var result = [];
  1174. findTablePart($table,'tbody').each(function () {
  1175. result.push.apply(result, findRows($(this), defaults.tbodySelector).toArray());
  1176. });
  1177. if ( defaults.tfootSelector.length ) {
  1178. findTablePart($table,'tfoot').each(function () {
  1179. result.push.apply(result, findRows($(this), defaults.tfootSelector).toArray());
  1180. });
  1181. }
  1182. return result;
  1183. }
  1184. function findTablePart ($table, type) {
  1185. var tl = $table.parents('table').length;
  1186. return $table.find(type).filter (function () {
  1187. return $(this).closest('table').parents('table').length === tl;
  1188. });
  1189. }
  1190. function findRows ($tpart, rowSelector) {
  1191. return $tpart.find(rowSelector).filter (function () {
  1192. return $(this).find('table').length === 0 && $(this).parents('table').length === 1;
  1193. });
  1194. }
  1195. function GetColumnNames (table) {
  1196. var result = [];
  1197. $(table).find('thead').first().find('th').each(function (index, el) {
  1198. if ( $(el).attr("data-field") !== undefined )
  1199. result[index] = $(el).attr("data-field");
  1200. else
  1201. result[index] = index.toString();
  1202. });
  1203. return result;
  1204. }
  1205. function isVisible ($element) {
  1206. var isCell = typeof $element[0].cellIndex !== 'undefined';
  1207. var isRow = typeof $element[0].rowIndex !== 'undefined';
  1208. var isElementVisible = (isCell || isRow) ? isTableElementVisible($element) : $element.is(':visible');
  1209. var tableexportDisplay = $element.data("tableexport-display");
  1210. if (isCell && tableexportDisplay != 'none' && tableexportDisplay != 'always') {
  1211. $element = $($element[0].parentNode);
  1212. isRow = typeof $element[0].rowIndex !== 'undefined';
  1213. tableexportDisplay = $element.data("tableexport-display");
  1214. }
  1215. if (isRow && tableexportDisplay != 'none' && tableexportDisplay != 'always') {
  1216. tableexportDisplay = $element.closest('table').data("tableexport-display");
  1217. }
  1218. return tableexportDisplay !== 'none' && (isElementVisible == true || tableexportDisplay == 'always');
  1219. }
  1220. function isTableElementVisible ($element) {
  1221. var hiddenEls = [];
  1222. if ( checkCellVisibilty ) {
  1223. hiddenEls = $hiddenTableElements.filter (function () {
  1224. var found = false;
  1225. if (this.nodeType == $element[0].nodeType) {
  1226. if (typeof this.rowIndex !== 'undefined' && this.rowIndex == $element[0].rowIndex)
  1227. found = true;
  1228. else if (typeof this.cellIndex !== 'undefined' && this.cellIndex == $element[0].cellIndex &&
  1229. typeof this.parentNode.rowIndex !== 'undefined' &&
  1230. typeof $element[0].parentNode.rowIndex !== 'undefined' &&
  1231. this.parentNode.rowIndex == $element[0].parentNode.rowIndex)
  1232. found = true;
  1233. }
  1234. return found;
  1235. });
  1236. }
  1237. return (checkCellVisibilty == false || hiddenEls.length == 0);
  1238. }
  1239. function isColumnIgnored ($cell, rowLength, colIndex) {
  1240. var result = false;
  1241. if (isVisible($cell)) {
  1242. if ( defaults.ignoreColumn.length > 0 ) {
  1243. if ( $.inArray(colIndex, defaults.ignoreColumn) != -1 ||
  1244. $.inArray(colIndex - rowLength, defaults.ignoreColumn) != -1 ||
  1245. (colNames.length > colIndex && typeof colNames[colIndex] != 'undefined' &&
  1246. $.inArray(colNames[colIndex], defaults.ignoreColumn) != -1) )
  1247. result = true;
  1248. }
  1249. }
  1250. else
  1251. result = true;
  1252. return result;
  1253. }
  1254. function ForEachVisibleCell (tableRow, selector, rowIndex, rowCount, cellcallback) {
  1255. if ( typeof (cellcallback) === 'function' ) {
  1256. var ignoreRow = false;
  1257. if (typeof defaults.onIgnoreRow === 'function')
  1258. ignoreRow = defaults.onIgnoreRow($(tableRow), rowIndex);
  1259. if (ignoreRow === false &&
  1260. $.inArray(rowIndex, defaults.ignoreRow) == -1 &&
  1261. $.inArray(rowIndex - rowCount, defaults.ignoreRow) == -1 &&
  1262. isVisible($(tableRow))) {
  1263. var $cells = $(tableRow).find(selector);
  1264. var cellCount = 0;
  1265. $cells.each(function (colIndex) {
  1266. var $cell = $(this);
  1267. var c;
  1268. var colspan = getColspan (this);
  1269. var rowspan = getRowspan (this);
  1270. // Skip ranges
  1271. $.each(ranges, function () {
  1272. var range = this;
  1273. if ( rowIndex >= range.s.r && rowIndex <= range.e.r && cellCount >= range.s.c && cellCount <= range.e.c ) {
  1274. for ( c = 0; c <= range.e.c - range.s.c; ++c )
  1275. cellcallback(null, rowIndex, cellCount++);
  1276. }
  1277. });
  1278. if ( isColumnIgnored($cell, $cells.length, colIndex) === false ) {
  1279. // Handle Row Span
  1280. if ( rowspan || colspan ) {
  1281. rowspan = rowspan || 1;
  1282. colspan = colspan || 1;
  1283. ranges.push({
  1284. s: {r: rowIndex, c: cellCount},
  1285. e: {r: rowIndex + rowspan - 1, c: cellCount + colspan - 1}
  1286. });
  1287. }
  1288. // Handle Value
  1289. cellcallback(this, rowIndex, cellCount++);
  1290. }
  1291. // Handle Colspan
  1292. if ( colspan )
  1293. for ( c = 0; c < colspan - 1; ++c )
  1294. cellcallback(null, rowIndex, cellCount++);
  1295. });
  1296. // Skip ranges
  1297. $.each(ranges, function () {
  1298. var range = this;
  1299. if ( rowIndex >= range.s.r && rowIndex <= range.e.r && cellCount >= range.s.c && cellCount <= range.e.c ) {
  1300. for ( c = 0; c <= range.e.c - range.s.c; ++c )
  1301. cellcallback(null, rowIndex, cellCount++);
  1302. }
  1303. });
  1304. }
  1305. }
  1306. }
  1307. function jsPdfOutput (doc, hasimages) {
  1308. if ( defaults.consoleLog === true )
  1309. console.log(doc.output());
  1310. if ( defaults.outputMode === 'string' )
  1311. return doc.output();
  1312. if ( defaults.outputMode === 'base64' )
  1313. return base64encode(doc.output());
  1314. if ( defaults.outputMode === 'window' ) {
  1315. window.URL = window.URL || window.webkitURL;
  1316. window.open(window.URL.createObjectURL(doc.output("blob")));
  1317. return;
  1318. }
  1319. try {
  1320. var blob = doc.output('blob');
  1321. saveAs(blob, defaults.fileName + '.pdf');
  1322. }
  1323. catch (e) {
  1324. downloadFile(defaults.fileName + '.pdf',
  1325. 'data:application/pdf' + (hasimages ? '' : ';base64') + ',',
  1326. hasimages ? doc.output('blob') : doc.output());
  1327. }
  1328. }
  1329. function prepareAutoTableText (cell, data, cellopt) {
  1330. var cs = 0;
  1331. if ( typeof cellopt !== 'undefined' )
  1332. cs = cellopt.colspan;
  1333. if ( cs >= 0 ) {
  1334. // colspan handling
  1335. var cellWidth = cell.width;
  1336. var textPosX = cell.textPos.x;
  1337. var i = data.table.columns.indexOf(data.column);
  1338. for ( var c = 1; c < cs; c++ ) {
  1339. var column = data.table.columns[i + c];
  1340. cellWidth += column.width;
  1341. }
  1342. if ( cs > 1 ) {
  1343. if ( cell.styles.halign === 'right' )
  1344. textPosX = cell.textPos.x + cellWidth - cell.width;
  1345. else if ( cell.styles.halign === 'center' )
  1346. textPosX = cell.textPos.x + (cellWidth - cell.width) / 2;
  1347. }
  1348. cell.width = cellWidth;
  1349. cell.textPos.x = textPosX;
  1350. if ( typeof cellopt !== 'undefined' && cellopt.rowspan > 1 )
  1351. cell.height = cell.height * cellopt.rowspan;
  1352. // fix jsPDF's calculation of text position
  1353. if ( cell.styles.valign === 'middle' || cell.styles.valign === 'bottom' ) {
  1354. var splittedText = typeof cell.text === 'string' ? cell.text.split(/\r\n|\r|\n/g) : cell.text;
  1355. var lineCount = splittedText.length || 1;
  1356. if ( lineCount > 2 )
  1357. cell.textPos.y -= ((2 - FONT_ROW_RATIO) / 2 * data.row.styles.fontSize) * (lineCount - 2) / 3;
  1358. }
  1359. return true;
  1360. }
  1361. else
  1362. return false; // cell is hidden (colspan = -1), don't draw it
  1363. }
  1364. function collectImages (cell, elements, teOptions) {
  1365. if ( typeof teOptions.images != 'undefined' ) {
  1366. elements.each(function () {
  1367. var kids = $(this).children();
  1368. if ( $(this).is("img") ) {
  1369. var hash = strHashCode(this.src);
  1370. teOptions.images[hash] = {
  1371. url: this.src,
  1372. src: this.src
  1373. };
  1374. }
  1375. if ( typeof kids != 'undefined' && kids.length > 0 )
  1376. collectImages(cell, kids, teOptions);
  1377. });
  1378. }
  1379. }
  1380. function loadImages (teOptions, callback) {
  1381. var i;
  1382. var imageCount = 0;
  1383. var x = 0;
  1384. function done () {
  1385. callback(imageCount);
  1386. }
  1387. function loadImage (image) {
  1388. if ( !image.url )
  1389. return;
  1390. var img = new Image();
  1391. imageCount = ++x;
  1392. img.crossOrigin = 'Anonymous';
  1393. img.onerror = img.onload = function () {
  1394. if ( img.complete ) {
  1395. if ( img.src.indexOf('data:image/') === 0 ) {
  1396. img.width = image.width || img.width || 0;
  1397. img.height = image.height || img.height || 0;
  1398. }
  1399. if ( img.width + img.height ) {
  1400. var canvas = document.createElement("canvas");
  1401. var ctx = canvas.getContext("2d");
  1402. canvas.width = img.width;
  1403. canvas.height = img.height;
  1404. ctx.drawImage(img, 0, 0);
  1405. image.src = canvas.toDataURL("image/jpeg");
  1406. }
  1407. }
  1408. if ( !--x )
  1409. done();
  1410. };
  1411. img.src = image.url;
  1412. }
  1413. if ( typeof teOptions.images != 'undefined' ) {
  1414. for ( i in teOptions.images )
  1415. if ( teOptions.images.hasOwnProperty(i) )
  1416. loadImage(teOptions.images[i]);
  1417. }
  1418. return x || done();
  1419. }
  1420. function drawAutotableElements (cell, elements, teOptions) {
  1421. elements.each(function () {
  1422. var kids = $(this).children();
  1423. var uy = 0;
  1424. if ( $(this).is("div") ) {
  1425. var bcolor = rgb2array(getStyle(this, 'background-color'), [255, 255, 255]);
  1426. var lcolor = rgb2array(getStyle(this, 'border-top-color'), [0, 0, 0]);
  1427. var lwidth = getPropertyUnitValue(this, 'border-top-width', defaults.jspdf.unit);
  1428. var r = this.getBoundingClientRect();
  1429. var ux = this.offsetLeft * teOptions.dw;
  1430. uy = this.offsetTop * teOptions.dh;
  1431. var uw = r.width * teOptions.dw;
  1432. var uh = r.height * teOptions.dh;
  1433. teOptions.doc.setDrawColor.apply(undefined, lcolor);
  1434. teOptions.doc.setFillColor.apply(undefined, bcolor);
  1435. teOptions.doc.setLineWidth(lwidth);
  1436. teOptions.doc.rect(cell.x + ux, cell.y + uy, uw, uh, lwidth ? "FD" : "F");
  1437. }
  1438. else if ( $(this).is("img") ) {
  1439. if ( typeof teOptions.images != 'undefined' ) {
  1440. var hash = strHashCode(this.src);
  1441. var image = teOptions.images[hash];
  1442. if ( typeof image != 'undefined' ) {
  1443. var arCell = cell.width / cell.height;
  1444. var arImg = this.width / this.height;
  1445. var imgWidth = cell.width;
  1446. var imgHeight = cell.height;
  1447. var px2pt = 0.264583 * 72 / 25.4;
  1448. if ( arImg <= arCell ) {
  1449. imgHeight = Math.min(cell.height, this.height);
  1450. imgWidth = this.width * imgHeight / this.height;
  1451. }
  1452. else if ( arImg > arCell ) {
  1453. imgWidth = Math.min(cell.width, this.width);
  1454. imgHeight = this.height * imgWidth / this.width;
  1455. }
  1456. imgWidth *= px2pt;
  1457. imgHeight *= px2pt;
  1458. if ( imgHeight < cell.height )
  1459. uy = (cell.height - imgHeight) / 2;
  1460. try {
  1461. teOptions.doc.addImage(image.src, cell.textPos.x, cell.y + uy, imgWidth, imgHeight);
  1462. }
  1463. catch (e) {
  1464. // TODO: IE -> convert png to jpeg
  1465. }
  1466. cell.textPos.x += imgWidth;
  1467. }
  1468. }
  1469. }
  1470. if ( typeof kids != 'undefined' && kids.length > 0 )
  1471. drawAutotableElements(cell, kids, teOptions);
  1472. });
  1473. }
  1474. function drawAutotableText (cell, texttags, teOptions) {
  1475. if ( typeof teOptions.onAutotableText === 'function' ) {
  1476. teOptions.onAutotableText(teOptions.doc, cell, texttags);
  1477. }
  1478. else {
  1479. var x = cell.textPos.x;
  1480. var y = cell.textPos.y;
  1481. var style = {halign: cell.styles.halign, valign: cell.styles.valign};
  1482. if ( texttags.length ) {
  1483. var tag = texttags[0];
  1484. while ( tag.previousSibling )
  1485. tag = tag.previousSibling;
  1486. var b = false, i = false;
  1487. while ( tag ) {
  1488. var txt = tag.innerText || tag.textContent || "";
  1489. txt = ((txt.length && txt[0] == " ") ? " " : "") +
  1490. $.trim(txt) +
  1491. ((txt.length > 1 && txt[txt.length - 1] == " ") ? " " : "");
  1492. if ( $(tag).is("br") ) {
  1493. x = cell.textPos.x;
  1494. y += teOptions.doc.internal.getFontSize();
  1495. }
  1496. if ( $(tag).is("b") )
  1497. b = true;
  1498. else if ( $(tag).is("i") )
  1499. i = true;
  1500. if ( b || i )
  1501. teOptions.doc.setFontType((b && i) ? "bolditalic" : b ? "bold" : "italic");
  1502. var w = teOptions.doc.getStringUnitWidth(txt) * teOptions.doc.internal.getFontSize();
  1503. if ( w ) {
  1504. if ( cell.styles.overflow === 'linebreak' &&
  1505. x > cell.textPos.x && (x + w) > (cell.textPos.x + cell.width) ) {
  1506. var chars = ".,!%*;:=-";
  1507. if ( chars.indexOf(txt.charAt(0)) >= 0 ) {
  1508. var s = txt.charAt(0);
  1509. w = teOptions.doc.getStringUnitWidth(s) * teOptions.doc.internal.getFontSize();
  1510. if ( (x + w) <= (cell.textPos.x + cell.width) ) {
  1511. teOptions.doc.autoTableText(s, x, y, style);
  1512. txt = txt.substring(1, txt.length);
  1513. }
  1514. w = teOptions.doc.getStringUnitWidth(txt) * teOptions.doc.internal.getFontSize();
  1515. }
  1516. x = cell.textPos.x;
  1517. y += teOptions.doc.internal.getFontSize();
  1518. }
  1519. while ( txt.length && (x + w) > (cell.textPos.x + cell.width) ) {
  1520. txt = txt.substring(0, txt.length - 1);
  1521. w = teOptions.doc.getStringUnitWidth(txt) * teOptions.doc.internal.getFontSize();
  1522. }
  1523. teOptions.doc.autoTableText(txt, x, y, style);
  1524. x += w;
  1525. }
  1526. if ( b || i ) {
  1527. if ( $(tag).is("b") )
  1528. b = false;
  1529. else if ( $(tag).is("i") )
  1530. i = false;
  1531. teOptions.doc.setFontType((!b && !i) ? "normal" : b ? "bold" : "italic");
  1532. }
  1533. tag = tag.nextSibling;
  1534. }
  1535. cell.textPos.x = x;
  1536. cell.textPos.y = y;
  1537. }
  1538. else {
  1539. teOptions.doc.autoTableText(cell.text, cell.textPos.x, cell.textPos.y, style);
  1540. }
  1541. }
  1542. }
  1543. function escapeRegExp (string) {
  1544. return string.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
  1545. }
  1546. function replaceAll (string, find, replace) {
  1547. return string.replace(new RegExp(escapeRegExp(find), 'g'), replace);
  1548. }
  1549. function parseNumber (value) {
  1550. value = value || "0";
  1551. value = replaceAll(value, defaults.numbers.html.thousandsSeparator, '');
  1552. value = replaceAll(value, defaults.numbers.html.decimalMark, '.');
  1553. return typeof value === "number" || jQuery.isNumeric(value) !== false ? value : false;
  1554. }
  1555. function parsePercent (value) {
  1556. if ( value.indexOf("%") > -1 ) {
  1557. value = parseNumber(value.replace(/%/g, ""));
  1558. if ( value !== false )
  1559. value = value / 100;
  1560. }
  1561. else
  1562. value = false;
  1563. return value;
  1564. }
  1565. function parseString (cell, rowIndex, colIndex) {
  1566. var result = '';
  1567. if ( cell !== null ) {
  1568. var $cell = $(cell);
  1569. var htmlData;
  1570. if ( $cell[0].hasAttribute("data-tableexport-value") ) {
  1571. htmlData = $cell.data("tableexport-value");
  1572. htmlData = htmlData ? htmlData + '' : ''
  1573. }
  1574. else {
  1575. htmlData = $cell.html();
  1576. if ( typeof defaults.onCellHtmlData === 'function' )
  1577. htmlData = defaults.onCellHtmlData($cell, rowIndex, colIndex, htmlData);
  1578. else if ( htmlData != '' ) {
  1579. var html = $.parseHTML(htmlData);
  1580. var inputidx = 0;
  1581. var selectidx = 0;
  1582. htmlData = '';
  1583. $.each(html, function () {
  1584. if ( $(this).is("input") )
  1585. htmlData += $cell.find('input').eq(inputidx++).val();
  1586. else if ( $(this).is("select") )
  1587. htmlData += $cell.find('select option:selected').eq(selectidx++).text();
  1588. else {
  1589. if ( typeof $(this).html() === 'undefined' )
  1590. htmlData += $(this).text();
  1591. else if ( jQuery().bootstrapTable === undefined ||
  1592. ($(this).hasClass('filterControl') !== true &&
  1593. $(cell).parents('.detail-view').length === 0) )
  1594. htmlData += $(this).html();
  1595. }
  1596. });
  1597. }
  1598. }
  1599. if ( defaults.htmlContent === true ) {
  1600. result = $.trim(htmlData);
  1601. }
  1602. else if ( htmlData && htmlData != '' ) {
  1603. var cellFormat = $(cell).data("tableexport-cellformat");
  1604. if ( cellFormat != '' ) {
  1605. var text = htmlData.replace(/\n/g, '\u2028').replace(/<br\s*[\/]?>/gi, '\u2060');
  1606. var obj = $('<div/>').html(text).contents();
  1607. var number = false;
  1608. text = '';
  1609. $.each(obj.text().split("\u2028"), function (i, v) {
  1610. if ( i > 0 )
  1611. text += " ";
  1612. text += $.trim(v);
  1613. });
  1614. $.each(text.split("\u2060"), function (i, v) {
  1615. if ( i > 0 )
  1616. result += "\n";
  1617. result += $.trim(v).replace(/\u00AD/g, ""); // remove soft hyphens
  1618. });
  1619. if ( defaults.type == 'json' ||
  1620. (defaults.type === 'excel' && defaults.excelFileFormat === 'xmlss') ||
  1621. defaults.numbers.output === false ) {
  1622. number = parseNumber(result);
  1623. if ( number !== false )
  1624. result = Number(number);
  1625. }
  1626. else if ( defaults.numbers.html.decimalMark != defaults.numbers.output.decimalMark ||
  1627. defaults.numbers.html.thousandsSeparator != defaults.numbers.output.thousandsSeparator ) {
  1628. number = parseNumber(result);
  1629. if ( number !== false ) {
  1630. var frac = ("" + number.substr(number < 0 ? 1 : 0)).split('.');
  1631. if ( frac.length == 1 )
  1632. frac[1] = "";
  1633. var mod = frac[0].length > 3 ? frac[0].length % 3 : 0;
  1634. result = (number < 0 ? "-" : "") +
  1635. (defaults.numbers.output.thousandsSeparator ? ((mod ? frac[0].substr(0, mod) + defaults.numbers.output.thousandsSeparator : "") + frac[0].substr(mod).replace(/(\d{3})(?=\d)/g, "$1" + defaults.numbers.output.thousandsSeparator)) : frac[0]) +
  1636. (frac[1].length ? defaults.numbers.output.decimalMark + frac[1] : "");
  1637. }
  1638. }
  1639. }
  1640. else
  1641. result = htmlData;
  1642. }
  1643. if ( defaults.escape === true ) {
  1644. //noinspection JSDeprecatedSymbols
  1645. result = escape(result);
  1646. }
  1647. if ( typeof defaults.onCellData === 'function' ) {
  1648. result = defaults.onCellData($cell, rowIndex, colIndex, result);
  1649. }
  1650. }
  1651. return result;
  1652. }
  1653. //noinspection JSUnusedLocalSymbols
  1654. function hyphenate (a, b, c) {
  1655. return b + "-" + c.toLowerCase();
  1656. }
  1657. function rgb2array (rgb_string, default_result) {
  1658. var re = /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/;
  1659. var bits = re.exec(rgb_string);
  1660. var result = default_result;
  1661. if ( bits )
  1662. result = [parseInt(bits[1]), parseInt(bits[2]), parseInt(bits[3])];
  1663. return result;
  1664. }
  1665. function getCellStyles (cell) {
  1666. var a = getStyle(cell, 'text-align');
  1667. var fw = getStyle(cell, 'font-weight');
  1668. var fs = getStyle(cell, 'font-style');
  1669. var f = '';
  1670. if ( a == 'start' )
  1671. a = getStyle(cell, 'direction') == 'rtl' ? 'right' : 'left';
  1672. if ( fw >= 700 )
  1673. f = 'bold';
  1674. if ( fs == 'italic' )
  1675. f += fs;
  1676. if ( f === '' )
  1677. f = 'normal';
  1678. var result = {
  1679. style: {
  1680. align: a,
  1681. bcolor: rgb2array(getStyle(cell, 'background-color'), [255, 255, 255]),
  1682. color: rgb2array(getStyle(cell, 'color'), [0, 0, 0]),
  1683. fstyle: f
  1684. },
  1685. colspan: getColspan (cell),
  1686. rowspan: getRowspan (cell)
  1687. };
  1688. if ( cell !== null ) {
  1689. var r = cell.getBoundingClientRect();
  1690. result.rect = {
  1691. width: r.width,
  1692. height: r.height
  1693. };
  1694. }
  1695. return result;
  1696. }
  1697. function getColspan (cell) {
  1698. var result = $(cell).data("tableexport-colspan");
  1699. if ( typeof result == 'undefined' && $(cell).is("[colspan]") )
  1700. result = $(cell).attr('colspan');
  1701. return (parseInt(result) || 0);
  1702. }
  1703. function getRowspan (cell) {
  1704. var result = $(cell).data("tableexport-rowspan");
  1705. if ( typeof result == 'undefined' && $(cell).is("[rowspan]") )
  1706. result = $(cell).attr('rowspan');
  1707. return (parseInt(result) || 0);
  1708. }
  1709. // get computed style property
  1710. function getStyle (target, prop) {
  1711. try {
  1712. if ( window.getComputedStyle ) { // gecko and webkit
  1713. prop = prop.replace(/([a-z])([A-Z])/, hyphenate); // requires hyphenated, not camel
  1714. return window.getComputedStyle(target, null).getPropertyValue(prop);
  1715. }
  1716. if ( target.currentStyle ) { // ie
  1717. return target.currentStyle[prop];
  1718. }
  1719. return target.style[prop];
  1720. }
  1721. catch (e) {
  1722. }
  1723. return "";
  1724. }
  1725. function getUnitValue (parent, value, unit) {
  1726. var baseline = 100; // any number serves
  1727. var temp = document.createElement("div"); // create temporary element
  1728. temp.style.overflow = "hidden"; // in case baseline is set too low
  1729. temp.style.visibility = "hidden"; // no need to show it
  1730. parent.appendChild(temp); // insert it into the parent for em, ex and %
  1731. temp.style.width = baseline + unit;
  1732. var factor = baseline / temp.offsetWidth;
  1733. parent.removeChild(temp); // clean up
  1734. return (value * factor);
  1735. }
  1736. function getPropertyUnitValue (target, prop, unit) {
  1737. var value = getStyle(target, prop); // get the computed style value
  1738. var numeric = value.match(/\d+/); // get the numeric component
  1739. if ( numeric !== null ) {
  1740. numeric = numeric[0]; // get the string
  1741. return getUnitValue(target.parentElement, numeric, unit);
  1742. }
  1743. return 0;
  1744. }
  1745. function jx_Workbook () {
  1746. if ( !(this instanceof jx_Workbook) ) {
  1747. //noinspection JSPotentiallyInvalidConstructorUsage
  1748. return new jx_Workbook();
  1749. }
  1750. this.SheetNames = [];
  1751. this.Sheets = {};
  1752. }
  1753. function jx_s2ab (s) {
  1754. var buf = new ArrayBuffer(s.length);
  1755. var view = new Uint8Array(buf);
  1756. for ( var i = 0; i != s.length; ++i ) view[i] = s.charCodeAt(i) & 0xFF;
  1757. return buf;
  1758. }
  1759. function jx_datenum (v, date1904) {
  1760. if ( date1904 ) v += 1462;
  1761. var epoch = Date.parse(v);
  1762. return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
  1763. }
  1764. function jx_createSheet (data) {
  1765. var ws = {};
  1766. var range = {s: {c: 10000000, r: 10000000}, e: {c: 0, r: 0}};
  1767. for ( var R = 0; R != data.length; ++R ) {
  1768. for ( var C = 0; C != data[R].length; ++C ) {
  1769. if ( range.s.r > R ) range.s.r = R;
  1770. if ( range.s.c > C ) range.s.c = C;
  1771. if ( range.e.r < R ) range.e.r = R;
  1772. if ( range.e.c < C ) range.e.c = C;
  1773. var cell = {v: data[R][C]};
  1774. if ( cell.v === null ) continue;
  1775. var cell_ref = XLSX.utils.encode_cell({c: C, r: R});
  1776. if ( typeof cell.v === 'number' ) cell.t = 'n';
  1777. else if ( typeof cell.v === 'boolean' ) cell.t = 'b';
  1778. else if ( cell.v instanceof Date ) {
  1779. cell.t = 'n';
  1780. cell.z = XLSX.SSF._table[14];
  1781. cell.v = jx_datenum(cell.v);
  1782. }
  1783. else cell.t = 's';
  1784. ws[cell_ref] = cell;
  1785. }
  1786. }
  1787. if ( range.s.c < 10000000 ) ws['!ref'] = XLSX.utils.encode_range(range);
  1788. return ws;
  1789. }
  1790. function strHashCode (str) {
  1791. var hash = 0, i, chr, len;
  1792. if ( str.length === 0 ) return hash;
  1793. for ( i = 0, len = str.length; i < len; i++ ) {
  1794. chr = str.charCodeAt(i);
  1795. hash = ((hash << 5) - hash) + chr;
  1796. hash |= 0; // Convert to 32bit integer
  1797. }
  1798. return hash;
  1799. }
  1800. function downloadFile (filename, header, data) {
  1801. var ua = window.navigator.userAgent;
  1802. if ( filename !== false && window.navigator.msSaveOrOpenBlob ) {
  1803. //noinspection JSUnresolvedFunction
  1804. window.navigator.msSaveOrOpenBlob(new Blob([data]), filename);
  1805. }
  1806. else if ( filename !== false && (ua.indexOf("MSIE ") > 0 || !!ua.match(/Trident.*rv\:11\./)) ) {
  1807. // Internet Explorer (<= 9) workaround by Darryl (https://github.com/dawiong/tableExport.jquery.plugin)
  1808. // based on sampopes answer on http://stackoverflow.com/questions/22317951
  1809. // ! Not working for json and pdf format !
  1810. var frame = document.createElement("iframe");
  1811. if ( frame ) {
  1812. document.body.appendChild(frame);
  1813. frame.setAttribute("style", "display:none");
  1814. frame.contentDocument.open("txt/plain", "replace");
  1815. frame.contentDocument.write(data);
  1816. frame.contentDocument.close();
  1817. frame.contentDocument.focus();
  1818. var extension = filename.substr((filename.lastIndexOf('.') +1));
  1819. switch(extension) {
  1820. case 'doc': case 'json': case 'png': case 'pdf': case 'xls': case 'xlsx':
  1821. filename += ".txt";
  1822. break;
  1823. }
  1824. frame.contentDocument.execCommand("SaveAs", true, filename);
  1825. document.body.removeChild(frame);
  1826. }
  1827. }
  1828. else {
  1829. var DownloadLink = document.createElement('a');
  1830. if ( DownloadLink ) {
  1831. var blobUrl = null;
  1832. DownloadLink.style.display = 'none';
  1833. if ( filename !== false )
  1834. DownloadLink.download = filename;
  1835. else
  1836. DownloadLink.target = '_blank';
  1837. if ( typeof data == 'object' ) {
  1838. window.URL = window.URL || window.webkitURL;
  1839. blobUrl = window.URL.createObjectURL(data);
  1840. DownloadLink.href = blobUrl;
  1841. }
  1842. else if ( header.toLowerCase().indexOf("base64,") >= 0 )
  1843. DownloadLink.href = header + base64encode(data);
  1844. else
  1845. DownloadLink.href = header + encodeURIComponent(data);
  1846. document.body.appendChild(DownloadLink);
  1847. if ( document.createEvent ) {
  1848. if ( DownloadEvt === null )
  1849. DownloadEvt = document.createEvent('MouseEvents');
  1850. DownloadEvt.initEvent('click', true, false);
  1851. DownloadLink.dispatchEvent(DownloadEvt);
  1852. }
  1853. else if ( document.createEventObject )
  1854. DownloadLink.fireEvent('onclick');
  1855. else if ( typeof DownloadLink.onclick == 'function' )
  1856. DownloadLink.onclick();
  1857. setTimeout(function(){
  1858. if ( blobUrl )
  1859. window.URL.revokeObjectURL(blobUrl);
  1860. document.body.removeChild(DownloadLink);
  1861. }, 100);
  1862. }
  1863. }
  1864. }
  1865. function utf8Encode (text) {
  1866. if (typeof text === 'string') {
  1867. text = text.replace(/\x0d\x0a/g, "\x0a");
  1868. var utftext = "";
  1869. for ( var n = 0; n < text.length; n++ ) {
  1870. var c = text.charCodeAt(n);
  1871. if ( c < 128 ) {
  1872. utftext += String.fromCharCode(c);
  1873. }
  1874. else if ( (c > 127) && (c < 2048) ) {
  1875. utftext += String.fromCharCode((c >> 6) | 192);
  1876. utftext += String.fromCharCode((c & 63) | 128);
  1877. }
  1878. else {
  1879. utftext += String.fromCharCode((c >> 12) | 224);
  1880. utftext += String.fromCharCode(((c >> 6) & 63) | 128);
  1881. utftext += String.fromCharCode((c & 63) | 128);
  1882. }
  1883. }
  1884. return utftext;
  1885. }
  1886. return text;
  1887. }
  1888. function base64encode (input) {
  1889. var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
  1890. var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  1891. var output = "";
  1892. var i = 0;
  1893. input = utf8Encode(input);
  1894. while ( i < input.length ) {
  1895. chr1 = input.charCodeAt(i++);
  1896. chr2 = input.charCodeAt(i++);
  1897. chr3 = input.charCodeAt(i++);
  1898. enc1 = chr1 >> 2;
  1899. enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
  1900. enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
  1901. enc4 = chr3 & 63;
  1902. if ( isNaN(chr2) ) {
  1903. enc3 = enc4 = 64;
  1904. } else if ( isNaN(chr3) ) {
  1905. enc4 = 64;
  1906. }
  1907. output = output +
  1908. keyStr.charAt(enc1) + keyStr.charAt(enc2) +
  1909. keyStr.charAt(enc3) + keyStr.charAt(enc4);
  1910. }
  1911. return output;
  1912. }
  1913. return this;
  1914. }
  1915. })(jQuery);