/** * DevExtreme (exporter/excel_creator.js) * Version: 19.1.16 * Build date: Tue Oct 18 2022 * * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; var _class = require("../core/class"); var _class2 = _interopRequireDefault(_class); var _window = require("../core/utils/window"); var _type = require("../core/utils/type"); var _extend = require("../core/utils/extend"); var _ui = require("../ui/widget/ui.errors"); var _ui2 = _interopRequireDefault(_ui); var _string = require("../core/utils/string"); var _string2 = _interopRequireDefault(_string); var _jszip = require("jszip"); var _jszip2 = _interopRequireDefault(_jszip); var _file_saver = require("./file_saver"); var _file_saver2 = _interopRequireDefault(_file_saver); var _excel_format_converter = require("./excel_format_converter"); var _excel_format_converter2 = _interopRequireDefault(_excel_format_converter); var _excel = require("./excel/excel.file"); var _excel2 = _interopRequireDefault(_excel); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj } } function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(obj) { return typeof obj } : function(obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj }, _typeof(obj) } var XML_TAG = ''; var GROUP_SHEET_PR_XML = ''; var SINGLE_SHEET_PR_XML = ""; var BASE_STYLE_XML2 = ''; var OPEN_XML_FORMAT_URL = "http://schemas.openxmlformats.org"; var RELATIONSHIP_PART_NAME = "rels"; var XL_FOLDER_NAME = "xl"; var WORKBOOK_FILE_NAME = "workbook.xml"; var CONTENTTYPES_FILE_NAME = "[Content_Types].xml"; var SHAREDSTRING_FILE_NAME = "sharedStrings.xml"; var STYLE_FILE_NAME = "styles.xml"; var WORKSHEETS_FOLDER = "worksheets"; var WORKSHEET_FILE_NAME = "sheet1.xml"; var WORKSHEET_HEADER_XML = ''; var VALID_TYPES = { "boolean": "b", date: "d", number: "n", string: "s" }; var EXCEL_START_TIME = Date.UTC(1899, 11, 30); var DAYS_COUNT_BEFORE_29_FEB_1900 = 60; var MAX_DIGIT_WIDTH_IN_PIXELS = 7; var UNSUPPORTED_FORMAT_MAPPING = { quarter: "shortDate", quarterAndYear: "shortDate", minute: "longTime", millisecond: "longTime" }; var ExcelCreator = _class2.default.inherit({ _getXMLTag: function(tagName, attributes, content) { var result = "<" + tagName; var i; var length = attributes.length; var attr; for (i = 0; i < length; i++) { attr = attributes[i]; if (void 0 !== attr.value) { result = result + " " + attr.name + '="' + attr.value + '"' } } return (0, _type.isDefined)(content) ? result + ">" + content + "" : result + " />" }, _convertToExcelCellRef: function(zeroBasedRowIndex, zeroBasedCellIndex) { var columnName = ""; var max = 26; var charCode; var isCellIndexFound; while (!isCellIndexFound) { charCode = 65 + (zeroBasedCellIndex >= max ? zeroBasedCellIndex % max : Math.ceil(zeroBasedCellIndex)); columnName = String.fromCharCode(charCode) + columnName; if (zeroBasedCellIndex >= max) { zeroBasedCellIndex = Math.floor(zeroBasedCellIndex / max) - 1 } else { isCellIndexFound = true } } return columnName + (zeroBasedRowIndex + 1) }, _convertToExcelCellRefAndTrackMaxIndex: function(rowIndex, cellIndex) { if (this._maxRowIndex < Number(rowIndex)) { this._maxRowIndex = Number(rowIndex) } if (this._maxColumnIndex < Number(cellIndex)) { this._maxColumnIndex = Number(cellIndex) } return this._convertToExcelCellRef(rowIndex, cellIndex) }, _getDataType: function(dataType) { return VALID_TYPES[dataType] || VALID_TYPES.string }, _tryGetExcelCellDataType: function(object) { if ((0, _type.isDefined)(object)) { if ("number" === typeof object) { if (isFinite(object)) { return VALID_TYPES.number } else { return VALID_TYPES.string } } else { if ((0, _type.isString)(object)) { return VALID_TYPES.string } else { if ((0, _type.isDate)(object)) { return VALID_TYPES.number } else { if ((0, _type.isBoolean)(object)) { return VALID_TYPES.boolean } } } } } }, _formatObjectConverter: function(format, dataType) { var result = { format: format, precision: format && format.precision, dataType: dataType }; if ((0, _type.isObject)(format)) { return (0, _extend.extend)(result, format, { format: format.formatter || format.type, currency: format.currency }) } return result }, _tryConvertToExcelNumberFormat: function(format, dataType) { var newFormat = this._formatObjectConverter(format, dataType); format = newFormat.format; var currency = newFormat.currency; dataType = newFormat.dataType; if ((0, _type.isDefined)(format) && "date" === dataType) { format = UNSUPPORTED_FORMAT_MAPPING[format && format.type || format] || format } return _excel_format_converter2.default.convertFormat(format, newFormat.precision, dataType, currency) }, _appendString: function(value) { if ((0, _type.isDefined)(value)) { value = String(value); if (value.length) { value = _string2.default.encodeHtml(value); if (void 0 === this._stringHash[value]) { this._stringHash[value] = this._stringArray.length; this._stringArray.push(value) } return this._stringHash[value] } } }, _tryGetExcelDateValue: function(date) { var days; var totalTime; if ((0, _type.isDate)(date)) { days = Math.floor((Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) - EXCEL_START_TIME) / 864e5); if (days < DAYS_COUNT_BEFORE_29_FEB_1900) { days-- } totalTime = (3600 * date.getHours() + 60 * date.getMinutes() + date.getSeconds()) / 86400; return days + totalTime } }, _prepareValue: function(rowIndex, cellIndex) { var dataProvider = this._dataProvider; var cellData = dataProvider.getCellData(rowIndex, cellIndex) || {}; var value = cellData.value; var cellSourceData = cellData.cellSourceData; var sourceValue; var type = this._getDataType(dataProvider.getCellType(rowIndex, cellIndex)); if (type === VALID_TYPES.date && !(0, _type.isDate)(value)) { type = VALID_TYPES.string } switch (type) { case VALID_TYPES.string: sourceValue = value; value = this._appendString(value); break; case VALID_TYPES.date: sourceValue = value; value = this._tryGetExcelDateValue(value); type = VALID_TYPES.number } return { value: value, type: type, sourceValue: sourceValue, cellSourceData: cellSourceData } }, _callCustomizeExcelCell: function(_ref) { var dataProvider = _ref.dataProvider, value = _ref.value, style = _ref.style, sourceData = _ref.sourceData; var styleCopy = _excel2.default.copyCellFormat(style); var args = { value: value, numberFormat: styleCopy.numberFormat, clearStyle: function() { this.horizontalAlignment = null; this.verticalAlignment = null; this.wrapTextEnabled = null; this.font = null; this.numberFormat = null } }; if ((0, _type.isDefined)(styleCopy)) { if ((0, _type.isDefined)(styleCopy.alignment)) { args.horizontalAlignment = styleCopy.alignment.horizontal; args.verticalAlignment = styleCopy.alignment.vertical; args.wrapTextEnabled = styleCopy.alignment.wrapText } args.backgroundColor = styleCopy.backgroundColor; args.fillPatternType = styleCopy.fillPatternType; args.fillPatternColor = styleCopy.fillPatternColor; args.font = styleCopy.font } dataProvider.customizeExcelCell(args, sourceData); var newStyle = styleCopy || {}; newStyle.font = args.font; newStyle.alignment = newStyle.alignment || {}; newStyle.alignment.horizontal = args.horizontalAlignment; newStyle.alignment.vertical = args.verticalAlignment; newStyle.alignment.wrapText = args.wrapTextEnabled; newStyle.backgroundColor = args.backgroundColor; newStyle.fillPatternType = args.fillPatternType; newStyle.fillPatternColor = args.fillPatternColor; newStyle.numberFormat = args.numberFormat; return { value: args.value, style: newStyle } }, _getDataArray: function() { var that = this; var rowIndex; var cellIndex; var cellsArray; var cellData; var result = []; var dataProvider = that._dataProvider; var rowsLength = dataProvider.getRowsCount(); var columns = dataProvider.getColumns(); var cellsLength; for (rowIndex = 0; rowIndex < rowsLength; rowIndex++) { cellsArray = []; cellsLength = columns.length; for (cellIndex = 0; cellIndex !== cellsLength; cellIndex++) { cellData = that._prepareValue(rowIndex, cellIndex); var styleArrayIndex = dataProvider.getStyleId(rowIndex, cellIndex); var cellStyleId = this._styleArrayIndexToCellStyleIdMap[styleArrayIndex]; if (dataProvider.hasCustomizeExcelCell && dataProvider.hasCustomizeExcelCell()) { var value = cellData.sourceValue || cellData.value; var modifiedExcelCell = this._callCustomizeExcelCell({ dataProvider: dataProvider, value: value, style: that._styleArray[styleArrayIndex], sourceData: cellData.cellSourceData }); if (modifiedExcelCell.value !== value) { if (_typeof(modifiedExcelCell.value) !== _typeof(value) || "number" === typeof modifiedExcelCell.value && !isFinite(modifiedExcelCell.value)) { var cellDataType = this._tryGetExcelCellDataType(modifiedExcelCell.value); if ((0, _type.isDefined)(cellDataType)) { cellData.type = cellDataType } } switch (cellData.type) { case VALID_TYPES.string: cellData.value = this._appendString(modifiedExcelCell.value); break; case VALID_TYPES.date: cellData.value = modifiedExcelCell.value; break; case VALID_TYPES.number: var newValue = modifiedExcelCell.value; var excelDateValue = this._tryGetExcelDateValue(newValue); if ((0, _type.isDefined)(excelDateValue)) { newValue = excelDateValue } cellData.value = newValue; break; default: cellData.value = modifiedExcelCell.value } } cellStyleId = this._excelFile.registerCellFormat(modifiedExcelCell.style) } cellsArray.push({ style: cellStyleId, value: cellData.value, type: cellData.type }) } if (!that._needSheetPr && dataProvider.getGroupLevel(rowIndex) > 0) { that._needSheetPr = true } result.push(cellsArray) } return result }, _calculateWidth: function(pixelsWidth) { pixelsWidth = parseInt(pixelsWidth, 10); if (!pixelsWidth || pixelsWidth < 5) { pixelsWidth = 100 } return Math.min(255, Math.floor((pixelsWidth - 5) / MAX_DIGIT_WIDTH_IN_PIXELS * 100 + .5) / 100) }, _prepareStyleData: function() { var _this = this; var that = this; var styles = that._dataProvider.getStyles(); that._dataProvider.getColumns().forEach(function(column) { that._colsArray.push(that._calculateWidth(column.width)) }); var fonts = [{ size: 11, color: { theme: 1 }, name: "Calibri", family: 2, scheme: "minor", bold: false }, { size: 11, color: { theme: 1 }, name: "Calibri", family: 2, scheme: "minor", bold: true }]; this._excelFile.registerFont(fonts[0]); this._excelFile.registerFont(fonts[1]); styles.forEach(function(style) { var numberFormat = that._tryConvertToExcelNumberFormat(style.format, style.dataType); if (!(0, _type.isDefined)(numberFormat)) { numberFormat = 0 } that._styleArray.push({ font: fonts[Number(!!style.bold)], numberFormat: numberFormat, alignment: { vertical: "top", wrapText: !!style.wrapText, horizontal: style.alignment || "left" } }) }); that._styleArrayIndexToCellStyleIdMap = that._styleArray.map(function(item) { return _this._excelFile.registerCellFormat(item) }) }, _prepareCellData: function() { this._cellsArray = this._getDataArray() }, _createXMLRelationships: function(xmlRelationships) { return this._getXMLTag("Relationships", [{ name: "xmlns", value: OPEN_XML_FORMAT_URL + "/package/2006/relationships" }], xmlRelationships) }, _createXMLRelationship: function(id, type, target) { return this._getXMLTag("Relationship", [{ name: "Id", value: "rId" + id }, { name: "Type", value: OPEN_XML_FORMAT_URL + "/officeDocument/2006/relationships/" + type }, { name: "Target", value: target }]) }, _getWorkbookContent: function() { var content = 'Sheet!$1:$1'; return XML_TAG + this._getXMLTag("workbook", [{ name: "xmlns:r", value: OPEN_XML_FORMAT_URL + "/officeDocument/2006/relationships" }, { name: "xmlns", value: OPEN_XML_FORMAT_URL + "/spreadsheetml/2006/main" }], content) }, _getContentTypesContent: function() { return XML_TAG + '' }, _generateStylesXML: function() { var that = this; var folder = that._zip.folder(XL_FOLDER_NAME); var XML = ""; XML += this._excelFile.generateNumberFormatsXml(); XML += this._excelFile.generateFontsXml(); XML += this._excelFile.generateFillsXml(); XML += BASE_STYLE_XML2; XML += this._excelFile.generateCellFormatsXml(); XML += that._getXMLTag("cellStyles", [{ name: "count", value: 1 }], that._getXMLTag("cellStyle", [{ name: "name", value: "Normal" }, { name: "xfId", value: 0 }, { name: "builtinId", value: 0 }])); XML = XML_TAG + that._getXMLTag("styleSheet", [{ name: "xmlns", value: OPEN_XML_FORMAT_URL + "/spreadsheetml/2006/main" }], XML); folder.file(STYLE_FILE_NAME, XML); that._styleArray = [] }, _generateStringsXML: function() { var folder = this._zip.folder(XL_FOLDER_NAME); var stringIndex; var stringsLength = this._stringArray.length; var sharedStringXml = XML_TAG; for (stringIndex = 0; stringIndex < stringsLength; stringIndex++) { this._stringArray[stringIndex] = this._getXMLTag("si", [], this._getXMLTag("t", [], this._stringArray[stringIndex])) } sharedStringXml += this._getXMLTag("sst", [{ name: "xmlns", value: OPEN_XML_FORMAT_URL + "/spreadsheetml/2006/main" }, { name: "count", value: this._stringArray.length }, { name: "uniqueCount", value: this._stringArray.length }], this._stringArray.join("")); folder.file(SHAREDSTRING_FILE_NAME, sharedStringXml); this._stringArray = [] }, _getPaneXML: function() { var attributes = [{ name: "activePane", value: "bottomLeft" }, { name: "state", value: "frozen" }]; var frozenArea = this._dataProvider.getFrozenArea(); if (!(frozenArea.x || frozenArea.y)) { return "" } if (frozenArea.x) { attributes.push({ name: "xSplit", value: frozenArea.x }) } if (frozenArea.y) { attributes.push({ name: "ySplit", value: frozenArea.y }) } attributes.push({ name: "topLeftCell", value: this._convertToExcelCellRefAndTrackMaxIndex(frozenArea.y, frozenArea.x) }); return this._getXMLTag("pane", attributes) }, _getAutoFilterXML: function(maxCellIndex) { if (this._options.autoFilterEnabled) { return '' } return "" }, _getIgnoredErrorsXML: function(maxCellIndex) { if (this._options.ignoreErrors) { return '' } return "" }, _generateWorksheetXML: function() { var colIndex; var rowIndex; var cellData; var xmlCells; var xmlRows = []; var rowsLength = this._cellsArray.length; var cellsLength; var colsLength = this._colsArray.length; var rSpans = "1:" + colsLength; var headerRowCount = this._dataProvider.getHeaderRowCount ? this._dataProvider.getHeaderRowCount() : 1; var xmlResult = [WORKSHEET_HEADER_XML]; xmlResult.push(this._needSheetPr ? GROUP_SHEET_PR_XML : SINGLE_SHEET_PR_XML); xmlResult.push(''); xmlResult.push("'); xmlResult.push(this._getPaneXML()); xmlResult.push(""); xmlResult.push(''); for (colIndex = 0; colIndex < colsLength; colIndex++) { this._colsArray[colIndex] = this._getXMLTag("col", [{ name: "width", value: this._colsArray[colIndex] }, { name: "min", value: Number(colIndex) + 1 }, { name: "max", value: Number(colIndex) + 1 }]) } xmlResult.push(this._getXMLTag("cols", [], this._colsArray.join("")) + ""); for (rowIndex = 0; rowIndex < rowsLength; rowIndex++) { xmlCells = []; cellsLength = this._cellsArray[rowIndex].length; for (colIndex = 0; colIndex < cellsLength; colIndex++) { rowIndex = Number(rowIndex); cellData = this._cellsArray[rowIndex][colIndex]; xmlCells.push(this._getXMLTag("c", [{ name: "r", value: this._convertToExcelCellRefAndTrackMaxIndex(rowIndex, colIndex) }, { name: "s", value: cellData.style }, { name: "t", value: cellData.type }], (0, _type.isDefined)(cellData.value) ? this._getXMLTag("v", [], cellData.value) : null)) } xmlRows.push(this._getXMLTag("row", [{ name: "r", value: Number(rowIndex) + 1 }, { name: "spans", value: rSpans }, { name: "outlineLevel", value: rowIndex >= headerRowCount ? this._dataProvider.getGroupLevel(rowIndex) : 0 }, { name: "x14ac:dyDescent", value: "0.25" }], xmlCells.join(""))); this._cellsArray[rowIndex] = null; if (xmlRows.length > 1e4) { xmlResult.push(xmlRows.join("")); xmlRows = [] } } xmlResult.push(xmlRows.join("")); xmlRows = []; var rightBottomCellRef = this._convertToExcelCellRef(this._maxRowIndex, this._maxColumnIndex); xmlResult.push("" + this._getAutoFilterXML(rightBottomCellRef) + this._generateMergingXML() + this._getIgnoredErrorsXML(rightBottomCellRef) + ""); this._zip.folder(XL_FOLDER_NAME).folder(WORKSHEETS_FOLDER).file(WORKSHEET_FILE_NAME, xmlResult.join("")); this._colsArray = []; this._cellsArray = []; xmlResult = [] }, _generateMergingXML: function() { var k; var l; var cellIndex; var rowIndex; var rowsLength = (0, _type.isDefined)(this._dataProvider.getHeaderRowCount) ? this._dataProvider.getHeaderRowCount() : this._dataProvider.getRowsCount(); var columnsLength = this._dataProvider.getColumns().length; var usedArea = []; var mergeArray = []; var mergeIndex; var mergeXML = ""; for (rowIndex = 0; rowIndex < rowsLength; rowIndex++) { for (cellIndex = 0; cellIndex !== columnsLength; cellIndex++) { if (!(0, _type.isDefined)(usedArea[rowIndex]) || !(0, _type.isDefined)(usedArea[rowIndex][cellIndex])) { var cellMerge = this._dataProvider.getCellMerging(rowIndex, cellIndex); if (cellMerge.colspan || cellMerge.rowspan) { mergeArray.push({ start: this._convertToExcelCellRefAndTrackMaxIndex(rowIndex, cellIndex), end: this._convertToExcelCellRefAndTrackMaxIndex(rowIndex + (cellMerge.rowspan || 0), cellIndex + (cellMerge.colspan || 0)) }); for (k = rowIndex; k <= rowIndex + cellMerge.rowspan || 0; k++) { for (l = cellIndex; l <= cellIndex + cellMerge.colspan || 0; l++) { if (!(0, _type.isDefined)(usedArea[k])) { usedArea[k] = [] } usedArea[k][l] = true } } } } } } var mergeArrayLength = mergeArray.length; for (mergeIndex = 0; mergeIndex < mergeArrayLength; mergeIndex++) { mergeXML += this._getXMLTag("mergeCell", [{ name: "ref", value: mergeArray[mergeIndex].start + ":" + mergeArray[mergeIndex].end }]) } return mergeXML.length ? this._getXMLTag("mergeCells", [{ name: "count", value: mergeArrayLength }], mergeXML) : "" }, _generateCommonXML: function() { var relsFileContent = XML_TAG + this._createXMLRelationships(this._createXMLRelationship(1, "officeDocument", "xl/" + WORKBOOK_FILE_NAME)); var folder = this._zip.folder(XL_FOLDER_NAME); var relsXML = XML_TAG; this._zip.folder("_" + RELATIONSHIP_PART_NAME).file("." + RELATIONSHIP_PART_NAME, relsFileContent); var xmlRelationships = this._createXMLRelationship(1, "worksheet", "worksheets/" + WORKSHEET_FILE_NAME) + this._createXMLRelationship(2, "styles", STYLE_FILE_NAME) + this._createXMLRelationship(3, "sharedStrings", SHAREDSTRING_FILE_NAME); relsXML += this._createXMLRelationships(xmlRelationships); folder.folder("_" + RELATIONSHIP_PART_NAME).file(WORKBOOK_FILE_NAME + ".rels", relsXML); folder.file(WORKBOOK_FILE_NAME, this._getWorkbookContent()); this._zip.file(CONTENTTYPES_FILE_NAME, this._getContentTypesContent()) }, _generateContent: function() { this._prepareStyleData(); this._prepareCellData(); this._generateWorkXML(); this._generateCommonXML() }, _generateWorkXML: function() { this._generateStylesXML(); this._generateStringsXML(); this._generateWorksheetXML() }, ctor: function(dataProvider, options) { this._rtlEnabled = options && !!options.rtlEnabled; this._options = options; this._maxRowIndex = 0; this._maxColumnIndex = 0; this._stringArray = []; this._stringHash = {}; this._styleArray = []; this._colsArray = []; this._cellsArray = []; this._needSheetPr = false; this._dataProvider = dataProvider; this._excelFile = new _excel2.default; if ((0, _type.isDefined)(ExcelCreator.JSZip)) { this._zip = new ExcelCreator.JSZip } else { this._zip = null } }, _checkZipState: function() { if (!this._zip) { throw _ui2.default.Error("E1041", "JSZip") } }, ready: function() { return this._dataProvider.ready() }, getData: function(isBlob) { var options = { type: isBlob ? "blob" : "base64", compression: "DEFLATE", mimeType: _file_saver2.default.MIME_TYPES.EXCEL }; this._checkZipState(); this._generateContent(); return this._zip.generateAsync ? this._zip.generateAsync(options) : this._zip.generate(options) } }); ExcelCreator.JSZip = _jszip2.default; exports.ExcelCreator = ExcelCreator; exports.getData = function(data, options, callback) { var excelCreator = new exports.ExcelCreator(data, options); excelCreator._checkZipState(); excelCreator.ready().done(function() { if (excelCreator._zip.generateAsync) { excelCreator.getData((0, _type.isFunction)((0, _window.getWindow)().Blob)).then(callback) } else { callback(excelCreator.getData((0, _type.isFunction)((0, _window.getWindow)().Blob))) } }) };