@slickgrid-universal/excel-export 2.5.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commonjs/excelExport.service.js +572 -572
- package/dist/commonjs/excelUtils.js +258 -258
- package/dist/commonjs/index.js +5 -5
- package/dist/commonjs/interfaces/excelCellFormat.interface.js +2 -2
- package/dist/commonjs/interfaces/excelMetadata.interface.js +2 -2
- package/dist/commonjs/interfaces/excelStylesheet.interface.js +2 -2
- package/dist/commonjs/interfaces/index.js +19 -19
- package/dist/esm/excelExport.service.js +570 -570
- package/dist/esm/excelUtils.js +247 -247
- package/dist/esm/index.js +1 -1
- package/dist/esm/interfaces/excelCellFormat.interface.js +1 -1
- package/dist/esm/interfaces/excelMetadata.interface.js +1 -1
- package/dist/esm/interfaces/excelStylesheet.interface.js +1 -1
- package/dist/esm/interfaces/index.js +3 -3
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/{commonjs → types}/excelExport.service.d.ts +137 -136
- package/dist/types/excelExport.service.d.ts.map +1 -0
- package/dist/{esm → types}/excelUtils.d.ts +32 -31
- package/dist/types/excelUtils.d.ts.map +1 -0
- package/dist/{esm → types}/index.d.ts +2 -1
- package/dist/types/index.d.ts.map +1 -0
- package/dist/{esm → types}/interfaces/excelCellFormat.interface.d.ts +6 -5
- package/dist/types/interfaces/excelCellFormat.interface.d.ts.map +1 -0
- package/dist/{commonjs → types}/interfaces/excelMetadata.interface.d.ts +10 -9
- package/dist/types/interfaces/excelMetadata.interface.d.ts.map +1 -0
- package/dist/{commonjs → types}/interfaces/excelStylesheet.interface.d.ts +34 -33
- package/dist/types/interfaces/excelStylesheet.interface.d.ts.map +1 -0
- package/dist/{commonjs → types}/interfaces/index.d.ts +4 -3
- package/dist/types/interfaces/index.d.ts.map +1 -0
- package/package.json +8 -8
- package/dist/commonjs/excelUtils.d.ts +0 -31
- package/dist/commonjs/index.d.ts +0 -1
- package/dist/commonjs/interfaces/excelCellFormat.interface.d.ts +0 -5
- package/dist/esm/excelExport.service.d.ts +0 -136
- package/dist/esm/interfaces/excelMetadata.interface.d.ts +0 -9
- package/dist/esm/interfaces/excelStylesheet.interface.d.ts +0 -33
- package/dist/esm/interfaces/index.d.ts +0 -3
|
@@ -1,573 +1,573 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ExcelExportService = void 0;
|
|
4
|
-
const ExcelBuilder_ = require("excel-builder-webpacker");
|
|
5
|
-
const ExcelBuilder = ExcelBuilder_['default'] || ExcelBuilder_; // patch to fix rollup "ExcelBuilder has no default export" issue, document here https://github.com/rollup/rollup/issues/670
|
|
6
|
-
const common_1 = require("@slickgrid-universal/common");
|
|
7
|
-
const utils_1 = require("@slickgrid-universal/utils");
|
|
8
|
-
const excelUtils_1 = require("./excelUtils");
|
|
9
|
-
const DEFAULT_EXPORT_OPTIONS = {
|
|
10
|
-
filename: 'export',
|
|
11
|
-
format: common_1.FileType.xlsx
|
|
12
|
-
};
|
|
13
|
-
class ExcelExportService {
|
|
14
|
-
constructor() {
|
|
15
|
-
this._fileFormat = common_1.FileType.xlsx;
|
|
16
|
-
this._columnHeaders = [];
|
|
17
|
-
this._hasColumnTitlePreHeader = false;
|
|
18
|
-
this._hasGroupedItems = false;
|
|
19
|
-
this._pubSubService = null;
|
|
20
|
-
// references of each detected cell and/or group total formats
|
|
21
|
-
this._regularCellExcelFormats = {};
|
|
22
|
-
this._groupTotalExcelFormats = {};
|
|
23
|
-
/** ExcelExportService class name which is use to find service instance in the external registered services */
|
|
24
|
-
this.className = 'ExcelExportService';
|
|
25
|
-
}
|
|
26
|
-
get _datasetIdPropName() {
|
|
27
|
-
var _a, _b;
|
|
28
|
-
return (_b = (_a = this._gridOptions) === null || _a === void 0 ? void 0 : _a.datasetIdPropertyName) !== null && _b !== void 0 ? _b : 'id';
|
|
29
|
-
}
|
|
30
|
-
/** Getter of SlickGrid DataView object */
|
|
31
|
-
get _dataView() {
|
|
32
|
-
var _a;
|
|
33
|
-
return ((_a = this._grid) === null || _a === void 0 ? void 0 : _a.getData());
|
|
34
|
-
}
|
|
35
|
-
/** Getter for the Grid Options pulled through the Grid Object */
|
|
36
|
-
get _gridOptions() {
|
|
37
|
-
var _a;
|
|
38
|
-
return ((_a = this._grid) === null || _a === void 0 ? void 0 : _a.getOptions()) || {};
|
|
39
|
-
}
|
|
40
|
-
get stylesheet() {
|
|
41
|
-
return this._stylesheet;
|
|
42
|
-
}
|
|
43
|
-
get stylesheetFormats() {
|
|
44
|
-
return this._stylesheetFormats;
|
|
45
|
-
}
|
|
46
|
-
get groupTotalExcelFormats() {
|
|
47
|
-
return this._groupTotalExcelFormats;
|
|
48
|
-
}
|
|
49
|
-
get regularCellExcelFormats() {
|
|
50
|
-
return this._regularCellExcelFormats;
|
|
51
|
-
}
|
|
52
|
-
dispose() {
|
|
53
|
-
var _a;
|
|
54
|
-
(_a = this._pubSubService) === null || _a === void 0 ? void 0 : _a.unsubscribeAll();
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Initialize the Export Service
|
|
58
|
-
* @param grid
|
|
59
|
-
* @param containerService
|
|
60
|
-
*/
|
|
61
|
-
init(grid, containerService) {
|
|
62
|
-
var _a, _b, _c;
|
|
63
|
-
this._grid = grid;
|
|
64
|
-
this._pubSubService = containerService.get('PubSubService');
|
|
65
|
-
// get locales provided by user in main file or else use default English locales via the Constants
|
|
66
|
-
this._locales = (_b = (_a = this._gridOptions) === null || _a === void 0 ? void 0 : _a.locales) !== null && _b !== void 0 ? _b : common_1.Constants.locales;
|
|
67
|
-
this._translaterService = (_c = this._gridOptions) === null || _c === void 0 ? void 0 : _c.translater;
|
|
68
|
-
if (this._gridOptions.enableTranslate && (!this._translaterService || !this._translaterService.translate)) {
|
|
69
|
-
throw new Error('[Slickgrid-Universal] requires a Translate Service to be passed in the "translater" Grid Options when "enableTranslate" is enabled. (example: this.gridOptions = { enableTranslate: true, translater: this.translaterService })');
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Function to export the Grid result to an Excel CSV format using javascript for it to produce the CSV file.
|
|
74
|
-
* This is a WYSIWYG export to file output (What You See is What You Get)
|
|
75
|
-
*
|
|
76
|
-
* NOTES: The column position needs to match perfectly the JSON Object position because of the way we are pulling the data,
|
|
77
|
-
* which means that if any column(s) got moved in the UI, it has to be reflected in the JSON array output as well
|
|
78
|
-
*
|
|
79
|
-
* Example: exportToExcel({ format: FileType.csv, delimiter: DelimiterType.comma })
|
|
80
|
-
*/
|
|
81
|
-
exportToExcel(options) {
|
|
82
|
-
var _a;
|
|
83
|
-
if (!this._grid || !this._dataView || !this._pubSubService) {
|
|
84
|
-
throw new Error('[Slickgrid-Universal] it seems that the SlickGrid & DataView objects and/or PubSubService are not initialized did you forget to enable the grid option flag "enableExcelExport"?');
|
|
85
|
-
}
|
|
86
|
-
(_a = this._pubSubService) === null || _a === void 0 ? void 0 : _a.publish(`onBeforeExportToExcel`, true);
|
|
87
|
-
this._excelExportOptions = (0, utils_1.deepCopy)({ ...DEFAULT_EXPORT_OPTIONS, ...this._gridOptions.excelExportOptions, ...options });
|
|
88
|
-
this._fileFormat = this._excelExportOptions.format || common_1.FileType.xlsx;
|
|
89
|
-
// reset references of detected Excel formats
|
|
90
|
-
this._regularCellExcelFormats = {};
|
|
91
|
-
this._groupTotalExcelFormats = {};
|
|
92
|
-
// wrap in a Promise so that we can add loading spinner
|
|
93
|
-
return new Promise(resolve => {
|
|
94
|
-
// prepare the Excel Workbook & Sheet
|
|
95
|
-
// we can use ExcelBuilder constructor with WebPack but we need to use function calls with RequireJS/SystemJS
|
|
96
|
-
const worksheetOptions = { name: this._excelExportOptions.sheetName || 'Sheet1' };
|
|
97
|
-
this._workbook = ExcelBuilder.Workbook ? new ExcelBuilder.Workbook() : ExcelBuilder.createWorkbook();
|
|
98
|
-
this._sheet = ExcelBuilder.Worksheet ? new ExcelBuilder.Worksheet(worksheetOptions) : this._workbook.createWorksheet(worksheetOptions);
|
|
99
|
-
// add any Excel Format/Stylesheet to current Workbook
|
|
100
|
-
this._stylesheet = this._workbook.getStyleSheet();
|
|
101
|
-
// create some common default Excel formatters that will be used
|
|
102
|
-
const boldFormatter = this._stylesheet.createFormat({ font: { bold: true } });
|
|
103
|
-
const stringFormatter = this._stylesheet.createFormat({ format: '@' });
|
|
104
|
-
const numberFormatter = this._stylesheet.createFormat({ format: '0' });
|
|
105
|
-
this._stylesheetFormats = {
|
|
106
|
-
boldFormatter,
|
|
107
|
-
numberFormatter,
|
|
108
|
-
stringFormatter,
|
|
109
|
-
};
|
|
110
|
-
this._sheet.setColumnFormats([boldFormatter]);
|
|
111
|
-
// get the CSV output from the grid data
|
|
112
|
-
const dataOutput = this.getDataOutput();
|
|
113
|
-
// trigger a download file
|
|
114
|
-
// wrap it into a setTimeout so that the EventAggregator has enough time to start a pre-process like showing a spinner
|
|
115
|
-
setTimeout(async () => {
|
|
116
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
117
|
-
if ((_b = (_a = this._gridOptions) === null || _a === void 0 ? void 0 : _a.excelExportOptions) === null || _b === void 0 ? void 0 : _b.customExcelHeader) {
|
|
118
|
-
this._gridOptions.excelExportOptions.customExcelHeader(this._workbook, this._sheet);
|
|
119
|
-
}
|
|
120
|
-
const columns = ((_c = this._grid) === null || _c === void 0 ? void 0 : _c.getColumns()) || [];
|
|
121
|
-
this._sheet.setColumns(this.getColumnStyles(columns));
|
|
122
|
-
const currentSheetData = this._sheet.data;
|
|
123
|
-
let finalOutput = currentSheetData;
|
|
124
|
-
if (Array.isArray(currentSheetData) && Array.isArray(dataOutput)) {
|
|
125
|
-
finalOutput = this._sheet.data.concat(dataOutput);
|
|
126
|
-
}
|
|
127
|
-
this._sheet.setData(finalOutput);
|
|
128
|
-
this._workbook.addWorksheet(this._sheet);
|
|
129
|
-
// using ExcelBuilder.Builder.createFile with WebPack but ExcelBuilder.createFile with RequireJS/SystemJS
|
|
130
|
-
const createFileFn = (_e = (_d = ExcelBuilder.Builder) === null || _d === void 0 ? void 0 : _d.createFile) !== null && _e !== void 0 ? _e : ExcelBuilder.createFile;
|
|
131
|
-
// MIME type could be undefined, if that's the case we'll detect the type by its file extension
|
|
132
|
-
// user could also provide its own mime type, if however an empty string is provided we will consider to be without any MIME type)
|
|
133
|
-
let mimeType = (_f = this._excelExportOptions) === null || _f === void 0 ? void 0 : _f.mimeType;
|
|
134
|
-
if (mimeType === undefined) {
|
|
135
|
-
mimeType = this._fileFormat === common_1.FileType.xls ? 'application/vnd.ms-excel' : 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
|
136
|
-
}
|
|
137
|
-
const createFileOptions = mimeType === '' ? { type: 'blob' } : { type: 'blob', mimeType };
|
|
138
|
-
const excelBlob = await createFileFn(this._workbook, createFileOptions);
|
|
139
|
-
const downloadOptions = {
|
|
140
|
-
filename: `${this._excelExportOptions.filename}.${this._fileFormat}`,
|
|
141
|
-
format: this._fileFormat
|
|
142
|
-
};
|
|
143
|
-
// start downloading but add the Blob property only on the start download not on the event itself
|
|
144
|
-
this.startDownloadFile({ ...downloadOptions, blob: excelBlob, data: this._sheet.data });
|
|
145
|
-
(_g = this._pubSubService) === null || _g === void 0 ? void 0 : _g.publish(`onAfterExportToExcel`, downloadOptions);
|
|
146
|
-
resolve(true);
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Takes a positive integer and returns the corresponding column name.
|
|
152
|
-
* dealing with the Excel column position is a bit tricky since the first 26 columns are single char (A,B,...) but after that it becomes double char (AA,AB,...)
|
|
153
|
-
* so we must first see if we are in the first section of 26 chars, if that is the case we just concatenate 1 (1st row) so it becomes (A1, B1, ...)
|
|
154
|
-
* and again if we go 26, we need to add yet again an extra prefix (AA1, AB1, ...) and so goes the cycle
|
|
155
|
-
* @param {number} colIndex - The positive integer to convert to a column name.
|
|
156
|
-
* @return {string} The column name.
|
|
157
|
-
*/
|
|
158
|
-
getExcelColumnNameByIndex(colIndex) {
|
|
159
|
-
const letters = 'ZABCDEFGHIJKLMNOPQRSTUVWXY';
|
|
160
|
-
let nextPos = Math.floor(colIndex / 26);
|
|
161
|
-
const lastPos = Math.floor(colIndex % 26);
|
|
162
|
-
if (lastPos === 0) {
|
|
163
|
-
nextPos--;
|
|
164
|
-
}
|
|
165
|
-
if (colIndex > 26) {
|
|
166
|
-
return this.getExcelColumnNameByIndex(nextPos) + letters[lastPos];
|
|
167
|
-
}
|
|
168
|
-
return letters[lastPos] + '';
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* Triggers download file with file format.
|
|
172
|
-
* IE(6-10) are not supported
|
|
173
|
-
* All other browsers will use plain javascript on client side to produce a file download.
|
|
174
|
-
* @param options
|
|
175
|
-
*/
|
|
176
|
-
startDownloadFile(options) {
|
|
177
|
-
// when using IE/Edge, then use different download call
|
|
178
|
-
if (typeof navigator.msSaveOrOpenBlob === 'function') {
|
|
179
|
-
navigator.msSaveOrOpenBlob(options.blob, options.filename);
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
// this trick will generate a temp <a /> tag
|
|
183
|
-
// the code will then trigger a hidden click for it to start downloading
|
|
184
|
-
const link = document.createElement('a');
|
|
185
|
-
const url = URL.createObjectURL(options.blob);
|
|
186
|
-
if (link && document) {
|
|
187
|
-
link.textContent = 'download';
|
|
188
|
-
link.href = url;
|
|
189
|
-
link.setAttribute('download', options.filename);
|
|
190
|
-
// set the visibility to hidden so there is no effect on your web-layout
|
|
191
|
-
link.style.visibility = 'hidden';
|
|
192
|
-
// this part will append the anchor tag, trigger a click (for download to start) and finally remove the tag once completed
|
|
193
|
-
document.body.appendChild(link);
|
|
194
|
-
link.click();
|
|
195
|
-
document.body.removeChild(link);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
// -----------------------
|
|
200
|
-
// protected functions
|
|
201
|
-
// -----------------------
|
|
202
|
-
getDataOutput() {
|
|
203
|
-
var _a, _b;
|
|
204
|
-
const columns = ((_a = this._grid) === null || _a === void 0 ? void 0 : _a.getColumns()) || [];
|
|
205
|
-
// data variable which will hold all the fields data of a row
|
|
206
|
-
const outputData = [];
|
|
207
|
-
const gridExportOptions = (_b = this._gridOptions) === null || _b === void 0 ? void 0 : _b.excelExportOptions;
|
|
208
|
-
const columnHeaderStyle = gridExportOptions === null || gridExportOptions === void 0 ? void 0 : gridExportOptions.columnHeaderStyle;
|
|
209
|
-
let columnHeaderStyleId = this._stylesheetFormats.boldFormatter.id;
|
|
210
|
-
if (columnHeaderStyle) {
|
|
211
|
-
columnHeaderStyleId = this._stylesheet.createFormat(columnHeaderStyle).id;
|
|
212
|
-
}
|
|
213
|
-
// get all Grouped Column Header Titles when defined (from pre-header row)
|
|
214
|
-
if (this._gridOptions.createPreHeaderPanel && this._gridOptions.showPreHeaderPanel && !this._gridOptions.enableDraggableGrouping) {
|
|
215
|
-
// when having Grouped Header Titles (in the pre-header), then make the cell Bold & Aligned Center
|
|
216
|
-
const boldCenterAlign = this._stylesheet.createFormat({ alignment: { horizontal: 'center' }, font: { bold: true } });
|
|
217
|
-
outputData.push(this.getColumnGroupedHeaderTitlesData(columns, { style: boldCenterAlign === null || boldCenterAlign === void 0 ? void 0 : boldCenterAlign.id }));
|
|
218
|
-
this._hasColumnTitlePreHeader = true;
|
|
219
|
-
}
|
|
220
|
-
// get all Column Header Titles (it might include a "Group by" title at A1 cell)
|
|
221
|
-
// also style the headers, defaults to Bold but user could pass his own style
|
|
222
|
-
outputData.push(this.getColumnHeaderData(columns, { style: columnHeaderStyleId }));
|
|
223
|
-
// Populate the rest of the Grid Data
|
|
224
|
-
this.pushAllGridRowDataToArray(outputData, columns);
|
|
225
|
-
return outputData;
|
|
226
|
-
}
|
|
227
|
-
/** Get each column style including a style for the width of each column */
|
|
228
|
-
getColumnStyles(columns) {
|
|
229
|
-
var _a, _b, _c;
|
|
230
|
-
const grouping = this._dataView.getGrouping();
|
|
231
|
-
const columnStyles = [];
|
|
232
|
-
if (Array.isArray(grouping) && grouping.length > 0) {
|
|
233
|
-
columnStyles.push({
|
|
234
|
-
bestFit: true,
|
|
235
|
-
columnStyles: (_c = (_b = (_a = this._gridOptions) === null || _a === void 0 ? void 0 : _a.excelExportOptions) === null || _b === void 0 ? void 0 : _b.customColumnWidth) !== null && _c !== void 0 ? _c : 10
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
columns.forEach((columnDef) => {
|
|
239
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
240
|
-
const skippedField = (_a = columnDef.excludeFromExport) !== null && _a !== void 0 ? _a : false;
|
|
241
|
-
// if column width is 0, then we consider that field as a hidden field and should not be part of the export
|
|
242
|
-
if ((columnDef.width === undefined || columnDef.width > 0) && !skippedField) {
|
|
243
|
-
columnStyles.push({
|
|
244
|
-
bestFit: true,
|
|
245
|
-
width: (_g = (_d = (_b = columnDef.exportColumnWidth) !== null && _b !== void 0 ? _b : (_c = columnDef.excelExportOptions) === null || _c === void 0 ? void 0 : _c.width) !== null && _d !== void 0 ? _d : (_f = (_e = this._gridOptions) === null || _e === void 0 ? void 0 : _e.excelExportOptions) === null || _f === void 0 ? void 0 : _f.customColumnWidth) !== null && _g !== void 0 ? _g : 10
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
});
|
|
249
|
-
return columnStyles;
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* Get all Grouped Header Titles and their keys, translate the title when required, and format them in Bold
|
|
253
|
-
* @param {Array<Object>} columns - grid column definitions
|
|
254
|
-
* @param {Object} metadata - Excel metadata
|
|
255
|
-
* @returns {Object} array of Excel cell format
|
|
256
|
-
*/
|
|
257
|
-
getColumnGroupedHeaderTitlesData(columns, metadata) {
|
|
258
|
-
let outputGroupedHeaderTitles = [];
|
|
259
|
-
// get all Column Header Titles
|
|
260
|
-
this._groupedColumnHeaders = this.getColumnGroupedHeaderTitles(columns) || [];
|
|
261
|
-
if (this._groupedColumnHeaders && Array.isArray(this._groupedColumnHeaders) && this._groupedColumnHeaders.length > 0) {
|
|
262
|
-
// add the header row + add a new line at the end of the row
|
|
263
|
-
outputGroupedHeaderTitles = this._groupedColumnHeaders.map((header) => ({ value: header.title, metadata }));
|
|
264
|
-
}
|
|
265
|
-
// merge necessary cells (any grouped header titles)
|
|
266
|
-
let colspanStartIndex = 0;
|
|
267
|
-
const headersLn = this._groupedColumnHeaders.length;
|
|
268
|
-
for (let cellIndex = 0; cellIndex < headersLn; cellIndex++) {
|
|
269
|
-
if ((cellIndex + 1) === headersLn || ((cellIndex + 1) < headersLn && this._groupedColumnHeaders[cellIndex].title !== this._groupedColumnHeaders[cellIndex + 1].title)) {
|
|
270
|
-
const leftExcelColumnChar = this.getExcelColumnNameByIndex(colspanStartIndex + 1);
|
|
271
|
-
const rightExcelColumnChar = this.getExcelColumnNameByIndex(cellIndex + 1);
|
|
272
|
-
this._sheet.mergeCells(`${leftExcelColumnChar}1`, `${rightExcelColumnChar}1`);
|
|
273
|
-
// next group starts 1 column index away
|
|
274
|
-
colspanStartIndex = cellIndex + 1;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
return outputGroupedHeaderTitles;
|
|
278
|
-
}
|
|
279
|
-
/** Get all column headers and format them in Bold */
|
|
280
|
-
getColumnHeaderData(columns, metadata) {
|
|
281
|
-
let outputHeaderTitles = [];
|
|
282
|
-
// get all Column Header Titles
|
|
283
|
-
this._columnHeaders = this.getColumnHeaders(columns) || [];
|
|
284
|
-
if (this._columnHeaders && Array.isArray(this._columnHeaders) && this._columnHeaders.length > 0) {
|
|
285
|
-
// add the header row + add a new line at the end of the row
|
|
286
|
-
outputHeaderTitles = this._columnHeaders.map((header) => ({ value: (0, common_1.sanitizeHtmlToText)(header.title), metadata }));
|
|
287
|
-
}
|
|
288
|
-
// do we have a Group by title?
|
|
289
|
-
const groupTitle = this.getGroupColumnTitle();
|
|
290
|
-
if (groupTitle) {
|
|
291
|
-
outputHeaderTitles.unshift({ value: groupTitle, metadata });
|
|
292
|
-
}
|
|
293
|
-
return outputHeaderTitles;
|
|
294
|
-
}
|
|
295
|
-
getGroupColumnTitle() {
|
|
296
|
-
var _a;
|
|
297
|
-
// Group By text, it could be set in the export options or from translation or if nothing is found then use the English constant text
|
|
298
|
-
let groupByColumnHeader = this._excelExportOptions.groupingColumnHeaderTitle;
|
|
299
|
-
if (!groupByColumnHeader && this._gridOptions.enableTranslate && ((_a = this._translaterService) === null || _a === void 0 ? void 0 : _a.translate)) {
|
|
300
|
-
groupByColumnHeader = this._translaterService.translate(`${(0, common_1.getTranslationPrefix)(this._gridOptions)}GROUP_BY`);
|
|
301
|
-
}
|
|
302
|
-
else if (!groupByColumnHeader) {
|
|
303
|
-
groupByColumnHeader = this._locales && this._locales.TEXT_GROUP_BY;
|
|
304
|
-
}
|
|
305
|
-
// get grouped column titles and if found, we will add a "Group by" column at the first column index
|
|
306
|
-
// if it's a CSV format, we'll escape the text in double quotes
|
|
307
|
-
const grouping = this._dataView.getGrouping();
|
|
308
|
-
if (Array.isArray(grouping) && grouping.length > 0) {
|
|
309
|
-
this._hasGroupedItems = true;
|
|
310
|
-
return groupByColumnHeader;
|
|
311
|
-
}
|
|
312
|
-
else {
|
|
313
|
-
this._hasGroupedItems = false;
|
|
314
|
-
}
|
|
315
|
-
return null;
|
|
316
|
-
}
|
|
317
|
-
/**
|
|
318
|
-
* Get all Grouped Header Titles and their keys, translate the title when required.
|
|
319
|
-
* @param {Array<object>} columns of the grid
|
|
320
|
-
*/
|
|
321
|
-
getColumnGroupedHeaderTitles(columns) {
|
|
322
|
-
const groupedColumnHeaders = [];
|
|
323
|
-
if (columns && Array.isArray(columns)) {
|
|
324
|
-
// Populate the Grouped Column Header, pull the columnGroup(Key) defined
|
|
325
|
-
columns.forEach((columnDef) => {
|
|
326
|
-
var _a;
|
|
327
|
-
let groupedHeaderTitle = '';
|
|
328
|
-
if (columnDef.columnGroupKey && this._gridOptions.enableTranslate && ((_a = this._translaterService) === null || _a === void 0 ? void 0 : _a.translate)) {
|
|
329
|
-
groupedHeaderTitle = this._translaterService.translate(columnDef.columnGroupKey);
|
|
330
|
-
}
|
|
331
|
-
else {
|
|
332
|
-
groupedHeaderTitle = columnDef.columnGroup || '';
|
|
333
|
-
}
|
|
334
|
-
const skippedField = columnDef.excludeFromExport || false;
|
|
335
|
-
// if column width is 0px, then we consider that field as a hidden field and should not be part of the export
|
|
336
|
-
if ((columnDef.width === undefined || columnDef.width > 0) && !skippedField) {
|
|
337
|
-
groupedColumnHeaders.push({
|
|
338
|
-
key: (columnDef.field || columnDef.id),
|
|
339
|
-
title: groupedHeaderTitle || ''
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
});
|
|
343
|
-
}
|
|
344
|
-
return groupedColumnHeaders;
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* Get all header titles and their keys, translate the title when required.
|
|
348
|
-
* @param {Array<object>} columns of the grid
|
|
349
|
-
*/
|
|
350
|
-
getColumnHeaders(columns) {
|
|
351
|
-
const columnHeaders = [];
|
|
352
|
-
if (columns && Array.isArray(columns)) {
|
|
353
|
-
// Populate the Column Header, pull the name defined
|
|
354
|
-
columns.forEach((columnDef) => {
|
|
355
|
-
var _a;
|
|
356
|
-
let headerTitle = '';
|
|
357
|
-
if ((columnDef.nameKey || columnDef.nameKey) && this._gridOptions.enableTranslate && ((_a = this._translaterService) === null || _a === void 0 ? void 0 : _a.translate)) {
|
|
358
|
-
headerTitle = this._translaterService.translate((columnDef.nameKey || columnDef.nameKey));
|
|
359
|
-
}
|
|
360
|
-
else {
|
|
361
|
-
headerTitle = columnDef.name || (0, utils_1.titleCase)(columnDef.field);
|
|
362
|
-
}
|
|
363
|
-
const skippedField = columnDef.excludeFromExport || false;
|
|
364
|
-
// if column width is 0, then we consider that field as a hidden field and should not be part of the export
|
|
365
|
-
if ((columnDef.width === undefined || columnDef.width > 0) && !skippedField) {
|
|
366
|
-
columnHeaders.push({
|
|
367
|
-
key: (columnDef.field || columnDef.id) + '',
|
|
368
|
-
title: headerTitle
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
return columnHeaders;
|
|
374
|
-
}
|
|
375
|
-
/**
|
|
376
|
-
* Get all the grid row data and return that as an output string
|
|
377
|
-
*/
|
|
378
|
-
pushAllGridRowDataToArray(originalDaraArray, columns) {
|
|
379
|
-
const lineCount = this._dataView.getLength();
|
|
380
|
-
// loop through all the grid rows of data
|
|
381
|
-
for (let rowNumber = 0; rowNumber < lineCount; rowNumber++) {
|
|
382
|
-
const itemObj = this._dataView.getItem(rowNumber);
|
|
383
|
-
// make sure we have a filled object AND that the item doesn't include the "getItem" method
|
|
384
|
-
// this happen could happen with an opened Row Detail as it seems to include an empty Slick DataView (we'll just skip those lines)
|
|
385
|
-
if (itemObj && !itemObj.hasOwnProperty('getItem')) {
|
|
386
|
-
// Normal row (not grouped by anything) would have an ID which was predefined in the Grid Columns definition
|
|
387
|
-
if (itemObj[this._datasetIdPropName] !== null && itemObj[this._datasetIdPropName] !== undefined) {
|
|
388
|
-
// get regular row item data
|
|
389
|
-
originalDaraArray.push(this.readRegularRowData(columns, rowNumber, itemObj));
|
|
390
|
-
}
|
|
391
|
-
else if (this._hasGroupedItems && itemObj.__groupTotals === undefined) {
|
|
392
|
-
// get the group row
|
|
393
|
-
originalDaraArray.push([this.readGroupedRowTitle(itemObj)]);
|
|
394
|
-
}
|
|
395
|
-
else if (itemObj.__groupTotals) {
|
|
396
|
-
// else if the row is a Group By and we have agreggators, then a property of '__groupTotals' would exist under that object
|
|
397
|
-
originalDaraArray.push(this.readGroupedTotalRows(columns, itemObj));
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
return originalDaraArray;
|
|
402
|
-
}
|
|
403
|
-
/**
|
|
404
|
-
* Get the data of a regular row (a row without grouping)
|
|
405
|
-
* @param {Array<Object>} columns - column definitions
|
|
406
|
-
* @param {Number} row - row index
|
|
407
|
-
* @param {Object} itemObj - item datacontext object
|
|
408
|
-
*/
|
|
409
|
-
readRegularRowData(columns, row, itemObj) {
|
|
410
|
-
var _a, _b, _c;
|
|
411
|
-
let idx = 0;
|
|
412
|
-
const rowOutputStrings = [];
|
|
413
|
-
const columnsLn = columns.length;
|
|
414
|
-
let prevColspan = 1;
|
|
415
|
-
let colspanStartIndex = 0;
|
|
416
|
-
const itemMetadata = this._dataView.getItemMetadata(row);
|
|
417
|
-
for (let col = 0; col < columnsLn; col++) {
|
|
418
|
-
const columnDef = columns[col];
|
|
419
|
-
// skip excluded column
|
|
420
|
-
if (columnDef.excludeFromExport) {
|
|
421
|
-
continue;
|
|
422
|
-
}
|
|
423
|
-
// if we are grouping and are on 1st column index, we need to skip this column since it will be used later by the grouping text:: Group by [columnX]
|
|
424
|
-
if (this._hasGroupedItems && idx === 0) {
|
|
425
|
-
rowOutputStrings.push('');
|
|
426
|
-
}
|
|
427
|
-
let colspan = 1;
|
|
428
|
-
let colspanColumnId;
|
|
429
|
-
if (itemMetadata === null || itemMetadata === void 0 ? void 0 : itemMetadata.columns) {
|
|
430
|
-
const metadata = itemMetadata.columns;
|
|
431
|
-
const columnData = metadata[columnDef.id] || metadata[col];
|
|
432
|
-
if (!((!isNaN(prevColspan) && +prevColspan > 1) || (prevColspan === '*' && col > 0))) {
|
|
433
|
-
prevColspan = (_a = columnData === null || columnData === void 0 ? void 0 : columnData.colspan) !== null && _a !== void 0 ? _a : 1;
|
|
434
|
-
}
|
|
435
|
-
if (prevColspan === '*') {
|
|
436
|
-
colspan = columns.length - col;
|
|
437
|
-
}
|
|
438
|
-
else {
|
|
439
|
-
colspan = prevColspan;
|
|
440
|
-
if (columnDef.id in metadata) {
|
|
441
|
-
colspanColumnId = columnDef.id;
|
|
442
|
-
colspanStartIndex = col;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
// when using grid with colspan, we will merge some cells together
|
|
447
|
-
if ((prevColspan === '*' && col > 0) || ((!isNaN(prevColspan) && +prevColspan > 1) && columnDef.id !== colspanColumnId)) {
|
|
448
|
-
// -- Merge Data
|
|
449
|
-
// Excel row starts at 2 or at 3 when dealing with pre-header grouping
|
|
450
|
-
const excelRowNumber = row + (this._hasColumnTitlePreHeader ? 3 : 2);
|
|
451
|
-
if (typeof prevColspan === 'number' && (colspan - 1) === 1) {
|
|
452
|
-
// partial column span
|
|
453
|
-
const leftExcelColumnChar = this.getExcelColumnNameByIndex(colspanStartIndex + 1);
|
|
454
|
-
const rightExcelColumnChar = this.getExcelColumnNameByIndex(col + 1);
|
|
455
|
-
this._sheet.mergeCells(`${leftExcelColumnChar}${excelRowNumber}`, `${rightExcelColumnChar}${excelRowNumber}`);
|
|
456
|
-
rowOutputStrings.push(''); // clear cell that won't be shown by a cell merge
|
|
457
|
-
}
|
|
458
|
-
else if (prevColspan === '*' && colspan === 1) {
|
|
459
|
-
// full column span (from A1 until the last column)
|
|
460
|
-
const rightExcelColumnChar = this.getExcelColumnNameByIndex(col + 1);
|
|
461
|
-
this._sheet.mergeCells(`A${excelRowNumber}`, `${rightExcelColumnChar}${excelRowNumber}`);
|
|
462
|
-
}
|
|
463
|
-
else {
|
|
464
|
-
rowOutputStrings.push(''); // clear cell that won't be shown by a cell merge
|
|
465
|
-
}
|
|
466
|
-
// decrement colspan until we reach colspan of 1 then proceed with cell merge OR full row merge when colspan is (*)
|
|
467
|
-
if (typeof prevColspan === 'number' && (!isNaN(prevColspan) && +prevColspan > 1)) {
|
|
468
|
-
colspan = prevColspan--;
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
else {
|
|
472
|
-
let itemData = '';
|
|
473
|
-
const fieldType = (0, common_1.getColumnFieldType)(columnDef);
|
|
474
|
-
// -- Read Data & Push to Data Array
|
|
475
|
-
// user might want to export with Formatter, and/or auto-detect Excel format, and/or export as regular cell data
|
|
476
|
-
// for column that are Date type, we'll always export with their associated Date Formatters unless `exportWithFormatter` is specifically set to false
|
|
477
|
-
const exportOptions = { ...this._excelExportOptions };
|
|
478
|
-
if ((columnDef === null || columnDef === void 0 ? void 0 : columnDef.exportWithFormatter) !== false && (0, common_1.isColumnDateType)(fieldType)) {
|
|
479
|
-
exportOptions.exportWithFormatter = true;
|
|
480
|
-
}
|
|
481
|
-
itemData = (0, common_1.exportWithFormatterWhenDefined)(row, col, columnDef, itemObj, this._grid, exportOptions);
|
|
482
|
-
// auto-detect best possible Excel format, unless the user provide his own formatting,
|
|
483
|
-
// we only do this check once per column (everything after that will be pull from temp ref)
|
|
484
|
-
if (!this._regularCellExcelFormats.hasOwnProperty(columnDef.id)) {
|
|
485
|
-
const cellStyleFormat = (0, excelUtils_1.useCellFormatByFieldType)(this._stylesheet, this._stylesheetFormats, columnDef, this._grid);
|
|
486
|
-
// user could also override style and/or valueParserCallback
|
|
487
|
-
if ((_b = columnDef.excelExportOptions) === null || _b === void 0 ? void 0 : _b.style) {
|
|
488
|
-
cellStyleFormat.stylesheetFormatterId = this._stylesheet.createFormat(columnDef.excelExportOptions.style).id;
|
|
489
|
-
}
|
|
490
|
-
if ((_c = columnDef.excelExportOptions) === null || _c === void 0 ? void 0 : _c.valueParserCallback) {
|
|
491
|
-
cellStyleFormat.getDataValueParser = columnDef.excelExportOptions.valueParserCallback;
|
|
492
|
-
}
|
|
493
|
-
this._regularCellExcelFormats[columnDef.id] = cellStyleFormat;
|
|
494
|
-
}
|
|
495
|
-
// sanitize early, when enabled, any HTML tags (remove HTML tags)
|
|
496
|
-
if (typeof itemData === 'string' && (columnDef.sanitizeDataExport || this._excelExportOptions.sanitizeDataExport)) {
|
|
497
|
-
itemData = (0, common_1.sanitizeHtmlToText)(itemData);
|
|
498
|
-
}
|
|
499
|
-
const { stylesheetFormatterId, getDataValueParser } = this._regularCellExcelFormats[columnDef.id];
|
|
500
|
-
itemData = getDataValueParser(itemData, columnDef, stylesheetFormatterId, this._stylesheet, this._gridOptions);
|
|
501
|
-
rowOutputStrings.push(itemData);
|
|
502
|
-
idx++;
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
return rowOutputStrings;
|
|
506
|
-
}
|
|
507
|
-
/**
|
|
508
|
-
* Get the grouped title(s) and its group title formatter, for example if we grouped by salesRep, the returned result would be:: 'Sales Rep: John Dow (2 items)'
|
|
509
|
-
* @param itemObj
|
|
510
|
-
*/
|
|
511
|
-
readGroupedRowTitle(itemObj) {
|
|
512
|
-
const groupName = (0, common_1.sanitizeHtmlToText)(itemObj.title);
|
|
513
|
-
if (this._excelExportOptions && this._excelExportOptions.addGroupIndentation) {
|
|
514
|
-
const collapsedSymbol = this._excelExportOptions && this._excelExportOptions.groupCollapsedSymbol || '⮞';
|
|
515
|
-
const expandedSymbol = this._excelExportOptions && this._excelExportOptions.groupExpandedSymbol || '⮟';
|
|
516
|
-
const chevron = itemObj.collapsed ? collapsedSymbol : expandedSymbol;
|
|
517
|
-
return chevron + ' ' + (0, utils_1.addWhiteSpaces)(5 * itemObj.level) + groupName;
|
|
518
|
-
}
|
|
519
|
-
return groupName;
|
|
520
|
-
}
|
|
521
|
-
/**
|
|
522
|
-
* Get the grouped totals (below the regular rows), these are set by Slick Aggregators.
|
|
523
|
-
* For example if we grouped by "salesRep" and we have a Sum Aggregator on "sales", then the returned output would be:: ["Sum 123$"]
|
|
524
|
-
* @param itemObj
|
|
525
|
-
*/
|
|
526
|
-
readGroupedTotalRows(columns, itemObj) {
|
|
527
|
-
const groupingAggregatorRowText = this._excelExportOptions.groupingAggregatorRowText || '';
|
|
528
|
-
const outputStrings = [groupingAggregatorRowText];
|
|
529
|
-
columns.forEach((columnDef) => {
|
|
530
|
-
var _a, _b, _c, _d, _e;
|
|
531
|
-
let itemData = '';
|
|
532
|
-
const fieldType = (0, common_1.getColumnFieldType)(columnDef);
|
|
533
|
-
const skippedField = columnDef.excludeFromExport || false;
|
|
534
|
-
// if there's a exportCustomGroupTotalsFormatter or groupTotalsFormatter, we will re-run it to get the exact same output as what is shown in UI
|
|
535
|
-
if (columnDef.exportCustomGroupTotalsFormatter) {
|
|
536
|
-
itemData = columnDef.exportCustomGroupTotalsFormatter(itemObj, columnDef, this._grid);
|
|
537
|
-
}
|
|
538
|
-
// auto-detect best possible Excel format for Group Totals, unless the user provide his own formatting,
|
|
539
|
-
// we only do this check once per column (everything after that will be pull from temp ref)
|
|
540
|
-
if (fieldType === common_1.FieldType.number) {
|
|
541
|
-
let groupCellFormat = this._groupTotalExcelFormats[columnDef.id];
|
|
542
|
-
if (!(groupCellFormat === null || groupCellFormat === void 0 ? void 0 : groupCellFormat.groupType)) {
|
|
543
|
-
groupCellFormat = (0, excelUtils_1.getExcelFormatFromGridFormatter)(this._stylesheet, this._stylesheetFormats, columnDef, this._grid, 'group');
|
|
544
|
-
if ((_a = columnDef.groupTotalsExcelExportOptions) === null || _a === void 0 ? void 0 : _a.style) {
|
|
545
|
-
groupCellFormat.stylesheetFormatter = this._stylesheet.createFormat(columnDef.groupTotalsExcelExportOptions.style);
|
|
546
|
-
}
|
|
547
|
-
this._groupTotalExcelFormats[columnDef.id] = groupCellFormat;
|
|
548
|
-
}
|
|
549
|
-
const groupTotalParser = (_c = (_b = columnDef.groupTotalsExcelExportOptions) === null || _b === void 0 ? void 0 : _b.valueParserCallback) !== null && _c !== void 0 ? _c : excelUtils_1.getGroupTotalValue;
|
|
550
|
-
if (((_d = itemObj[groupCellFormat.groupType]) === null || _d === void 0 ? void 0 : _d[columnDef.field]) !== undefined) {
|
|
551
|
-
itemData = {
|
|
552
|
-
value: groupTotalParser(itemObj, columnDef, groupCellFormat.groupType, this._stylesheet),
|
|
553
|
-
metadata: { style: (_e = groupCellFormat.stylesheetFormatter) === null || _e === void 0 ? void 0 : _e.id }
|
|
554
|
-
};
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
else if (columnDef.groupTotalsFormatter) {
|
|
558
|
-
itemData = columnDef.groupTotalsFormatter(itemObj, columnDef, this._grid);
|
|
559
|
-
}
|
|
560
|
-
// does the user want to sanitize the output data (remove HTML tags)?
|
|
561
|
-
if (typeof itemData === 'string' && (columnDef.sanitizeDataExport || this._excelExportOptions.sanitizeDataExport)) {
|
|
562
|
-
itemData = (0, common_1.sanitizeHtmlToText)(itemData);
|
|
563
|
-
}
|
|
564
|
-
// add the column (unless user wants to skip it)
|
|
565
|
-
if ((columnDef.width === undefined || columnDef.width > 0) && !skippedField) {
|
|
566
|
-
outputStrings.push(itemData);
|
|
567
|
-
}
|
|
568
|
-
});
|
|
569
|
-
return outputStrings;
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
exports.ExcelExportService = ExcelExportService;
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExcelExportService = void 0;
|
|
4
|
+
const ExcelBuilder_ = require("excel-builder-webpacker");
|
|
5
|
+
const ExcelBuilder = ExcelBuilder_['default'] || ExcelBuilder_; // patch to fix rollup "ExcelBuilder has no default export" issue, document here https://github.com/rollup/rollup/issues/670
|
|
6
|
+
const common_1 = require("@slickgrid-universal/common");
|
|
7
|
+
const utils_1 = require("@slickgrid-universal/utils");
|
|
8
|
+
const excelUtils_1 = require("./excelUtils");
|
|
9
|
+
const DEFAULT_EXPORT_OPTIONS = {
|
|
10
|
+
filename: 'export',
|
|
11
|
+
format: common_1.FileType.xlsx
|
|
12
|
+
};
|
|
13
|
+
class ExcelExportService {
|
|
14
|
+
constructor() {
|
|
15
|
+
this._fileFormat = common_1.FileType.xlsx;
|
|
16
|
+
this._columnHeaders = [];
|
|
17
|
+
this._hasColumnTitlePreHeader = false;
|
|
18
|
+
this._hasGroupedItems = false;
|
|
19
|
+
this._pubSubService = null;
|
|
20
|
+
// references of each detected cell and/or group total formats
|
|
21
|
+
this._regularCellExcelFormats = {};
|
|
22
|
+
this._groupTotalExcelFormats = {};
|
|
23
|
+
/** ExcelExportService class name which is use to find service instance in the external registered services */
|
|
24
|
+
this.className = 'ExcelExportService';
|
|
25
|
+
}
|
|
26
|
+
get _datasetIdPropName() {
|
|
27
|
+
var _a, _b;
|
|
28
|
+
return (_b = (_a = this._gridOptions) === null || _a === void 0 ? void 0 : _a.datasetIdPropertyName) !== null && _b !== void 0 ? _b : 'id';
|
|
29
|
+
}
|
|
30
|
+
/** Getter of SlickGrid DataView object */
|
|
31
|
+
get _dataView() {
|
|
32
|
+
var _a;
|
|
33
|
+
return ((_a = this._grid) === null || _a === void 0 ? void 0 : _a.getData());
|
|
34
|
+
}
|
|
35
|
+
/** Getter for the Grid Options pulled through the Grid Object */
|
|
36
|
+
get _gridOptions() {
|
|
37
|
+
var _a;
|
|
38
|
+
return ((_a = this._grid) === null || _a === void 0 ? void 0 : _a.getOptions()) || {};
|
|
39
|
+
}
|
|
40
|
+
get stylesheet() {
|
|
41
|
+
return this._stylesheet;
|
|
42
|
+
}
|
|
43
|
+
get stylesheetFormats() {
|
|
44
|
+
return this._stylesheetFormats;
|
|
45
|
+
}
|
|
46
|
+
get groupTotalExcelFormats() {
|
|
47
|
+
return this._groupTotalExcelFormats;
|
|
48
|
+
}
|
|
49
|
+
get regularCellExcelFormats() {
|
|
50
|
+
return this._regularCellExcelFormats;
|
|
51
|
+
}
|
|
52
|
+
dispose() {
|
|
53
|
+
var _a;
|
|
54
|
+
(_a = this._pubSubService) === null || _a === void 0 ? void 0 : _a.unsubscribeAll();
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Initialize the Export Service
|
|
58
|
+
* @param grid
|
|
59
|
+
* @param containerService
|
|
60
|
+
*/
|
|
61
|
+
init(grid, containerService) {
|
|
62
|
+
var _a, _b, _c;
|
|
63
|
+
this._grid = grid;
|
|
64
|
+
this._pubSubService = containerService.get('PubSubService');
|
|
65
|
+
// get locales provided by user in main file or else use default English locales via the Constants
|
|
66
|
+
this._locales = (_b = (_a = this._gridOptions) === null || _a === void 0 ? void 0 : _a.locales) !== null && _b !== void 0 ? _b : common_1.Constants.locales;
|
|
67
|
+
this._translaterService = (_c = this._gridOptions) === null || _c === void 0 ? void 0 : _c.translater;
|
|
68
|
+
if (this._gridOptions.enableTranslate && (!this._translaterService || !this._translaterService.translate)) {
|
|
69
|
+
throw new Error('[Slickgrid-Universal] requires a Translate Service to be passed in the "translater" Grid Options when "enableTranslate" is enabled. (example: this.gridOptions = { enableTranslate: true, translater: this.translaterService })');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Function to export the Grid result to an Excel CSV format using javascript for it to produce the CSV file.
|
|
74
|
+
* This is a WYSIWYG export to file output (What You See is What You Get)
|
|
75
|
+
*
|
|
76
|
+
* NOTES: The column position needs to match perfectly the JSON Object position because of the way we are pulling the data,
|
|
77
|
+
* which means that if any column(s) got moved in the UI, it has to be reflected in the JSON array output as well
|
|
78
|
+
*
|
|
79
|
+
* Example: exportToExcel({ format: FileType.csv, delimiter: DelimiterType.comma })
|
|
80
|
+
*/
|
|
81
|
+
exportToExcel(options) {
|
|
82
|
+
var _a;
|
|
83
|
+
if (!this._grid || !this._dataView || !this._pubSubService) {
|
|
84
|
+
throw new Error('[Slickgrid-Universal] it seems that the SlickGrid & DataView objects and/or PubSubService are not initialized did you forget to enable the grid option flag "enableExcelExport"?');
|
|
85
|
+
}
|
|
86
|
+
(_a = this._pubSubService) === null || _a === void 0 ? void 0 : _a.publish(`onBeforeExportToExcel`, true);
|
|
87
|
+
this._excelExportOptions = (0, utils_1.deepCopy)({ ...DEFAULT_EXPORT_OPTIONS, ...this._gridOptions.excelExportOptions, ...options });
|
|
88
|
+
this._fileFormat = this._excelExportOptions.format || common_1.FileType.xlsx;
|
|
89
|
+
// reset references of detected Excel formats
|
|
90
|
+
this._regularCellExcelFormats = {};
|
|
91
|
+
this._groupTotalExcelFormats = {};
|
|
92
|
+
// wrap in a Promise so that we can add loading spinner
|
|
93
|
+
return new Promise(resolve => {
|
|
94
|
+
// prepare the Excel Workbook & Sheet
|
|
95
|
+
// we can use ExcelBuilder constructor with WebPack but we need to use function calls with RequireJS/SystemJS
|
|
96
|
+
const worksheetOptions = { name: this._excelExportOptions.sheetName || 'Sheet1' };
|
|
97
|
+
this._workbook = ExcelBuilder.Workbook ? new ExcelBuilder.Workbook() : ExcelBuilder.createWorkbook();
|
|
98
|
+
this._sheet = ExcelBuilder.Worksheet ? new ExcelBuilder.Worksheet(worksheetOptions) : this._workbook.createWorksheet(worksheetOptions);
|
|
99
|
+
// add any Excel Format/Stylesheet to current Workbook
|
|
100
|
+
this._stylesheet = this._workbook.getStyleSheet();
|
|
101
|
+
// create some common default Excel formatters that will be used
|
|
102
|
+
const boldFormatter = this._stylesheet.createFormat({ font: { bold: true } });
|
|
103
|
+
const stringFormatter = this._stylesheet.createFormat({ format: '@' });
|
|
104
|
+
const numberFormatter = this._stylesheet.createFormat({ format: '0' });
|
|
105
|
+
this._stylesheetFormats = {
|
|
106
|
+
boldFormatter,
|
|
107
|
+
numberFormatter,
|
|
108
|
+
stringFormatter,
|
|
109
|
+
};
|
|
110
|
+
this._sheet.setColumnFormats([boldFormatter]);
|
|
111
|
+
// get the CSV output from the grid data
|
|
112
|
+
const dataOutput = this.getDataOutput();
|
|
113
|
+
// trigger a download file
|
|
114
|
+
// wrap it into a setTimeout so that the EventAggregator has enough time to start a pre-process like showing a spinner
|
|
115
|
+
setTimeout(async () => {
|
|
116
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
117
|
+
if ((_b = (_a = this._gridOptions) === null || _a === void 0 ? void 0 : _a.excelExportOptions) === null || _b === void 0 ? void 0 : _b.customExcelHeader) {
|
|
118
|
+
this._gridOptions.excelExportOptions.customExcelHeader(this._workbook, this._sheet);
|
|
119
|
+
}
|
|
120
|
+
const columns = ((_c = this._grid) === null || _c === void 0 ? void 0 : _c.getColumns()) || [];
|
|
121
|
+
this._sheet.setColumns(this.getColumnStyles(columns));
|
|
122
|
+
const currentSheetData = this._sheet.data;
|
|
123
|
+
let finalOutput = currentSheetData;
|
|
124
|
+
if (Array.isArray(currentSheetData) && Array.isArray(dataOutput)) {
|
|
125
|
+
finalOutput = this._sheet.data.concat(dataOutput);
|
|
126
|
+
}
|
|
127
|
+
this._sheet.setData(finalOutput);
|
|
128
|
+
this._workbook.addWorksheet(this._sheet);
|
|
129
|
+
// using ExcelBuilder.Builder.createFile with WebPack but ExcelBuilder.createFile with RequireJS/SystemJS
|
|
130
|
+
const createFileFn = (_e = (_d = ExcelBuilder.Builder) === null || _d === void 0 ? void 0 : _d.createFile) !== null && _e !== void 0 ? _e : ExcelBuilder.createFile;
|
|
131
|
+
// MIME type could be undefined, if that's the case we'll detect the type by its file extension
|
|
132
|
+
// user could also provide its own mime type, if however an empty string is provided we will consider to be without any MIME type)
|
|
133
|
+
let mimeType = (_f = this._excelExportOptions) === null || _f === void 0 ? void 0 : _f.mimeType;
|
|
134
|
+
if (mimeType === undefined) {
|
|
135
|
+
mimeType = this._fileFormat === common_1.FileType.xls ? 'application/vnd.ms-excel' : 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
|
136
|
+
}
|
|
137
|
+
const createFileOptions = mimeType === '' ? { type: 'blob' } : { type: 'blob', mimeType };
|
|
138
|
+
const excelBlob = await createFileFn(this._workbook, createFileOptions);
|
|
139
|
+
const downloadOptions = {
|
|
140
|
+
filename: `${this._excelExportOptions.filename}.${this._fileFormat}`,
|
|
141
|
+
format: this._fileFormat
|
|
142
|
+
};
|
|
143
|
+
// start downloading but add the Blob property only on the start download not on the event itself
|
|
144
|
+
this.startDownloadFile({ ...downloadOptions, blob: excelBlob, data: this._sheet.data });
|
|
145
|
+
(_g = this._pubSubService) === null || _g === void 0 ? void 0 : _g.publish(`onAfterExportToExcel`, downloadOptions);
|
|
146
|
+
resolve(true);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Takes a positive integer and returns the corresponding column name.
|
|
152
|
+
* dealing with the Excel column position is a bit tricky since the first 26 columns are single char (A,B,...) but after that it becomes double char (AA,AB,...)
|
|
153
|
+
* so we must first see if we are in the first section of 26 chars, if that is the case we just concatenate 1 (1st row) so it becomes (A1, B1, ...)
|
|
154
|
+
* and again if we go 26, we need to add yet again an extra prefix (AA1, AB1, ...) and so goes the cycle
|
|
155
|
+
* @param {number} colIndex - The positive integer to convert to a column name.
|
|
156
|
+
* @return {string} The column name.
|
|
157
|
+
*/
|
|
158
|
+
getExcelColumnNameByIndex(colIndex) {
|
|
159
|
+
const letters = 'ZABCDEFGHIJKLMNOPQRSTUVWXY';
|
|
160
|
+
let nextPos = Math.floor(colIndex / 26);
|
|
161
|
+
const lastPos = Math.floor(colIndex % 26);
|
|
162
|
+
if (lastPos === 0) {
|
|
163
|
+
nextPos--;
|
|
164
|
+
}
|
|
165
|
+
if (colIndex > 26) {
|
|
166
|
+
return this.getExcelColumnNameByIndex(nextPos) + letters[lastPos];
|
|
167
|
+
}
|
|
168
|
+
return letters[lastPos] + '';
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Triggers download file with file format.
|
|
172
|
+
* IE(6-10) are not supported
|
|
173
|
+
* All other browsers will use plain javascript on client side to produce a file download.
|
|
174
|
+
* @param options
|
|
175
|
+
*/
|
|
176
|
+
startDownloadFile(options) {
|
|
177
|
+
// when using IE/Edge, then use different download call
|
|
178
|
+
if (typeof navigator.msSaveOrOpenBlob === 'function') {
|
|
179
|
+
navigator.msSaveOrOpenBlob(options.blob, options.filename);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
// this trick will generate a temp <a /> tag
|
|
183
|
+
// the code will then trigger a hidden click for it to start downloading
|
|
184
|
+
const link = document.createElement('a');
|
|
185
|
+
const url = URL.createObjectURL(options.blob);
|
|
186
|
+
if (link && document) {
|
|
187
|
+
link.textContent = 'download';
|
|
188
|
+
link.href = url;
|
|
189
|
+
link.setAttribute('download', options.filename);
|
|
190
|
+
// set the visibility to hidden so there is no effect on your web-layout
|
|
191
|
+
link.style.visibility = 'hidden';
|
|
192
|
+
// this part will append the anchor tag, trigger a click (for download to start) and finally remove the tag once completed
|
|
193
|
+
document.body.appendChild(link);
|
|
194
|
+
link.click();
|
|
195
|
+
document.body.removeChild(link);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// -----------------------
|
|
200
|
+
// protected functions
|
|
201
|
+
// -----------------------
|
|
202
|
+
getDataOutput() {
|
|
203
|
+
var _a, _b;
|
|
204
|
+
const columns = ((_a = this._grid) === null || _a === void 0 ? void 0 : _a.getColumns()) || [];
|
|
205
|
+
// data variable which will hold all the fields data of a row
|
|
206
|
+
const outputData = [];
|
|
207
|
+
const gridExportOptions = (_b = this._gridOptions) === null || _b === void 0 ? void 0 : _b.excelExportOptions;
|
|
208
|
+
const columnHeaderStyle = gridExportOptions === null || gridExportOptions === void 0 ? void 0 : gridExportOptions.columnHeaderStyle;
|
|
209
|
+
let columnHeaderStyleId = this._stylesheetFormats.boldFormatter.id;
|
|
210
|
+
if (columnHeaderStyle) {
|
|
211
|
+
columnHeaderStyleId = this._stylesheet.createFormat(columnHeaderStyle).id;
|
|
212
|
+
}
|
|
213
|
+
// get all Grouped Column Header Titles when defined (from pre-header row)
|
|
214
|
+
if (this._gridOptions.createPreHeaderPanel && this._gridOptions.showPreHeaderPanel && !this._gridOptions.enableDraggableGrouping) {
|
|
215
|
+
// when having Grouped Header Titles (in the pre-header), then make the cell Bold & Aligned Center
|
|
216
|
+
const boldCenterAlign = this._stylesheet.createFormat({ alignment: { horizontal: 'center' }, font: { bold: true } });
|
|
217
|
+
outputData.push(this.getColumnGroupedHeaderTitlesData(columns, { style: boldCenterAlign === null || boldCenterAlign === void 0 ? void 0 : boldCenterAlign.id }));
|
|
218
|
+
this._hasColumnTitlePreHeader = true;
|
|
219
|
+
}
|
|
220
|
+
// get all Column Header Titles (it might include a "Group by" title at A1 cell)
|
|
221
|
+
// also style the headers, defaults to Bold but user could pass his own style
|
|
222
|
+
outputData.push(this.getColumnHeaderData(columns, { style: columnHeaderStyleId }));
|
|
223
|
+
// Populate the rest of the Grid Data
|
|
224
|
+
this.pushAllGridRowDataToArray(outputData, columns);
|
|
225
|
+
return outputData;
|
|
226
|
+
}
|
|
227
|
+
/** Get each column style including a style for the width of each column */
|
|
228
|
+
getColumnStyles(columns) {
|
|
229
|
+
var _a, _b, _c;
|
|
230
|
+
const grouping = this._dataView.getGrouping();
|
|
231
|
+
const columnStyles = [];
|
|
232
|
+
if (Array.isArray(grouping) && grouping.length > 0) {
|
|
233
|
+
columnStyles.push({
|
|
234
|
+
bestFit: true,
|
|
235
|
+
columnStyles: (_c = (_b = (_a = this._gridOptions) === null || _a === void 0 ? void 0 : _a.excelExportOptions) === null || _b === void 0 ? void 0 : _b.customColumnWidth) !== null && _c !== void 0 ? _c : 10
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
columns.forEach((columnDef) => {
|
|
239
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
240
|
+
const skippedField = (_a = columnDef.excludeFromExport) !== null && _a !== void 0 ? _a : false;
|
|
241
|
+
// if column width is 0, then we consider that field as a hidden field and should not be part of the export
|
|
242
|
+
if ((columnDef.width === undefined || columnDef.width > 0) && !skippedField) {
|
|
243
|
+
columnStyles.push({
|
|
244
|
+
bestFit: true,
|
|
245
|
+
width: (_g = (_d = (_b = columnDef.exportColumnWidth) !== null && _b !== void 0 ? _b : (_c = columnDef.excelExportOptions) === null || _c === void 0 ? void 0 : _c.width) !== null && _d !== void 0 ? _d : (_f = (_e = this._gridOptions) === null || _e === void 0 ? void 0 : _e.excelExportOptions) === null || _f === void 0 ? void 0 : _f.customColumnWidth) !== null && _g !== void 0 ? _g : 10
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
return columnStyles;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Get all Grouped Header Titles and their keys, translate the title when required, and format them in Bold
|
|
253
|
+
* @param {Array<Object>} columns - grid column definitions
|
|
254
|
+
* @param {Object} metadata - Excel metadata
|
|
255
|
+
* @returns {Object} array of Excel cell format
|
|
256
|
+
*/
|
|
257
|
+
getColumnGroupedHeaderTitlesData(columns, metadata) {
|
|
258
|
+
let outputGroupedHeaderTitles = [];
|
|
259
|
+
// get all Column Header Titles
|
|
260
|
+
this._groupedColumnHeaders = this.getColumnGroupedHeaderTitles(columns) || [];
|
|
261
|
+
if (this._groupedColumnHeaders && Array.isArray(this._groupedColumnHeaders) && this._groupedColumnHeaders.length > 0) {
|
|
262
|
+
// add the header row + add a new line at the end of the row
|
|
263
|
+
outputGroupedHeaderTitles = this._groupedColumnHeaders.map((header) => ({ value: header.title, metadata }));
|
|
264
|
+
}
|
|
265
|
+
// merge necessary cells (any grouped header titles)
|
|
266
|
+
let colspanStartIndex = 0;
|
|
267
|
+
const headersLn = this._groupedColumnHeaders.length;
|
|
268
|
+
for (let cellIndex = 0; cellIndex < headersLn; cellIndex++) {
|
|
269
|
+
if ((cellIndex + 1) === headersLn || ((cellIndex + 1) < headersLn && this._groupedColumnHeaders[cellIndex].title !== this._groupedColumnHeaders[cellIndex + 1].title)) {
|
|
270
|
+
const leftExcelColumnChar = this.getExcelColumnNameByIndex(colspanStartIndex + 1);
|
|
271
|
+
const rightExcelColumnChar = this.getExcelColumnNameByIndex(cellIndex + 1);
|
|
272
|
+
this._sheet.mergeCells(`${leftExcelColumnChar}1`, `${rightExcelColumnChar}1`);
|
|
273
|
+
// next group starts 1 column index away
|
|
274
|
+
colspanStartIndex = cellIndex + 1;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return outputGroupedHeaderTitles;
|
|
278
|
+
}
|
|
279
|
+
/** Get all column headers and format them in Bold */
|
|
280
|
+
getColumnHeaderData(columns, metadata) {
|
|
281
|
+
let outputHeaderTitles = [];
|
|
282
|
+
// get all Column Header Titles
|
|
283
|
+
this._columnHeaders = this.getColumnHeaders(columns) || [];
|
|
284
|
+
if (this._columnHeaders && Array.isArray(this._columnHeaders) && this._columnHeaders.length > 0) {
|
|
285
|
+
// add the header row + add a new line at the end of the row
|
|
286
|
+
outputHeaderTitles = this._columnHeaders.map((header) => ({ value: (0, common_1.sanitizeHtmlToText)(header.title), metadata }));
|
|
287
|
+
}
|
|
288
|
+
// do we have a Group by title?
|
|
289
|
+
const groupTitle = this.getGroupColumnTitle();
|
|
290
|
+
if (groupTitle) {
|
|
291
|
+
outputHeaderTitles.unshift({ value: groupTitle, metadata });
|
|
292
|
+
}
|
|
293
|
+
return outputHeaderTitles;
|
|
294
|
+
}
|
|
295
|
+
getGroupColumnTitle() {
|
|
296
|
+
var _a;
|
|
297
|
+
// Group By text, it could be set in the export options or from translation or if nothing is found then use the English constant text
|
|
298
|
+
let groupByColumnHeader = this._excelExportOptions.groupingColumnHeaderTitle;
|
|
299
|
+
if (!groupByColumnHeader && this._gridOptions.enableTranslate && ((_a = this._translaterService) === null || _a === void 0 ? void 0 : _a.translate)) {
|
|
300
|
+
groupByColumnHeader = this._translaterService.translate(`${(0, common_1.getTranslationPrefix)(this._gridOptions)}GROUP_BY`);
|
|
301
|
+
}
|
|
302
|
+
else if (!groupByColumnHeader) {
|
|
303
|
+
groupByColumnHeader = this._locales && this._locales.TEXT_GROUP_BY;
|
|
304
|
+
}
|
|
305
|
+
// get grouped column titles and if found, we will add a "Group by" column at the first column index
|
|
306
|
+
// if it's a CSV format, we'll escape the text in double quotes
|
|
307
|
+
const grouping = this._dataView.getGrouping();
|
|
308
|
+
if (Array.isArray(grouping) && grouping.length > 0) {
|
|
309
|
+
this._hasGroupedItems = true;
|
|
310
|
+
return groupByColumnHeader;
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
this._hasGroupedItems = false;
|
|
314
|
+
}
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Get all Grouped Header Titles and their keys, translate the title when required.
|
|
319
|
+
* @param {Array<object>} columns of the grid
|
|
320
|
+
*/
|
|
321
|
+
getColumnGroupedHeaderTitles(columns) {
|
|
322
|
+
const groupedColumnHeaders = [];
|
|
323
|
+
if (columns && Array.isArray(columns)) {
|
|
324
|
+
// Populate the Grouped Column Header, pull the columnGroup(Key) defined
|
|
325
|
+
columns.forEach((columnDef) => {
|
|
326
|
+
var _a;
|
|
327
|
+
let groupedHeaderTitle = '';
|
|
328
|
+
if (columnDef.columnGroupKey && this._gridOptions.enableTranslate && ((_a = this._translaterService) === null || _a === void 0 ? void 0 : _a.translate)) {
|
|
329
|
+
groupedHeaderTitle = this._translaterService.translate(columnDef.columnGroupKey);
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
groupedHeaderTitle = columnDef.columnGroup || '';
|
|
333
|
+
}
|
|
334
|
+
const skippedField = columnDef.excludeFromExport || false;
|
|
335
|
+
// if column width is 0px, then we consider that field as a hidden field and should not be part of the export
|
|
336
|
+
if ((columnDef.width === undefined || columnDef.width > 0) && !skippedField) {
|
|
337
|
+
groupedColumnHeaders.push({
|
|
338
|
+
key: (columnDef.field || columnDef.id),
|
|
339
|
+
title: groupedHeaderTitle || ''
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
return groupedColumnHeaders;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Get all header titles and their keys, translate the title when required.
|
|
348
|
+
* @param {Array<object>} columns of the grid
|
|
349
|
+
*/
|
|
350
|
+
getColumnHeaders(columns) {
|
|
351
|
+
const columnHeaders = [];
|
|
352
|
+
if (columns && Array.isArray(columns)) {
|
|
353
|
+
// Populate the Column Header, pull the name defined
|
|
354
|
+
columns.forEach((columnDef) => {
|
|
355
|
+
var _a;
|
|
356
|
+
let headerTitle = '';
|
|
357
|
+
if ((columnDef.nameKey || columnDef.nameKey) && this._gridOptions.enableTranslate && ((_a = this._translaterService) === null || _a === void 0 ? void 0 : _a.translate)) {
|
|
358
|
+
headerTitle = this._translaterService.translate((columnDef.nameKey || columnDef.nameKey));
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
headerTitle = columnDef.name || (0, utils_1.titleCase)(columnDef.field);
|
|
362
|
+
}
|
|
363
|
+
const skippedField = columnDef.excludeFromExport || false;
|
|
364
|
+
// if column width is 0, then we consider that field as a hidden field and should not be part of the export
|
|
365
|
+
if ((columnDef.width === undefined || columnDef.width > 0) && !skippedField) {
|
|
366
|
+
columnHeaders.push({
|
|
367
|
+
key: (columnDef.field || columnDef.id) + '',
|
|
368
|
+
title: headerTitle
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
return columnHeaders;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Get all the grid row data and return that as an output string
|
|
377
|
+
*/
|
|
378
|
+
pushAllGridRowDataToArray(originalDaraArray, columns) {
|
|
379
|
+
const lineCount = this._dataView.getLength();
|
|
380
|
+
// loop through all the grid rows of data
|
|
381
|
+
for (let rowNumber = 0; rowNumber < lineCount; rowNumber++) {
|
|
382
|
+
const itemObj = this._dataView.getItem(rowNumber);
|
|
383
|
+
// make sure we have a filled object AND that the item doesn't include the "getItem" method
|
|
384
|
+
// this happen could happen with an opened Row Detail as it seems to include an empty Slick DataView (we'll just skip those lines)
|
|
385
|
+
if (itemObj && !itemObj.hasOwnProperty('getItem')) {
|
|
386
|
+
// Normal row (not grouped by anything) would have an ID which was predefined in the Grid Columns definition
|
|
387
|
+
if (itemObj[this._datasetIdPropName] !== null && itemObj[this._datasetIdPropName] !== undefined) {
|
|
388
|
+
// get regular row item data
|
|
389
|
+
originalDaraArray.push(this.readRegularRowData(columns, rowNumber, itemObj));
|
|
390
|
+
}
|
|
391
|
+
else if (this._hasGroupedItems && itemObj.__groupTotals === undefined) {
|
|
392
|
+
// get the group row
|
|
393
|
+
originalDaraArray.push([this.readGroupedRowTitle(itemObj)]);
|
|
394
|
+
}
|
|
395
|
+
else if (itemObj.__groupTotals) {
|
|
396
|
+
// else if the row is a Group By and we have agreggators, then a property of '__groupTotals' would exist under that object
|
|
397
|
+
originalDaraArray.push(this.readGroupedTotalRows(columns, itemObj));
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
return originalDaraArray;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Get the data of a regular row (a row without grouping)
|
|
405
|
+
* @param {Array<Object>} columns - column definitions
|
|
406
|
+
* @param {Number} row - row index
|
|
407
|
+
* @param {Object} itemObj - item datacontext object
|
|
408
|
+
*/
|
|
409
|
+
readRegularRowData(columns, row, itemObj) {
|
|
410
|
+
var _a, _b, _c;
|
|
411
|
+
let idx = 0;
|
|
412
|
+
const rowOutputStrings = [];
|
|
413
|
+
const columnsLn = columns.length;
|
|
414
|
+
let prevColspan = 1;
|
|
415
|
+
let colspanStartIndex = 0;
|
|
416
|
+
const itemMetadata = this._dataView.getItemMetadata(row);
|
|
417
|
+
for (let col = 0; col < columnsLn; col++) {
|
|
418
|
+
const columnDef = columns[col];
|
|
419
|
+
// skip excluded column
|
|
420
|
+
if (columnDef.excludeFromExport) {
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
// if we are grouping and are on 1st column index, we need to skip this column since it will be used later by the grouping text:: Group by [columnX]
|
|
424
|
+
if (this._hasGroupedItems && idx === 0) {
|
|
425
|
+
rowOutputStrings.push('');
|
|
426
|
+
}
|
|
427
|
+
let colspan = 1;
|
|
428
|
+
let colspanColumnId;
|
|
429
|
+
if (itemMetadata === null || itemMetadata === void 0 ? void 0 : itemMetadata.columns) {
|
|
430
|
+
const metadata = itemMetadata.columns;
|
|
431
|
+
const columnData = metadata[columnDef.id] || metadata[col];
|
|
432
|
+
if (!((!isNaN(prevColspan) && +prevColspan > 1) || (prevColspan === '*' && col > 0))) {
|
|
433
|
+
prevColspan = (_a = columnData === null || columnData === void 0 ? void 0 : columnData.colspan) !== null && _a !== void 0 ? _a : 1;
|
|
434
|
+
}
|
|
435
|
+
if (prevColspan === '*') {
|
|
436
|
+
colspan = columns.length - col;
|
|
437
|
+
}
|
|
438
|
+
else {
|
|
439
|
+
colspan = prevColspan;
|
|
440
|
+
if (columnDef.id in metadata) {
|
|
441
|
+
colspanColumnId = columnDef.id;
|
|
442
|
+
colspanStartIndex = col;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
// when using grid with colspan, we will merge some cells together
|
|
447
|
+
if ((prevColspan === '*' && col > 0) || ((!isNaN(prevColspan) && +prevColspan > 1) && columnDef.id !== colspanColumnId)) {
|
|
448
|
+
// -- Merge Data
|
|
449
|
+
// Excel row starts at 2 or at 3 when dealing with pre-header grouping
|
|
450
|
+
const excelRowNumber = row + (this._hasColumnTitlePreHeader ? 3 : 2);
|
|
451
|
+
if (typeof prevColspan === 'number' && (colspan - 1) === 1) {
|
|
452
|
+
// partial column span
|
|
453
|
+
const leftExcelColumnChar = this.getExcelColumnNameByIndex(colspanStartIndex + 1);
|
|
454
|
+
const rightExcelColumnChar = this.getExcelColumnNameByIndex(col + 1);
|
|
455
|
+
this._sheet.mergeCells(`${leftExcelColumnChar}${excelRowNumber}`, `${rightExcelColumnChar}${excelRowNumber}`);
|
|
456
|
+
rowOutputStrings.push(''); // clear cell that won't be shown by a cell merge
|
|
457
|
+
}
|
|
458
|
+
else if (prevColspan === '*' && colspan === 1) {
|
|
459
|
+
// full column span (from A1 until the last column)
|
|
460
|
+
const rightExcelColumnChar = this.getExcelColumnNameByIndex(col + 1);
|
|
461
|
+
this._sheet.mergeCells(`A${excelRowNumber}`, `${rightExcelColumnChar}${excelRowNumber}`);
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
rowOutputStrings.push(''); // clear cell that won't be shown by a cell merge
|
|
465
|
+
}
|
|
466
|
+
// decrement colspan until we reach colspan of 1 then proceed with cell merge OR full row merge when colspan is (*)
|
|
467
|
+
if (typeof prevColspan === 'number' && (!isNaN(prevColspan) && +prevColspan > 1)) {
|
|
468
|
+
colspan = prevColspan--;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
else {
|
|
472
|
+
let itemData = '';
|
|
473
|
+
const fieldType = (0, common_1.getColumnFieldType)(columnDef);
|
|
474
|
+
// -- Read Data & Push to Data Array
|
|
475
|
+
// user might want to export with Formatter, and/or auto-detect Excel format, and/or export as regular cell data
|
|
476
|
+
// for column that are Date type, we'll always export with their associated Date Formatters unless `exportWithFormatter` is specifically set to false
|
|
477
|
+
const exportOptions = { ...this._excelExportOptions };
|
|
478
|
+
if ((columnDef === null || columnDef === void 0 ? void 0 : columnDef.exportWithFormatter) !== false && (0, common_1.isColumnDateType)(fieldType)) {
|
|
479
|
+
exportOptions.exportWithFormatter = true;
|
|
480
|
+
}
|
|
481
|
+
itemData = (0, common_1.exportWithFormatterWhenDefined)(row, col, columnDef, itemObj, this._grid, exportOptions);
|
|
482
|
+
// auto-detect best possible Excel format, unless the user provide his own formatting,
|
|
483
|
+
// we only do this check once per column (everything after that will be pull from temp ref)
|
|
484
|
+
if (!this._regularCellExcelFormats.hasOwnProperty(columnDef.id)) {
|
|
485
|
+
const cellStyleFormat = (0, excelUtils_1.useCellFormatByFieldType)(this._stylesheet, this._stylesheetFormats, columnDef, this._grid);
|
|
486
|
+
// user could also override style and/or valueParserCallback
|
|
487
|
+
if ((_b = columnDef.excelExportOptions) === null || _b === void 0 ? void 0 : _b.style) {
|
|
488
|
+
cellStyleFormat.stylesheetFormatterId = this._stylesheet.createFormat(columnDef.excelExportOptions.style).id;
|
|
489
|
+
}
|
|
490
|
+
if ((_c = columnDef.excelExportOptions) === null || _c === void 0 ? void 0 : _c.valueParserCallback) {
|
|
491
|
+
cellStyleFormat.getDataValueParser = columnDef.excelExportOptions.valueParserCallback;
|
|
492
|
+
}
|
|
493
|
+
this._regularCellExcelFormats[columnDef.id] = cellStyleFormat;
|
|
494
|
+
}
|
|
495
|
+
// sanitize early, when enabled, any HTML tags (remove HTML tags)
|
|
496
|
+
if (typeof itemData === 'string' && (columnDef.sanitizeDataExport || this._excelExportOptions.sanitizeDataExport)) {
|
|
497
|
+
itemData = (0, common_1.sanitizeHtmlToText)(itemData);
|
|
498
|
+
}
|
|
499
|
+
const { stylesheetFormatterId, getDataValueParser } = this._regularCellExcelFormats[columnDef.id];
|
|
500
|
+
itemData = getDataValueParser(itemData, columnDef, stylesheetFormatterId, this._stylesheet, this._gridOptions);
|
|
501
|
+
rowOutputStrings.push(itemData);
|
|
502
|
+
idx++;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return rowOutputStrings;
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Get the grouped title(s) and its group title formatter, for example if we grouped by salesRep, the returned result would be:: 'Sales Rep: John Dow (2 items)'
|
|
509
|
+
* @param itemObj
|
|
510
|
+
*/
|
|
511
|
+
readGroupedRowTitle(itemObj) {
|
|
512
|
+
const groupName = (0, common_1.sanitizeHtmlToText)(itemObj.title);
|
|
513
|
+
if (this._excelExportOptions && this._excelExportOptions.addGroupIndentation) {
|
|
514
|
+
const collapsedSymbol = this._excelExportOptions && this._excelExportOptions.groupCollapsedSymbol || '⮞';
|
|
515
|
+
const expandedSymbol = this._excelExportOptions && this._excelExportOptions.groupExpandedSymbol || '⮟';
|
|
516
|
+
const chevron = itemObj.collapsed ? collapsedSymbol : expandedSymbol;
|
|
517
|
+
return chevron + ' ' + (0, utils_1.addWhiteSpaces)(5 * itemObj.level) + groupName;
|
|
518
|
+
}
|
|
519
|
+
return groupName;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Get the grouped totals (below the regular rows), these are set by Slick Aggregators.
|
|
523
|
+
* For example if we grouped by "salesRep" and we have a Sum Aggregator on "sales", then the returned output would be:: ["Sum 123$"]
|
|
524
|
+
* @param itemObj
|
|
525
|
+
*/
|
|
526
|
+
readGroupedTotalRows(columns, itemObj) {
|
|
527
|
+
const groupingAggregatorRowText = this._excelExportOptions.groupingAggregatorRowText || '';
|
|
528
|
+
const outputStrings = [groupingAggregatorRowText];
|
|
529
|
+
columns.forEach((columnDef) => {
|
|
530
|
+
var _a, _b, _c, _d, _e;
|
|
531
|
+
let itemData = '';
|
|
532
|
+
const fieldType = (0, common_1.getColumnFieldType)(columnDef);
|
|
533
|
+
const skippedField = columnDef.excludeFromExport || false;
|
|
534
|
+
// if there's a exportCustomGroupTotalsFormatter or groupTotalsFormatter, we will re-run it to get the exact same output as what is shown in UI
|
|
535
|
+
if (columnDef.exportCustomGroupTotalsFormatter) {
|
|
536
|
+
itemData = columnDef.exportCustomGroupTotalsFormatter(itemObj, columnDef, this._grid);
|
|
537
|
+
}
|
|
538
|
+
// auto-detect best possible Excel format for Group Totals, unless the user provide his own formatting,
|
|
539
|
+
// we only do this check once per column (everything after that will be pull from temp ref)
|
|
540
|
+
if (fieldType === common_1.FieldType.number) {
|
|
541
|
+
let groupCellFormat = this._groupTotalExcelFormats[columnDef.id];
|
|
542
|
+
if (!(groupCellFormat === null || groupCellFormat === void 0 ? void 0 : groupCellFormat.groupType)) {
|
|
543
|
+
groupCellFormat = (0, excelUtils_1.getExcelFormatFromGridFormatter)(this._stylesheet, this._stylesheetFormats, columnDef, this._grid, 'group');
|
|
544
|
+
if ((_a = columnDef.groupTotalsExcelExportOptions) === null || _a === void 0 ? void 0 : _a.style) {
|
|
545
|
+
groupCellFormat.stylesheetFormatter = this._stylesheet.createFormat(columnDef.groupTotalsExcelExportOptions.style);
|
|
546
|
+
}
|
|
547
|
+
this._groupTotalExcelFormats[columnDef.id] = groupCellFormat;
|
|
548
|
+
}
|
|
549
|
+
const groupTotalParser = (_c = (_b = columnDef.groupTotalsExcelExportOptions) === null || _b === void 0 ? void 0 : _b.valueParserCallback) !== null && _c !== void 0 ? _c : excelUtils_1.getGroupTotalValue;
|
|
550
|
+
if (((_d = itemObj[groupCellFormat.groupType]) === null || _d === void 0 ? void 0 : _d[columnDef.field]) !== undefined) {
|
|
551
|
+
itemData = {
|
|
552
|
+
value: groupTotalParser(itemObj, columnDef, groupCellFormat.groupType, this._stylesheet),
|
|
553
|
+
metadata: { style: (_e = groupCellFormat.stylesheetFormatter) === null || _e === void 0 ? void 0 : _e.id }
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
else if (columnDef.groupTotalsFormatter) {
|
|
558
|
+
itemData = columnDef.groupTotalsFormatter(itemObj, columnDef, this._grid);
|
|
559
|
+
}
|
|
560
|
+
// does the user want to sanitize the output data (remove HTML tags)?
|
|
561
|
+
if (typeof itemData === 'string' && (columnDef.sanitizeDataExport || this._excelExportOptions.sanitizeDataExport)) {
|
|
562
|
+
itemData = (0, common_1.sanitizeHtmlToText)(itemData);
|
|
563
|
+
}
|
|
564
|
+
// add the column (unless user wants to skip it)
|
|
565
|
+
if ((columnDef.width === undefined || columnDef.width > 0) && !skippedField) {
|
|
566
|
+
outputStrings.push(itemData);
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
return outputStrings;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
exports.ExcelExportService = ExcelExportService;
|
|
573
573
|
//# sourceMappingURL=excelExport.service.js.map
|