|
1 /* tslint:disable */ |
|
2 /* eslint-disable */ |
|
3 (function ($) { |
|
4 window.jqxToDash = function(value) { |
|
5 return value.split(/(?=[A-Z])/).join('-').toLowerCase(); |
|
6 } |
|
7 |
|
8 class DataExporter { |
|
9 constructor(exportDetails, groupBy, filterBy, conditionalFormatting) { |
|
10 const that = this; |
|
11 |
|
12 if (!exportDetails) { |
|
13 exportDetails = {}; |
|
14 } |
|
15 |
|
16 /* |
|
17 * "style" object definition (all properties are optional): |
|
18 * |
|
19 * «any valid CSS property» - applied to whole table |
|
20 * header (Object) |
|
21 * «any valid CSS property» - applied to header cells |
|
22 * «any column name» (Object) |
|
23 * «any valid CSS property» - applied to particular column header cell |
|
24 * columns (Object) |
|
25 * «any valid CSS property» - applied to column cells |
|
26 * «any column name» (Object) |
|
27 * «any valid CSS property» - applied to the cells of particular column |
|
28 * format - applicable to numeric and date columns |
|
29 * «n» (Object), where «n» is a row index (related to use of "ConditionalFormatting" object) |
|
30 * background |
|
31 * border |
|
32 * color |
|
33 * rows (Object) |
|
34 * «any valid CSS property» - applied to rows |
|
35 * alternationCount |
|
36 * alternationStart |
|
37 * alternationEnd |
|
38 * alternationIndex«n»Color, where «n» is an integer |
|
39 * alternationIndex«n»BorderColor, where «n» is an integer |
|
40 * alternationIndex«n»BackgroundColor, where «n» is an integer |
|
41 * «n» (Object), where «n» is a row index |
|
42 * «any valid CSS property» - applied to particular row |
|
43 */ |
|
44 that.style = exportDetails.style; |
|
45 |
|
46 that.header = exportDetails.header; |
|
47 that.exportHeader = exportDetails.exportHeader || true; |
|
48 that.hierarchical = exportDetails.hierarchical; |
|
49 that.expandChar = exportDetails.expandChar || '+'; |
|
50 that.collapseChar = exportDetails.collapseChar || '-'; |
|
51 that.pageOrientation = exportDetails.pageOrientation; |
|
52 |
|
53 if (!that.hierarchical && groupBy && groupBy.length > 0) { |
|
54 that.groupBy = groupBy; |
|
55 } |
|
56 else { |
|
57 that.mergedCells = exportDetails.mergedCells; |
|
58 } |
|
59 |
|
60 if (!that.groupBy && filterBy && Object.keys(filterBy).length > 0) { |
|
61 that.filterBy = filterBy; |
|
62 } |
|
63 |
|
64 if (conditionalFormatting) { |
|
65 that.conditionalFormatting = conditionalFormatting; |
|
66 } |
|
67 |
|
68 that.timeBetween1900And1970 = new Date(1970, 0, 1).getTime() - new Date(1900, 0, 1).getTime(); |
|
69 } |
|
70 |
|
71 /** |
|
72 * Generates and downloads a file. |
|
73 */ |
|
74 downloadFile(data, type, fileName) { |
|
75 let file; |
|
76 |
|
77 if (!fileName) { |
|
78 return data; |
|
79 } |
|
80 |
|
81 if (data instanceof Blob) { |
|
82 file = data; |
|
83 } |
|
84 else { |
|
85 file = new Blob([data], { type: type }); |
|
86 } |
|
87 |
|
88 if (window.navigator.msSaveOrOpenBlob) { // Edge |
|
89 window.navigator.msSaveOrOpenBlob(file, fileName); |
|
90 } |
|
91 else { // Chrome, Firefox, Safari |
|
92 const a = document.createElement('a'), |
|
93 url = URL.createObjectURL(file); |
|
94 |
|
95 a.href = url; |
|
96 a.download = fileName; |
|
97 a.style.position = 'absolute'; |
|
98 a.style.visibility = 'hidden'; |
|
99 |
|
100 document.body.appendChild(a); |
|
101 |
|
102 a.click(); |
|
103 |
|
104 setTimeout(function () { |
|
105 document.body.removeChild(a); |
|
106 window.URL.revokeObjectURL(url); |
|
107 }, 0); |
|
108 } |
|
109 } |
|
110 |
|
111 /** |
|
112 * Exports data. |
|
113 */ |
|
114 exportData(data, format, fileName, callback) { |
|
115 const that = this; |
|
116 |
|
117 that.actualHierarchy = that.hierarchical; |
|
118 format = format.toLowerCase(); |
|
119 |
|
120 if (that.exportHeader) { |
|
121 if (that.header) { |
|
122 data = data.slice(0); |
|
123 |
|
124 if (data.length === 0) { |
|
125 that.actualHierarchy = false; |
|
126 } |
|
127 |
|
128 that.processComplexHeader(that.header, data, format); |
|
129 } |
|
130 else if (data.length === 1) { |
|
131 that.actualHierarchy = false; |
|
132 } |
|
133 } |
|
134 |
|
135 if (data.length === 0) { |
|
136 // eslint-disable-next-line |
|
137 console.warn('No data to export.'); |
|
138 return; |
|
139 } |
|
140 |
|
141 if (format === 'xlsx') { |
|
142 that.xlsxStartIndex = that.complexHeader ? that.complexHeader.length : +that.exportHeader; |
|
143 } |
|
144 |
|
145 if (that.actualHierarchy) { |
|
146 data = that.processHierarchicalData(data, format); |
|
147 } |
|
148 |
|
149 that.getDatafields(data); |
|
150 |
|
151 if (fileName && fileName.slice(fileName.length - format.length - 1, fileName.length) !== '.' + format) { |
|
152 fileName += '.' + format; |
|
153 } |
|
154 |
|
155 let output = null; |
|
156 switch (format) { |
|
157 case 'csv': |
|
158 output = that.exportToCSVAndTSV(data, { delimiter: ', ', MIME: 'text/csv', toRemove: 2 }, fileName); |
|
159 break; |
|
160 case 'html': |
|
161 output = that.exportToHTML(data, fileName); |
|
162 break; |
|
163 case 'jpeg': |
|
164 case 'png': |
|
165 that.exportToImage(data, fileName, format, callback); |
|
166 break; |
|
167 case 'json': |
|
168 output = that.exportToJSON(data, fileName); |
|
169 break; |
|
170 case 'pdf': |
|
171 output = that.exportToPDF(data, fileName); |
|
172 break; |
|
173 case 'tsv': |
|
174 output = that.exportToCSVAndTSV(data, { delimiter: '\t', MIME: 'text/tab-separated-values', toRemove: 1 }, fileName); |
|
175 break; |
|
176 case 'xlsx': |
|
177 output = that.exportToXLSX(data, fileName); |
|
178 break; |
|
179 case 'xml': |
|
180 output = that.exportToXML(data, fileName); |
|
181 break; |
|
182 } |
|
183 |
|
184 if (callback && output) { |
|
185 callback(output); |
|
186 } |
|
187 |
|
188 delete that.complexHeader; |
|
189 |
|
190 return output; |
|
191 } |
|
192 |
|
193 /** |
|
194 * Exports to CSV and TSV. |
|
195 */ |
|
196 exportToCSVAndTSV(data, formatOptions, fileName) { |
|
197 const that = this, |
|
198 datafields = that.datafields; |
|
199 let stringResult = ''; |
|
200 |
|
201 for (let i = 0; i < data.length; i++) { |
|
202 const currentRecord = data[i]; |
|
203 let stringifiedCurrentRecord = ''; |
|
204 |
|
205 for (let j = 0; j < datafields.length; j++) { |
|
206 if (that.actualHierarchy && j === 0) { |
|
207 stringifiedCurrentRecord += ('""' + formatOptions.delimiter).repeat(currentRecord._level - 1) + |
|
208 '"' + currentRecord[datafields[j]] + '"' + formatOptions.delimiter + |
|
209 ('""' + formatOptions.delimiter).repeat(that.maxLevel - currentRecord._level); |
|
210 continue; |
|
211 } |
|
212 |
|
213 stringifiedCurrentRecord += '"' + currentRecord[datafields[j]] + '"' + formatOptions.delimiter; |
|
214 } |
|
215 |
|
216 stringifiedCurrentRecord = stringifiedCurrentRecord.slice(0, stringifiedCurrentRecord.length - formatOptions.toRemove) + '\n'; |
|
217 stringResult += stringifiedCurrentRecord; |
|
218 } |
|
219 |
|
220 return this.downloadFile(stringResult, formatOptions.MIME, fileName); |
|
221 } |
|
222 |
|
223 /** |
|
224 * Exports to HTML. |
|
225 */ |
|
226 exportToHTML(data, fileName) { |
|
227 const that = this, |
|
228 datafields = that.datafields, |
|
229 style = that.style; |
|
230 let header = '', |
|
231 startIndex = 0, |
|
232 html2canvas = ''; |
|
233 |
|
234 data = that.processGroupingInformation(data); |
|
235 that.data = data; |
|
236 |
|
237 if (that.exportHeader) { |
|
238 header = that.getHTMLHeader(datafields, data); |
|
239 startIndex = 1; |
|
240 } |
|
241 |
|
242 if (arguments[2]) { |
|
243 const scripts = Array.from(document.getElementsByTagName('script')), |
|
244 html2canvasScript = scripts.find(script => script.src.indexOf('html2canvas') !== -1); |
|
245 html2canvas = `<script type="text/javascript" src="${html2canvasScript.src}"></script>`; |
|
246 } |
|
247 |
|
248 let htmlContent = `<!DOCTYPE html> |
|
249 <html> |
|
250 <head> |
|
251 <meta charset="UTF-8"> |
|
252 <style type="text/css"> |
|
253 ${that.getRowStyle()}${that.getColumnStyle()} |
|
254 </style>${html2canvas}${that.toggleableFunctionality()} |
|
255 </head> |
|
256 <body> |
|
257 <table${that.getTableStyle()}>${header} |
|
258 <tbody>\n`; |
|
259 |
|
260 const mergedMainCells = {}, |
|
261 mergedSecondaryCells = {}, |
|
262 groupsHandled = []; |
|
263 |
|
264 that.getMergedCellsInfo(mergedMainCells, mergedSecondaryCells); |
|
265 |
|
266 mainLoop: |
|
267 for (let i = startIndex; i < data.length; i++) { |
|
268 const currentRecord = data[i], |
|
269 row = i - startIndex; |
|
270 let n = that.getAlternationIndex(row, ' rowN'), |
|
271 toCollapse = '', |
|
272 level = '', |
|
273 groupId = '', |
|
274 outlineLevel = 0; |
|
275 |
|
276 if (that.actualHierarchy) { |
|
277 if (currentRecord._collapsed) { |
|
278 toCollapse = ' collapsed'; |
|
279 } |
|
280 |
|
281 level = ` level="${currentRecord._level}"`; |
|
282 } |
|
283 else if (that.groupBy) { |
|
284 for (let k = 0; k < that.groupBy.length; k++) { |
|
285 const datafield = that.groupBy[k], |
|
286 currentGroup = currentRecord[datafield], |
|
287 currentGroupLabel = that.groups[datafield][currentGroup]; |
|
288 |
|
289 groupId += currentGroup; |
|
290 |
|
291 if (groupsHandled.indexOf(groupId) === -1) { |
|
292 htmlContent += ` <tr class="row"> |
|
293 <td class="column group" style="padding-left: ${outlineLevel * 25}px;" colspan="${that.datafields.length}">${currentGroupLabel}</td> |
|
294 </tr>`; |
|
295 groupsHandled.push(groupId); |
|
296 i--; |
|
297 continue mainLoop; |
|
298 } |
|
299 |
|
300 outlineLevel++; |
|
301 } |
|
302 } |
|
303 |
|
304 let currentContent = ` <tr class="row row${row}${n}${toCollapse}"${level}`; |
|
305 |
|
306 if (!fileName) { |
|
307 currentContent += ' style="page-break-inside: avoid;"' |
|
308 } |
|
309 |
|
310 currentContent += '>\n'; |
|
311 |
|
312 for (let j = 0; j < datafields.length; j++) { |
|
313 const cellCode = j + ',' + (row); |
|
314 let colspan = 1, rowspan = 1; |
|
315 |
|
316 if (mergedMainCells[cellCode]) { |
|
317 colspan = mergedMainCells[cellCode].colspan; |
|
318 rowspan = mergedMainCells[cellCode].rowspan; |
|
319 } |
|
320 else if (mergedSecondaryCells[cellCode]) { |
|
321 continue; |
|
322 } |
|
323 |
|
324 const datafield = datafields[j]; |
|
325 let value = currentRecord[datafield], |
|
326 indent = ''; |
|
327 |
|
328 if (that.actualHierarchy && j === 0) { |
|
329 let sign = ''; |
|
330 |
|
331 if (currentRecord._expanded) { |
|
332 sign = that.collapseChar; |
|
333 } |
|
334 else if (currentRecord._expanded === false) { |
|
335 sign = that.expandChar; |
|
336 } |
|
337 |
|
338 indent = `<div class="toggle-element" style="margin-left: ${25 * (currentRecord._level - 1) + 5}px;" expanded>${sign}</div>`; |
|
339 } |
|
340 |
|
341 value = that.getFormattedValue(value, datafield); |
|
342 |
|
343 let css = ''; |
|
344 |
|
345 if (style && style.columns && style.columns[datafield] && style.columns[datafield][row]) { |
|
346 const uniqueStyle = style.columns[datafield][row]; |
|
347 |
|
348 css += `border-color: ${uniqueStyle.border}; background-color: ${uniqueStyle.background}; color: ${uniqueStyle.color};"`; |
|
349 } |
|
350 |
|
351 if (j === 0 && outlineLevel > 1) { |
|
352 css += `padding-left: ${(outlineLevel - 1) * 25}px;"`; |
|
353 } |
|
354 |
|
355 if (css) { |
|
356 css = ` style="${css}"`; |
|
357 } |
|
358 |
|
359 currentContent += ` <td class="column column${datafield}"${css} colspan="${colspan}" rowspan="${rowspan}">${indent + value}</td>\n`; |
|
360 } |
|
361 |
|
362 htmlContent += currentContent + ' </tr>\n'; |
|
363 } |
|
364 |
|
365 htmlContent += ` </tbody> |
|
366 </table> |
|
367 </body> |
|
368 </html>`; |
|
369 |
|
370 if (arguments[2]) { |
|
371 return htmlContent; |
|
372 } |
|
373 |
|
374 return this.downloadFile(htmlContent, 'text/html', fileName); |
|
375 } |
|
376 |
|
377 /** |
|
378 * Exports to an image (PNG/JPEG). |
|
379 */ |
|
380 exportToImage(data, fileName, fileExtension, callback) { |
|
381 const that = this; |
|
382 |
|
383 try { |
|
384 html2canvas; |
|
385 } |
|
386 catch (error) { |
|
387 throw new Error('jqx-grid: Missing reference to \'html2canvas.min.js\'.'); |
|
388 } |
|
389 |
|
390 let imageData = null; |
|
391 |
|
392 const htmlContent = that.exportToHTML(data, fileName, true), |
|
393 iframe = document.createElement('iframe'); |
|
394 |
|
395 iframe.style.position = 'absolute'; |
|
396 iframe.style.top = 0; |
|
397 iframe.style.left = 0; |
|
398 iframe.style.border = 'none'; |
|
399 iframe.style.width = '100%'; |
|
400 iframe.style.height = '100%'; |
|
401 iframe.style.opacity = 0; |
|
402 |
|
403 document.body.appendChild(iframe); |
|
404 |
|
405 iframe.contentDocument.write(htmlContent); |
|
406 |
|
407 function checkIframePopulated() { |
|
408 if (!iframe.contentDocument.body || !iframe.contentDocument.body.firstElementChild) { |
|
409 requestAnimationFrame(checkIframePopulated); |
|
410 } |
|
411 else { |
|
412 iframe.contentWindow.html2canvas(iframe.contentDocument.body.firstElementChild).then(canvas => { |
|
413 const draw = $.jqxDraw(document.createElement('div')); |
|
414 |
|
415 imageData = canvas.toDataURL('image/png'); |
|
416 |
|
417 if (callback) { |
|
418 callback(imageData); |
|
419 } |
|
420 else { |
|
421 document.body.appendChild(canvas); |
|
422 draw.exportImage(undefined, canvas, fileExtension, fileName); |
|
423 } |
|
424 |
|
425 iframe.remove(); |
|
426 canvas.remove(); |
|
427 }); |
|
428 } |
|
429 } |
|
430 |
|
431 checkIframePopulated(); |
|
432 |
|
433 return imageData; |
|
434 } |
|
435 |
|
436 /** |
|
437 * Gets merged cells information (for use in HTML and PDF export). |
|
438 */ |
|
439 getMergedCellsInfo(mergedMainCells, mergedSecondaryCells, mapping) { |
|
440 const that = this; |
|
441 |
|
442 if (!that.mergedCells) { |
|
443 return; |
|
444 } |
|
445 |
|
446 const multipleTables = mapping && mapping[that.datafields.length - 1] !== 0; |
|
447 |
|
448 that.mergedCellsPDF = that.mergedCells.slice(0); |
|
449 |
|
450 for (let i = 0; i < that.mergedCellsPDF.length; i++) { |
|
451 const cellDefinition = that.mergedCellsPDF[i]; |
|
452 let colspan = cellDefinition.colspan, |
|
453 rowspan = cellDefinition.rowspan; |
|
454 |
|
455 if (rowspan < 2 && colspan < 2) { |
|
456 continue; |
|
457 } |
|
458 |
|
459 const row = cellDefinition.cell[1]; |
|
460 let col = cellDefinition.cell[0]; |
|
461 |
|
462 if (multipleTables && colspan > 1) { |
|
463 const startTable = mapping[col], |
|
464 endTable = mapping[col + colspan - 1], |
|
465 splitCells = []; |
|
466 |
|
467 if (endTable > startTable) { |
|
468 let currentTable = startTable, |
|
469 currentColumn = col, |
|
470 overal = 0; |
|
471 |
|
472 mainLoop: |
|
473 for (let i = startTable; i <= endTable; i++) { |
|
474 let start = currentColumn, |
|
475 span = 0; |
|
476 |
|
477 while (mapping[currentColumn] === currentTable) { |
|
478 currentColumn++; |
|
479 overal++; |
|
480 span++; |
|
481 |
|
482 if (overal === colspan) { |
|
483 splitCells.push({ start: start, span: span }); |
|
484 break mainLoop; |
|
485 } |
|
486 } |
|
487 |
|
488 splitCells.push({ start: start, span: span }); |
|
489 currentTable = mapping[currentColumn]; |
|
490 } |
|
491 |
|
492 colspan = splitCells[0].span; |
|
493 |
|
494 for (let i = 1; i < splitCells.length; i++) { |
|
495 that.mergedCellsPDF.push({ cell: [splitCells[i].start, row], colspan: splitCells[i].span, rowspan: rowspan, originalCell: col }); |
|
496 } |
|
497 } |
|
498 } |
|
499 |
|
500 for (let j = col; j < col + colspan; j++) { |
|
501 for (let k = row; k < row + rowspan; k++) { |
|
502 const code = j + ',' + k; |
|
503 |
|
504 if (j === col && k === row) { |
|
505 mergedMainCells[code] = { colspan: colspan, rowspan: rowspan, originalCell: cellDefinition.originalCell }; |
|
506 continue; |
|
507 } |
|
508 |
|
509 mergedSecondaryCells[code] = true; |
|
510 } |
|
511 } |
|
512 } |
|
513 } |
|
514 |
|
515 /** |
|
516 * Gets alternation index. |
|
517 */ |
|
518 getAlternationIndex(row, prefix) { |
|
519 const that = this; |
|
520 |
|
521 if (!that.style) { |
|
522 return ''; |
|
523 } |
|
524 |
|
525 const rowsDefinition = that.style.rows, |
|
526 alternationCount = rowsDefinition && rowsDefinition.alternationCount; |
|
527 |
|
528 if (alternationCount && |
|
529 (((rowsDefinition.alternationStart === undefined || row >= rowsDefinition.alternationStart) && |
|
530 (rowsDefinition.alternationEnd === undefined || row <= rowsDefinition.alternationEnd)) || |
|
531 rowsDefinition.alternationStart === rowsDefinition.alternationEnd)) { |
|
532 return prefix + (row % rowsDefinition.alternationCount); |
|
533 } |
|
534 |
|
535 return ''; |
|
536 } |
|
537 |
|
538 /** |
|
539 * Gets formatted numeric or date value (for use in HTML and PDF export). |
|
540 */ |
|
541 getFormattedValue(value, datafield) { |
|
542 const that = this, |
|
543 style = that.style; |
|
544 |
|
545 if (datafield && style && style.columns && |
|
546 style.columns[datafield] && style.columns[datafield].format) { |
|
547 if (typeof value === 'number') { |
|
548 return that.formatNumber(value, style.columns[datafield].format); |
|
549 } |
|
550 else if (value instanceof Date) { |
|
551 return that.formatDate(value, style.columns[datafield].format); |
|
552 } |
|
553 } |
|
554 else if (value instanceof Date) { |
|
555 return that.formatDate(value, 'd'); |
|
556 } |
|
557 |
|
558 return value; |
|
559 } |
|
560 |
|
561 /** |
|
562 * Exports to JSON. |
|
563 */ |
|
564 exportToJSON(data, fileName) { |
|
565 return this.downloadFile(JSON.stringify(data, this.datafields.concat('rows')), 'application/json', fileName); |
|
566 } |
|
567 |
|
568 /** |
|
569 * Exports to PDF. |
|
570 */ |
|
571 exportToPDF(data, fileName) { |
|
572 const that = this, |
|
573 datafields = that.datafields, |
|
574 startIndex = +that.exportHeader, |
|
575 groupsHandled = [], |
|
576 mergedMainCells = {}, |
|
577 mergedSecondaryCells = {}, |
|
578 mapping = {}, |
|
579 headerRows = startIndex ? that.complexHeader ? that.complexHeader.length : 1 : 0, |
|
580 docDefinition = { |
|
581 pageOrientation: that.pageOrientation || 'portrait' |
|
582 }; |
|
583 let header = [], content = [], tables; |
|
584 |
|
585 function createTableRow() { |
|
586 let tableRow = []; |
|
587 |
|
588 for (let i = 0; i < tables.length; i++) { |
|
589 tableRow.push([]); |
|
590 } |
|
591 |
|
592 return tableRow; |
|
593 } |
|
594 |
|
595 data = that.processGroupingInformation(data); |
|
596 that.data = data; |
|
597 that.headerRows = headerRows; |
|
598 that.getPDFStyle(); |
|
599 |
|
600 const styleInfo = that.styleInfo; |
|
601 |
|
602 tables = styleInfo ? that.wrapPDFColumns(docDefinition, mapping) : [{ body: header, datafields: datafields }]; |
|
603 |
|
604 if (startIndex) { |
|
605 header = that.getPDFHeader(datafields, tables, mapping); |
|
606 } |
|
607 |
|
608 that.getMergedCellsInfo(mergedMainCells, mergedSecondaryCells, mapping); |
|
609 |
|
610 mainLoop: |
|
611 for (let i = startIndex; i < data.length; i++) { |
|
612 const currentRecord = data[i]; |
|
613 let groupId = '', |
|
614 outlineLevel = 0; |
|
615 |
|
616 if (that.groupBy) { |
|
617 for (let k = 0; k < that.groupBy.length; k++) { |
|
618 const datafield = that.groupBy[k], |
|
619 currentGroup = currentRecord[datafield], |
|
620 currentGroupLabel = that.groups[datafield][currentGroup]; |
|
621 |
|
622 groupId += currentGroup; |
|
623 |
|
624 if (groupsHandled.indexOf(groupId) === -1) { |
|
625 that.createGroupHeaderRow(tables, { text: currentGroupLabel, style: ['row', 'cell', 'group'], marginLeft: outlineLevel * 7.5 }); |
|
626 groupsHandled.push(groupId); |
|
627 i--; |
|
628 continue mainLoop; |
|
629 } |
|
630 |
|
631 outlineLevel++; |
|
632 } |
|
633 } |
|
634 |
|
635 const tableRow = createTableRow(), |
|
636 row = i - startIndex; |
|
637 let n = that.getAlternationIndex(row, ''); |
|
638 |
|
639 for (let j = 0; j < datafields.length; j++) { |
|
640 const datafield = datafields[j], |
|
641 entry = { style: ['row', 'row' + row, 'cell', 'cell' + datafield] }, |
|
642 tableIndex = mapping[j] || 0; |
|
643 |
|
644 if (n !== undefined) { |
|
645 entry.style.splice(1, 0, 'rowN' + n); |
|
646 } |
|
647 |
|
648 if (that.mergedCellsPDF) { |
|
649 const cellCode = j + ',' + row, |
|
650 mergeInfo = mergedMainCells[cellCode]; |
|
651 |
|
652 if (mergeInfo) { |
|
653 entry.colSpan = mergeInfo.colspan; |
|
654 entry.rowSpan = mergeInfo.rowspan; |
|
655 |
|
656 if (mergeInfo.originalCell !== undefined) { |
|
657 entry.text = ''; |
|
658 entry.style[entry.style.length - 1] = 'cell' + datafields[mergeInfo.originalCell]; |
|
659 tableRow[tableIndex].push(entry); |
|
660 continue; |
|
661 } |
|
662 } |
|
663 else if (mergedSecondaryCells[cellCode]) { |
|
664 tableRow[tableIndex].push({}); |
|
665 continue; |
|
666 } |
|
667 } |
|
668 |
|
669 const value = that.getFormattedValue(currentRecord[datafield], datafield); |
|
670 |
|
671 entry.text = value.toString(); |
|
672 that.getUniqueStylePDF(entry, datafield, row); |
|
673 that.setIndentation(entry, { j: j, currentRecord: currentRecord, value: value, outlineLevel: outlineLevel }); |
|
674 tableRow[tableIndex].push(entry); |
|
675 } |
|
676 |
|
677 for (let k = 0; k < tables.length; k++) { |
|
678 tables[k].body.push(tableRow[k]); |
|
679 } |
|
680 } |
|
681 |
|
682 if (styleInfo) { |
|
683 for (let i = 0; i < tables.length; i++) { |
|
684 const body = tables[i].body; |
|
685 |
|
686 for (let j = headerRows - 1; j >= 0; j--) { |
|
687 body.unshift(header[i][j]); |
|
688 } |
|
689 |
|
690 content.push({ |
|
691 table: { |
|
692 headerRows: headerRows, |
|
693 widths: tables[i].widths, |
|
694 heights: function (row) { |
|
695 if (styleInfo.heights[row]) { |
|
696 return styleInfo.heights[row]; |
|
697 } |
|
698 |
|
699 if (styleInfo.defaultHeight) { |
|
700 return styleInfo.defaultHeight; |
|
701 } |
|
702 }, |
|
703 body: body |
|
704 }, |
|
705 pageBreak: 'after' |
|
706 }); |
|
707 } |
|
708 |
|
709 delete content[tables.length - 1].pageBreak; |
|
710 docDefinition.styles = styleInfo.styles; |
|
711 } |
|
712 else { |
|
713 const body = tables[0].body; |
|
714 |
|
715 for (let j = headerRows - 1; j >= 0; j--) { |
|
716 body.unshift(header[0][j]); |
|
717 } |
|
718 |
|
719 content = [{ table: { headerRows: headerRows, body: body } }]; |
|
720 docDefinition.styles = { header: { bold: true }, group: { bold: true } }; |
|
721 } |
|
722 |
|
723 docDefinition.content = content; |
|
724 pdfMake.createPdf(docDefinition).download(fileName); |
|
725 |
|
726 delete that.mergedCellsPDF; |
|
727 delete that.styleInfo; |
|
728 } |
|
729 |
|
730 /** |
|
731 * Gets the header content when exporting to PDF. |
|
732 */ |
|
733 getPDFStyle() { |
|
734 const that = this, |
|
735 style = that.style; |
|
736 |
|
737 if (!style) { |
|
738 return ''; |
|
739 } |
|
740 |
|
741 const sampleRecord = that.data[0], |
|
742 headerDefinition = style.header, |
|
743 columnsDefinition = style.columns, |
|
744 rowsDefinition = style.rows, |
|
745 styleInfo = { |
|
746 heights: [], |
|
747 widths: Array(that.datafields.length).fill('*'), |
|
748 styles: { |
|
749 header: {}, |
|
750 row: {}, |
|
751 cell: {}, |
|
752 group: { fillColor: '#FFFFFF', color: '#000000', bold: true } |
|
753 } |
|
754 }; |
|
755 |
|
756 that.styleInfo = styleInfo; |
|
757 |
|
758 function processStyleDefinition(definition, type) { |
|
759 if (!definition) { |
|
760 return; |
|
761 } |
|
762 |
|
763 for (let prop in definition) { |
|
764 if (!definition.hasOwnProperty(prop)) { |
|
765 continue; |
|
766 } |
|
767 |
|
768 if (sampleRecord[prop] === undefined) { |
|
769 if (prop === 'height' && type === 'header') { |
|
770 for (let i = 0; i < that.headerRows; i++) { |
|
771 styleInfo.heights[i] = (parseInt(definition[prop], 10) / that.headerRows) / 1.57; |
|
772 } |
|
773 } |
|
774 else { |
|
775 that.storePDFStyle({ prop: prop, value: definition[prop], toUpdate: type }); |
|
776 } |
|
777 } |
|
778 else { |
|
779 for (let columnProp in definition[prop]) { |
|
780 if (!isNaN(columnProp) || !definition[prop].hasOwnProperty(columnProp)) { |
|
781 continue; |
|
782 } |
|
783 |
|
784 const value = definition[prop][columnProp], |
|
785 index = that.datafields.indexOf(prop); |
|
786 |
|
787 if (columnProp === 'width' && styleInfo.widths[index] === '*') { |
|
788 styleInfo.widths[index] = parseFloat(value); |
|
789 } |
|
790 else { |
|
791 that.storePDFStyle({ prop: columnProp, value: value, toUpdate: type + prop }); |
|
792 } |
|
793 } |
|
794 } |
|
795 } |
|
796 } |
|
797 |
|
798 processStyleDefinition(headerDefinition, 'header'); |
|
799 processStyleDefinition(columnsDefinition, 'cell'); |
|
800 |
|
801 if (!rowsDefinition) { |
|
802 return; |
|
803 } |
|
804 |
|
805 for (let prop in rowsDefinition) { |
|
806 if (!rowsDefinition.hasOwnProperty(prop) || prop.indexOf('alt') !== -1) { |
|
807 continue; |
|
808 } |
|
809 |
|
810 const value = rowsDefinition[prop]; |
|
811 |
|
812 if (!isNaN(prop)) { |
|
813 for (let rowProp in value) { |
|
814 if (value.hasOwnProperty(rowProp)) { |
|
815 if (rowProp === 'height') { |
|
816 styleInfo.heights[parseFloat(prop) + that.headerRows] = parseFloat(value[rowProp]) / 1.57; |
|
817 } |
|
818 else { |
|
819 that.storePDFStyle({ prop: rowProp, value: value[rowProp], toUpdate: 'row' + prop }); |
|
820 } |
|
821 } |
|
822 } |
|
823 |
|
824 continue; |
|
825 } |
|
826 |
|
827 if (prop === 'height') { |
|
828 styleInfo.defaultHeight = parseFloat(value) / 1.57; |
|
829 } |
|
830 else { |
|
831 that.storePDFStyle({ prop: prop, value: value, toUpdate: 'row' }); |
|
832 } |
|
833 } |
|
834 |
|
835 if (!rowsDefinition.alternationCount) { |
|
836 return; |
|
837 } |
|
838 |
|
839 for (let i = 0; i < rowsDefinition.alternationCount; i++) { |
|
840 const styleN = {}; |
|
841 |
|
842 if (rowsDefinition[`alternationIndex${i}Color`]) { |
|
843 styleN.color = rowsDefinition[`alternationIndex${i}Color`]; |
|
844 } |
|
845 |
|
846 if (rowsDefinition[`alternationIndex${i}BackgroundColor`]) { |
|
847 styleN.fillColor = rowsDefinition[`alternationIndex${i}BackgroundColor`]; |
|
848 } |
|
849 |
|
850 styleInfo.styles['rowN' + i] = styleN; |
|
851 } |
|
852 } |
|
853 |
|
854 /** |
|
855 * Stores style in object to be applied to generated PDF. |
|
856 */ |
|
857 storePDFStyle(details) { |
|
858 const that = this; |
|
859 let objectToUpdate = that.styleInfo.styles[details.toUpdate]; |
|
860 |
|
861 if (!objectToUpdate) { |
|
862 objectToUpdate = {}; |
|
863 that.styleInfo.styles[details.toUpdate] = objectToUpdate; |
|
864 } |
|
865 |
|
866 let value = details.value; |
|
867 |
|
868 switch (details.prop) { |
|
869 case 'backgroundColor': |
|
870 objectToUpdate.fillColor = value; |
|
871 break; |
|
872 case 'color': |
|
873 objectToUpdate.color = value; |
|
874 break; |
|
875 case 'fontSize': |
|
876 objectToUpdate.fontSize = parseFloat(value); |
|
877 break; |
|
878 case 'fontStyle': |
|
879 if (value === 'italic') { |
|
880 objectToUpdate.italics = true; |
|
881 } |
|
882 |
|
883 break; |
|
884 case 'fontWeight': |
|
885 if (value === 'bold') { |
|
886 objectToUpdate.bold = true; |
|
887 } |
|
888 |
|
889 break; |
|
890 case 'textAlign': |
|
891 objectToUpdate.alignment = value; |
|
892 break; |
|
893 } |
|
894 } |
|
895 |
|
896 /** |
|
897 * Enables column wrapping when exporting to PDF. |
|
898 */ |
|
899 wrapPDFColumns(docDefinition, mapping) { |
|
900 const that = this, |
|
901 styleInfo = this.styleInfo, |
|
902 maxPerPage = docDefinition.pageOrientation === 'portrait' ? 775 : 1155, // maximum of 775px (portrait) or 1155px (landscape) per A4 page |
|
903 tables = []; |
|
904 let currentPage = 0; |
|
905 |
|
906 for (let i = 0; i < styleInfo.widths.length; i++) { |
|
907 let currentWidth = styleInfo.widths[i], |
|
908 numericWidth = currentWidth; |
|
909 |
|
910 if (currentWidth === '*') { |
|
911 numericWidth = 150; |
|
912 } |
|
913 else if (currentWidth >= maxPerPage) { |
|
914 numericWidth = maxPerPage |
|
915 currentWidth = '*'; |
|
916 } |
|
917 else { |
|
918 currentWidth /= 1.57; |
|
919 } |
|
920 |
|
921 if (tables[currentPage] === undefined) { |
|
922 const body = []; |
|
923 |
|
924 tables[currentPage] = { |
|
925 body: body, |
|
926 width: numericWidth, |
|
927 widths: [currentWidth], |
|
928 datafields: [that.datafields[i]] |
|
929 }; |
|
930 mapping[i] = currentPage; |
|
931 continue; |
|
932 } |
|
933 |
|
934 const table = tables[currentPage]; |
|
935 |
|
936 if (table.width + numericWidth > maxPerPage) { |
|
937 currentPage++; |
|
938 i--; |
|
939 continue; |
|
940 } |
|
941 |
|
942 mapping[i] = currentPage; |
|
943 table.width += numericWidth; |
|
944 table.widths.push(currentWidth); |
|
945 table.datafields.push(that.datafields[i]); |
|
946 } |
|
947 |
|
948 return tables; |
|
949 } |
|
950 |
|
951 /** |
|
952 * Gets the header content when exporting to PDF. |
|
953 */ |
|
954 getPDFHeader(datafields, tables, mapping) { |
|
955 const that = this, |
|
956 headerArray = [], |
|
957 headerRows = that.headerRows, |
|
958 headerStructure = that.complexHeader ? that.complexHeader : [Object.values(that.data[0])], |
|
959 headers = []; |
|
960 let result = []; |
|
961 |
|
962 for (let i = 0; i < headerRows; i++) { |
|
963 const row = headerStructure[i]; |
|
964 |
|
965 for (let k = 0; k < row.length; k++) { |
|
966 let tableIndex = mapping[k] || 0; |
|
967 |
|
968 if (!headers[tableIndex]) { |
|
969 headers[tableIndex] = []; |
|
970 } |
|
971 |
|
972 if (!headers[tableIndex][i]) { |
|
973 headers[tableIndex][i] = []; |
|
974 } |
|
975 |
|
976 headers[tableIndex][i].push(row[k]); |
|
977 } |
|
978 } |
|
979 |
|
980 function processHeader(header, result, table) { |
|
981 for (let j = 0; j < headerRows; j++) { |
|
982 const row = header[j]; |
|
983 const tableRow = []; |
|
984 |
|
985 for (let k = 0; k < row.length; k++) { |
|
986 const currentLabel = row[k]; |
|
987 let colspan = 1, rowspan = 1; |
|
988 |
|
989 if ((row[k - 1] && row[k - 1] === currentLabel) || |
|
990 (header[j - 1] && (header[j - 1][k] === currentLabel))) { |
|
991 tableRow.push({}); |
|
992 continue; |
|
993 } |
|
994 |
|
995 let iterator = k + 1; |
|
996 |
|
997 while (row[iterator] && row[iterator] === row[iterator - 1]) { |
|
998 colspan++; |
|
999 iterator++; |
|
1000 } |
|
1001 |
|
1002 iterator = j + 1; |
|
1003 |
|
1004 while (header[iterator] && header[iterator][k] === currentLabel) { |
|
1005 rowspan++; |
|
1006 iterator++; |
|
1007 } |
|
1008 |
|
1009 const datafield = j === headerRows - 1 || rowspan + j === headerRows ? |
|
1010 table.datafields[k] : null, |
|
1011 entry = { |
|
1012 text: currentLabel, colSpan: colspan, rowSpan: rowspan |
|
1013 }; |
|
1014 |
|
1015 if (!datafield) { |
|
1016 entry.alignment = 'center'; |
|
1017 entry.style = 'header'; |
|
1018 } |
|
1019 else { |
|
1020 entry.style = ['header', 'header' + datafield]; |
|
1021 } |
|
1022 |
|
1023 tableRow.push(entry); |
|
1024 } |
|
1025 |
|
1026 result.push(tableRow); |
|
1027 } |
|
1028 } |
|
1029 |
|
1030 for (let i = 0; i < tables.length; i++) { |
|
1031 result = []; |
|
1032 processHeader(headers[i], result, tables[i]); |
|
1033 headerArray.push(result); |
|
1034 } |
|
1035 |
|
1036 return headerArray; |
|
1037 } |
|
1038 |
|
1039 /** |
|
1040 * Creates group header rows when exporting to PDF. |
|
1041 */ |
|
1042 createGroupHeaderRow(tables, entryTemplate) { |
|
1043 for (let i = 0; i < tables.length; i++) { |
|
1044 const entry = Object.assign({}, entryTemplate), |
|
1045 colspan = tables[i].datafields.length, |
|
1046 tableRow = [entry]; |
|
1047 |
|
1048 entry.colSpan = colspan; |
|
1049 tableRow.length = colspan; |
|
1050 tableRow.fill({}, 1, colspan - 1); |
|
1051 |
|
1052 tables[i].body.push(tableRow); |
|
1053 } |
|
1054 } |
|
1055 |
|
1056 /** |
|
1057 * Gets unique cell style when exporting to PDF. |
|
1058 */ |
|
1059 getUniqueStylePDF(entry, datafield, row) { |
|
1060 const style = this.style; |
|
1061 |
|
1062 function toHex(background) { |
|
1063 const parts = /rgba\((\d+),(\d+),(\d+)\,(\d*.\d+|\d+)\)/gi.exec(background.replace(/\s/g, '')), |
|
1064 r = parseFloat(parts[1]).toString(16).toUpperCase(), |
|
1065 g = parseFloat(parts[2]).toString(16).toUpperCase(), |
|
1066 b = parseFloat(parts[3]).toString(16).toUpperCase(); |
|
1067 |
|
1068 return '#' + ('0').repeat(2 - r.length) + r + |
|
1069 ('0').repeat(2 - g.length) + g + |
|
1070 ('0').repeat(2 - b.length) + b; |
|
1071 } |
|
1072 |
|
1073 if (!style || !style.columns || !style.columns[datafield]) { |
|
1074 return; |
|
1075 } |
|
1076 |
|
1077 const uniqueStyle = style.columns[datafield][row]; |
|
1078 |
|
1079 if (!uniqueStyle) { |
|
1080 return; |
|
1081 } |
|
1082 |
|
1083 entry.fillColor = toHex(uniqueStyle.background); |
|
1084 entry.color = uniqueStyle.color.toLowerCase(); |
|
1085 } |
|
1086 |
|
1087 /** |
|
1088 * Sets the indentation of a PDF cell. |
|
1089 */ |
|
1090 setIndentation(entry, details) { |
|
1091 if (details.j !== 0) { |
|
1092 return; |
|
1093 } |
|
1094 |
|
1095 const that = this; |
|
1096 |
|
1097 if (that.actualHierarchy) { |
|
1098 const currentRecord = details.currentRecord; |
|
1099 |
|
1100 if (currentRecord._expanded !== undefined) { |
|
1101 entry.marginLeft = 25 * (currentRecord._level - 1); |
|
1102 entry.text = that.collapseChar + ' ' + details.value; |
|
1103 } |
|
1104 else { |
|
1105 entry.marginLeft = 25 * (currentRecord._level - 1) + 6; |
|
1106 } |
|
1107 } |
|
1108 else if (details.outlineLevel > 1) { |
|
1109 entry.marginLeft = (details.outlineLevel - 1) * 7.5; |
|
1110 } |
|
1111 } |
|
1112 |
|
1113 /** |
|
1114 * Exports to XLSX. |
|
1115 */ |
|
1116 exportToXLSX(data, fileName) { |
|
1117 const that = this; |
|
1118 let style = that.style; |
|
1119 |
|
1120 data = that.processGroupingInformation(data, true); |
|
1121 that.data = data; |
|
1122 that.getColumnsArray(); |
|
1123 |
|
1124 that.complexHeaderMergedCells = []; |
|
1125 |
|
1126 if (that.complexHeaderMergeInfo) { |
|
1127 for (let cell in that.complexHeaderMergeInfo) { |
|
1128 if (that.complexHeaderMergeInfo.hasOwnProperty(cell)) { |
|
1129 const currentEntry = that.complexHeaderMergeInfo[cell]; |
|
1130 |
|
1131 if (currentEntry.from[0] === currentEntry.to[0] && |
|
1132 currentEntry.from[1] === currentEntry.to[1]) { |
|
1133 continue; |
|
1134 } |
|
1135 |
|
1136 that.complexHeaderMergedCells.push({ |
|
1137 from: that.columnsArray[currentEntry.from[1]] + (currentEntry.from[0] + 1), |
|
1138 to: that.columnsArray[currentEntry.to[1]] + (currentEntry.to[0] + 1) |
|
1139 }); |
|
1140 } |
|
1141 } |
|
1142 } |
|
1143 |
|
1144 that.getConditionalFormatting(); |
|
1145 |
|
1146 if (!style) { |
|
1147 style = that.generateDefaultStyle(data); |
|
1148 } |
|
1149 |
|
1150 const sharedStrings = that.generateSharedStrings(data), |
|
1151 sharedStringsCollection = sharedStrings.collection, |
|
1152 sharedStringsXML = sharedStrings.xml, |
|
1153 stylesXML = that.generateStyles(style), |
|
1154 sheet1XML = that.groupBy ? that.generateSheet1WithGrouping(data, sharedStringsCollection) : |
|
1155 that.generateSheet1(data, sharedStringsCollection), |
|
1156 auxiliaryFiles = that.generateAuxiliaryFiles(), |
|
1157 |
|
1158 // eslint-disable-next-line |
|
1159 zip = new JSZip(), |
|
1160 _rels = zip.folder('_rels'), |
|
1161 docProps = zip.folder('docProps'), |
|
1162 xl = zip.folder('xl'), |
|
1163 xl_rels = xl.folder('_rels'), |
|
1164 theme = xl.folder('theme'), |
|
1165 worksheets = xl.folder('worksheets'); |
|
1166 |
|
1167 _rels.file('.rels', auxiliaryFiles._relsRels); |
|
1168 docProps.file('app.xml', auxiliaryFiles.docPropsAppXml); |
|
1169 docProps.file('core.xml', auxiliaryFiles.docPropsCoreXml); |
|
1170 xl_rels.file('workbook.xml.rels', auxiliaryFiles.xl_relsWorkbookXmlRels); |
|
1171 theme.file('theme1.xml', auxiliaryFiles.xlThemeTheme1Xml); |
|
1172 worksheets.file('sheet1.xml', sheet1XML); |
|
1173 xl.file('sharedStrings.xml', sharedStringsXML); |
|
1174 xl.file('styles.xml', stylesXML); |
|
1175 xl.file('workbook.xml', auxiliaryFiles.xlWorkbookXml); |
|
1176 zip.file('[Content_Types].xml', auxiliaryFiles.Content_TypesXml); |
|
1177 |
|
1178 zip.generateAsync({ |
|
1179 type: 'blob', |
|
1180 mimeType: |
|
1181 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' |
|
1182 }) |
|
1183 .then(function (content) { |
|
1184 return that.downloadFile(content, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', fileName); |
|
1185 }); |
|
1186 |
|
1187 delete that.conditionalFormattingXLSX; |
|
1188 delete that.complexHeaderMergeInfo; |
|
1189 delete that.defaultRowHeight; |
|
1190 delete that.rowHeight; |
|
1191 } |
|
1192 |
|
1193 /** |
|
1194 * Processes grouping information. |
|
1195 */ |
|
1196 processGroupingInformation(data, xlsx) { |
|
1197 const that = this; |
|
1198 |
|
1199 if (!that.groupBy) { |
|
1200 return data; |
|
1201 } |
|
1202 |
|
1203 let header; |
|
1204 |
|
1205 data = data.slice(0); |
|
1206 |
|
1207 if (that.exportHeader) { |
|
1208 if (xlsx && that.complexHeader) { |
|
1209 header = data.slice(0, that.complexHeader.length); |
|
1210 data.splice(0, that.complexHeader.length); |
|
1211 } |
|
1212 else { |
|
1213 header = [data[0]]; |
|
1214 data.splice(0, 1); |
|
1215 } |
|
1216 } |
|
1217 |
|
1218 if (data.length > 1) { |
|
1219 const getCompareFunction = function (a, knownDataType) { |
|
1220 // gets data type of column (not necessary if the Grid provides this information) |
|
1221 const dataType = knownDataType || typeof a; |
|
1222 let compareFunction; |
|
1223 |
|
1224 switch (dataType) { |
|
1225 case 'string': |
|
1226 compareFunction = new Intl.Collator().compare; |
|
1227 break; |
|
1228 case 'number': |
|
1229 compareFunction = function (a, b) { |
|
1230 return a - b; |
|
1231 }; |
|
1232 break; |
|
1233 case 'boolean': |
|
1234 case 'bool': |
|
1235 compareFunction = function (a, b) { |
|
1236 if (a === b) { |
|
1237 return 0; |
|
1238 } |
|
1239 else if (a === false) { |
|
1240 return -1; |
|
1241 } |
|
1242 else { |
|
1243 return 1; |
|
1244 } |
|
1245 }; |
|
1246 break; |
|
1247 case 'date': |
|
1248 case 'time': |
|
1249 case 'dateTime': |
|
1250 if (a instanceof Date) { |
|
1251 compareFunction = function (a, b) { |
|
1252 return a.compare(b); |
|
1253 }; |
|
1254 } |
|
1255 break; |
|
1256 case 'object': |
|
1257 if (a instanceof Date) { |
|
1258 compareFunction = function (a, b) { |
|
1259 return a.getTime() - b.getTime(); |
|
1260 }; |
|
1261 } |
|
1262 |
|
1263 |
|
1264 break; |
|
1265 } |
|
1266 |
|
1267 return compareFunction; |
|
1268 } |
|
1269 |
|
1270 const sortByMultipleColumns = function (dataSource, sortColumns, directions, customSortingCallback) { |
|
1271 if (!dataSource || !(Array.isArray(dataSource)) || dataSource.length === 0 || |
|
1272 !sortColumns || Array.isArray(sortColumns) && sortColumns.length === 0) { |
|
1273 return; |
|
1274 } |
|
1275 |
|
1276 if (typeof sortColumns === 'string') { |
|
1277 sortColumns = [sortColumns]; |
|
1278 } |
|
1279 |
|
1280 const directionCoefficients = [], |
|
1281 compareFunctions = []; |
|
1282 |
|
1283 if (directions === undefined) { |
|
1284 directions = []; |
|
1285 } |
|
1286 |
|
1287 for (let i = 0; i < sortColumns.length; i++) { |
|
1288 if (directions[i] === undefined || directions[i] === 'asc' || directions[i] === 'ascending') { |
|
1289 directionCoefficients[i] = 1; |
|
1290 } |
|
1291 else { |
|
1292 directionCoefficients[i] = -1; |
|
1293 } |
|
1294 |
|
1295 compareFunctions[i] = getCompareFunction(dataSource[0][sortColumns[i]]); |
|
1296 } |
|
1297 |
|
1298 if (customSortingCallback) { |
|
1299 customSortingCallback(dataSource, sortColumns, directions, compareFunctions); |
|
1300 return; |
|
1301 } |
|
1302 |
|
1303 dataSource.sort(function (a, b) { |
|
1304 for (let i = 0; i < sortColumns.length; i++) { |
|
1305 const result = compareFunctions[i](a[sortColumns[i]], b[sortColumns[i]]); |
|
1306 |
|
1307 if (result === 0) { |
|
1308 if (sortColumns[i + 1]) { |
|
1309 continue; |
|
1310 } |
|
1311 else if (a._index !== undefined) { |
|
1312 // makes sorting stable |
|
1313 return (a._index - b._index) * directionCoefficients[i]; |
|
1314 } |
|
1315 |
|
1316 return 0; |
|
1317 } |
|
1318 |
|
1319 return result * directionCoefficients[i]; |
|
1320 } |
|
1321 }); |
|
1322 } |
|
1323 |
|
1324 sortByMultipleColumns(data, that.groupBy); |
|
1325 } |
|
1326 |
|
1327 if (header) { |
|
1328 data = header.concat(data); |
|
1329 } |
|
1330 |
|
1331 that.getGroupLabels(data); |
|
1332 |
|
1333 return data; |
|
1334 } |
|
1335 |
|
1336 /** |
|
1337 * Exports to XML. |
|
1338 */ |
|
1339 exportToXML(data, fileName) { |
|
1340 const datafields = this.datafields.slice(0); |
|
1341 let xmlContent = '<?xml version="1.0" encoding="UTF-8" ?>\n<table>\n'; |
|
1342 |
|
1343 if (datafields.indexOf('rows') === -1) { |
|
1344 datafields.push('rows'); |
|
1345 } |
|
1346 |
|
1347 function recursion(records, indent) { |
|
1348 let content = ''; |
|
1349 |
|
1350 for (let i = 0; i < records.length; i++) { |
|
1351 const currentRecord = records[i]; |
|
1352 |
|
1353 content += indent + '<row>\n'; |
|
1354 |
|
1355 for (let j = 0; j < datafields.length; j++) { |
|
1356 const datafield = datafields[j]; |
|
1357 |
|
1358 if (datafield === 'rows') { |
|
1359 if (!currentRecord.rows) { |
|
1360 continue; |
|
1361 } |
|
1362 |
|
1363 content += `${indent} <rows>\n${recursion(currentRecord.rows, indent + ' ')}${indent} </rows>\n`; |
|
1364 continue; |
|
1365 } |
|
1366 |
|
1367 content += indent + ` <${datafield}>${currentRecord[datafield]}</${datafield}>\n`; |
|
1368 } |
|
1369 |
|
1370 content += indent + '</row>\n'; |
|
1371 } |
|
1372 |
|
1373 return content; |
|
1374 } |
|
1375 |
|
1376 xmlContent += recursion(data, ' ') + '</table>'; |
|
1377 |
|
1378 return this.downloadFile(xmlContent, 'application/xml', fileName); |
|
1379 } |
|
1380 |
|
1381 /** |
|
1382 * Formats a date. |
|
1383 */ |
|
1384 formatDate(value, format) { |
|
1385 var date = $.jqx.formatDate(value, format); |
|
1386 |
|
1387 return date; |
|
1388 } |
|
1389 |
|
1390 /** |
|
1391 * Formats a number. |
|
1392 */ |
|
1393 formatNumber(value, format) { |
|
1394 var number = $.jqx.formatNumber(value, format); |
|
1395 |
|
1396 return number; |
|
1397 } |
|
1398 |
|
1399 /** |
|
1400 * Generates auxiliary files necessary for XLSX. |
|
1401 */ |
|
1402 generateAuxiliaryFiles() { |
|
1403 // _rels\.rels |
|
1404 const _relsRels = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
|
1405 <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/></Relationships>`; |
|
1406 |
|
1407 // docProps\app.xml |
|
1408 const docPropsAppXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
|
1409 <Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"><Application>Microsoft Excel</Application><DocSecurity>0</DocSecurity><ScaleCrop>false</ScaleCrop><HeadingPairs><vt:vector size="2" baseType="variant"><vt:variant><vt:lpstr>Worksheets</vt:lpstr></vt:variant><vt:variant><vt:i4>1</vt:i4></vt:variant></vt:vector></HeadingPairs><TitlesOfParts><vt:vector size="1" baseType="lpstr"><vt:lpstr>Sheet1</vt:lpstr></vt:vector></TitlesOfParts><Company></Company><LinksUpToDate>false</LinksUpToDate><SharedDoc>false</SharedDoc><HyperlinksChanged>false</HyperlinksChanged><AppVersion>16.0300</AppVersion></Properties>`; |
|
1410 |
|
1411 // docProps\core.xml |
|
1412 const now = new Date().toISOString(), |
|
1413 docPropsCoreXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
|
1414 <cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><dc:creator>Smart HTML Elements</dc:creator><cp:lastModifiedBy>Smart HTML Elements</cp:lastModifiedBy><dcterms:created xsi:type="dcterms:W3CDTF">${now}</dcterms:created><dcterms:modified xsi:type="dcterms:W3CDTF">${now}</dcterms:modified></cp:coreProperties>`; |
|
1415 |
|
1416 // xl\_rels\workbook.xml.rels |
|
1417 const xl_relsWorkbookXmlRels = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
|
1418 <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="theme/theme1.xml"/><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/><Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" Target="sharedStrings.xml"/></Relationships>`; |
|
1419 |
|
1420 // xl\theme\theme1.xml |
|
1421 const xlThemeTheme1Xml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
|
1422 <a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office Theme"><a:themeElements><a:clrScheme name="Office"><a:dk1><a:sysClr val="windowText" lastClr="000000"/></a:dk1><a:lt1><a:sysClr val="window" lastClr="FFFFFF"/></a:lt1><a:dk2><a:srgbClr val="44546A"/></a:dk2><a:lt2><a:srgbClr val="E7E6E6"/></a:lt2><a:accent1><a:srgbClr val="4472C4"/></a:accent1><a:accent2><a:srgbClr val="ED7D31"/></a:accent2><a:accent3><a:srgbClr val="A5A5A5"/></a:accent3><a:accent4><a:srgbClr val="FFC000"/></a:accent4><a:accent5><a:srgbClr val="5B9BD5"/></a:accent5><a:accent6><a:srgbClr val="70AD47"/></a:accent6><a:hlink><a:srgbClr val="0563C1"/></a:hlink><a:folHlink><a:srgbClr val="954F72"/></a:folHlink></a:clrScheme><a:fontScheme name="Office"><a:majorFont><a:latin typeface="Calibri Light" panose="020F0302020204030204"/><a:ea typeface=""/><a:cs typeface=""/><a:font script="Jpan" typeface="游ゴシック Light"/><a:font script="Hang" typeface="맑은 고딕"/><a:font script="Hans" typeface="等线 Light"/><a:font script="Hant" typeface="新細明體"/><a:font script="Arab" typeface="Times New Roman"/><a:font script="Hebr" typeface="Times New Roman"/><a:font script="Thai" typeface="Tahoma"/><a:font script="Ethi" typeface="Nyala"/><a:font script="Beng" typeface="Vrinda"/><a:font script="Gujr" typeface="Shruti"/><a:font script="Khmr" typeface="MoolBoran"/><a:font script="Knda" typeface="Tunga"/><a:font script="Guru" typeface="Raavi"/><a:font script="Cans" typeface="Euphemia"/><a:font script="Cher" typeface="Plantagenet Cherokee"/><a:font script="Yiii" typeface="Microsoft Yi Baiti"/><a:font script="Tibt" typeface="Microsoft Himalaya"/><a:font script="Thaa" typeface="MV Boli"/><a:font script="Deva" typeface="Mangal"/><a:font script="Telu" typeface="Gautami"/><a:font script="Taml" typeface="Latha"/><a:font script="Syrc" typeface="Estrangelo Edessa"/><a:font script="Orya" typeface="Kalinga"/><a:font script="Mlym" typeface="Kartika"/><a:font script="Laoo" typeface="DokChampa"/><a:font script="Sinh" typeface="Iskoola Pota"/><a:font script="Mong" typeface="Mongolian Baiti"/><a:font script="Viet" typeface="Times New Roman"/><a:font script="Uigh" typeface="Microsoft Uighur"/><a:font script="Geor" typeface="Sylfaen"/><a:font script="Armn" typeface="Arial"/><a:font script="Bugi" typeface="Leelawadee UI"/><a:font script="Bopo" typeface="Microsoft JhengHei"/><a:font script="Java" typeface="Javanese Text"/><a:font script="Lisu" typeface="Segoe UI"/><a:font script="Mymr" typeface="Myanmar Text"/><a:font script="Nkoo" typeface="Ebrima"/><a:font script="Olck" typeface="Nirmala UI"/><a:font script="Osma" typeface="Ebrima"/><a:font script="Phag" typeface="Phagspa"/><a:font script="Syrn" typeface="Estrangelo Edessa"/><a:font script="Syrj" typeface="Estrangelo Edessa"/><a:font script="Syre" typeface="Estrangelo Edessa"/><a:font script="Sora" typeface="Nirmala UI"/><a:font script="Tale" typeface="Microsoft Tai Le"/><a:font script="Talu" typeface="Microsoft New Tai Lue"/><a:font script="Tfng" typeface="Ebrima"/></a:majorFont><a:minorFont><a:latin typeface="Calibri" panose="020F0502020204030204"/><a:ea typeface=""/><a:cs typeface=""/><a:font script="Jpan" typeface="游ゴシック"/><a:font script="Hang" typeface="맑은 고딕"/><a:font script="Hans" typeface="等线"/><a:font script="Hant" typeface="新細明體"/><a:font script="Arab" typeface="Arial"/><a:font script="Hebr" typeface="Arial"/><a:font script="Thai" typeface="Tahoma"/><a:font script="Ethi" typeface="Nyala"/><a:font script="Beng" typeface="Vrinda"/><a:font script="Gujr" typeface="Shruti"/><a:font script="Khmr" typeface="DaunPenh"/><a:font script="Knda" typeface="Tunga"/><a:font script="Guru" typeface="Raavi"/><a:font script="Cans" typeface="Euphemia"/><a:font script="Cher" typeface="Plantagenet Cherokee"/><a:font script="Yiii" typeface="Microsoft Yi Baiti"/><a:font script="Tibt" typeface="Microsoft Himalaya"/><a:font script="Thaa" typeface="MV Boli"/><a:font script="Deva" typeface="Mangal"/><a:font script="Telu" typeface="Gautami"/><a:font script="Taml" typeface="Latha"/><a:font script="Syrc" typeface="Estrangelo Edessa"/><a:font script="Orya" typeface="Kalinga"/><a:font script="Mlym" typeface="Kartika"/><a:font script="Laoo" typeface="DokChampa"/><a:font script="Sinh" typeface="Iskoola Pota"/><a:font script="Mong" typeface="Mongolian Baiti"/><a:font script="Viet" typeface="Arial"/><a:font script="Uigh" typeface="Microsoft Uighur"/><a:font script="Geor" typeface="Sylfaen"/><a:font script="Armn" typeface="Arial"/><a:font script="Bugi" typeface="Leelawadee UI"/><a:font script="Bopo" typeface="Microsoft JhengHei"/><a:font script="Java" typeface="Javanese Text"/><a:font script="Lisu" typeface="Segoe UI"/><a:font script="Mymr" typeface="Myanmar Text"/><a:font script="Nkoo" typeface="Ebrima"/><a:font script="Olck" typeface="Nirmala UI"/><a:font script="Osma" typeface="Ebrima"/><a:font script="Phag" typeface="Phagspa"/><a:font script="Syrn" typeface="Estrangelo Edessa"/><a:font script="Syrj" typeface="Estrangelo Edessa"/><a:font script="Syre" typeface="Estrangelo Edessa"/><a:font script="Sora" typeface="Nirmala UI"/><a:font script="Tale" typeface="Microsoft Tai Le"/><a:font script="Talu" typeface="Microsoft New Tai Lue"/><a:font script="Tfng" typeface="Ebrima"/></a:minorFont></a:fontScheme><a:fmtScheme name="Office"><a:fillStyleLst><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:lumMod val="110000"/><a:satMod val="105000"/><a:tint val="67000"/></a:schemeClr></a:gs><a:gs pos="50000"><a:schemeClr val="phClr"><a:lumMod val="105000"/><a:satMod val="103000"/><a:tint val="73000"/></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:lumMod val="105000"/><a:satMod val="109000"/><a:tint val="81000"/></a:schemeClr></a:gs></a:gsLst><a:lin ang="5400000" scaled="0"/></a:gradFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:satMod val="103000"/><a:lumMod val="102000"/><a:tint val="94000"/></a:schemeClr></a:gs><a:gs pos="50000"><a:schemeClr val="phClr"><a:satMod val="110000"/><a:lumMod val="100000"/><a:shade val="100000"/></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:lumMod val="99000"/><a:satMod val="120000"/><a:shade val="78000"/></a:schemeClr></a:gs></a:gsLst><a:lin ang="5400000" scaled="0"/></a:gradFill></a:fillStyleLst><a:lnStyleLst><a:ln w="6350" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/><a:miter lim="800000"/></a:ln><a:ln w="12700" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/><a:miter lim="800000"/></a:ln><a:ln w="19050" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/><a:miter lim="800000"/></a:ln></a:lnStyleLst><a:effectStyleLst><a:effectStyle><a:effectLst/></a:effectStyle><a:effectStyle><a:effectLst/></a:effectStyle><a:effectStyle><a:effectLst><a:outerShdw blurRad="57150" dist="19050" dir="5400000" algn="ctr" rotWithShape="0"><a:srgbClr val="000000"><a:alpha val="63000"/></a:srgbClr></a:outerShdw></a:effectLst></a:effectStyle></a:effectStyleLst><a:bgFillStyleLst><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:solidFill><a:schemeClr val="phClr"><a:tint val="95000"/><a:satMod val="170000"/></a:schemeClr></a:solidFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="93000"/><a:satMod val="150000"/><a:shade val="98000"/><a:lumMod val="102000"/></a:schemeClr></a:gs><a:gs pos="50000"><a:schemeClr val="phClr"><a:tint val="98000"/><a:satMod val="130000"/><a:shade val="90000"/><a:lumMod val="103000"/></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="63000"/><a:satMod val="120000"/></a:schemeClr></a:gs></a:gsLst><a:lin ang="5400000" scaled="0"/></a:gradFill></a:bgFillStyleLst></a:fmtScheme></a:themeElements><a:objectDefaults/><a:extraClrSchemeLst/><a:extLst><a:ext uri="{05A4C25C-085E-4340-85A3-A5531E510DB2}"><thm15:themeFamily xmlns:thm15="http://schemas.microsoft.com/office/thememl/2012/main" name="Office Theme" id="{62F939B6-93AF-4DB8-9C6B-D6C7DFDC589F}" vid="{4A3C46E8-61CC-4603-A589-7422A47A8E4A}"/></a:ext></a:extLst></a:theme>`; |
|
1423 |
|
1424 // xl\workbook.xml |
|
1425 const xlWorkbookXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
|
1426 <workbook 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="x15 xr xr6 xr10 xr2" xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main" xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision" xmlns:xr6="http://schemas.microsoft.com/office/spreadsheetml/2016/revision6" xmlns:xr10="http://schemas.microsoft.com/office/spreadsheetml/2016/revision10" xmlns:xr2="http://schemas.microsoft.com/office/spreadsheetml/2015/revision2"><fileVersion appName="xl" lastEdited="7" lowestEdited="7" rupBuild="20325"/><workbookPr defaultThemeVersion="166925"/><mc:AlternateContent xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"><mc:Choice Requires="x15"><x15ac:absPath url="C:\Users\jqwidgets\Desktop\" xmlns:x15ac="http://schemas.microsoft.com/office/spreadsheetml/2010/11/ac"/></mc:Choice></mc:AlternateContent><xr:revisionPtr revIDLastSave="0" documentId="13_ncr:1_{0DEDCB6D-5403-4CD8-AAA5-59B6D238A8B6}" xr6:coauthVersionLast="34" xr6:coauthVersionMax="34" xr10:uidLastSave="{00000000-0000-0000-0000-000000000000}"/><bookViews><workbookView xWindow="0" yWindow="0" windowWidth="19200" windowHeight="6950" xr2:uid="{0CB664E6-3800-4A88-B158-B46A682E7484}"/></bookViews><sheets><sheet name="Sheet1" sheetId="1" r:id="rId1"/></sheets><calcPr calcId="179021"/><extLst><ext uri="{140A7094-0E35-4892-8432-C4D2E57EDEB5}" xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"><x15:workbookPr chartTrackingRefBase="1"/></ext></extLst></workbook>`; |
|
1427 |
|
1428 // [Content_Types].xml |
|
1429 const Content_TypesXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
|
1430 <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="bin" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings"/><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/><Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/><Override PartName="/xl/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/><Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/><Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/></Types>`; |
|
1431 |
|
1432 return { |
|
1433 _relsRels: _relsRels, |
|
1434 docPropsAppXml: docPropsAppXml, |
|
1435 docPropsCoreXml: docPropsCoreXml, |
|
1436 xl_relsWorkbookXmlRels: xl_relsWorkbookXmlRels, |
|
1437 xlThemeTheme1Xml: xlThemeTheme1Xml, |
|
1438 xlWorkbookXml: xlWorkbookXml, |
|
1439 Content_TypesXml: Content_TypesXml |
|
1440 }; |
|
1441 } |
|
1442 |
|
1443 /** |
|
1444 * Generates default style object (for use in XLSX export). |
|
1445 */ |
|
1446 generateDefaultStyle(data) { |
|
1447 const that = this, |
|
1448 defaultStyle = {}, |
|
1449 datafields = that.datafields, |
|
1450 firstRecord = that.complexHeader ? data[that.complexHeader.length] : data[+that.exportHeader]; |
|
1451 |
|
1452 if (!firstRecord) { |
|
1453 return defaultStyle; |
|
1454 } |
|
1455 |
|
1456 for (let i = 0; i < datafields.length; i++) { |
|
1457 const sampleValue = firstRecord[datafields[i]]; |
|
1458 |
|
1459 if (sampleValue instanceof Date) { |
|
1460 if (!defaultStyle.columns) { |
|
1461 defaultStyle.columns = []; |
|
1462 } |
|
1463 |
|
1464 defaultStyle.columns[datafields[i]] = { format: 'd' }; |
|
1465 } |
|
1466 } |
|
1467 |
|
1468 return defaultStyle; |
|
1469 } |
|
1470 |
|
1471 /** |
|
1472 * Generates group row. |
|
1473 */ |
|
1474 generateGroupRow(details) { |
|
1475 const rowNumber = details.rowNumber, |
|
1476 from = 'A' + rowNumber, |
|
1477 recordXML = ` <row r="${rowNumber}" outlineLevel="${details.outlineLevel}" spans="1:${details.numberOfColumns}"${this.getCustomRowHeight(rowNumber - 1)} x14ac:dyDescent="0.45"> |
|
1478 <c r="${from}" t="s" s="0"> |
|
1479 <v>${details.sharedStringIndex}</v> |
|
1480 </c> |
|
1481 </row>\n`; |
|
1482 |
|
1483 details.mergedCells.push({ from: from, to: this.columnsArray[details.numberOfColumns - 1] + rowNumber }); |
|
1484 |
|
1485 return recordXML; |
|
1486 } |
|
1487 |
|
1488 /** |
|
1489 * Generates sharedStrings.xml. |
|
1490 */ |
|
1491 generateSharedStrings(data) { |
|
1492 const that = this, |
|
1493 datafields = that.datafields, |
|
1494 collection = []; |
|
1495 let xml = '', |
|
1496 count = 0, |
|
1497 uniqueCount = 0; |
|
1498 |
|
1499 function addSharedString(currentValue) { |
|
1500 count++; |
|
1501 |
|
1502 if (collection.indexOf(currentValue) === -1) { |
|
1503 uniqueCount++; |
|
1504 collection.push(currentValue); |
|
1505 |
|
1506 currentValue = currentValue.replace(/&(?!amp;)/g, '&'); |
|
1507 currentValue = currentValue.replace(/'/g, '''); |
|
1508 currentValue = currentValue.replace(/"/g, '"'); |
|
1509 currentValue = currentValue.replace(/>/g, '>'); |
|
1510 currentValue = currentValue.replace(/</g, '<'); |
|
1511 |
|
1512 xml += `<si><t>${currentValue}</t></si>`; |
|
1513 } |
|
1514 } |
|
1515 |
|
1516 for (let i = 0; i < data.length; i++) { |
|
1517 const currentRecord = data[i]; |
|
1518 |
|
1519 for (let j = 0; j < datafields.length; j++) { |
|
1520 let currentValue = currentRecord[datafields[j]]; |
|
1521 |
|
1522 if (typeof currentValue !== 'string') { |
|
1523 continue; |
|
1524 } |
|
1525 |
|
1526 addSharedString(currentValue); |
|
1527 } |
|
1528 } |
|
1529 |
|
1530 if (that.groupLabels) { |
|
1531 for (let i = 0; i < that.groupLabels.length; i++) { |
|
1532 addSharedString(that.groupLabels[i]); |
|
1533 } |
|
1534 } |
|
1535 |
|
1536 xml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
|
1537 <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="${count}" uniqueCount="${uniqueCount}">${xml}</sst>`; |
|
1538 |
|
1539 return { collection: collection, xml: xml }; |
|
1540 } |
|
1541 |
|
1542 /** |
|
1543 * Generates sheet1.xml. |
|
1544 */ |
|
1545 generateSheet1(data, sharedStrings) { |
|
1546 const that = this, |
|
1547 numberOfColumns = that.columnsArray.length, |
|
1548 numberOfRows = data.length, |
|
1549 dimensionEnd = that.columnsArray[numberOfColumns - 1] + numberOfRows, |
|
1550 datafields = that.datafields, |
|
1551 autoFilter = that.getFilters(), |
|
1552 mergedCells = [].concat(that.complexHeaderMergedCells); |
|
1553 |
|
1554 let xmlContent = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
|
1555 <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 xr xr2 xr3" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision" xmlns:xr2="http://schemas.microsoft.com/office/spreadsheetml/2015/revision2" xmlns:xr3="http://schemas.microsoft.com/office/spreadsheetml/2016/revision3" xr:uid="{7F25248B-C640-4C64-AD47-C0EA0E5D90D0}"> |
|
1556 <sheetPr filterMode="${autoFilter !== ''}" /> |
|
1557 <dimension ref="A1:${dimensionEnd}" /> |
|
1558 <sheetViews> |
|
1559 <sheetView tabSelected="1" workbookViewId="0" /> |
|
1560 </sheetViews> |
|
1561 <sheetFormatPr defaultRowHeight="14.5" x14ac:dyDescent="0.35" />${that.getCustomColumnWidths()} |
|
1562 <sheetData>\n`; |
|
1563 |
|
1564 function r(col, row) { |
|
1565 return that.columnsArray[col] + row; |
|
1566 } |
|
1567 |
|
1568 for (let i = 0; i <= data.length; i++) { |
|
1569 const currentRecord = data[i], |
|
1570 rowNumber = i + 1; |
|
1571 let collapsed = ''; |
|
1572 |
|
1573 if (that.actualHierarchy) { |
|
1574 const previousRecord = data[i - 1]; |
|
1575 |
|
1576 if (previousRecord && previousRecord._collapsed && |
|
1577 (!currentRecord || previousRecord._level > currentRecord._level)) { |
|
1578 collapsed = ' collapsed="true"'; |
|
1579 } |
|
1580 } |
|
1581 |
|
1582 if (i === data.length) { |
|
1583 if (collapsed) { |
|
1584 xmlContent += ` <row r="${rowNumber}" outlineLevel="${Math.max(data[i - 1]._level - 2, 0)}" hidden="false" collapsed="true" />\n`; |
|
1585 } |
|
1586 |
|
1587 break; |
|
1588 } |
|
1589 |
|
1590 let recordXML = ` <row r="${rowNumber}"${that.getOutlineLevel(currentRecord)} hidden="${currentRecord._hidden || currentRecord._collapsed || false}"${collapsed} spans="1:${numberOfColumns}"${that.getCustomRowHeight(rowNumber - 1)} x14ac:dyDescent="0.45">\n`; |
|
1591 |
|
1592 for (let j = 0; j < datafields.length; j++) { |
|
1593 const s = that.getXLSXCellStyle(r(j, rowNumber)); |
|
1594 |
|
1595 recordXML += that.getActualCellData(currentRecord[datafields[j]], { r: r(j, rowNumber), s: s }, sharedStrings); |
|
1596 } |
|
1597 |
|
1598 recordXML += ' </row>\n'; |
|
1599 xmlContent += recordXML; |
|
1600 } |
|
1601 |
|
1602 xmlContent += ` </sheetData>${that.conditionalFormattingXLSX.conditions}${autoFilter}${that.getMergedCells(mergedCells)} |
|
1603 <pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3" /> |
|
1604 <pageSetup paperSize="9" orientation="portrait" r:id="rId1" /> |
|
1605 </worksheet>`; |
|
1606 |
|
1607 return xmlContent; |
|
1608 } |
|
1609 |
|
1610 /** |
|
1611 * Generates sheet1.xml with grouping. |
|
1612 */ |
|
1613 generateSheet1WithGrouping(data, sharedStrings) { |
|
1614 const that = this, |
|
1615 numberOfColumns = that.columnsArray.length, |
|
1616 numberOfRows = data.length, |
|
1617 dimensionEnd = that.columnsArray[numberOfColumns - 1] + numberOfRows, |
|
1618 datafields = that.datafields, |
|
1619 mergedCells = [].concat(that.complexHeaderMergedCells); |
|
1620 |
|
1621 let xmlContent = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
|
1622 <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 xr xr2 xr3" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision" xmlns:xr2="http://schemas.microsoft.com/office/spreadsheetml/2015/revision2" xmlns:xr3="http://schemas.microsoft.com/office/spreadsheetml/2016/revision3" xr:uid="{7F25248B-C640-4C64-AD47-C0EA0E5D90D0}"> |
|
1623 <dimension ref="A1:${dimensionEnd}" /> |
|
1624 <sheetViews> |
|
1625 <sheetView tabSelected="1" workbookViewId="0" /> |
|
1626 </sheetViews> |
|
1627 <sheetFormatPr defaultRowHeight="14.5" x14ac:dyDescent="0.35" />${that.getCustomColumnWidths()} |
|
1628 <sheetData>\n`, |
|
1629 rowNumberCorrection = 0, |
|
1630 groupsHandled = []; |
|
1631 |
|
1632 function r(col, row) { |
|
1633 return that.columnsArray[col] + row; |
|
1634 } |
|
1635 |
|
1636 mainLoop: |
|
1637 for (let i = 0; i < data.length; i++) { |
|
1638 const currentRecord = data[i], |
|
1639 rowNumber = i + 1 + rowNumberCorrection; |
|
1640 let outlineLevel = 0, |
|
1641 outlineXML = ''; |
|
1642 |
|
1643 if (!that.exportHeader || |
|
1644 (!that.complexHeader && i !== 0) || |
|
1645 (that.complexHeader && i >= that.complexHeader.length)) { |
|
1646 let groupId = ''; |
|
1647 |
|
1648 for (let k = 0; k < that.groupBy.length; k++) { |
|
1649 const datafield = that.groupBy[k], |
|
1650 currentGroup = currentRecord[datafield], |
|
1651 currentGroupLabel = that.groups[datafield][currentGroup]; |
|
1652 |
|
1653 groupId += currentGroup; |
|
1654 |
|
1655 if (groupsHandled.indexOf(groupId) === -1) { |
|
1656 let sharedStringIndex = sharedStrings.indexOf(currentGroupLabel); |
|
1657 |
|
1658 xmlContent += that.generateGroupRow({ |
|
1659 rowNumber: rowNumber, |
|
1660 outlineLevel: outlineLevel, |
|
1661 numberOfColumns: numberOfColumns, |
|
1662 sharedStringIndex: sharedStringIndex, |
|
1663 mergedCells: mergedCells |
|
1664 }); |
|
1665 groupsHandled.push(groupId); |
|
1666 i--; |
|
1667 rowNumberCorrection++; |
|
1668 continue mainLoop; |
|
1669 } |
|
1670 |
|
1671 outlineLevel++; |
|
1672 } |
|
1673 |
|
1674 outlineXML = ` outlineLevel="${outlineLevel}"`; |
|
1675 } |
|
1676 |
|
1677 let recordXML = ` <row r="${rowNumber}"${outlineXML} spans="1:${numberOfColumns}"${that.getCustomRowHeight(rowNumber - 1)} x14ac:dyDescent="0.45">\n`; |
|
1678 |
|
1679 for (let j = 0; j < datafields.length; j++) { |
|
1680 const s = that.getXLSXCellStyle(r(j, i + 1)); |
|
1681 |
|
1682 recordXML += that.getActualCellData(currentRecord[datafields[j]], { r: r(j, rowNumber), s: s }, sharedStrings); |
|
1683 } |
|
1684 |
|
1685 recordXML += ' </row>\n'; |
|
1686 xmlContent += recordXML; |
|
1687 } |
|
1688 |
|
1689 xmlContent += ` </sheetData>${that.getMergedCells(mergedCells)} |
|
1690 <pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3" /> |
|
1691 <pageSetup paperSize="9" orientation="portrait" r:id="rId1" /> |
|
1692 </worksheet>`; |
|
1693 |
|
1694 return xmlContent; |
|
1695 } |
|
1696 |
|
1697 /** |
|
1698 * Gets actual spreadsheet cell data. |
|
1699 */ |
|
1700 getActualCellData(currentValue, details, sharedStrings) { |
|
1701 const r = details.r, |
|
1702 s = details.s || ' s="0"'; |
|
1703 |
|
1704 if (typeof currentValue === 'string') { |
|
1705 return ` <c r="${r}" t="s"${s}> |
|
1706 <v>${sharedStrings.indexOf(currentValue)}</v> |
|
1707 </c>\n`; |
|
1708 } |
|
1709 |
|
1710 if (typeof currentValue === 'boolean') { |
|
1711 return ` <c r="${r}" t="b"${s}> |
|
1712 <v>${+currentValue}</v> |
|
1713 </c>\n`; |
|
1714 } |
|
1715 |
|
1716 if (currentValue instanceof Date) { |
|
1717 const excelDate = (currentValue.getTime() + this.timeBetween1900And1970) / 86400000 + 2; |
|
1718 |
|
1719 return ` <c r="${r}"${s}> |
|
1720 <v>${excelDate}</v> |
|
1721 </c>\n`; |
|
1722 } |
|
1723 |
|
1724 // numeric cells |
|
1725 return ` <c r="${r}"${s}> |
|
1726 <v>${currentValue}</v> |
|
1727 </c>\n`; |
|
1728 } |
|
1729 |
|
1730 /** |
|
1731 * Gets column labels. |
|
1732 */ |
|
1733 getColumnsArray() { |
|
1734 const that = this, |
|
1735 numberOfColumns = that.datafields.length, |
|
1736 columnsCollection = []; |
|
1737 |
|
1738 function getIterator(i) { |
|
1739 if (i < 26) { |
|
1740 return ''; |
|
1741 } |
|
1742 |
|
1743 return String.fromCharCode(64 + Math.floor(i / 26)); |
|
1744 } |
|
1745 |
|
1746 for (let i = 0; i < numberOfColumns; i++) { |
|
1747 columnsCollection.push(getIterator(i) + String.fromCharCode(65 + (i < 26 ? i : i % 26))); |
|
1748 } |
|
1749 |
|
1750 that.columnsArray = columnsCollection; |
|
1751 } |
|
1752 |
|
1753 /** |
|
1754 * Gets column style. |
|
1755 */ |
|
1756 getColumnStyle() { |
|
1757 const that = this, |
|
1758 style = that.style; |
|
1759 |
|
1760 if (!style) { |
|
1761 return ` .header { border: 1px solid black; padding: 5px; } |
|
1762 .column { border: 1px solid black; padding: 5px; } |
|
1763 .group { background-color: #FFFFFF; color: #000000; font-weight: bold; }`; |
|
1764 } |
|
1765 |
|
1766 const styles = { |
|
1767 header: 'border: 1px solid black; padding: 5px; ', |
|
1768 column: 'white-space: nowrap; overflow: hidden; border: 1px solid black; padding: 5px; ', |
|
1769 group: 'background-color: #FFFFFF; color: #000000; font-weight: bold; ' |
|
1770 }, |
|
1771 sampleRecord = that.data[0]; |
|
1772 let generatedStyle = ''; |
|
1773 |
|
1774 const headerDefinition = style.header || {}; |
|
1775 |
|
1776 for (let prop in headerDefinition) { |
|
1777 if (!headerDefinition.hasOwnProperty(prop)) { |
|
1778 continue; |
|
1779 } |
|
1780 |
|
1781 const value = headerDefinition[prop]; |
|
1782 |
|
1783 if (sampleRecord[prop]) { |
|
1784 if (!styles['header' + prop]) { |
|
1785 styles['header' + prop] = ''; |
|
1786 } |
|
1787 |
|
1788 for (let columnProp in value) { |
|
1789 if (value.hasOwnProperty(columnProp)) { |
|
1790 const css = window.jqxToDash(columnProp) + ': ' + value[columnProp] + '; '; |
|
1791 |
|
1792 styles['header' + prop] += css; |
|
1793 |
|
1794 if (columnProp === 'width') { |
|
1795 if (!styles['column' + prop]) { |
|
1796 styles['column' + prop] = ''; |
|
1797 } |
|
1798 |
|
1799 styles['column' + prop] += css; |
|
1800 } |
|
1801 } |
|
1802 } |
|
1803 |
|
1804 continue; |
|
1805 } |
|
1806 |
|
1807 if (prop === 'height' && that.complexHeader) { |
|
1808 styles.header += 'height: ' + parseInt(headerDefinition[prop], 10) / that.complexHeader.length + 'px; '; |
|
1809 } |
|
1810 else { |
|
1811 styles.header += window.jqxToDash(prop) + ': ' + headerDefinition[prop] + '; '; |
|
1812 } |
|
1813 } |
|
1814 |
|
1815 const columnsDefinition = style.columns || {}; |
|
1816 |
|
1817 for (let prop in columnsDefinition) { |
|
1818 if (!columnsDefinition.hasOwnProperty(prop)) { |
|
1819 continue; |
|
1820 } |
|
1821 |
|
1822 const value = columnsDefinition[prop]; |
|
1823 |
|
1824 if (sampleRecord[prop]) { |
|
1825 if (!styles['column' + prop]) { |
|
1826 styles['column' + prop] = ''; |
|
1827 } |
|
1828 |
|
1829 for (let columnProp in value) { |
|
1830 if (isNaN(columnProp) && value.hasOwnProperty(columnProp) && columnProp !== 'format') { |
|
1831 styles['column' + prop] += window.jqxToDash(columnProp) + ': ' + value[columnProp] + '; '; |
|
1832 } |
|
1833 } |
|
1834 |
|
1835 continue; |
|
1836 } |
|
1837 |
|
1838 styles.column += window.jqxToDash(prop) + ': ' + value + '; '; |
|
1839 } |
|
1840 |
|
1841 for (let prop in styles) { |
|
1842 if (styles.hasOwnProperty(prop)) { |
|
1843 generatedStyle += ` .${prop} { ${styles[prop]}}\n`; |
|
1844 } |
|
1845 } |
|
1846 |
|
1847 return generatedStyle; |
|
1848 } |
|
1849 |
|
1850 /** |
|
1851 * Gets custom column widths. |
|
1852 */ |
|
1853 getCustomColumnWidths() { |
|
1854 const that = this; |
|
1855 |
|
1856 if (!that.style || !that.columnWidth || that.columnWidth.length === 0) { |
|
1857 return ''; |
|
1858 } |
|
1859 |
|
1860 let xml = '\n <cols>\n'; |
|
1861 |
|
1862 for (let i = 0; i < that.columnWidth.length; i++) { |
|
1863 let width = that.columnWidth[i]; |
|
1864 |
|
1865 if (width !== undefined) { |
|
1866 width = Math.round(parseFloat(width)) / 11; |
|
1867 xml += ` <col min="${i + 1}" max="${i + 1}" width="${width}" customWidth="1" />\n`; |
|
1868 } |
|
1869 } |
|
1870 |
|
1871 xml += ' </cols>'; |
|
1872 |
|
1873 return xml; |
|
1874 } |
|
1875 |
|
1876 /** |
|
1877 * Returns customFilter tag. |
|
1878 */ |
|
1879 getCustomFilter(value, condition) { |
|
1880 let operator = 'equal', |
|
1881 val; |
|
1882 |
|
1883 if (value instanceof Date) { |
|
1884 value = (value.getTime() + this.timeBetween1900And1970) / 86400000 + 2; |
|
1885 } |
|
1886 |
|
1887 condition = condition.toUpperCase(); |
|
1888 |
|
1889 switch (condition) { |
|
1890 case 'EMPTY': |
|
1891 val = ''; |
|
1892 break; |
|
1893 case 'NOT_EMPTY': |
|
1894 val = ''; |
|
1895 operator = 'notEqual'; |
|
1896 break; |
|
1897 case 'CONTAINS': |
|
1898 case 'CONTAINS_CASE_SENSITIVE': |
|
1899 val = `*${value}*`; |
|
1900 break; |
|
1901 case 'DOES_NOT_CONTAIN': |
|
1902 case 'DOES_NOT_CONTAIN_CASE_SENSITIVE': |
|
1903 val = `*${value}*`; |
|
1904 operator = 'notEqual'; |
|
1905 break; |
|
1906 case 'STARTS_WITH': |
|
1907 case 'STARTS_WITH_CASE_SENSITIVE': |
|
1908 val = `${value}*`; |
|
1909 break; |
|
1910 case 'ENDS_WITH': |
|
1911 case 'ENDS_WITH_CASE_SENSITIVE': |
|
1912 val = `*${value}`; |
|
1913 break; |
|
1914 case 'EQUAL': |
|
1915 case 'EQUAL_CASE_SENSITIVE': |
|
1916 val = value; |
|
1917 break; |
|
1918 case 'NULL': |
|
1919 val = null; |
|
1920 break; |
|
1921 case 'NOT_NULL': |
|
1922 val = null; |
|
1923 operator = 'notEqual'; |
|
1924 break; |
|
1925 case 'NOT_EQUAL': |
|
1926 val = value; |
|
1927 operator = 'notEqual'; |
|
1928 break; |
|
1929 case 'LESS_THAN': |
|
1930 val = value; |
|
1931 operator = 'lessThan'; |
|
1932 break; |
|
1933 case 'LESS_THAN_OR_EQUAL': |
|
1934 val = value; |
|
1935 operator = 'lessThanOrEqual'; |
|
1936 break; |
|
1937 case 'GREATER_THAN': |
|
1938 val = value; |
|
1939 operator = 'greaterThan'; |
|
1940 break; |
|
1941 case 'GREATER_THAN_OR_EQUAL': |
|
1942 val = value; |
|
1943 operator = 'greaterThanOrEqual'; |
|
1944 break; |
|
1945 } |
|
1946 |
|
1947 return ` <customFilter val="${val}" operator="${operator}"/>\n`; |
|
1948 } |
|
1949 |
|
1950 /** |
|
1951 * Gets custom row height. |
|
1952 */ |
|
1953 getCustomRowHeight(row) { |
|
1954 const that = this; |
|
1955 |
|
1956 if (that.style) { |
|
1957 return that.rowHeight[row] || that.defaultRowHeight || ''; |
|
1958 } |
|
1959 |
|
1960 return ''; |
|
1961 } |
|
1962 |
|
1963 /** |
|
1964 * Gets datafields. |
|
1965 */ |
|
1966 getDatafields(data) { |
|
1967 const that = this, |
|
1968 sampleRecord = data[0], |
|
1969 datafields = []; |
|
1970 |
|
1971 for (let prop in sampleRecord) { |
|
1972 if (sampleRecord.hasOwnProperty(prop) && prop.charAt(0) !== '_') { |
|
1973 datafields.push(prop); |
|
1974 } |
|
1975 } |
|
1976 |
|
1977 that.datafields = datafields; |
|
1978 } |
|
1979 |
|
1980 /** |
|
1981 * Returns autoFilter XML. |
|
1982 */ |
|
1983 getFilters() { |
|
1984 const that = this, |
|
1985 filterBy = that.filterBy; |
|
1986 |
|
1987 if (!filterBy) { |
|
1988 return ''; |
|
1989 } |
|
1990 |
|
1991 let xml = ''; |
|
1992 |
|
1993 for (let datafield in filterBy) { |
|
1994 if (filterBy.hasOwnProperty(datafield)) { |
|
1995 const colId = that.datafields.indexOf(datafield); |
|
1996 |
|
1997 if (colId === -1) { |
|
1998 continue; |
|
1999 } |
|
2000 |
|
2001 const filterDetails = filterBy[datafield], |
|
2002 filters = filterDetails.filters; |
|
2003 |
|
2004 xml += ` <filterColumn colId="${colId}"> |
|
2005 <customFilters and="${!filterDetails.operator}">\n`; |
|
2006 |
|
2007 for (let i = 0; i < filters.length; i++) { |
|
2008 xml += that.getCustomFilter(filters[i].value, filters[i].condition); |
|
2009 } |
|
2010 |
|
2011 xml += ` </customFilters> |
|
2012 </filterColumn>`; |
|
2013 } |
|
2014 } |
|
2015 |
|
2016 if (!xml) { |
|
2017 return ''; |
|
2018 } |
|
2019 |
|
2020 xml = `\n <autoFilter ref="A1:${that.columnsArray[that.columnsArray.length - 1] + that.data.length}">\n${xml}\n </autoFilter>`; |
|
2021 return xml; |
|
2022 } |
|
2023 |
|
2024 /** |
|
2025 * Gets group labels based on data. |
|
2026 */ |
|
2027 getGroupLabels(data) { |
|
2028 const that = this, |
|
2029 startIndex = that.xlsxStartIndex !== undefined ? that.xlsxStartIndex : +that.exportHeader, |
|
2030 groups = {}, |
|
2031 groupLabels = []; |
|
2032 |
|
2033 for (let i = startIndex; i < data.length; i++) { |
|
2034 const currentRecord = data[i]; |
|
2035 |
|
2036 for (let j = 0; j < that.groupBy.length; j++) { |
|
2037 const datafield = that.groupBy[j], |
|
2038 currentValue = currentRecord[datafield]; |
|
2039 let group = groups[datafield]; |
|
2040 |
|
2041 if (group === undefined) { |
|
2042 groups[datafield] = {}; |
|
2043 group = groups[datafield]; |
|
2044 } |
|
2045 |
|
2046 if (group[currentValue] === undefined) { |
|
2047 group[currentValue] = (that.exportHeader ? data[startIndex - 1][datafield] : datafield) + ': ' + currentValue; |
|
2048 groupLabels.push(group[currentValue]); |
|
2049 } |
|
2050 } |
|
2051 } |
|
2052 |
|
2053 that.groups = groups; |
|
2054 that.groupLabels = groupLabels; |
|
2055 } |
|
2056 |
|
2057 /** |
|
2058 * Gets the header content when exporting to HTML. |
|
2059 */ |
|
2060 getHTMLHeader(datafields, data) { |
|
2061 const that = this; |
|
2062 let header = '\n <thead>\n'; |
|
2063 |
|
2064 if (!that.complexHeader) { |
|
2065 header += ' <tr>\n'; |
|
2066 |
|
2067 for (let j = 0; j < datafields.length; j++) { |
|
2068 const datafield = datafields[j]; |
|
2069 |
|
2070 header += ` <th class="header header${datafield}">${data[0][datafield]}</th>\n`; |
|
2071 } |
|
2072 |
|
2073 header += ' </tr>\n </thead>'; |
|
2074 return header; |
|
2075 } |
|
2076 |
|
2077 for (let j = 0; j < that.complexHeader.length; j++) { |
|
2078 const row = that.complexHeader[j]; |
|
2079 |
|
2080 header += ' <tr>\n'; |
|
2081 |
|
2082 for (let k = 0; k < row.length; k++) { |
|
2083 const currentLabel = row[k]; |
|
2084 let colspan = 1, rowspan = 1; |
|
2085 |
|
2086 if ((row[k - 1] && row[k - 1] === currentLabel) || |
|
2087 (that.complexHeader[j - 1] && (that.complexHeader[j - 1][k] === currentLabel))) { |
|
2088 continue; |
|
2089 } |
|
2090 |
|
2091 let iterator = k + 1; |
|
2092 |
|
2093 while (row[iterator] && row[iterator] === row[iterator - 1]) { |
|
2094 colspan++; |
|
2095 iterator++; |
|
2096 } |
|
2097 |
|
2098 iterator = j + 1; |
|
2099 |
|
2100 while (that.complexHeader[iterator] && that.complexHeader[iterator][k] === currentLabel) { |
|
2101 rowspan++; |
|
2102 iterator++; |
|
2103 } |
|
2104 |
|
2105 const datafield = j === that.complexHeader.length - 1 || rowspan + j === that.complexHeader.length ? |
|
2106 ' header' + datafields[k] : ''; |
|
2107 |
|
2108 header += ` <th class="header${datafield}" colspan="${colspan}" rowspan="${rowspan}">${currentLabel}</th>\n`; |
|
2109 } |
|
2110 |
|
2111 header += ' </tr>\n'; |
|
2112 } |
|
2113 |
|
2114 header += ' </thead>'; |
|
2115 return header; |
|
2116 } |
|
2117 |
|
2118 /** |
|
2119 * Gets conditional formatting XML. |
|
2120 */ |
|
2121 getConditionalFormatting() { |
|
2122 const that = this, |
|
2123 conditionalFormatting = that.conditionalFormatting; |
|
2124 |
|
2125 if (!conditionalFormatting) { |
|
2126 that.conditionalFormattingXLSX = { conditions: '', styles: '' }; |
|
2127 return; |
|
2128 } |
|
2129 |
|
2130 const dxfCodes = []; |
|
2131 let conditionsXml = '', |
|
2132 stylesXml = ''; |
|
2133 |
|
2134 for (let i = conditionalFormatting.length - 1; i >= 0; i--) { |
|
2135 const columnFormat = conditionalFormatting[i], |
|
2136 columnLetter = that.columnsArray[that.datafields.indexOf(columnFormat.column)], |
|
2137 startCell = columnLetter + (that.xlsxStartIndex + 1), |
|
2138 sqref = startCell + ':' + columnLetter + (that.data.length), |
|
2139 dxfCode = columnFormat.background + columnFormat.color, |
|
2140 attr = that.getConditionalAttributes(columnFormat, startCell); |
|
2141 let dxfId = dxfCodes.indexOf(dxfCode); |
|
2142 |
|
2143 if (dxfId === -1) { |
|
2144 const newDxf = ` <dxf> |
|
2145 <font> |
|
2146 <b val="0"/> |
|
2147 <i val="0"/> |
|
2148 <color rgb="${columnFormat.color === 'White' ? 'FFFFFFFF' : 'FF000000'}"/> |
|
2149 <sz val="10"/> |
|
2150 </font> |
|
2151 <fill> |
|
2152 <patternFill> |
|
2153 <bgColor rgb="${that.toARGB(columnFormat.background)}"/> |
|
2154 </patternFill> |
|
2155 </fill> |
|
2156 </dxf>\n`; |
|
2157 |
|
2158 stylesXml += newDxf; |
|
2159 dxfId = dxfCodes.length; |
|
2160 dxfCodes.push(dxfCode); |
|
2161 } |
|
2162 |
|
2163 conditionsXml += ` <conditionalFormatting sqref="${sqref}"> |
|
2164 <cfRule dxfId="${dxfId}" text="${attr.text}" rank="${attr.rank}" percent="${attr.percent}" bottom="${attr.bottom}" equalAverage="${attr.equalAverage}" aboveAverage="${attr.aboveAverage}"${attr.operator}${attr.timePeriod} priority="${i + 2}" type="${attr.type}"> |
|
2165 ${attr.formula} </cfRule> |
|
2166 </conditionalFormatting>\n`; |
|
2167 } |
|
2168 |
|
2169 stylesXml = ` <dxfs count="${dxfCodes.length}">\n${stylesXml} </dxfs>`; |
|
2170 |
|
2171 that.conditionalFormattingXLSX = { conditions: conditionsXml, styles: stylesXml }; |
|
2172 } |
|
2173 |
|
2174 /** |
|
2175 * Gets conditional formatting XML attributes. |
|
2176 */ |
|
2177 getConditionalAttributes(columnFormat, startCell) { |
|
2178 let condition = columnFormat.condition, |
|
2179 comparator = columnFormat.comparator, |
|
2180 text = '', |
|
2181 rank = 0, |
|
2182 percent = 0, |
|
2183 bottom = 0, |
|
2184 equalAverage = 0, |
|
2185 aboveAverage = 0, |
|
2186 operator = '', |
|
2187 timePeriod = '', |
|
2188 type = '', |
|
2189 formula = ''; |
|
2190 |
|
2191 switch (condition) { |
|
2192 case 'equal': |
|
2193 operator = 'equal'; |
|
2194 type = 'cellIs'; |
|
2195 formula = ` <formula>${comparator}</formula>\n`; |
|
2196 break; |
|
2197 case 'lessThan': |
|
2198 operator = 'lessThan'; |
|
2199 type = 'cellIs'; |
|
2200 formula = ` <formula>${comparator}</formula>\n`; |
|
2201 break; |
|
2202 case 'greaterThan': |
|
2203 operator = 'greaterThan'; |
|
2204 type = 'cellIs'; |
|
2205 formula = ` <formula>${comparator}</formula>\n`; |
|
2206 break; |
|
2207 case 'notEqual': |
|
2208 operator = 'notEqual'; |
|
2209 type = 'cellIs'; |
|
2210 formula = ` <formula>${comparator}</formula>\n`; |
|
2211 break; |
|
2212 case 'between': |
|
2213 operator = 'between'; |
|
2214 type = 'cellIs'; |
|
2215 formula = ` <formula>${columnFormat.min}</formula> |
|
2216 <formula>${columnFormat.max}</formula>\n`; |
|
2217 break; |
|
2218 case 'duplicate': |
|
2219 type = 'duplicateValues'; |
|
2220 formula = ' <formula>0</formula>\n'; |
|
2221 break; |
|
2222 case 'topNItems': |
|
2223 rank = comparator; |
|
2224 type = 'top10'; |
|
2225 break; |
|
2226 case 'bottomNItems': |
|
2227 rank = comparator; |
|
2228 bottom = 1; |
|
2229 type = 'top10'; |
|
2230 break; |
|
2231 case 'topNPercent': |
|
2232 rank = comparator; |
|
2233 percent = 1; |
|
2234 type = 'top10'; |
|
2235 break; |
|
2236 case 'bottomNPercent': |
|
2237 rank = comparator; |
|
2238 percent = 1; |
|
2239 bottom = 1; |
|
2240 type = 'top10'; |
|
2241 break; |
|
2242 case 'aboveAverage': |
|
2243 aboveAverage = 1; |
|
2244 type = 'aboveAverage'; |
|
2245 formula = ' <formula>0</formula>\n'; |
|
2246 break; |
|
2247 case 'belowAverage': |
|
2248 type = 'aboveAverage'; |
|
2249 formula = ' <formula>0</formula>\n'; |
|
2250 break; |
|
2251 case 'contains': |
|
2252 text = comparator; |
|
2253 operator = 'containsText'; |
|
2254 type = 'containsText'; |
|
2255 formula = ` <formula>NOT(ISERROR(SEARCH("${comparator}",${startCell})))</formula>\n`; |
|
2256 break; |
|
2257 case 'doesNotContain': |
|
2258 text = comparator; |
|
2259 operator = 'notContains'; |
|
2260 type = 'notContainsText'; |
|
2261 formula = ` <formula>ISERROR(SEARCH("${comparator}",${startCell}))</formula>\n`; |
|
2262 break; |
|
2263 case 'dateOccur': |
|
2264 timePeriod = ` timePeriod="${comparator}"`; |
|
2265 type = 'timePeriod'; |
|
2266 break; |
|
2267 } |
|
2268 |
|
2269 if (operator) { |
|
2270 operator = ` operator="${operator}" `; |
|
2271 } |
|
2272 |
|
2273 return { |
|
2274 text: text, |
|
2275 rank: rank, |
|
2276 percent: percent, |
|
2277 bottom: bottom, |
|
2278 equalAverage: equalAverage, |
|
2279 aboveAverage: aboveAverage, |
|
2280 operator: operator, |
|
2281 timePeriod: timePeriod, |
|
2282 type: type, |
|
2283 formula: formula |
|
2284 } |
|
2285 } |
|
2286 |
|
2287 /** |
|
2288 * Gets merged cells XML. |
|
2289 */ |
|
2290 getMergedCells(mergedCells) { |
|
2291 const that = this; |
|
2292 |
|
2293 let mergeCellsXml = ''; |
|
2294 |
|
2295 for (let i = 0; i < mergedCells.length; i++) { |
|
2296 if (mergedCells[i].from === mergedCells[i].to) { |
|
2297 continue; |
|
2298 } |
|
2299 |
|
2300 mergeCellsXml += `\n <mergeCell ref="${mergedCells[i].from}:${mergedCells[i].to}" />\n`; |
|
2301 } |
|
2302 |
|
2303 if (that.mergedCells) { |
|
2304 for (let i = 0; i < that.mergedCells.length; i++) { |
|
2305 const cellDefinition = that.mergedCells[i]; |
|
2306 |
|
2307 if (cellDefinition.rowspan < 2 && cellDefinition.colspan < 2) { |
|
2308 continue; |
|
2309 } |
|
2310 |
|
2311 const from = that.columnsArray[cellDefinition.cell[0]] + (cellDefinition.cell[1] + that.xlsxStartIndex + 1), |
|
2312 to = that.columnsArray[cellDefinition.cell[0] + cellDefinition.colspan - 1] + (cellDefinition.cell[1] + that.xlsxStartIndex + cellDefinition.rowspan); |
|
2313 |
|
2314 mergeCellsXml += `\n <mergeCell ref="${from}:${to}" />\n`; |
|
2315 } |
|
2316 } |
|
2317 |
|
2318 if (mergeCellsXml) { |
|
2319 mergeCellsXml = `\n <mergeCells count="${mergedCells.length}">${mergeCellsXml} </mergeCells>`; |
|
2320 } |
|
2321 |
|
2322 return mergeCellsXml; |
|
2323 } |
|
2324 |
|
2325 /** |
|
2326 * Gets numFmt index. |
|
2327 */ |
|
2328 getNumFmtIndex(format, numFmts) { |
|
2329 let index = numFmts.collection.indexOf(format); |
|
2330 |
|
2331 if (index === -1) { |
|
2332 index = numFmts.collection.length + 100; |
|
2333 numFmts.collection.push(format); |
|
2334 numFmts.xml += `<numFmt numFmtId="${index}" formatCode="${format}"/>`; |
|
2335 } |
|
2336 else { |
|
2337 index += 100; |
|
2338 } |
|
2339 |
|
2340 return index; |
|
2341 } |
|
2342 |
|
2343 /** |
|
2344 * Returns outlineLevel. |
|
2345 */ |
|
2346 getOutlineLevel(record) { |
|
2347 if (!this.actualHierarchy || record._level === 1) { |
|
2348 return ''; |
|
2349 } |
|
2350 |
|
2351 return ` outlineLevel="${record._level - 1}"`; |
|
2352 } |
|
2353 |
|
2354 /** |
|
2355 * Gets row style. |
|
2356 */ |
|
2357 getRowStyle() { |
|
2358 const that = this, |
|
2359 style = that.style; |
|
2360 |
|
2361 if (!style) { |
|
2362 return ''; |
|
2363 } |
|
2364 |
|
2365 const rowsDefinition = style.rows; |
|
2366 |
|
2367 if (!rowsDefinition) { |
|
2368 return ''; |
|
2369 } |
|
2370 |
|
2371 const styles = { |
|
2372 row: '' |
|
2373 }; |
|
2374 let generatedStyle = ''; |
|
2375 |
|
2376 for (let prop in rowsDefinition) { |
|
2377 if (!rowsDefinition.hasOwnProperty(prop) || |
|
2378 prop === 'alternationCount' || |
|
2379 prop === 'alternationStart' || |
|
2380 prop === 'alternationEnd') { |
|
2381 continue; |
|
2382 } |
|
2383 |
|
2384 const value = rowsDefinition[prop]; |
|
2385 |
|
2386 if (prop.indexOf('alt') !== -1) { |
|
2387 const i = prop.slice(16, 17), |
|
2388 property = prop.slice(17); |
|
2389 |
|
2390 if (!styles['rowN' + i]) { |
|
2391 styles['rowN' + i] = ''; |
|
2392 } |
|
2393 |
|
2394 if (property === 'Color') { |
|
2395 styles['rowN' + i] += 'color : ' + value + '; '; |
|
2396 } |
|
2397 else if (property === 'BorderColor') { |
|
2398 styles['rowN' + i] += 'border-color : ' + value + '; '; |
|
2399 } |
|
2400 else { |
|
2401 styles['rowN' + i] += 'background-color : ' + value + '; '; |
|
2402 } |
|
2403 |
|
2404 continue; |
|
2405 } |
|
2406 |
|
2407 if (!isNaN(prop)) { |
|
2408 if (!styles['row' + prop]) { |
|
2409 styles['row' + prop] = ''; |
|
2410 } |
|
2411 |
|
2412 for (let rowProp in value) { |
|
2413 if (value.hasOwnProperty(rowProp)) { |
|
2414 styles['row' + prop] += window.jqxToDash(rowProp) + ': ' + value[rowProp] + '; '; |
|
2415 } |
|
2416 } |
|
2417 |
|
2418 continue; |
|
2419 } |
|
2420 |
|
2421 styles.row += window.jqxToDash(prop) + ': ' + rowsDefinition[prop] + '; '; |
|
2422 } |
|
2423 |
|
2424 let keys = Object.keys(styles); |
|
2425 |
|
2426 keys.sort(function (a, b) { |
|
2427 if (a === 'row') { |
|
2428 return -1; |
|
2429 } |
|
2430 |
|
2431 if (b === 'row') { |
|
2432 return 1; |
|
2433 } |
|
2434 |
|
2435 const aIsNum = !isNaN(a.slice(3)), |
|
2436 bIsNum = !isNaN(b.slice(3)); |
|
2437 |
|
2438 if (aIsNum && !bIsNum) { |
|
2439 return 1; |
|
2440 } |
|
2441 |
|
2442 if (!aIsNum && bIsNum) { |
|
2443 return -1; |
|
2444 } |
|
2445 |
|
2446 return +(a < b); |
|
2447 }); |
|
2448 |
|
2449 for (let i = 0; i < keys.length; i++) { |
|
2450 generatedStyle += ` .${keys[i]} { ${styles[keys[i]]}}\n`; |
|
2451 } |
|
2452 |
|
2453 return generatedStyle; |
|
2454 } |
|
2455 |
|
2456 /** |
|
2457 * Gets table style. |
|
2458 */ |
|
2459 getTableStyle() { |
|
2460 const that = this, |
|
2461 style = that.style; |
|
2462 |
|
2463 if (!style) { |
|
2464 return ' style="table-layout: fixed; border: 1px solid black; border-collapse: collapse;"'; |
|
2465 } |
|
2466 |
|
2467 let generatedStyle = 'table-layout: fixed; '; |
|
2468 |
|
2469 for (let prop in style) { |
|
2470 if (style.hasOwnProperty(prop) && ['header', 'columns', 'rows'].indexOf(prop) === -1) { |
|
2471 generatedStyle += window.jqxToDash(prop) + ': ' + style[prop] + '; '; |
|
2472 } |
|
2473 } |
|
2474 |
|
2475 if (generatedStyle) { |
|
2476 generatedStyle = ' style="' + generatedStyle + '"'; |
|
2477 } |
|
2478 |
|
2479 return generatedStyle; |
|
2480 } |
|
2481 |
|
2482 /** |
|
2483 * Gets the "s" (style) attribute of an XLSX cell. |
|
2484 */ |
|
2485 getXLSXCellStyle(r) { |
|
2486 const that = this; |
|
2487 |
|
2488 if (that.cellStyleMapping[r] !== undefined) { |
|
2489 return ` s="${that.cellStyleMapping[r]}"`; |
|
2490 } |
|
2491 |
|
2492 return ''; |
|
2493 } |
|
2494 |
|
2495 /** |
|
2496 * Gets the "s" (style) attribute of an XLSX cell. |
|
2497 */ |
|
2498 getXLSXFormat(format, cellValue) { |
|
2499 if (typeof cellValue === 'number') { |
|
2500 let precision = parseFloat(format.slice(1)) || 0, |
|
2501 precisionCode = precision > 0 ? '.' + ('0').repeat(precision) : ''; |
|
2502 |
|
2503 format = format.slice(0, 1); |
|
2504 |
|
2505 switch (format) { |
|
2506 case 'C': |
|
2507 case 'c': |
|
2508 return '\$#,0' + precisionCode; |
|
2509 case 'D': |
|
2510 case 'd': |
|
2511 if (precision) { |
|
2512 return ('0').repeat(precision); |
|
2513 } |
|
2514 |
|
2515 return '0'; |
|
2516 case 'E': |
|
2517 case 'e': |
|
2518 return '0' + precisionCode + format + '000'; |
|
2519 case 'F': |
|
2520 case 'f': |
|
2521 return '0' + precisionCode; |
|
2522 case 'N': |
|
2523 case 'n': |
|
2524 return '#,0' + precisionCode; |
|
2525 case 'P': |
|
2526 case 'p': |
|
2527 return '#,0' + precisionCode + ' %'; |
|
2528 default: |
|
2529 return; |
|
2530 } |
|
2531 } |
|
2532 else if (cellValue instanceof Date) { |
|
2533 switch (format) { |
|
2534 case 'd': |
|
2535 return 'm/d/yyyy'; |
|
2536 case 'D': |
|
2537 return 'nnnnmmmm dd, yyyy'; |
|
2538 case 't': |
|
2539 return 'h:m AM/PM'; |
|
2540 case 'T': |
|
2541 return 'h:mm:ss AM/PM'; |
|
2542 case 'f': |
|
2543 return 'nnnnmmmm dd, yyyy h:m AM/PM'; |
|
2544 case 'F': |
|
2545 return 'nnnnmmmm dd, yyyy h:mm:ss AM/PM'; |
|
2546 case 'M': |
|
2547 return 'mmmm d'; |
|
2548 case 'Y': |
|
2549 return 'yyyy mmmm'; |
|
2550 case 'FP': |
|
2551 case 'PP': |
|
2552 return 'yyyy-mm-dd hh:mm:ss'; |
|
2553 case 'FT': |
|
2554 case 'PT': |
|
2555 return 'hh:mm:ss'; |
|
2556 } |
|
2557 |
|
2558 format = format.replace(/f|u|n|p|e|a|x|o/gi, ''); |
|
2559 format = format.replace(/tt/gi, 'AM/PM'); |
|
2560 format = format.replace(/:{2,}|:\s|:$|\.$/g, ''); |
|
2561 format = format.trim(); |
|
2562 return format; |
|
2563 } |
|
2564 } |
|
2565 |
|
2566 /** |
|
2567 * Processes column styles. |
|
2568 */ |
|
2569 processColumnStyle(style) { |
|
2570 const that = this, |
|
2571 headerDefinition = style.header, |
|
2572 columnsDefinition = style.columns, |
|
2573 sampleRecord = that.data[0], |
|
2574 startIndex = that.xlsxStartIndex; |
|
2575 |
|
2576 that.columnWidth = []; |
|
2577 |
|
2578 if (startIndex && headerDefinition) { |
|
2579 for (let i = 0; i < that.columnsArray.length; i++) { |
|
2580 const columnLetter = that.columnsArray[i], |
|
2581 cell = columnLetter + startIndex, |
|
2582 columnSpecific = headerDefinition[that.datafields[i]]; |
|
2583 |
|
2584 for (let prop in headerDefinition) { |
|
2585 if (headerDefinition.hasOwnProperty(prop) && sampleRecord[prop] === undefined) { |
|
2586 if (that.complexHeader) { |
|
2587 for (let j = 0; j < that.complexHeader.length; j++) { |
|
2588 if (prop === 'height') { |
|
2589 that.rowHeight[j] = ` ht="${(parseFloat(headerDefinition.height) / that.complexHeader.length) / 2}"`; |
|
2590 continue; |
|
2591 } |
|
2592 else { |
|
2593 that.storeCellStyle(columnLetter + (j + 1), prop, headerDefinition[prop]); |
|
2594 } |
|
2595 } |
|
2596 } |
|
2597 else { |
|
2598 if (prop === 'height') { |
|
2599 that.rowHeight[0] = ` ht="${parseFloat(headerDefinition.height) / 2}"`; |
|
2600 continue; |
|
2601 } |
|
2602 |
|
2603 that.storeCellStyle(cell, prop, headerDefinition[prop]); |
|
2604 } |
|
2605 } |
|
2606 } |
|
2607 |
|
2608 if (!columnSpecific) { |
|
2609 continue; |
|
2610 } |
|
2611 |
|
2612 for (let prop in columnSpecific) { |
|
2613 if (columnSpecific.hasOwnProperty(prop)) { |
|
2614 if (prop === 'width') { |
|
2615 that.columnWidth[i] = columnSpecific.width; |
|
2616 continue; |
|
2617 } |
|
2618 |
|
2619 that.storeCellStyle(cell, prop, columnSpecific[prop]); |
|
2620 } |
|
2621 } |
|
2622 } |
|
2623 } |
|
2624 else if (headerDefinition) { |
|
2625 for (let i = 0; i < that.columnsArray.length; i++) { |
|
2626 const columnSpecific = headerDefinition[that.datafields[i]]; |
|
2627 |
|
2628 if (columnSpecific && columnSpecific.width !== undefined) { |
|
2629 that.columnWidth[i] = columnSpecific.width; |
|
2630 } |
|
2631 } |
|
2632 } |
|
2633 |
|
2634 if (!columnsDefinition) { |
|
2635 return ''; |
|
2636 } |
|
2637 |
|
2638 for (let i = startIndex; i < that.data.length; i++) { |
|
2639 for (let j = 0; j < that.columnsArray.length; j++) { |
|
2640 const columnLetter = that.columnsArray[j], |
|
2641 cell = columnLetter + (i + 1), |
|
2642 datafield = that.datafields[j], |
|
2643 columnSpecific = columnsDefinition[datafield]; |
|
2644 |
|
2645 for (let prop in columnsDefinition) { |
|
2646 if (columnsDefinition.hasOwnProperty(prop) && sampleRecord[prop] === undefined) { |
|
2647 that.storeCellStyle(cell, prop, columnsDefinition[prop]); |
|
2648 } |
|
2649 } |
|
2650 |
|
2651 if (!columnSpecific) { |
|
2652 continue; |
|
2653 } |
|
2654 |
|
2655 for (let prop in columnSpecific) { |
|
2656 if (!isNaN(prop) || !columnSpecific.hasOwnProperty(prop)) { |
|
2657 continue; |
|
2658 } |
|
2659 |
|
2660 that.storeCellStyle(cell, prop, columnSpecific[prop], that.data[i][datafield]); |
|
2661 } |
|
2662 } |
|
2663 } |
|
2664 } |
|
2665 |
|
2666 /** |
|
2667 * Processes complex header object. |
|
2668 */ |
|
2669 processComplexHeader(header, data, format) { |
|
2670 const that = this, |
|
2671 flatHeader = {}, |
|
2672 processGrouping = ['html', 'jpeg', 'pdf', 'png', 'xlsx'].indexOf(format) !== -1 && header.columngroups, |
|
2673 datafieldMapping = [], |
|
2674 columnGroupHierarchy = {}, |
|
2675 complexHeader = []; |
|
2676 let headerDepth = 0; |
|
2677 |
|
2678 function getColumnGroup(columnGroup) { |
|
2679 for (let i = 0; i < header.columngroups.length; i++) { |
|
2680 const currentGroupDefinition = header.columngroups[i]; |
|
2681 |
|
2682 if (currentGroupDefinition.name === columnGroup) { |
|
2683 return currentGroupDefinition; |
|
2684 } |
|
2685 } |
|
2686 } |
|
2687 |
|
2688 function getColumnGroupHierarchy(groupDefinition) { |
|
2689 const columnGroups = []; |
|
2690 |
|
2691 while (groupDefinition) { |
|
2692 columnGroups.unshift(groupDefinition.label); |
|
2693 |
|
2694 if (groupDefinition.parentGroup) { |
|
2695 groupDefinition = getColumnGroup(groupDefinition.parentGroup); |
|
2696 } |
|
2697 else { |
|
2698 return columnGroups; |
|
2699 } |
|
2700 } |
|
2701 } |
|
2702 |
|
2703 if (processGrouping) { |
|
2704 for (let i = 0; i < header.columngroups.length; i++) { |
|
2705 const currentGroupDefinition = header.columngroups[i], |
|
2706 groupHierarchy = getColumnGroupHierarchy(currentGroupDefinition); |
|
2707 |
|
2708 columnGroupHierarchy[currentGroupDefinition.name] = groupHierarchy; |
|
2709 headerDepth = Math.max(headerDepth, groupHierarchy.length); |
|
2710 } |
|
2711 |
|
2712 headerDepth++; |
|
2713 |
|
2714 for (let i = 0; i < headerDepth; i++) { |
|
2715 complexHeader[i] = []; |
|
2716 } |
|
2717 } |
|
2718 |
|
2719 for (let i = 0; i < header.columns.length; i++) { |
|
2720 const currentColumn = header.columns[i]; |
|
2721 |
|
2722 flatHeader[currentColumn.dataField] = currentColumn.label; |
|
2723 |
|
2724 if (!processGrouping) { |
|
2725 continue; |
|
2726 } |
|
2727 |
|
2728 datafieldMapping[i] = currentColumn.dataField; |
|
2729 complexHeader[headerDepth - 1][i] = currentColumn.label; |
|
2730 |
|
2731 if (!currentColumn.columnGroup) { |
|
2732 continue; |
|
2733 } |
|
2734 |
|
2735 const columnGroups = columnGroupHierarchy[currentColumn.columnGroup]; |
|
2736 |
|
2737 for (let j = 0; j < columnGroups.length; j++) { |
|
2738 complexHeader[j][i] = columnGroups[j]; |
|
2739 } |
|
2740 } |
|
2741 |
|
2742 if (complexHeader.length > 1) { |
|
2743 const numberOfDatafields = Object.keys(flatHeader).length; |
|
2744 |
|
2745 for (let i = 0; i < headerDepth - 1; i++) { |
|
2746 const entry = {}; |
|
2747 |
|
2748 for (let j = 0; j < numberOfDatafields; j++) { |
|
2749 if (complexHeader[i][j] === undefined) { |
|
2750 let iterator = i + 1; |
|
2751 |
|
2752 while (complexHeader[iterator][j] === undefined) { |
|
2753 iterator++; |
|
2754 } |
|
2755 |
|
2756 complexHeader[i][j] = complexHeader[iterator][j]; |
|
2757 } |
|
2758 |
|
2759 entry[datafieldMapping[j]] = complexHeader[i][j]; |
|
2760 } |
|
2761 |
|
2762 if (format === 'xlsx') { |
|
2763 data.splice(i, 0, entry); |
|
2764 } |
|
2765 } |
|
2766 |
|
2767 that.complexHeader = complexHeader; |
|
2768 |
|
2769 if (format !== 'xlsx') { |
|
2770 data.unshift(flatHeader); |
|
2771 } |
|
2772 else { |
|
2773 data.splice(headerDepth - 1, 0, flatHeader); |
|
2774 |
|
2775 const toMerge = {}; |
|
2776 |
|
2777 for (let i = 0; i < headerDepth; i++) { |
|
2778 for (let j = 0; j < numberOfDatafields; j++) { |
|
2779 const label = complexHeader[i][j]; |
|
2780 |
|
2781 if (!toMerge[label]) { |
|
2782 toMerge[label] = { from: [i, j] }; |
|
2783 toMerge[label].to = toMerge[label].from; |
|
2784 } |
|
2785 else { |
|
2786 toMerge[label].to = [i, j]; |
|
2787 } |
|
2788 } |
|
2789 } |
|
2790 |
|
2791 that.complexHeaderMergeInfo = toMerge; |
|
2792 } |
|
2793 } |
|
2794 else { |
|
2795 data.unshift(flatHeader); |
|
2796 } |
|
2797 } |
|
2798 |
|
2799 /** |
|
2800 * Processes hierarchical data. |
|
2801 */ |
|
2802 processHierarchicalData(data, format) { |
|
2803 const that = this, |
|
2804 startIndex = format !== 'xlsx' ? +that.exportHeader : that.xlsxStartIndex, |
|
2805 siblingGroups = {}, |
|
2806 processedData = []; |
|
2807 let maxLevel = 0, |
|
2808 actualHierarchy = false; |
|
2809 |
|
2810 function process(parentKey, level, collapsed) { |
|
2811 const group = siblingGroups[parentKey]; |
|
2812 |
|
2813 maxLevel = Math.max(maxLevel, level); |
|
2814 |
|
2815 if (group === undefined) { |
|
2816 return; |
|
2817 } |
|
2818 |
|
2819 for (let i = 0; i < group.length; i++) { |
|
2820 const currentRecord = group[i], |
|
2821 keyDataField = currentRecord._keyDataField; |
|
2822 |
|
2823 currentRecord._collapsed = collapsed; |
|
2824 currentRecord._level = level; |
|
2825 processedData.push(currentRecord); |
|
2826 |
|
2827 if (siblingGroups[keyDataField]) { |
|
2828 actualHierarchy = true; |
|
2829 currentRecord._expanded = currentRecord._expanded !== undefined ? currentRecord._expanded : true; |
|
2830 process(keyDataField, level + 1, collapsed || !currentRecord._expanded); |
|
2831 } |
|
2832 } |
|
2833 } |
|
2834 |
|
2835 function processJSONXML(parentKey, level, parent) { |
|
2836 const group = siblingGroups[parentKey]; |
|
2837 |
|
2838 maxLevel = Math.max(maxLevel, level); |
|
2839 |
|
2840 if (group === undefined) { |
|
2841 return; |
|
2842 } |
|
2843 |
|
2844 for (let i = 0; i < group.length; i++) { |
|
2845 const currentRecord = group[i], |
|
2846 keyDataField = currentRecord._keyDataField; |
|
2847 let cleanedRecord; |
|
2848 |
|
2849 if (format === 'json') { |
|
2850 cleanedRecord = {}; |
|
2851 |
|
2852 for (let prop in currentRecord) { |
|
2853 if (currentRecord.hasOwnProperty(prop) && prop.charAt(0) !== '_') { |
|
2854 cleanedRecord[prop] = currentRecord[prop]; |
|
2855 } |
|
2856 } |
|
2857 } |
|
2858 else { |
|
2859 cleanedRecord = Object.assign({}, currentRecord); |
|
2860 } |
|
2861 |
|
2862 parent.push(cleanedRecord); |
|
2863 |
|
2864 if (siblingGroups[keyDataField]) { |
|
2865 actualHierarchy = true; |
|
2866 cleanedRecord.rows = []; |
|
2867 processJSONXML(keyDataField, level + 1, cleanedRecord.rows); |
|
2868 } |
|
2869 } |
|
2870 } |
|
2871 |
|
2872 if (data[startIndex]._keyDataField === undefined) { |
|
2873 return that.processNestedData(data, format, startIndex); |
|
2874 } |
|
2875 |
|
2876 for (let i = startIndex; i < data.length; i++) { |
|
2877 const currentRecord = Object.assign({}, data[i]), |
|
2878 parentKey = currentRecord._parentDataField; |
|
2879 |
|
2880 if (siblingGroups[parentKey] === undefined) { |
|
2881 siblingGroups[parentKey] = [currentRecord]; |
|
2882 } |
|
2883 else { |
|
2884 siblingGroups[parentKey].push(currentRecord); |
|
2885 } |
|
2886 } |
|
2887 |
|
2888 if (startIndex) { |
|
2889 for (let i = 0; i < startIndex; i++) { |
|
2890 processedData.push(Object.assign({}, data[i])); |
|
2891 |
|
2892 if (['json', 'pdf', 'xml'].indexOf(format) === -1) { |
|
2893 processedData[i]._level = 1; |
|
2894 } |
|
2895 } |
|
2896 } |
|
2897 |
|
2898 if (format !== 'json' && format !== 'xml') { |
|
2899 process(null, 1, false); |
|
2900 } |
|
2901 else { |
|
2902 processJSONXML(null, 1, processedData); |
|
2903 } |
|
2904 |
|
2905 if (!actualHierarchy) { |
|
2906 that.actualHierarchy = false; |
|
2907 } |
|
2908 |
|
2909 that.maxLevel = maxLevel; |
|
2910 return processedData; |
|
2911 } |
|
2912 |
|
2913 /** |
|
2914 * Processes nested hierarchical data. |
|
2915 */ |
|
2916 processNestedData(data, format, startIndex) { |
|
2917 const that = this, |
|
2918 processedData = []; |
|
2919 let maxLevel = 0, |
|
2920 actualHierarchy = false; |
|
2921 |
|
2922 function process(start, children, level, collapsed) { |
|
2923 maxLevel = Math.max(maxLevel, level); |
|
2924 |
|
2925 for (let i = start; i < children.length; i++) { |
|
2926 const currentRecord = Object.assign({}, children[i]); |
|
2927 |
|
2928 currentRecord._collapsed = collapsed; |
|
2929 currentRecord._level = level; |
|
2930 processedData.push(currentRecord); |
|
2931 |
|
2932 if (currentRecord.children && currentRecord.children.length > 0) { |
|
2933 actualHierarchy = true; |
|
2934 currentRecord._expanded = currentRecord._expanded !== undefined ? currentRecord._expanded : true; |
|
2935 process(0, currentRecord.children, level + 1, collapsed || !currentRecord._expanded); |
|
2936 } |
|
2937 |
|
2938 delete currentRecord.children; |
|
2939 } |
|
2940 } |
|
2941 |
|
2942 function processJSONXML(start, children, rows, level) { |
|
2943 maxLevel = Math.max(maxLevel, level); |
|
2944 |
|
2945 for (let i = start; i < children.length; i++) { |
|
2946 const currentRecord = Object.assign({}, children[i]); |
|
2947 |
|
2948 if (level === 1) { |
|
2949 processedData[i] = currentRecord; |
|
2950 } |
|
2951 else { |
|
2952 rows[i] = currentRecord; |
|
2953 } |
|
2954 |
|
2955 if (currentRecord.children && currentRecord.children.length > 0) { |
|
2956 actualHierarchy = true; |
|
2957 currentRecord.rows = []; |
|
2958 processJSONXML(0, currentRecord.children, currentRecord.rows, level + 1); |
|
2959 } |
|
2960 |
|
2961 delete currentRecord.children; |
|
2962 } |
|
2963 } |
|
2964 |
|
2965 if (startIndex) { |
|
2966 for (let i = 0; i < startIndex; i++) { |
|
2967 processedData.push(Object.assign({}, data[i])); |
|
2968 |
|
2969 if (['json', 'pdf', 'xml'].indexOf(format) === -1) { |
|
2970 processedData[i]._level = 1; |
|
2971 } |
|
2972 } |
|
2973 } |
|
2974 |
|
2975 if (format !== 'json' && format !== 'xml') { |
|
2976 process(startIndex, data, 1, false); |
|
2977 } |
|
2978 else { |
|
2979 processJSONXML(startIndex, data, undefined, 1); |
|
2980 } |
|
2981 |
|
2982 if (!actualHierarchy) { |
|
2983 that.actualHierarchy = false; |
|
2984 } |
|
2985 |
|
2986 that.maxLevel = maxLevel; |
|
2987 return processedData; |
|
2988 } |
|
2989 |
|
2990 /** |
|
2991 * Processes row styles. |
|
2992 */ |
|
2993 processRowStyle(style) { |
|
2994 const that = this, |
|
2995 rowsDefinition = style.rows; |
|
2996 |
|
2997 that.rowHeight = []; |
|
2998 |
|
2999 if (!rowsDefinition) { |
|
3000 return; |
|
3001 } |
|
3002 |
|
3003 const startIndex = that.xlsxStartIndex; |
|
3004 |
|
3005 function applyToRowCells(row, prop, value) { |
|
3006 for (let j = 0; j < that.columnsArray.length; j++) { |
|
3007 const currentCell = that.columnsArray[j] + (row + 1 + startIndex); |
|
3008 |
|
3009 that.storeCellStyle(currentCell, prop, value); |
|
3010 } |
|
3011 } |
|
3012 |
|
3013 if (rowsDefinition.height) { |
|
3014 that.defaultRowHeight = ` ht="${parseFloat(rowsDefinition.height) / 2}"`; |
|
3015 } |
|
3016 |
|
3017 for (let i = startIndex; i < that.data.length; i++) { |
|
3018 const row = i - startIndex; |
|
3019 |
|
3020 for (let prop in rowsDefinition) { |
|
3021 if (rowsDefinition.hasOwnProperty(prop) && |
|
3022 prop.indexOf('alt') === -1 && |
|
3023 isNaN(prop) && |
|
3024 prop !== 'height') { |
|
3025 applyToRowCells(row, prop, rowsDefinition[prop]); |
|
3026 } |
|
3027 } |
|
3028 |
|
3029 if (rowsDefinition.alternationCount && |
|
3030 (((rowsDefinition.alternationStart === undefined || row >= rowsDefinition.alternationStart) && |
|
3031 (rowsDefinition.alternationEnd === undefined || row <= rowsDefinition.alternationEnd)) || |
|
3032 rowsDefinition.alternationStart === rowsDefinition.alternationEnd)) { |
|
3033 const start = rowsDefinition.alternationStart || 0, |
|
3034 i = (row - start) % rowsDefinition.alternationCount; |
|
3035 |
|
3036 if (rowsDefinition[`alternationIndex${i}Color`]) { |
|
3037 applyToRowCells(row, 'color', rowsDefinition[`alternationIndex${i}Color`]); |
|
3038 } |
|
3039 |
|
3040 if (rowsDefinition[`alternationIndex${i}BorderColor`]) { |
|
3041 applyToRowCells(row, 'borderColor', rowsDefinition[`alternationIndex${i}BorderColor`]); |
|
3042 } |
|
3043 |
|
3044 if (rowsDefinition[`alternationIndex${i}BackgroundColor`]) { |
|
3045 applyToRowCells(row, 'backgroundColor', rowsDefinition[`alternationIndex${i}BackgroundColor`]); |
|
3046 } |
|
3047 } |
|
3048 |
|
3049 if (rowsDefinition[row]) { |
|
3050 for (let prop in rowsDefinition[row]) { |
|
3051 if (rowsDefinition[row].hasOwnProperty(prop)) { |
|
3052 if (prop === 'height') { |
|
3053 that.rowHeight[i] = ` ht="${parseFloat(rowsDefinition[row].height) / 2}"`; |
|
3054 continue; |
|
3055 } |
|
3056 |
|
3057 applyToRowCells(row, prop, rowsDefinition[row][prop]); |
|
3058 } |
|
3059 } |
|
3060 } |
|
3061 } |
|
3062 } |
|
3063 |
|
3064 /** |
|
3065 * Stores cell style in "styleMap" object. |
|
3066 */ |
|
3067 storeCellStyle(cell, prop, value) { |
|
3068 const that = this, |
|
3069 cellMap = that.styleMap[cell]; |
|
3070 |
|
3071 switch (prop) { |
|
3072 case 'backgroundColor': |
|
3073 cellMap.fills.fgColor = value; |
|
3074 break; |
|
3075 case 'color': |
|
3076 cellMap.fonts.color = value; |
|
3077 break; |
|
3078 case 'fontFamily': |
|
3079 cellMap.fonts.name = value.replace(/"/g, '\''); |
|
3080 break; |
|
3081 case 'fontSize': |
|
3082 cellMap.fonts.sz = parseFloat(value); |
|
3083 break; |
|
3084 case 'fontStyle': |
|
3085 if (value === 'italic') { |
|
3086 cellMap.fonts.i = true; |
|
3087 } |
|
3088 else { |
|
3089 delete cellMap.fonts.i; |
|
3090 } |
|
3091 |
|
3092 break; |
|
3093 case 'fontWeight': |
|
3094 if (value === 'bold') { |
|
3095 cellMap.fonts.b = true; |
|
3096 } |
|
3097 else { |
|
3098 delete cellMap.fonts.b; |
|
3099 } |
|
3100 |
|
3101 break; |
|
3102 case 'numFmt': { |
|
3103 cellMap.numFmt = value; |
|
3104 break; |
|
3105 } |
|
3106 case 'textAlign': |
|
3107 cellMap.alignment.horizontal = value; |
|
3108 break; |
|
3109 case 'textDecoration': |
|
3110 if (value === 'underline') { |
|
3111 cellMap.fonts.u = true; |
|
3112 } |
|
3113 else { |
|
3114 delete cellMap.fonts.u; |
|
3115 } |
|
3116 |
|
3117 break; |
|
3118 case 'verticalAlign': |
|
3119 if (value === 'middle') { |
|
3120 value = 'center'; |
|
3121 } |
|
3122 |
|
3123 cellMap.alignment.vertical = value; |
|
3124 break; |
|
3125 } |
|
3126 } |
|
3127 |
|
3128 /** |
|
3129 * Returns an Alpha Red Green Blue color value. |
|
3130 */ |
|
3131 toARGB(color) { |
|
3132 color = color.replace(/\s/g, ''); |
|
3133 |
|
3134 const rgbResult = /rgb\((\d+),(\d+),(\d+)\)/gi.exec(color); |
|
3135 |
|
3136 if (rgbResult !== null) { |
|
3137 const r = parseFloat(rgbResult[1]).toString(16).toUpperCase(), |
|
3138 g = parseFloat(rgbResult[2]).toString(16).toUpperCase(), |
|
3139 b = parseFloat(rgbResult[3]).toString(16).toUpperCase(); |
|
3140 |
|
3141 return 'FF' + ('0').repeat(2 - r.length) + r + |
|
3142 ('0').repeat(2 - g.length) + g + |
|
3143 ('0').repeat(2 - b.length) + b; |
|
3144 } |
|
3145 |
|
3146 const rgbaResult = /rgba\((\d+),(\d+),(\d+)\,(\d*.\d+|\d+)\)/gi.exec(color); |
|
3147 |
|
3148 if (rgbaResult !== null) { |
|
3149 const a = Math.round(parseFloat(rgbaResult[4]) * 255).toString(16).toUpperCase(), |
|
3150 r = parseFloat(rgbaResult[1]).toString(16).toUpperCase(), |
|
3151 g = parseFloat(rgbaResult[2]).toString(16).toUpperCase(), |
|
3152 b = parseFloat(rgbaResult[3]).toString(16).toUpperCase(); |
|
3153 |
|
3154 return ('0').repeat(2 - a.length) + a + |
|
3155 ('0').repeat(2 - r.length) + r + |
|
3156 ('0').repeat(2 - g.length) + g + |
|
3157 ('0').repeat(2 - b.length) + b; |
|
3158 } |
|
3159 |
|
3160 const shortHexResult = /^#(.)(.)(.)$/gi.exec(color); |
|
3161 |
|
3162 if (shortHexResult !== null) { |
|
3163 const r = shortHexResult[1].toUpperCase(), |
|
3164 g = shortHexResult[2].toUpperCase(), |
|
3165 b = shortHexResult[3].toUpperCase(); |
|
3166 |
|
3167 return 'FF' + r + r + g + g + b + b; |
|
3168 } |
|
3169 |
|
3170 return 'FF' + color.toUpperCase().slice(1); |
|
3171 } |
|
3172 |
|
3173 /** |
|
3174 * Adds toggleable functionality. |
|
3175 */ |
|
3176 toggleableFunctionality() { |
|
3177 const that = this; |
|
3178 |
|
3179 if (!that.actualHierarchy) { |
|
3180 return ''; |
|
3181 } |
|
3182 |
|
3183 return `\n <style type="text/css"> |
|
3184 .toggle-element { |
|
3185 width: 5px; |
|
3186 height: 1px; |
|
3187 padding-right: 5px; |
|
3188 float: left; |
|
3189 text-align: right; |
|
3190 cursor: pointer; |
|
3191 user-select: none; |
|
3192 } |
|
3193 |
|
3194 .collapsed { |
|
3195 display: none; |
|
3196 } |
|
3197 </style> |
|
3198 <script type="text/javascript"> |
|
3199 window.onload = function () { |
|
3200 var expandChar = '${that.expandChar}', |
|
3201 collapseChar = '${that.collapseChar}', |
|
3202 toggleElements = document.getElementsByClassName('toggle-element'); |
|
3203 |
|
3204 function getParent(child) { |
|
3205 var prevSibling = child.previousElementSibling; |
|
3206 |
|
3207 while (prevSibling) { |
|
3208 if (child.getAttribute('level') > prevSibling.getAttribute('level')) { |
|
3209 return prevSibling; |
|
3210 } |
|
3211 |
|
3212 prevSibling = prevSibling.previousElementSibling; |
|
3213 } |
|
3214 |
|
3215 } |
|
3216 |
|
3217 function getFirstCollapsedAncestor(child) { |
|
3218 var parent = getParent(child); |
|
3219 |
|
3220 while (parent) { |
|
3221 if (parent.firstElementChild.firstElementChild.innerHTML === expandChar) { |
|
3222 return parent; |
|
3223 } |
|
3224 |
|
3225 parent = getParent(parent); |
|
3226 } |
|
3227 } |
|
3228 |
|
3229 for (var i = 0; i < toggleElements.length; i++) { |
|
3230 toggleElements[i].addEventListener('click', function (event) { |
|
3231 var expanded = this.innerHTML === collapseChar, |
|
3232 row = this.parentElement.parentElement, |
|
3233 sibling = row.nextElementSibling; |
|
3234 |
|
3235 if (expanded) { |
|
3236 this.innerHTML = expandChar; |
|
3237 } |
|
3238 else { |
|
3239 this.innerHTML = collapseChar; |
|
3240 } |
|
3241 |
|
3242 while (sibling && row.getAttribute('level') < sibling.getAttribute('level')) { |
|
3243 if (expanded) { |
|
3244 sibling.style.display = 'none'; |
|
3245 } |
|
3246 else { |
|
3247 var firstCollapsedAncestor = getFirstCollapsedAncestor(sibling); |
|
3248 |
|
3249 if (!firstCollapsedAncestor || firstCollapsedAncestor === row) { |
|
3250 sibling.classList.remove('collapsed'); |
|
3251 sibling.style.display = null; |
|
3252 } |
|
3253 |
|
3254 } |
|
3255 |
|
3256 sibling = sibling.nextElementSibling; |
|
3257 } |
|
3258 }); |
|
3259 } |
|
3260 } |
|
3261 </script>`; |
|
3262 } |
|
3263 |
|
3264 /** |
|
3265 * Generates styles.xml. |
|
3266 */ |
|
3267 generateStyles(style) { |
|
3268 const that = this; |
|
3269 |
|
3270 that.cellStyleMapping = {}; |
|
3271 |
|
3272 if (Object.keys(style).length === 0 && !that.complexHeader) { |
|
3273 // default style |
|
3274 return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
|
3275 <styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac x16r2 xr" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" xmlns:x16r2="http://schemas.microsoft.com/office/spreadsheetml/2015/02/main" xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision"><fonts count="1" x14ac:knownFonts="1"><font><sz val="11"/><color theme="1"/><name val="Calibri"/><family val="2"/><charset val="204"/><scheme val="minor"/></font></fonts><fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills><borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders><cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs><cellXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0"/></cellXfs><cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles>${that.conditionalFormattingXLSX.styles || '<dxfs count="0"/>'}<tableStyles count="0" defaultTableStyle="TableStyleMedium2" defaultPivotStyle="PivotStyleLight16"/><extLst><ext uri="{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"><x14:slicerStyles defaultSlicerStyle="SlicerStyleLight1"/></ext><ext uri="{9260A510-F301-46a8-8635-F512D64BE5F5}" xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"><x15:timelineStyles defaultTimelineStyle="TimeSlicerStyleLight1"/></ext></extLst></styleSheet>`; |
|
3276 } |
|
3277 |
|
3278 that.styleMap = {}; |
|
3279 |
|
3280 for (let i = 0; i < that.data.length; i++) { |
|
3281 for (let j = 0; j < that.columnsArray.length; j++) { |
|
3282 that.styleMap[that.columnsArray[j] + (i + 1)] = { |
|
3283 numFmts: {}, fonts: {}, fills: {}, borders: {}, alignment: {} |
|
3284 } |
|
3285 } |
|
3286 } |
|
3287 |
|
3288 if (style && style.columns) { |
|
3289 for (let i = 0; i < that.columnsArray.length; i++) { |
|
3290 const datafield = that.datafields[i]; |
|
3291 |
|
3292 if (!style.columns[datafield] || !style.columns[datafield].format) { |
|
3293 continue; |
|
3294 } |
|
3295 |
|
3296 const XLSXFormat = that.getXLSXFormat(style.columns[datafield].format, that.data[that.data.length - 1][datafield]); |
|
3297 |
|
3298 if (XLSXFormat) { |
|
3299 style.columns[datafield].numFmt = XLSXFormat; |
|
3300 } |
|
3301 } |
|
3302 } |
|
3303 |
|
3304 that.processRowStyle(style); |
|
3305 that.processColumnStyle(style); |
|
3306 |
|
3307 const cellAliases = {}; |
|
3308 |
|
3309 for (let i = 0; i < that.complexHeaderMergedCells.length; i++) { |
|
3310 const currentCell = that.complexHeaderMergedCells[i]; |
|
3311 |
|
3312 if (parseFloat(currentCell.to[1]) === that.complexHeader.length) { |
|
3313 cellAliases[currentCell.to] = currentCell.from; |
|
3314 continue; |
|
3315 } |
|
3316 |
|
3317 that.styleMap[currentCell.from].alignment.horizontal = 'center'; |
|
3318 that.styleMap[currentCell.from].alignment.vertical = 'center'; |
|
3319 } |
|
3320 |
|
3321 const fonts = { |
|
3322 xml: '<font><sz val="11" /><color theme="1" /><name val="Calibri" /><family val="2" /><charset val="204" /><scheme val="minor" /></font>', |
|
3323 collection: ['default'] |
|
3324 }, |
|
3325 fills = { |
|
3326 xml: '<fill><patternFill patternType="none" /></fill><fill><patternFill patternType="gray125" /></fill>', |
|
3327 collection: ['default', 'gray125'] |
|
3328 }, |
|
3329 numFmts = { |
|
3330 xml: '', |
|
3331 collection: [] |
|
3332 }, |
|
3333 cellXfs = { |
|
3334 xml: '<xf fontId="0" fillId="0" borderId="1"/>', |
|
3335 collection: ['default'] |
|
3336 }; |
|
3337 |
|
3338 for (let i = 0; i < that.data.length; i++) { // iterate rows |
|
3339 for (let j = 0; j < that.columnsArray.length; j++) { // iterate columns |
|
3340 const currentCell = that.columnsArray[j] + (i + 1), |
|
3341 currentCellStyle = that.styleMap[currentCell]; |
|
3342 let currentFont = '', currentFill = '', currentAlignment = '', |
|
3343 currentFontCode = [], currentFillCode = [], currentAlignmentCode = [], xf = []; |
|
3344 |
|
3345 for (let prop in currentCellStyle.fonts) { |
|
3346 if (currentCellStyle.fonts.hasOwnProperty(prop)) { |
|
3347 const value = currentCellStyle.fonts[prop]; |
|
3348 |
|
3349 switch (prop) { |
|
3350 case 'color': |
|
3351 currentFontCode[0] = value; |
|
3352 currentFont += `<color rgb="${that.toARGB(value)}" />`; |
|
3353 break; |
|
3354 case 'name': |
|
3355 currentFontCode[1] = value; |
|
3356 currentFont += `<name val="${value}" />`; |
|
3357 break; |
|
3358 case 'sz': |
|
3359 currentFontCode[2] = value; |
|
3360 currentFont += `<sz val="${value}" />`; |
|
3361 break; |
|
3362 case 'i': |
|
3363 currentFontCode[3] = value; |
|
3364 currentFont += '<i />'; |
|
3365 break; |
|
3366 case 'b': |
|
3367 currentFontCode[4] = value; |
|
3368 currentFont += '<b />'; |
|
3369 break; |
|
3370 case 'u': |
|
3371 currentFontCode[5] = value; |
|
3372 currentFont += '<u />'; |
|
3373 break; |
|
3374 } |
|
3375 } |
|
3376 } |
|
3377 |
|
3378 for (let prop in currentCellStyle.fills) { |
|
3379 if (currentCellStyle.fills.hasOwnProperty(prop)) { |
|
3380 const value = currentCellStyle.fills[prop]; |
|
3381 |
|
3382 switch (prop) { |
|
3383 case 'fgColor': |
|
3384 currentFillCode[0] = value; |
|
3385 currentFill += `<fgColor rgb="${that.toARGB(value)}" />`; |
|
3386 break; |
|
3387 } |
|
3388 } |
|
3389 } |
|
3390 |
|
3391 for (let prop in currentCellStyle.alignment) { |
|
3392 if (currentCellStyle.alignment.hasOwnProperty(prop)) { |
|
3393 const value = currentCellStyle.alignment[prop]; |
|
3394 |
|
3395 switch (prop) { |
|
3396 case 'horizontal': |
|
3397 currentAlignmentCode[0] = value; |
|
3398 currentAlignment += `horizontal="${value}" `; |
|
3399 break; |
|
3400 case 'vertical': |
|
3401 currentAlignmentCode[1] = value; |
|
3402 currentAlignment += `vertical="${value}" `; |
|
3403 break; |
|
3404 } |
|
3405 } |
|
3406 } |
|
3407 |
|
3408 currentFontCode = currentFontCode.toString(); |
|
3409 currentFillCode = currentFillCode.toString(); |
|
3410 |
|
3411 if (currentFont !== '') { |
|
3412 let fontIndex = fonts.collection.indexOf(currentFontCode); |
|
3413 |
|
3414 if (fontIndex === -1) { |
|
3415 fontIndex = fonts.collection.length; |
|
3416 |
|
3417 fonts.xml += '<font>' + currentFont + '</font>'; |
|
3418 fonts.collection.push(currentFontCode); |
|
3419 } |
|
3420 |
|
3421 xf[0] = fontIndex; |
|
3422 } |
|
3423 |
|
3424 if (currentFill !== '') { |
|
3425 let fillIndex = fills.collection.indexOf(currentFillCode); |
|
3426 |
|
3427 if (fillIndex === -1) { |
|
3428 fillIndex = fills.collection.length; |
|
3429 |
|
3430 fills.xml += '<fill><patternFill patternType="solid">' + currentFill + '</patternFill></fill>'; |
|
3431 fills.collection.push(currentFillCode); |
|
3432 } |
|
3433 |
|
3434 xf[1] = fillIndex; |
|
3435 } |
|
3436 |
|
3437 if (currentAlignmentCode.length > 0) { |
|
3438 xf[2] = currentAlignment; |
|
3439 } |
|
3440 |
|
3441 if (currentCellStyle.numFmt !== undefined) { |
|
3442 xf[3] = that.getNumFmtIndex(currentCellStyle.numFmt, numFmts); |
|
3443 } |
|
3444 |
|
3445 const xfCode = xf.toString(); |
|
3446 |
|
3447 if (xfCode !== '') { |
|
3448 let xfIndex = cellXfs.collection.indexOf(xfCode); |
|
3449 |
|
3450 if (xfIndex === -1) { |
|
3451 let newXfXML = '<xf '; |
|
3452 |
|
3453 xfIndex = cellXfs.collection.length; |
|
3454 |
|
3455 if (xf[0] !== undefined) { |
|
3456 newXfXML += `fontId="${xf[0]}" `; |
|
3457 } |
|
3458 |
|
3459 if (xf[1] !== undefined) { |
|
3460 newXfXML += `fillId="${xf[1]}" `; |
|
3461 } |
|
3462 |
|
3463 if (xf[3] !== undefined) { |
|
3464 newXfXML += `numFmtId="${xf[3]}" `; |
|
3465 } |
|
3466 |
|
3467 if (xf[2] !== undefined) { |
|
3468 newXfXML += `applyAlignment="1" borderId="1"><alignment ${currentAlignment}/></xf>`; |
|
3469 } |
|
3470 else { |
|
3471 newXfXML += ' borderId="1"/>'; |
|
3472 } |
|
3473 |
|
3474 cellXfs.xml += newXfXML; |
|
3475 cellXfs.collection.push(xfCode); |
|
3476 } |
|
3477 |
|
3478 that.cellStyleMapping[cellAliases[currentCell] || currentCell] = xfIndex; |
|
3479 } |
|
3480 } |
|
3481 } |
|
3482 |
|
3483 if (numFmts.collection.length) { |
|
3484 numFmts.xml = `<numFmts count="${numFmts.collection.length}">${numFmts.xml}</numFmts>`; |
|
3485 } |
|
3486 |
|
3487 return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
|
3488 <styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac x16r2 xr" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" xmlns:x16r2="http://schemas.microsoft.com/office/spreadsheetml/2015/02/main" xmlns:xr="http://schemas.microsoft.com/office/spreadsheetml/2014/revision">${numFmts.xml}<fonts count="${fonts.collection.length}" x14ac:knownFonts="1">${fonts.xml}</fonts><fills count="${fills.collection.length}">${fills.xml}</fills><borders count="2"><border><left/><right/><top/><bottom/></border><border><left style="hair"/><right style="hair"/><top style="hair"/><bottom style="hair"/><diagonal/></border></borders><cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs><cellXfs count="${cellXfs.collection.length}">${cellXfs.xml}</cellXfs><cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles>${that.conditionalFormattingXLSX.styles}<dxfs count="0"/><tableStyles count="0" defaultTableStyle="TableStyleMedium2" defaultPivotStyle="PivotStyleLight16"/><extLst><ext uri="{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"><x14:slicerStyles defaultSlicerStyle="SlicerStyleLight1"/></ext><ext uri="{9260A510-F301-46a8-8635-F512D64BE5F5}" xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"><x15:timelineStyles defaultTimelineStyle="TimeSlicerStyleLight1"/></ext></extLst></styleSheet>`; |
|
3489 } |
|
3490 } |
|
3491 |
|
3492 if ($.jqx && $.jqx.dataAdapter) { |
|
3493 $.jqx.dataAdapter.DataExporter = DataExporter; |
|
3494 } |
|
3495 })(jqxBaseFramework); |