import { ICommand } from 'valor-unistore-undo'; import { IStoreState, ID, IRow } from '../index.data'; import { insertTreeRow, deleteTreeRowOperation } from '../store/actions/row'; import { getCurrentRowIndex, getRowWithCells_subtree, restoreSelection, getRowWithCells, getCurrentRowIndexes, } from './helper'; import * as R from 'rambda'; import { IRowWithCell } from '../SpreadSheetProvider/index.data'; import { getRow, getRowi, isTreeRow } from '../store/selectors'; import { RootNodeId } from 'valor-app-utils/dist/tree/interface'; import { Store } from 'unistore'; import { insertRow, deleteRowOperation } from '../store/actions/flattenRow'; import { SpreadSheetRuntime } from '../RuntimeContext'; type ITreeUndoContext = { parentI: number; // 被删除的行的parent index: number; // 被删除的行, 在parent下的index rows: IRowWithCell[]; // 不用记录i, 直接使用 rows[0].i }; type IFlattenUndoContext = { rows: IRowWithCell[]; }; export type DeleteRowCommandParams = { helpers: { normalizeRow: (rows: IRow[], row: IRowWithCell) => IRowWithCell; }; }; type IUndoContext = ITreeUndoContext | IFlattenUndoContext; class DeleteRowCommand extends ICommand< IStoreState, DeleteRowCommandParams, IUndoContext, SpreadSheetRuntime > { deleteI?: number[]; isTreeArea?: boolean = false; executeTree = (state: IStoreState, deleteI: number) => { this.isTreeArea = true; if (deleteI < 0) return false; /** * 恢复逻辑: 必须保证恢复到原位 * A * A1 * A2 * A21 * A3 * 因此全部使用 parentId + index模式 */ const rootRow = state.rows[deleteI]; // 被删除的行 ( 作为根的行 ) if (rootRow.sealed) return false; const parentId = state.treeContext[rootRow.id].parentId; const parentI = parentId === '-1' ? -1 : getRowi(state, parentId); this.undoContext = { parentI, index: state.treeContext[rootRow.id].index, rows: R.clone(getRowWithCells_subtree(state, deleteI)), }; // 2020-04-09: 删除前先选中 兄弟行 或 父行 deleteTreeRowOperation(this.store, deleteI, this.params.helpers, this.runtime!); // 收尾 return true; }; // deleteI=[fromIndex, toIndex] executeFlatten = (state: IStoreState, deleteI: number[]) => { this.isTreeArea = false; const deletedRows = R.range(deleteI[0], R.last(deleteI)! + 1).map(i => getRowWithCells(state, i), ); this.undoContext = { rows: R.clone(deletedRows), }; deleteRowOperation(this.store, deleteI, this.runtime!); return true; }; /** * 删除一行, 如果该行有子树, 则一同删除 */ execute = () => { const state = this.store.getState(); const deleteI = R.is(Array, this.deleteI) ? this.deleteI : getCurrentRowIndexes(state); if (!deleteI || deleteI.length <= 0) return false; this.deleteI = deleteI; if (deleteI.length < 0) return false; // 保证表内至少有一行 if (state.rows.length === 0) return false; const firstSelectedRow = state.rows[deleteI[0]]; const lastSelectedRow = state.rows[R.last(deleteI)!]; if (isTreeRow(firstSelectedRow) && isTreeRow(lastSelectedRow)) { return this.executeTree(state, deleteI[0]); } else if (!isTreeRow(firstSelectedRow) && !isTreeRow(lastSelectedRow)) { return this.executeFlatten(state, deleteI); } else { console.log('不允许同时删除 tree area 与 flatten area'); return false; } }; undo = () => { const state = this.store.getState(); if (this.isTreeArea) { const undoContext = this.undoContext as ITreeUndoContext; const newState = insertTreeRow( state, 'child', undoContext['parentI'], undoContext['rows'], undoContext['index'], this.params.helpers, this.runtime!, ); this.store.setState(Object.assign(newState, { readyDimensions: true })); } else { const undoContext = this.undoContext as IFlattenUndoContext; const newState = insertRow(state, this.deleteI![0] - 1, undoContext['rows'], this.runtime!); this.store.setState(Object.assign(newState, { readyDimensions: true })); } setTimeout(() => { this.runtime!.setSheetDimensions(); restoreSelection(this.store, this.undoContext['rows'][0].cells![0]!.id, this.runtime!); }); }; } export default DeleteRowCommand;