diff --git a/src/helpers/sheet.ts b/src/helpers/sheet.ts index 60db59ee02..b8f5887030 100644 --- a/src/helpers/sheet.ts +++ b/src/helpers/sheet.ts @@ -1,18 +1,7 @@ import { _t } from "../translation"; -import { HeaderIndex, Row } from "../types/misc"; +import { HeaderIndex } from "../types/misc"; import { getUnquotedSheetName, isDefined, memoize } from "./misc"; -export function createDefaultRows(rowNumber: number): Row[] { - const rows: Row[] = []; - for (let i = 0; i < rowNumber; i++) { - const row = { - cells: {}, - }; - rows.push(row); - } - return rows; -} - export function moveHeaderIndexesOnHeaderAddition( indexHeaderAdded: HeaderIndex, numberAdded: number, diff --git a/src/plugins/core/cell.ts b/src/plugins/core/cell.ts index 1b2183bf46..e99ff69d12 100644 --- a/src/plugins/core/cell.ts +++ b/src/plugins/core/cell.ts @@ -5,7 +5,15 @@ import { groupItemIdsByZones, iterateItemIdsPositions, } from "../../helpers/data_normalization"; -import { deepEquals, range, replaceNewLines } from "../../helpers/misc"; +import { + deepEquals, + groupConsecutive, + isDefined, + largeMax, + largeMin, + range, + replaceNewLines, +} from "../../helpers/misc"; import { toXC } from "../../helpers/coordinates"; import { CorePlugin } from "../core_plugin"; @@ -21,7 +29,7 @@ import { SetFormattingCommand, UpdateCellCommand, } from "../../types/commands"; -import { CellPosition, HeaderIndex, RangeAdapterFunctions, UID } from "../../types/misc"; +import { CellPosition, Dimension, HeaderIndex, RangeAdapterFunctions, UID } from "../../types/misc"; import { CompiledFormula, SerializedCompiledFormula } from "../../formulas/compiler"; import { @@ -42,6 +50,10 @@ import { Unsquisher } from "./unsquisher"; interface CoreState { // this.cells[sheetId][cellId] --> cell|undefined cells: Record | undefined>; + // this.grid[sheetId][row][col] --> cellId|undefined (position --> id) + grid: Record | undefined> | undefined>; + // this.positions[cellId] --> position (id --> position) + positions: Record; nextId: number; } @@ -55,6 +67,10 @@ export class CellPlugin extends CorePlugin implements CoreState { static getters = [ "zoneToXC", "getCells", + "getCell", + "getCellPosition", + "tryGetCellPosition", + "getRowCellIds", "getTranslatedCellFormula", "getCellStyle", "getCellById", @@ -63,6 +79,12 @@ export class CellPlugin extends CorePlugin implements CoreState { ] as const; readonly nextId = 1; public readonly cells: { [sheetId: string]: { [id: string]: Cell } } = {}; + public readonly grid: { + [sheetId: string]: + | { [row: number]: { [col: number]: number | undefined } | undefined } + | undefined; + } = {}; + public readonly positions: Record = {}; adaptRanges(adapters: RangeAdapterFunctions) { for (const sheet of Object.keys(this.cells)) { @@ -93,10 +115,6 @@ export class CellPlugin extends CorePlugin implements CoreState { return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell); case "CLEAR_CELL": return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell); - case "UPDATE_CELL_POSITION": - return !cmd.cellId || this.cells[cmd.sheetId]?.[cmd.cellId] - ? CommandResult.Success - : CommandResult.InvalidCellId; case "SET_FORMATTING": return this.checkUselessSetFormatting(cmd); default: @@ -112,13 +130,19 @@ export class CellPlugin extends CorePlugin implements CoreState { case "CLEAR_FORMATTING": this.clearFormatting(cmd.sheetId, cmd.target); break; - case "ADD_COLUMNS_ROWS": + case "ADD_COLUMNS_ROWS": { + const addedIndex = cmd.position === "before" ? cmd.base : cmd.base + 1; + this.moveCellsOnAddition(cmd.sheetId, cmd.dimension, addedIndex, cmd.quantity); if (cmd.dimension === "COL") { this.handleAddColumnsRows(cmd, this.copyColumnStyle.bind(this)); } else { this.handleAddColumnsRows(cmd, this.copyRowStyle.bind(this)); } break; + } + case "REMOVE_COLUMNS_ROWS": + this.moveCellsOnDeletion(cmd.sheetId, cmd.dimension, cmd.elements); + break; case "UPDATE_CELL": this.updateCell(cmd.sheetId, cmd.col, cmd.row, cmd); break; @@ -142,7 +166,116 @@ export class CellPlugin extends CorePlugin implements CoreState { this.clearZones(cmd.sheetId, cmd.target); break; case "DELETE_SHEET": { + for (const cell of this.getCells(cmd.sheetId)) { + this.history.update("positions", cell.id, undefined); + } this.history.update("cells", cmd.sheetId, undefined); + this.history.update("grid", cmd.sheetId, undefined); + } + } + } + + /** + * Set the cell at a new position and clear its previous position. + */ + private setNewPosition(cellId: number, sheetId: UID, col: HeaderIndex, row: HeaderIndex) { + const currentPosition = this.positions[cellId]; + if (currentPosition) { + this.clearPosition(sheetId, currentPosition.col, currentPosition.row); + } + this.history.update("positions", cellId, { row, col, sheetId }); + this.history.update("grid", sheetId, row, col, cellId); + } + + /** + * Remove the cell at the given position (if there's one) + */ + private clearPosition(sheetId: UID, col: HeaderIndex, row: HeaderIndex) { + const cellId = this.grid[sheetId]?.[row]?.[col]; + if (cellId) { + this.history.update("positions", cellId, undefined); + this.history.update("grid", sheetId, row, col, undefined); + } + } + + /** + * Positioned cells of a sheet, sorted by the given dimension. The sort order + * guarantees that shifting cells never overwrites a cell that has not been + * moved yet: ascending when cells move toward the origin (deletion), descending + * when they move away from it (addition). + */ + private getPositionedCells( + sheetId: UID, + dimension: Dimension, + order: "asc" | "desc" + ): { cellId: number; col: HeaderIndex; row: HeaderIndex }[] { + const cells = this.getCells(sheetId).map((cell) => { + const { col, row } = this.positions[cell.id]!; + return { cellId: cell.id, col, row }; + }); + const key = dimension === "COL" ? "col" : "row"; + return cells.sort((a, b) => (order === "asc" ? a[key] - b[key] : b[key] - a[key])); + } + + /** + * Shift the cells located after an inserted column/row away from the origin. + */ + private moveCellsOnAddition( + sheetId: UID, + dimension: Dimension, + addedIndex: HeaderIndex, + quantity: number + ) { + for (const { cellId, col, row } of this.getPositionedCells(sheetId, dimension, "desc")) { + const index = dimension === "COL" ? col : row; + if (index >= addedIndex) { + this.setNewPosition( + cellId, + sheetId, + dimension === "COL" ? col + quantity : col, + dimension === "ROW" ? row + quantity : row + ); + } + } + } + + /** + * Clear the cells and shift the cells located after deleted columns/rows toward the origin. + * The cells located on the deleted headers have already been removed. + */ + private moveCellsOnDeletion(sheetId: UID, dimension: Dimension, elements: HeaderIndex[]) { + if (dimension === "COL") { + this.dispatch("CLEAR_CELLS", { + sheetId, + target: elements.map((col) => ({ + left: col, + top: 0, + right: col, + bottom: this.getters.getNumberRows(sheetId) - 1, + })), + }); + } else { + this.dispatch("CLEAR_CELLS", { + sheetId, + target: groupConsecutive(elements).map((group) => ({ + left: 0, + top: largeMin(group), + right: this.getters.getNumberCols(sheetId) - 1, + bottom: largeMax(group), + })), + }); + } + const deleted = [...elements].sort((a, b) => a - b); + for (const { cellId, col, row } of this.getPositionedCells(sheetId, dimension, "asc")) { + const index = dimension === "COL" ? col : row; + const shift = deleted.filter((deletedIndex) => deletedIndex < index).length; + if (shift > 0) { + this.setNewPosition( + cellId, + sheetId, + dimension === "COL" ? col - shift : col, + dimension === "ROW" ? row - shift : row + ); } } } @@ -279,10 +412,7 @@ export class CellPlugin extends CorePlugin implements CoreState { cellData?.compiledFormula ); this.history.update("cells", sheet.id, cell.id, cell); - this.dispatch("UPDATE_CELL_POSITION", { - cellId: cell.id, - ...position, - }); + this.setNewPosition(cell.id, position.sheetId, position.col, position.row); } } } @@ -391,15 +521,41 @@ export class CellPlugin extends CorePlugin implements CoreState { return Object.values(this.cells[sheetId] || {}); } + getCell({ sheetId, col, row }: CellPosition): Cell | undefined { + const cellId = this.grid[sheetId]?.[row]?.[col]; + if (cellId === undefined) { + return undefined; + } + return this.cells[sheetId]?.[cellId]; + } + + getCellPosition(cellId: number): CellPosition { + const position = this.positions[cellId]; + if (!position) { + throw new Error(`asking for a cell position that doesn't exist, cell id: ${cellId}`); + } + return position; + } + + tryGetCellPosition(cellId: number): CellPosition | undefined { + return this.positions[cellId]; + } + + getRowCellIds(sheetId: UID, row: HeaderIndex): number[] { + return Object.values(this.grid[sheetId]?.[row] || {}).filter(isDefined); + } + /** * get a cell by ID. Used in evaluation when evaluating an async cell, we need to be able to find it back after * starting an async evaluation even if it has been moved or re-allocated */ getCellById(cellId: number): Cell | undefined { // this must be as fast as possible - const position = this.getters.getCellPosition(cellId); - const sheet = this.cells[position.sheetId]; - return sheet[cellId]; + const position = this.positions[cellId]; + if (!position) { + return undefined; + } + return this.cells[position.sheetId]?.[cellId]; } /* @@ -617,12 +773,7 @@ export class CellPlugin extends CorePlugin implements CoreState { ) { if (before) { this.history.update("cells", sheetId, before.id, undefined); - this.dispatch("UPDATE_CELL_POSITION", { - cellId: undefined, - col, - row, - sheetId, - }); + this.clearPosition(sheetId, col, row); } return; } @@ -630,7 +781,7 @@ export class CellPlugin extends CorePlugin implements CoreState { const cellId = before?.id || this.getNextCellId(); const cell = createCell(this.getters, cellId, afterContent, format, style, sheetId); this.history.update("cells", sheetId, cell.id, cell); - this.dispatch("UPDATE_CELL_POSITION", { cellId: cell.id, col, row, sheetId }); + this.setNewPosition(cell.id, sheetId, col, row); } private checkCellOutOfSheet(cmd: PositionDependentCommand): CommandResult { diff --git a/src/plugins/core/sheet.ts b/src/plugins/core/sheet.ts index 683bdc4e5e..2f70df0129 100644 --- a/src/plugins/core/sheet.ts +++ b/src/plugins/core/sheet.ts @@ -1,23 +1,13 @@ import { FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX } from "../../constants"; import { isColorValid } from "../../helpers/color"; +import { deepCopy, includesAll, isDefined, largeMax, largeMin, range } from "../../helpers/misc"; import { - deepCopy, - groupConsecutive, - includesAll, - isDefined, - largeMax, - largeMin, - range, -} from "../../helpers/misc"; -import { - createDefaultRows, getDuplicateSheetName, getNextSheetName, isSheetNameEqual, toStandardizedSheetName, } from "../../helpers/sheet"; import { isZoneInside, isZoneValid, toZone } from "../../helpers/zones"; -import { Cell } from "../../types/cells"; import { Command, CommandResult, @@ -26,16 +16,13 @@ import { FreezeColumnsCommand, FreezeRowsCommand, RenameSheetCommand, - UpdateCellPositionCommand, isRangeDependant, isTargetDependent, } from "../../types/commands"; import { - CellPosition, Dimension, HeaderIndex, PaneDivision, - Row, Sheet, UID, UnboundedZone, @@ -49,7 +36,6 @@ interface SheetState { readonly sheets: Record; readonly orderedSheetIds: UID[]; readonly sheetIdsMapName: Record; - readonly cellPosition: Record; } export class SheetPlugin extends CorePlugin implements SheetState { @@ -64,10 +50,7 @@ export class SheetPlugin extends CorePlugin implements SheetState { "isSheetVisible", "doesHeaderExist", "doesHeadersExist", - "getCell", - "getCellPosition", "getColsZone", - "getRowCellIds", "getRowsZone", "getNumberCols", "getNumberRows", @@ -82,14 +65,12 @@ export class SheetPlugin extends CorePlugin implements SheetState { "getUnboundedZone", "checkElementsIncludeAllNonFrozenHeaders", "getDuplicateSheetName", - "tryGetCellPosition", "isSheetLocked", ] as const; readonly sheetIdsMapName: Record = {}; readonly orderedSheetIds: UID[] = []; readonly sheets: Record = {}; - readonly cellPosition: Record = {}; // --------------------------------------------------------------------------- // Command Handling @@ -260,9 +241,6 @@ export class SheetPlugin extends CorePlugin implements SheetState { this.addRows(this.sheets[cmd.sheetId]!, cmd.base, cmd.position, cmd.quantity); } break; - case "UPDATE_CELL_POSITION": - this.updateCellPosition(cmd); - break; case "FREEZE_COLUMNS": this.setPaneDivisions(cmd.sheetId, cmd.quantity, "COL"); break; @@ -307,7 +285,7 @@ export class SheetPlugin extends CorePlugin implements SheetState { id: sheetData.id, name: name, numberOfCols: colNumber, - rows: createDefaultRows(rowNumber), + numberOfRows: rowNumber, areGridLinesVisible: sheetData.areGridLinesVisible === undefined ? true : sheetData.areGridLinesVisible, isVisible: sheetData.isVisible, @@ -430,15 +408,6 @@ export class SheetPlugin extends CorePlugin implements SheetState { return headerIndexes.every((index) => this.doesHeaderExist(sheetId, dimension, index)); } - getCell({ sheetId, col, row }: CellPosition): Cell | undefined { - const sheet = this.tryGetSheet(sheetId); - const cellId = sheet?.rows[row]?.cells[col]; - if (cellId === undefined) { - return undefined; - } - return this.getters.getCellById(cellId); - } - getColsZone(sheetId: UID, start: HeaderIndex, end: HeaderIndex): Zone { return { top: 0, @@ -448,10 +417,6 @@ export class SheetPlugin extends CorePlugin implements SheetState { }; } - getRowCellIds(sheetId: UID, row: HeaderIndex): number[] { - return Object.values(this.getSheet(sheetId).rows[row]?.cells).filter(isDefined); - } - getRowsZone(sheetId: UID, start: HeaderIndex, end: HeaderIndex): Zone { return { top: start, @@ -461,24 +426,12 @@ export class SheetPlugin extends CorePlugin implements SheetState { }; } - getCellPosition(cellId: number): CellPosition { - const cell = this.cellPosition[cellId]; - if (!cell) { - throw new Error(`asking for a cell position that doesn't exist, cell id: ${cellId}`); - } - return cell; - } - - tryGetCellPosition(cellId: number): CellPosition | undefined { - return this.cellPosition[cellId]; - } - getNumberCols(sheetId: UID) { return this.getSheet(sheetId).numberOfCols; } getNumberRows(sheetId: UID) { - return this.getSheet(sheetId).rows.length; + return this.getSheet(sheetId).numberOfRows; } getNumberHeaders(sheetId: UID, dimension: Dimension): HeaderIndex { @@ -596,42 +549,6 @@ export class SheetPlugin extends CorePlugin implements SheetState { return CommandResult.Success; } - private updateCellPosition(cmd: Omit) { - const { sheetId, cellId, col, row } = cmd; - if (cellId) { - this.setNewPosition(cellId, sheetId, col, row); - } else { - this.clearPosition(sheetId, col, row); - } - } - - /** - * Set the cell at a new position and clear its previous position. - */ - private setNewPosition(cellId: number, sheetId: UID, col: HeaderIndex, row: HeaderIndex) { - const currentPosition = this.cellPosition[cellId]; - if (currentPosition) { - this.clearPosition(sheetId, currentPosition.col, currentPosition.row); - } - this.history.update("cellPosition", cellId, { - row: row, - col: col, - sheetId: sheetId, - }); - this.history.update("sheets", sheetId, "rows", row, "cells", col, cellId); - } - - /** - * Remove the cell at the given position (if there's one) - */ - private clearPosition(sheetId: UID, col: HeaderIndex, row: HeaderIndex) { - const cellId = this.sheets[sheetId]?.rows[row].cells[col]; - if (cellId) { - this.history.update("cellPosition", cellId, undefined); - this.history.update("sheets", sheetId, "rows", row, "cells", col, undefined); - } - } - private setGridLinesVisibility(sheetId: UID, areGridLinesVisible: boolean) { this.history.update("sheets", sheetId, "areGridLinesVisible", areGridLinesVisible); } @@ -647,7 +564,7 @@ export class SheetPlugin extends CorePlugin implements SheetState { id, name, numberOfCols: colNumber, - rows: createDefaultRows(rowNumber), + numberOfRows: rowNumber, areGridLinesVisible: true, isVisible: true, panes: { @@ -791,13 +708,6 @@ export class SheetPlugin extends CorePlugin implements SheetState { newSheet.id = toId; newSheet.name = toName; newSheet.isLocked = false; - for (let col = 0; col <= newSheet.numberOfCols; col++) { - for (let row = 0; row <= newSheet.rows.length; row++) { - if (newSheet.rows[row]) { - newSheet.rows[row].cells[col] = undefined; - } - } - } const orderedSheetIds = this.orderedSheetIds.slice(); const currentIndex = orderedSheetIds.indexOf(fromId); orderedSheetIds.splice(currentIndex + 1, 0, newSheet.id); @@ -805,7 +715,7 @@ export class SheetPlugin extends CorePlugin implements SheetState { this.history.update("sheets", Object.assign({}, this.sheets, { [newSheet.id]: newSheet })); for (const cell of Object.values(this.getters.getCells(fromId))) { - const { col, row } = this.getCellPosition(cell.id); + const { col, row } = this.getters.getCellPosition(cell.id); this.dispatch("UPDATE_CELL", { sheetId: newSheet.id, col, @@ -855,14 +765,7 @@ export class SheetPlugin extends CorePlugin implements SheetState { * @param columns Columns to delete */ private removeColumns(sheet: Sheet, columns: HeaderIndex[]) { - // This is necessary because we have to delete elements in correct order: - // begin with the end. - columns.sort((a, b) => b - a); - for (const column of columns) { - // Move the cells. - this.moveCellOnColumnsDeletion(sheet, column); - } - const numberOfCols = this.sheets[sheet.id]!.numberOfCols; + const numberOfCols = sheet.numberOfCols; this.history.update("sheets", sheet.id, "numberOfCols", numberOfCols - columns.length); const count = columns.filter((col) => col < sheet.panes.xSplit).length; if (count) { @@ -882,19 +785,8 @@ export class SheetPlugin extends CorePlugin implements SheetState { * @param rows Rows to delete */ private removeRows(sheet: Sheet, rows: HeaderIndex[]) { - // This is necessary because we have to delete elements in correct order: - // begin with the end. - rows.sort((a, b) => b - a); - - for (const group of groupConsecutive(rows)) { - // indexes are sorted in the descending order - const from = group[group.length - 1]; - const to = group[0]; - // Move the cells. - this.moveCellOnRowsDeletion(sheet, from, to); - // Effectively delete the rows - this.updateRowsStructureOnDeletion(sheet, from, to); - } + const numberOfRows = sheet.numberOfRows; + this.history.update("sheets", sheet.id, "numberOfRows", numberOfRows - rows.length); const count = rows.filter((row) => row < sheet.panes.ySplit).length; if (count) { this.setPaneDivisions(sheet.id, sheet.panes.ySplit - count, "ROW"); @@ -908,10 +800,7 @@ export class SheetPlugin extends CorePlugin implements SheetState { quantity: number ) { const index = position === "before" ? column : column + 1; - // Move the cells. - this.moveCellsOnAddition(sheet, index, quantity, "columns"); - - const numberOfCols = this.sheets[sheet.id]!.numberOfCols; + const numberOfCols = sheet.numberOfCols; this.history.update("sheets", sheet.id, "numberOfCols", numberOfCols + quantity); if (index < sheet.panes.xSplit) { this.setPaneDivisions(sheet.id, sheet.panes.xSplit + quantity, "COL"); @@ -920,153 +809,13 @@ export class SheetPlugin extends CorePlugin implements SheetState { private addRows(sheet: Sheet, row: HeaderIndex, position: "before" | "after", quantity: number) { const index = position === "before" ? row : row + 1; - this.addEmptyRows(sheet, quantity); - - // Move the cells. - this.moveCellsOnAddition(sheet, index, quantity, "rows"); - + const numberOfRows = sheet.numberOfRows; + this.history.update("sheets", sheet.id, "numberOfRows", numberOfRows + quantity); if (index < sheet.panes.ySplit) { this.setPaneDivisions(sheet.id, sheet.panes.ySplit + quantity, "ROW"); } } - private moveCellOnColumnsDeletion(sheet: Sheet, deletedColumn: number) { - this.dispatch("CLEAR_CELLS", { - sheetId: sheet.id, - target: [ - { - left: deletedColumn, - top: 0, - right: deletedColumn, - bottom: sheet.rows.length - 1, - }, - ], - }); - - for (let rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) { - const row = sheet.rows[rowIndex]; - for (const i in row.cells) { - const colIndex = Number(i); - const cellId = row.cells[i]; - if (cellId) { - if (colIndex > deletedColumn) { - this.setNewPosition(cellId, sheet.id, colIndex - 1, rowIndex); - } - } - } - } - } - - /** - * Move the cells after a column or rows insertion - */ - private moveCellsOnAddition( - sheet: Sheet, - addedElement: HeaderIndex, - quantity: number, - dimension: "rows" | "columns" - ) { - const updates: UpdateCellPositionCommand[] = []; - for (let rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) { - const row = sheet.rows[rowIndex]; - if (dimension !== "rows" || rowIndex >= addedElement) { - for (const i in row.cells) { - const colIndex = Number(i); - const cellId = row.cells[i]; - if (cellId) { - if (dimension === "rows" || colIndex >= addedElement) { - updates.push({ - sheetId: sheet.id, - cellId: cellId, - col: colIndex + (dimension === "columns" ? quantity : 0), - row: rowIndex + (dimension === "rows" ? quantity : 0), - type: "UPDATE_CELL_POSITION", - }); - } - } - } - } - } - for (const update of updates.reverse()) { - this.updateCellPosition(update); - } - } - - /** - * Move all the cells that are from the row under `deleteToRow` up to `deleteFromRow` - * - * b.e. - * move vertically with delete from 3 and delete to 5 will first clear all the cells from lines 3 to 5, - * then take all the row starting at index 6 and add them back at index 3 - * - */ - private moveCellOnRowsDeletion( - sheet: Sheet, - deleteFromRow: HeaderIndex, - deleteToRow: HeaderIndex - ) { - this.dispatch("CLEAR_CELLS", { - sheetId: sheet.id, - target: [ - { - left: 0, - top: deleteFromRow, - right: this.getters.getNumberCols(sheet.id), - bottom: deleteToRow, - }, - ], - }); - - const numberRows = deleteToRow - deleteFromRow + 1; - for (let rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) { - const row = sheet.rows[rowIndex]; - if (rowIndex > deleteToRow) { - for (const i in row.cells) { - const colIndex = Number(i); - const cellId = row.cells[i]; - if (cellId) { - this.setNewPosition(cellId, sheet.id, colIndex, rowIndex - numberRows); - } - } - } - } - } - - private updateRowsStructureOnDeletion( - sheet: Sheet, - deleteFromRow: HeaderIndex, - deleteToRow: HeaderIndex - ) { - const rows: Row[] = []; - const cellsQueue = sheet.rows.map((row) => row.cells).reverse(); - for (const i in sheet.rows) { - const row = Number(i); - if (row >= deleteFromRow && row <= deleteToRow) { - continue; - } - rows.push({ - cells: cellsQueue.pop()!, - }); - } - this.history.update("sheets", sheet.id, "rows", rows); - } - - /** - * Add empty rows at the end of the rows - * - * @param sheet Sheet - * @param quantity Number of rows to add - */ - private addEmptyRows(sheet: Sheet, quantity: number) { - const rows: Row[] = sheet.rows.slice(); - for (let i = 0; i < quantity; i++) { - rows.push({ - cells: {}, - }); - } - this.history.update("sheets", sheet.id, "rows", rows); - } - private getImportedSheetSize(data: SheetData): { rowNumber: number; colNumber: number } { const positions = Object.keys(data.cells).map(toZone); diff --git a/src/types/commands.ts b/src/types/commands.ts index c37458041b..7b15a42520 100644 --- a/src/types/commands.ts +++ b/src/types/commands.ts @@ -258,7 +258,6 @@ export const lockedSheetAllowedCommands = new Set([ export const coreTypes = new Set([ /** CELLS */ "UPDATE_CELL", - "UPDATE_CELL_POSITION", "CLEAR_CELL", "CLEAR_CELLS", "DELETE_CONTENT", @@ -379,14 +378,6 @@ export interface UpdateCellCommand extends PositionDependentCommand { format?: Format; } -/** - * Move a cell to a given position or clear the position. - */ -export interface UpdateCellPositionCommand extends PositionDependentCommand { - type: "UPDATE_CELL_POSITION"; - cellId?: number; -} - //------------------------------------------------------------------------------ // Grid Shape //------------------------------------------------------------------------------ @@ -1246,7 +1237,6 @@ export type CoreCommand = /** CELLS */ | UpdateCellCommand - | UpdateCellPositionCommand | ClearCellCommand | ClearCellsCommand | DeleteContentCommand @@ -1492,7 +1482,6 @@ export const enum CommandResult { InvalidRange = "InvalidRange", InvalidZones = "InvalidZones", InvalidSheetId = "InvalidSheetId", - InvalidCellId = "InvalidCellId", InvalidFigureId = "InvalidFigureId", InputAlreadyFocused = "InputAlreadyFocused", MaximumRangesReached = "MaximumRangesReached", diff --git a/src/types/misc.ts b/src/types/misc.ts index 7924b90050..b3fb996861 100644 --- a/src/types/misc.ts +++ b/src/types/misc.ts @@ -133,7 +133,7 @@ export interface Sheet { id: UID; name: string; numberOfCols: number; - rows: Row[]; + numberOfRows: number; areGridLinesVisible: boolean; isVisible: boolean; panes: PaneDivision; @@ -232,10 +232,6 @@ export interface HeaderDimensions { end: Pixel; } -export interface Row { - cells: Record; // number is a column index -} - export interface Position { col: HeaderIndex; row: HeaderIndex; diff --git a/tests/collaborative/inverses.test.ts b/tests/collaborative/inverses.test.ts index 9d56493753..5ee31004cd 100644 --- a/tests/collaborative/inverses.test.ts +++ b/tests/collaborative/inverses.test.ts @@ -17,7 +17,6 @@ import { SetZoneBordersCommand, UnlockSheetCommand, UpdateCellCommand, - UpdateCellPositionCommand, UpdateChartCommand, UpdateFigureCommand, } from "../../src"; @@ -283,13 +282,6 @@ describe("Inverses commands", () => { sheetId: "1", content: "test", }; - const updateCellPosition: UpdateCellPositionCommand = { - type: "UPDATE_CELL_POSITION", - sheetId: "1", - cellId: 1, - col: 1, - row: 1, - }; const clearCell: ClearCellCommand = { type: "CLEAR_CELL", sheetId: "1", @@ -354,7 +346,6 @@ describe("Inverses commands", () => { }; test.each([ updateCell, - updateCellPosition, clearCell, clearCells, deleteContent, diff --git a/tests/sheet/sheet_manipulation_plugin.test.ts b/tests/sheet/sheet_manipulation_plugin.test.ts index 5cb4aab71d..f027b6d422 100644 --- a/tests/sheet/sheet_manipulation_plugin.test.ts +++ b/tests/sheet/sheet_manipulation_plugin.test.ts @@ -239,7 +239,7 @@ describe("Columns", () => { test("On addition before first", () => { addColumns(model, "before", "A", 1); expect(model.getters.getActiveSheet().numberOfCols).toBe(5); - expect(model.getters.getActiveSheet().rows).toHaveLength(1); + expect(model.getters.getActiveSheet().numberOfRows).toBe(1); }); test("On addition before", () => { addColumns(model, "before", "B", 2); @@ -938,7 +938,7 @@ describe("Rows", () => { test("On addition before first", () => { addRows(model, "before", 0, 1); expect(model.getters.getActiveSheet().numberOfCols).toBe(1); - expect(model.getters.getActiveSheet().rows).toHaveLength(5); + expect(model.getters.getActiveSheet().numberOfRows).toBe(5); }); test("On addition before", () => { addRows(model, "before", 1, 2); diff --git a/tests/sheet/sheets_plugin.test.ts b/tests/sheet/sheets_plugin.test.ts index 7d0fa148b1..0e5949af5a 100644 --- a/tests/sheet/sheets_plugin.test.ts +++ b/tests/sheet/sheets_plugin.test.ts @@ -925,26 +925,6 @@ describe("sheets", () => { expect(getEvaluatedCell(model, "A1").value).toBe(42); }); - test("UPDATE_CELL_POSITION remove the old position if exist", () => { - const model = new Model(); - setCellContent(model, "A1", "test"); - const cell = getCell(model, "A1")!; - model.dispatch("UPDATE_CELL_POSITION", { - sheetId: model.getters.getActiveSheetId(), - col: 1, - row: 1, - cellId: cell.id, - }); - const sheet = model.getters.getActiveSheet(); - expect(sheet.rows[0].cells[0]).toBeUndefined(); - expect(sheet.rows[1].cells[1]).toBe(cell.id); - expect(model.getters.getCellPosition(cell.id)).toEqual({ - col: 1, - row: 1, - sheetId: model.getters.getActiveSheetId(), - }); - }); - test("Cannot remove more columns/rows than there are inside the sheet", () => { const model = new Model({ sheets: [{ colNumber: 3, rowNumber: 3 }] }); expect(deleteRows(model, [0, 1, 2])).toBeCancelledBecause(CommandResult.NotEnoughElements); diff --git a/tests/test_helpers/constants.ts b/tests/test_helpers/constants.ts index 565686a27a..0135590a68 100644 --- a/tests/test_helpers/constants.ts +++ b/tests/test_helpers/constants.ts @@ -136,13 +136,6 @@ export const TEST_COMMANDS: CommandMapping = { content: "hello", sheetId: "Sheet1", }, - UPDATE_CELL_POSITION: { - type: "UPDATE_CELL_POSITION", - cellId: -1, // Makes this command always rejected in monkey party - sheetId: "Sheet1", - row: 0, - col: 0, - }, CLEAR_CELL: { type: "CLEAR_CELL", col: 0, @@ -575,7 +568,6 @@ export const TEST_COMMANDS: CommandMapping = { export const OT_TESTS_SINGLE_CELL_COMMANDS = [ TEST_COMMANDS.UPDATE_CELL, - TEST_COMMANDS.UPDATE_CELL_POSITION, TEST_COMMANDS.CLEAR_CELL, TEST_COMMANDS.SET_BORDER, ];