UNPKG

@syncfusion/ej2-spreadsheet

Version:

Feature-rich JavaScript Spreadsheet (Excel) control with built-in support for selection, editing, formatting, importing and exporting to Excel

353 lines (352 loc) 15.9 kB
import { getCell, setCell, getData, getSheet, isHiddenRow, wrap as wrapText } from '../base/index'; import { DataManager, Query, DataUtil, Deferred } from '@syncfusion/ej2-data'; import { getCellIndexes, getColumnHeaderText, getRangeAddress, workbookLocale, isNumber, getUpdatedFormula, getDataRange, getCellAddress } from '../common/index'; import { getSwapRange } from '../common/index'; import { parseIntValue, getColIndex } from '../common/index'; import { initiateSort, updateSortedDataOnCell } from '../common/event'; import { extend, isNullOrUndefined } from '@syncfusion/ej2-base'; import { refreshFilterRange } from '../../spreadsheet/common/event'; /** * The `WorkbookSort` module is used to handle sort action in Spreadsheet. */ var WorkbookSort = /** @class */ (function () { /** * Constructor for WorkbookSort module. * * @param {Workbook} parent - Specifies the workbook. */ function WorkbookSort(parent) { this.parent = parent; this.addEventListener(); } /** * To destroy the sort module. * * @returns {void} - To destroy the sort module. */ WorkbookSort.prototype.destroy = function () { this.removeEventListener(); this.parent = null; }; WorkbookSort.prototype.addEventListener = function () { this.parent.on(initiateSort, this.initiateSortHandler, this); this.parent.on(updateSortedDataOnCell, this.updateSortedDataOnCell, this); }; WorkbookSort.prototype.removeEventListener = function () { if (!this.parent.isDestroyed) { this.parent.off(initiateSort, this.initiateSortHandler); this.parent.off(updateSortedDataOnCell, this.updateSortedDataOnCell); } }; /** * Sorts range of cells in the sheet. * * @param {{ args: BeforeSortEventArgs, promise: Promise<SortEventArgs> }} eventArgs - Specify the arguments. * @param {BeforeSortEventArgs} eventArgs.args - arguments for sorting. * @param {Promise<SortEventArgs>} eventArgs.promise - Specify the promise. * @param {SortCollectionModel} eventArgs.previousSort - Specify the previous sort model. * @returns {void} - Sorts range of cells in the sheet. */ WorkbookSort.prototype.initiateSortHandler = function (eventArgs) { var _this = this; var args = eventArgs.args; var deferred = new Deferred(); var addressInfo = this.parent.getAddressInfo(args.range); var sheet = getSheet(this.parent, addressInfo.sheetIndex); var range = getSwapRange(addressInfo.indices); var sortOptions = args.sortOptions || { sortDescriptors: {}, containsHeader: true }; var isSingleCell = false; eventArgs.promise = deferred.promise; if (range[0] > sheet.usedRange.rowIndex || range[1] > sheet.usedRange.colIndex) { deferred.reject(this.parent.serviceLocator.getService(workbookLocale).getConstant('SortOutOfRangeError')); return; } var containsHeader = sortOptions.containsHeader; var checkForHeader = args.checkForHeader; if (range[0] === range[2] || checkForHeader) { //if selected range is a single cell if (!checkForHeader) { range = getDataRange(range[0], range[1], sheet); } isSingleCell = true; if (isNullOrUndefined(sortOptions.containsHeader)) { if (typeof getCell(range[0], range[1], sheet, null, true).value === typeof getCell(range[0] + 1, range[1], sheet, null, true).value) { containsHeader = this.isSameStyle(getCell(range[0], range[1], sheet, null, true).style, getCell(range[0] + 1, range[1], sheet, null, true).style) ? this.isHeaderRow(sheet, range) : true; } else { containsHeader = true; } } } if ((isNullOrUndefined(args.sortOptions) || isNullOrUndefined(args.sortOptions.containsHeader)) && !isSingleCell) { var firstCell = getCell(range[0], range[1], sheet); var secondCell = getCell(range[0] + 1, range[1], sheet); if (firstCell && secondCell) { if (typeof firstCell.value === typeof secondCell.value) { containsHeader = !this.isSameStyle(firstCell.style, secondCell.style) || this.isHeaderRow(sheet, range); } else { containsHeader = true; } } } range[0] = containsHeader ? range[0] + 1 : range[0]; var cell = getCellIndexes(sheet.activeCell); var header = getColumnHeaderText(cell[1] + 1); delete sortOptions.containsHeader; var sortDescriptors = sortOptions.sortDescriptors; var query = new Query(); if (Array.isArray(sortDescriptors)) { //multi-column sorting. if (!sortDescriptors || sortDescriptors.length === 0) { sortDescriptors = [{ field: header }]; } for (var length_1 = sortDescriptors.length, i = length_1 - 1; i > -1; i--) { if (!sortDescriptors[length_1 - 1].field) { sortDescriptors[length_1 - 1].field = header; } if (!sortDescriptors[i].field) { continue; } var comparerFn = sortDescriptors[i].sortComparer || this.sortComparer.bind(this, sortDescriptors[i], sortOptions.caseSensitive); query.sortBy(sortDescriptors[i].field, comparerFn); header = sortDescriptors[i].field; } } else { //single column sorting. if (!sortDescriptors) { sortDescriptors = { field: header }; } if (!sortDescriptors.field) { sortDescriptors.field = header; } var comparerFn = sortDescriptors.sortComparer || this.sortComparer.bind(this, sortDescriptors, sortOptions.caseSensitive); query.sortBy(sortDescriptors.field, comparerFn); header = sortDescriptors.field; } var address = getRangeAddress(range); getData(this.parent, sheet.name + "!" + address, true, null, null, null, null, null, undefined, null, getColIndex(header)).then(function (jsonData) { var dataManager = new DataManager(jsonData); if (jsonData.length === 1 && (jsonData[0].throwMergeAlert)) { var sortModel = _this.parent.sortCollection && _this.parent.sortCollection[_this.parent.sortCollection.length - 1]; if (sortModel) { var prevSortModel = void 0; if (eventArgs.previousSort && eventArgs.previousSort.length) { for (var i = 0; i < eventArgs.previousSort.length; i++) { var sort = eventArgs.previousSort[i]; if (sortModel.sheetIndex === sort.sheetIndex) { prevSortModel = sort; } } } if (prevSortModel) { sortModel.columnIndex = prevSortModel.columnIndex; sortModel.order = prevSortModel.order; sortModel.sortRange = prevSortModel.sortRange; } else { _this.parent.sortCollection.pop(); } _this.parent.notify(refreshFilterRange, null); } deferred.reject(_this.parent.serviceLocator.getService(workbookLocale).getConstant('AutoFillMergeAlertMsg')); return; } dataManager.executeQuery(query).then(function (e) { _this.parent.notify('setActionData', { args: { action: 'beforeSort', eventArgs: { range: address, cellDetails: jsonData, sortedCellDetails: e.result } } }); _this.updateSortedDataOnCell({ result: e.result, range: range, sheet: sheet, jsonData: jsonData }); var sortArgs = { range: sheet.name + "!" + address, sortOptions: args.sortOptions }; if (eventArgs.previousSort) { sortArgs.previousSort = eventArgs.previousSort; } deferred.resolve(sortArgs); }); }); }; WorkbookSort.prototype.isHeaderRow = function (sheet, range) { if (!sheet.ranges || !sheet.ranges.length) { return false; } return sheet.ranges.some(function (rangeItem) { if (!rangeItem.dataSource || !rangeItem.showFieldAsHeader) { return false; } var startCellIndexes = getCellIndexes(rangeItem.startCell); return startCellIndexes[0] === range[0] && startCellIndexes[1] >= range[1] && startCellIndexes[1] <= range[3]; }); }; WorkbookSort.prototype.updateSortedDataOnCell = function (args) { var _this = this; var fields = []; var cell; var updateCell = function (rowIdx, data) { for (var j = args.range[1], k = 0; j <= args.range[3]; j++, k++) { if (!fields[k]) { fields[k] = getColumnHeaderText(j + 1); } if (data[fields[k]]) { cell = extend({}, data[fields[k]], null, true); } else { if (!getCell(rowIdx, j, args.sheet)) { continue; } cell = null; } cell = _this.skipBorderOnSorting(rowIdx, j, args.sheet, cell); if (cell && cell.validation) { delete cell.validation; } var existingCell = getCell(rowIdx, j, args.sheet); if (existingCell) { if (existingCell.validation) { cell = Object.assign({}, cell, { validation: existingCell.validation }); // To preserve validation settings } if (existingCell.wrap) { wrapText(getCellAddress(rowIdx, j), false, _this.parent); } } if (cell && cell.formula) { cell.formula = getUpdatedFormula([rowIdx, j], [parseInt(data['__rowIndex'], 10) - 1, j], args.sheet, _this.parent, cell, true); } setCell(rowIdx, j, args.sheet, cell); } }; var updatedCellDetails = args.isUndo && {}; var rIdx; var result; for (var i = args.range[0], idx = 0; i <= args.range[2]; i++, idx++) { if (isHiddenRow(args.sheet, i)) { idx--; continue; } result = args.result[idx]; if (args.isUndo) { if (result) { rIdx = parseInt(result['__rowIndex'], 10) - 1; updatedCellDetails[rIdx] = true; updateCell(rIdx, result); if (i === rIdx) { continue; } } if (!updatedCellDetails[i] && args.sheet.rows[i]) { updateCell(i, {}); } } else { updateCell(i, result || {}); } } }; WorkbookSort.prototype.skipBorderOnSorting = function (rowIndex, colIndex, sheet, cell) { var prevCell = getCell(rowIndex, colIndex, sheet); var borders = ['borderBottom', 'borderTop', 'borderRight', 'borderLeft', 'border']; if (cell && cell.style) { for (var _i = 0, borders_1 = borders; _i < borders_1.length; _i++) { var border = borders_1[_i]; delete cell.style["" + border]; } } if (prevCell && prevCell.style) { for (var _a = 0, borders_2 = borders; _a < borders_2.length; _a++) { var border = borders_2[_a]; if (prevCell.style["" + border]) { if (!cell) { cell = {}; } if (!cell.style) { cell.style = {}; } cell.style["" + border] = prevCell.style["" + border]; } } } return cell; }; WorkbookSort.prototype.isSameStyle = function (firstCellStyle, secondCellStyle) { if (!firstCellStyle) { firstCellStyle = {}; } if (!secondCellStyle) { secondCellStyle = {}; } var sameStyle = true; var keys = Object.keys(firstCellStyle); for (var i = 0; i < keys.length; i++) { if (firstCellStyle[keys[i]] === secondCellStyle[keys[i]] || this.parent.cellStyle[keys[i]] === firstCellStyle[keys[i]]) { sameStyle = true; } else { sameStyle = false; break; } } return sameStyle; }; /** * Compares the two cells for sorting. * * @param {SortDescriptor} sortDescriptor - protocol for sorting. * @param {boolean} caseSensitive - value for case sensitive. * @param {CellModel} x - first cell * @param {CellModel} y - second cell * @returns {number} - Compares the two cells for sorting. */ WorkbookSort.prototype.sortComparer = function (sortDescriptor, caseSensitive, x, y) { var direction = sortDescriptor.order || ''; var comparer = DataUtil.fnSort(direction); var xVal = x ? ((x.hyperlink && !x.value && x.value !== 0) ? (typeof x.hyperlink === 'object' ? x.hyperlink.address : x.hyperlink) : x.value) : x; var yVal = y ? ((y.hyperlink && !y.value && y.value !== 0) ? (typeof y.hyperlink === 'object' ? y.hyperlink.address : y.hyperlink) : y.value) : y; if (x && y && (typeof xVal === 'string' || typeof yVal === 'string') && xVal !== '' && yVal !== '') { var isXStringVal = void 0; var isYStringVal = void 0; if (isNumber(x.value)) { // Imported number values are of string type, need to handle this case in server side xVal = parseIntValue(x.value); if (x.format !== '@') { x.value = xVal; } isXStringVal = true; } if (isNumber(y.value)) { yVal = parseIntValue(y.value); if (y.format !== '@') { y.value = yVal; } isYStringVal = true; } if (!isXStringVal && !isYStringVal) { var caseOptions = { sensitivity: caseSensitive ? 'case' : 'base' }; var collator = new Intl.Collator(this.parent.locale, caseOptions); if (!direction || direction.toLowerCase() === 'ascending') { return collator.compare(xVal, yVal); } else { return collator.compare(xVal, yVal) * -1; } } } if (isNullOrUndefined(yVal) || yVal === '') { return -1; } if (isNullOrUndefined(xVal) || xVal === '') { return 1; } return comparer(xVal, yVal); }; /** * Gets the module name. * * @returns {string} - Get the module name. */ WorkbookSort.prototype.getModuleName = function () { return 'workbookSort'; }; return WorkbookSort; }()); export { WorkbookSort };