UNPKG

@syncfusion/ej2-spreadsheet

Version:

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

589 lines (588 loc) 28.5 kB
import { getSheet, isHiddenRow, getCell, setCell } from '../base/index'; import { cellValidation, addHighlight, getCellAddress, updateHighlight, getSwapRange, getUpdatedRange } from '../common/index'; import { removeHighlight, checkIsFormula, getSheetIndexFromAddress, getRangeFromAddress } from '../common/index'; import { getRangeIndexes, getUpdatedFormulaOnInsertDelete, getUpdatedFormula } from '../common/index'; import { updateCell, beforeInsert, beforeDelete, addListValidationDropdown, importModelUpdate } from '../common/index'; import { getSplittedAddressForColumn } from '../common/index'; import { getSheetIndexFromId, setColumn, refreshInsertDelete, workbookFormulaOperation, isHiddenCol } from '../index'; import { getSheetIndex, getRow, checkColumnValidation } from '../base/index'; import { extend, isNullOrUndefined } from '@syncfusion/ej2-base'; /** * The `WorkbookHyperlink` module is used to handle Hyperlink action in Spreadsheet. */ var WorkbookDataValidation = /** @class */ (function () { /** * Constructor for WorkbookSort module. * * @param {Workbook} parent - Specifies the parent element. */ function WorkbookDataValidation(parent) { this.parent = parent; this.addEventListener(); } /** * To destroy the sort module. * * @returns {void} */ WorkbookDataValidation.prototype.destroy = function () { this.removeEventListener(); this.highlightInvalidData = null; this.parent = null; }; WorkbookDataValidation.prototype.addEventListener = function () { this.parent.on(cellValidation, this.updateValidationHandler, this); this.parent.on(addHighlight, this.addHighlightHandler, this); this.parent.on(removeHighlight, this.removeHighlightHandler, this); this.parent.on(beforeInsert, this.beforeInsertDeleteHandler, this); this.parent.on(beforeDelete, this.beforeInsertDeleteHandler, this); this.parent.on(refreshInsertDelete, this.beforeInsertDeleteHandler, this); this.parent.on(importModelUpdate, this.updataSheetValidation, this); }; WorkbookDataValidation.prototype.removeEventListener = function () { if (!this.parent.isDestroyed) { this.parent.off(cellValidation, this.updateValidationHandler); this.parent.off(addHighlight, this.addHighlightHandler); this.parent.off(removeHighlight, this.removeHighlightHandler); this.parent.off(beforeInsert, this.beforeInsertDeleteHandler); this.parent.off(beforeDelete, this.beforeInsertDeleteHandler); this.parent.off(refreshInsertDelete, this.beforeInsertDeleteHandler); this.parent.off(importModelUpdate, this.updataSheetValidation); } }; WorkbookDataValidation.prototype.updateValidationHandler = function (args) { var _this = this; var sheetName; var lastIndex = args.range.lastIndexOf('!'); var sheet; var isActiveSheet; if (lastIndex > -1) { sheetName = args.range.substring(0, lastIndex); args.range = args.range.substring(lastIndex + 1); var sheetIdx = getSheetIndex(this.parent, sheetName); sheet = getSheet(this.parent, sheetIdx); isActiveSheet = sheetIdx === this.parent.activeSheetIndex; } else { sheet = this.parent.getActiveSheet(); isActiveSheet = true; } var rangeInfo = this.getRangeWhenColumnSelected(args.range, sheet); if (sheetName) { args.range = sheetName + '!' + rangeInfo.range; } var indexes = getSwapRange(getRangeIndexes(rangeInfo.range)); var column; var cell; var frozenRow; var uiRefresh; var viewport; var updateCellHighlightOnUI; var updateColHighlightOnUI; var options = { colIdx: indexes[1] }; if (isActiveSheet) { frozenRow = this.parent.frozenRowCount(sheet); var frozenCol_1 = this.parent.frozenColCount(sheet); var parent_1 = this.parent; var viewOffset = parent_1.viewport || {}; viewport = parent_1.scrollSettings && parent_1.scrollSettings.enableVirtualization ? [frozenRow + viewOffset.topIndex, frozenCol_1 + viewOffset.leftIndex, viewOffset.bottomIndex, viewOffset.rightIndex] : [0, 0, sheet.rowCount - 1, sheet.colCount - 1]; if (rangeInfo.isFullCol) { var viewportRowIndexes_1 = [[viewport[0], viewport[2]]]; if (frozenRow) { viewportRowIndexes_1.push([getRangeIndexes(sheet.topLeftCell)[0], frozenRow - 1]); } updateColHighlightOnUI = function (validation) { if (validation.isHighlighted && ((options.colIdx >= viewport[1] && options.colIdx <= viewport[3]) || options.colIdx < frozenCol_1) && !isHiddenCol(sheet, options.colIdx)) { viewportRowIndexes_1.forEach(function (indexes) { for (options.rowIdx = indexes[0]; options.rowIdx <= indexes[1]; options.rowIdx++) { if (!isHiddenRow(sheet, options.rowIdx)) { options.cell = getCell(options.rowIdx, options.colIdx, sheet, false, true); options.validation = options.cell.validation ? options.cell.validation : validation; _this.parent.notify(updateHighlight, options); } } }); } }; } updateCellHighlightOnUI = function (validation) { if (validation.isHighlighted && uiRefresh && ((options.colIdx >= viewport[1] && options.colIdx <= viewport[3]) || options.colIdx < frozenCol_1) && !isHiddenCol(sheet, options.colIdx)) { _this.parent.notify(updateHighlight, options); } }; } var highlightObj; var isListType; var activeIdx; var updateFormula; if (args.isRemoveValidation) { if (isActiveSheet) { activeIdx = getRangeIndexes(sheet.activeCell); if (activeIdx[0] >= indexes[0] && activeIdx[1] >= indexes[1] && activeIdx[0] <= indexes[2] && activeIdx[1] <= indexes[3]) { var validation = getCell(activeIdx[0], activeIdx[1], sheet, false, true).validation || (checkColumnValidation(sheet.columns[indexes[1]], activeIdx[0], activeIdx[1]) && sheet.columns[activeIdx[1]].validation); isListType = validation && validation.type === 'List'; } options.isRemoveValidation = true; options.isRemoveHighlightedData = true; } } else { if (args.isAction && this.highlightInvalidData) { highlightObj = { isHighlighted: this.highlightInvalidData }; } if (args.rules.type === 'List') { activeIdx = getRangeIndexes(sheet.activeCell); isListType = isActiveSheet && activeIdx[0] >= indexes[0] && activeIdx[1] >= indexes[1] && activeIdx[0] <= indexes[2] && activeIdx[1] <= indexes[3]; if (args.rules.value1) { args.rules.value1 = args.rules.value1.trim(); if (args.rules.value1[args.rules.value1.length - 1] === this.parent.listSeparator) { args.rules.value1 = args.rules.value1.substring(0, args.rules.value1.length - 1); } } } else if (args.rules.type === 'Custom' && !isNullOrUndefined(args.rules.value2)) { delete args.rules.value2; } if (isActiveSheet) { options.removeOnValidData = true; } var isFormulaVal1_1 = checkIsFormula(args.rules.value1); var isFormulaVal2_1 = checkIsFormula(args.rules.value2); updateFormula = function (rowIdx) { // Calculate previous indexes based on the original starting point of the formula if (isFormulaVal1_1) { options.validation.value1 = getUpdatedFormula([rowIdx, options.colIdx, rowIdx, options.colIdx], indexes, sheet, _this.parent, { formula: args.rules.value1 }, null, true); } if (isFormulaVal2_1) { options.validation.value2 = getUpdatedFormula([rowIdx, options.colIdx, rowIdx, options.colIdx], indexes, sheet, _this.parent, { formula: args.rules.value2 }, null, true); } }; } for (options.colIdx; options.colIdx <= indexes[3]; options.colIdx++) { if (rangeInfo.isFullCol) { if (args.isRemoveValidation) { column = sheet.columns[options.colIdx]; if (column && column.validation) { if (isActiveSheet) { updateColHighlightOnUI(column.validation); } delete column.validation; } } else { options.validation = Object.assign({}, args.rules, highlightObj); updateFormula(0); if (!sheet.columns[options.colIdx]) { sheet.columns[options.colIdx] = {}; } sheet.columns[options.colIdx].validation = options.validation; if (isActiveSheet) { updateColHighlightOnUI(options.validation); } continue; } } for (options.rowIdx = indexes[0]; options.rowIdx <= indexes[2]; options.rowIdx++) { uiRefresh = isActiveSheet && ((options.rowIdx >= viewport[0] && options.rowIdx <= viewport[2]) || options.rowIdx < frozenRow) && !isHiddenRow(sheet, options.rowIdx); if (args.isRemoveValidation) { column = sheet.columns[options.colIdx]; if (column && column.validation) { if (options.rowIdx === indexes[2]) { column.validation.address = getSplittedAddressForColumn(column.validation.address, [indexes[0], options.colIdx, indexes[2], options.colIdx], options.colIdx); } if (isActiveSheet) { updateCellHighlightOnUI(column.validation); } } cell = getCell(options.rowIdx, options.colIdx, sheet); if (cell && cell.validation && !updateCell(this.parent, sheet, { cell: { validation: {} }, rowIdx: options.rowIdx, colIdx: options.colIdx })) { if (isActiveSheet) { updateCellHighlightOnUI(cell.validation); } delete cell.validation; } } else { options.validation = Object.assign({}, args.rules, highlightObj); updateFormula(options.rowIdx); if (!updateCell(this.parent, sheet, { cell: { validation: options.validation }, rowIdx: options.rowIdx, colIdx: options.colIdx })) { if (isActiveSheet) { options.cell = getCell(options.rowIdx, options.colIdx, sheet); updateCellHighlightOnUI(options.validation); } } } } } if (isListType) { cell = getCell(activeIdx[0], activeIdx[1], sheet, false, true); var validation = cell.validation; if (!validation) { validation = checkColumnValidation(sheet.columns[activeIdx[1]], activeIdx[0], activeIdx[1]) ? sheet.columns[activeIdx[1]].validation : {}; } this.parent.notify(addListValidationDropdown, { validation: validation, cell: cell, rowIdx: activeIdx[0], colIdx: activeIdx[1], isRefresh: true }); } }; WorkbookDataValidation.prototype.addHighlightHandler = function (args) { if (args.isAction) { this.highlightInvalidData = true; } this.invalidDataHandler(args.range); }; WorkbookDataValidation.prototype.removeHighlightHandler = function (args) { if (args.isAction) { this.highlightInvalidData = null; } this.invalidDataHandler(args.range, true); }; WorkbookDataValidation.prototype.invalidDataHandler = function (range, isRemoveHighlightedData) { var _this = this; var cell; var col; var rowIdx; var colIdx; var indexes; var uiRefresh; var isActiveSheet; var isFullRange; var lastColIdx; var row; var parent = this.parent; var sheet = this.parent.getActiveSheet(); var frozenRow = this.parent.frozenRowCount(sheet); var frozenCol = this.parent.frozenColCount(sheet); var viewport = parent.scrollSettings && parent.scrollSettings.enableVirtualization ? (parent.viewport ? [frozenRow + parent.viewport.topIndex, frozenCol + parent.viewport.leftIndex, parent.viewport.bottomIndex, parent.viewport.rightIndex] : []) : [0, 0, sheet.rowCount - 1, sheet.colCount - 1]; var updateHighlightOnUI = function (validation, col) { if (uiRefresh && ((colIdx >= viewport[1] && colIdx <= viewport[3]) || colIdx < frozenCol) && !isHiddenCol(sheet, colIdx)) { _this.parent.notify(updateHighlight, { isRemoveHighlightedData: isRemoveHighlightedData, rowIdx: rowIdx, colIdx: colIdx, cell: cell, validation: validation, removeOnValidData: true, col: col }); } }; var updateHighlightProp; if (isRemoveHighlightedData) { updateHighlightProp = function (validation, updateHighlight) { if (validation.isHighlighted) { if (updateHighlight) { delete validation.isHighlighted; } updateHighlightOnUI(validation); } }; } else { updateHighlightProp = function (validation, updateHighlight, col) { if (updateHighlight) { validation.isHighlighted = true; } updateHighlightOnUI(validation, col); }; } var updateValidationHighlight = function () { for (rowIdx = indexes[0]; rowIdx <= indexes[2]; rowIdx++) { uiRefresh = isActiveSheet && ((rowIdx >= viewport[0] && rowIdx <= viewport[2]) || rowIdx < frozenRow) && !isHiddenRow(sheet, rowIdx); if (isFullRange) { row = getRow(sheet, rowIdx); lastColIdx = Math.max(row && row.cells ? row.cells.length - 1 : null, sheet.columns.length - 1, indexes[3]); } for (colIdx = indexes[1]; colIdx <= lastColIdx; colIdx++) { cell = getCell(rowIdx, colIdx, sheet, false, true); col = sheet.columns[colIdx]; if (cell.validation) { updateHighlightProp(cell.validation, true, col); } else { if (checkColumnValidation(col, rowIdx, colIdx)) { updateHighlightProp(col.validation, rowIdx === indexes[2]); } } } } }; if (range) { if (range.includes('!')) { var sheetIdx = getSheetIndexFromAddress(this.parent, range); sheet = getSheet(this.parent, sheetIdx); range = getRangeFromAddress(range); isActiveSheet = sheetIdx === this.parent.activeSheetIndex; } else { isActiveSheet = true; } indexes = getSwapRange(getRangeIndexes(this.getRangeWhenColumnSelected(getUpdatedRange(sheet, range), sheet).range)); lastColIdx = indexes[3]; updateValidationHighlight(); } else { isFullRange = true; this.parent.sheets.forEach(function (model, sheetIdx) { sheet = model; indexes = [0, 0, Math.max(sheet.rows.length - 1, viewport[2]), Math.max(sheet.usedRange.colIndex, viewport[3])]; isActiveSheet = sheetIdx === _this.parent.activeSheetIndex; updateValidationHighlight(); }); } }; WorkbookDataValidation.prototype.beforeInsertDeleteHandler = function (args) { var _this = this; var isSheetAction; if (args.modelType === 'Sheet') { if (args.name !== refreshInsertDelete) { return; } isSheetAction = true; } else if (args.name === refreshInsertDelete) { return; } var isInsert = args.name === beforeInsert; var eventArgs; var endIdx; var curSheet; var prevIdx; if (isInsert) { curSheet = getSheet(this.parent, args.activeSheetIndex); endIdx = args.index + (args.model.length - 1); eventArgs = { insertDeleteArgs: { startIndex: args.index, endIndex: endIdx, modelType: args.modelType, isInsert: true, sheet: curSheet }, sheetIdx: args.activeSheetIndex }; prevIdx = args.index - 1; } else if (isSheetAction) { var sheetNames = []; var sheetId = void 0; var formulaArgs = { action: 'getSheetInfo', sheetInfo: [] }; this.parent.notify(workbookFormulaOperation, formulaArgs); for (var idx = args.startIndex; idx <= args.endIndex; idx++) { sheetId = this.parent.sheets[idx].id; for (var i = 0; i < formulaArgs.sheetInfo.length; i++) { if (formulaArgs.sheetInfo[i].index === sheetId) { sheetNames.push(formulaArgs.sheetInfo[i].sheet); break; } } } eventArgs = { sheetNames: sheetNames }; } else { curSheet = args.model; eventArgs = { insertDeleteArgs: { startIndex: args.start, modelType: args.modelType, endIndex: args.end, sheet: curSheet }, sheetIdx: getSheetIndexFromId(this.parent, curSheet.id) }; } var updateFormula = function (validation) { if (checkIsFormula(validation.value1) && (!eventArgs.otherSheet || validation.value1.includes(curSheet.name))) { eventArgs.cell = { formula: validation.value1 }; _this.parent.notify(getUpdatedFormulaOnInsertDelete, eventArgs); validation.value1 = eventArgs.cell.formula; } if (checkIsFormula(validation.value2) && (!eventArgs.otherSheet || validation.value2.includes(curSheet.name))) { eventArgs.cell = { formula: validation.value2 }; _this.parent.notify(getUpdatedFormulaOnInsertDelete, eventArgs); validation.value2 = eventArgs.cell.formula; } }; var isColAction = args.modelType === 'Column'; var updateValidationToInsertedModel = function (validation, isColUpdate) { if (validation) { eventArgs.insertDeleteArgs.forceUpdate = true; for (var insertIdx = args.index; insertIdx <= endIdx; insertIdx++) { validation = extend({}, validation); updateFormula(validation); if (isColUpdate) { setColumn(curSheet, insertIdx, { validation: validation }); } else if (isColAction) { setCell(rowIdx, insertIdx, curSheet, { validation: validation }, true); } else { setCell(insertIdx, colIdx, curSheet, { validation: validation }, true); } } delete eventArgs.insertDeleteArgs.forceUpdate; } }; var cell; var column; var endRowCount; var endColCount; var rowIdx; var colIdx; var isInsertOnCurSheet; this.parent.sheets.forEach(function (sheet, sheetIdx) { if (isSheetAction) { if (sheetIdx >= args.startIndex && sheetIdx <= args.endIndex) { return; } } else { if (sheetIdx === eventArgs.sheetIdx) { isInsertOnCurSheet = isInsert; delete eventArgs.otherSheet; delete eventArgs.formulaSheet; } else { eventArgs.otherSheet = true; eventArgs.formulaSheet = sheet; isInsertOnCurSheet = false; } } endRowCount = sheet.usedRange.rowIndex + 1; for (colIdx = 0, endColCount = sheet.usedRange.colIndex + 1; colIdx < endColCount; colIdx++) { if (isInsertOnCurSheet && isColAction && colIdx >= args.index && colIdx <= endIdx) { continue; } column = sheet.columns && sheet.columns[colIdx]; if (column && column.validation) { updateFormula(column.validation); if (isInsertOnCurSheet && isColAction && prevIdx === colIdx) { updateValidationToInsertedModel(column.validation, true); } } for (rowIdx = 0; rowIdx < endRowCount; rowIdx++) { cell = getCell(rowIdx, colIdx, sheet, false, true); if (cell.validation && (!isInsertOnCurSheet || isColAction || rowIdx < args.index || rowIdx > endIdx)) { updateFormula(cell.validation); if (isInsertOnCurSheet && prevIdx === (isColAction ? colIdx : rowIdx)) { updateValidationToInsertedModel(cell.validation); } } } } }); }; WorkbookDataValidation.prototype.getRangeWhenColumnSelected = function (range, sheet) { var isFullCol; var colNames = range.split(':'); if (range.match(/\D/g) && !range.match(/[0-9]/g)) { colNames[0] += 1; colNames[1] += sheet.rowCount; range = colNames[0] + ':' + colNames[1]; isFullCol = true; } else if (!range.match(/\D/g) && range.match(/[0-9]/g)) { colNames[0] = 'A' + colNames[0]; colNames[1] = getCellAddress(0, sheet.colCount - 1).replace(/[0-9]/g, '') + colNames[1]; range = colNames[0] + ':' + colNames[1]; } return { range: range, isFullCol: isFullCol }; }; WorkbookDataValidation.prototype.updataSheetValidation = function () { var _this = this; var ranges; var validation; var rowIdx; var colIdx; var prevIndexes; var updateFormulaValidation = function (model, sheet) { var indexes = getRangeIndexes(ranges.shift()); prevIndexes = [indexes[0], indexes[1]]; if (ranges.length) { var rangeIndexes_1 = [indexes]; ranges.forEach(function (range) { indexes = getRangeIndexes(range); if (indexes[0] < prevIndexes[0]) { prevIndexes[0] = indexes[0]; } if (indexes[1] < prevIndexes[1]) { prevIndexes[1] = indexes[1]; } rangeIndexes_1.push(indexes); }); rangeIndexes_1.forEach(function (indexes) { setValidation(indexes, model, sheet); }); } else { setValidation(indexes, model, sheet); } }; var updateFormula; var setValidation = function (indexes, model, sheet) { if (indexes[0] === 0 && indexes[2] === 1048575) { colIdx = indexes[1]; rowIdx = 0; while (colIdx <= indexes[3]) { validation = Object.assign({}, model); updateFormula(); setColumn(sheet, colIdx, { validation: validation }); colIdx++; } } else { rowIdx = indexes[0]; var endRowIdx = Math.min(indexes[2], sheet.usedRange.rowIndex); var endColIdx = Math.min(indexes[3], sheet.usedRange.colIndex); while (rowIdx <= endRowIdx) { colIdx = indexes[1]; while (colIdx <= endColIdx) { validation = Object.assign({}, model); updateFormula(); setCell(rowIdx, colIdx, sheet, { validation: validation }, true); colIdx++; } rowIdx++; } } }; this.parent.sheets.forEach(function (sheet) { if (sheet.validations) { sheet.validations.forEach(function (model) { if (model.range && model.range.length) { ranges = model.range; delete model.range; if (checkIsFormula(model.value2)) { if (checkIsFormula(model.value1)) { updateFormula = function () { validation.value1 = getUpdatedFormula([rowIdx, colIdx], prevIndexes, sheet, _this.parent, { formula: validation.value1 }, null, true); validation.value2 = getUpdatedFormula([rowIdx, colIdx], prevIndexes, sheet, _this.parent, { formula: validation.value2 }, null, true); }; } else { updateFormula = function () { validation.value2 = getUpdatedFormula([rowIdx, colIdx], prevIndexes, sheet, _this.parent, { formula: validation.value2 }, null, true); }; } updateFormulaValidation(model, sheet); } else if (checkIsFormula(model.value1)) { updateFormula = function () { validation.value1 = getUpdatedFormula([rowIdx, colIdx], prevIndexes, sheet, _this.parent, { formula: validation.value1 }, null, true); }; updateFormulaValidation(model, sheet); } else { updateFormula = function () { }; ranges.forEach(function (range) { setValidation(getRangeIndexes(range), model, sheet); }); } } }); delete sheet.validations; } }); }; /** * Gets the module name. * * @returns {string} string */ WorkbookDataValidation.prototype.getModuleName = function () { return 'workbookDataValidation'; }; return WorkbookDataValidation; }()); export { WorkbookDataValidation };