Sat, 01 Oct 2022 16:16:36 +0200
Upgraded drawing to kicad 6.0.8
617 | 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); |