handsontable
Version:
Handsontable is a JavaScript Spreadsheet Component available for React, Angular and Vue.
140 lines (125 loc) • 4.76 kB
JavaScript
import "core-js/modules/es.object.to-string.js";
import "core-js/modules/es.regexp.to-string.js";
import { arrayEach } from "../../../helpers/array.mjs";
import { cellCoordFactory, isFormulaExpression } from "../utils.mjs";
import CellValue from "../cell/value.mjs";
import ExpressionModifier from "../expressionModifier.mjs";
/**
* When "remove_column" is triggered the following operations must be performed:
*
* - All formulas which contain cell coordinates must be updated and saved into source data - Column must be decreased
* by "amount" of times (eq: D4 to C4, $F$5 to $E$5);
* - Mark all formulas which need update with "STATE_OUT_OFF_DATE" flag, so they can be recalculated after the operation.
*/
export var OPERATION_NAME = 'remove_column';
/**
* Execute changes.
*
* @param {number} start Index column from which the operation starts.
* @param {number} amount Count of columns to be removed.
* @param {boolean} [modifyFormula=true] If `true` all formula expressions will be modified according to the changes.
* `false` value is used by UndoRedo plugin which saves snapshoots before alter
* operation so it doesn't modify formulas if undo action is triggered.
*/
export function operate(start, amount) {
var modifyFormula = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
var columnsAmount = -amount;
var matrix = this.matrix,
dataProvider = this.dataProvider,
sheet = this.sheet;
var translate = [0, columnsAmount];
var indexOffset = Math.abs(columnsAmount) - 1;
var removedCellRef = matrix.removeCellRefsAtRange({
column: start
}, {
column: start + indexOffset
});
var toRemove = [];
arrayEach(matrix.data, function (cell) {
arrayEach(removedCellRef, function (cellRef) {
if (!cell.hasPrecedent(cellRef)) {
return;
}
cell.removePrecedent(cellRef);
cell.setState(CellValue.STATE_OUT_OFF_DATE);
arrayEach(sheet.getCellDependencies(cell.row, cell.column), function (cellValue) {
cellValue.setState(CellValue.STATE_OUT_OFF_DATE);
});
});
if (cell.column >= start && cell.column <= start + indexOffset) {
toRemove.push(cell);
}
});
matrix.remove(toRemove);
arrayEach(matrix.cellReferences, function (cell) {
if (cell.column >= start) {
cell.translateTo.apply(cell, translate);
}
});
arrayEach(matrix.data, function (cell) {
var origRow = cell.row,
origColumn = cell.column;
if (cell.column >= start) {
cell.translateTo.apply(cell, translate);
cell.setState(CellValue.STATE_OUT_OFF_DATE);
}
if (modifyFormula) {
var row = cell.row,
column = cell.column;
var value = dataProvider.getSourceDataAtCell(row, column);
if (isFormulaExpression(value)) {
var startCoord = cellCoordFactory('column', start);
var expModifier = new ExpressionModifier(value);
expModifier.useCustomModifier(customTranslateModifier);
expModifier.translate({
column: columnsAmount
}, startCoord({
row: origRow,
column: origColumn
}));
dataProvider.updateSourceData(row, column, expModifier.toString());
}
}
});
}
/**
* @param {cellCoord} cell The cell coordinates.
* @param {string} axis The axis defined as "row" or "column".
* @param {number} delta The shift/delta betwen old and new position.
* @param {number} startFromIndex The index from the operation was performed.
* @returns {Array}
*/
function customTranslateModifier(cell, axis, delta, startFromIndex) {
var start = cell.start,
end = cell.end,
type = cell.type;
var startIndex = start[axis].index;
var endIndex = end[axis].index;
var indexOffset = Math.abs(delta) - 1;
var deltaStart = delta;
var deltaEnd = delta;
var refError = false; // Mark all cells as #REF! which refer to removed cells between startFromIndex and startFromIndex + delta
if (startIndex >= startFromIndex && endIndex <= startFromIndex + indexOffset) {
refError = true;
} // Decrement all cells below startFromIndex
if (!refError && type === 'cell') {
if (startFromIndex >= startIndex) {
deltaStart = 0;
deltaEnd = 0;
}
}
if (!refError && type === 'range') {
if (startFromIndex >= startIndex) {
deltaStart = 0;
}
if (startFromIndex > endIndex) {
deltaEnd = 0;
} else if (endIndex <= startFromIndex + indexOffset) {
deltaEnd -= Math.min(endIndex - (startFromIndex + indexOffset), 0);
}
}
if (startIndex + deltaStart < 0) {
deltaStart -= startIndex + deltaStart;
}
return [deltaStart, deltaEnd, refError];
}