import { ICommand } from 'valor-unistore-undo'; import { IStoreState, ID, ICell, ICellNN, ISelection } from '../index.data'; import { setCellData } from '../store/actions'; import { restoreSelection, splitCell, mergeCells, placeCells } from './helper'; import { SpreadSheetRuntime } from '../RuntimeContext'; import { getCell, getCellij, getRangeByIj, getCellByij, selectionIsOneCell, } from '../store/selectors'; import * as R from 'rambda'; import { IMergeCellUndoContext } from './index.data'; import { min, max } from 'valor-app-utils'; export interface MergeCellCommandParams { selectedCellRange?: [ID, ID]; } class MergeCellCommand extends ICommand< IStoreState, MergeCellCommandParams, IMergeCellUndoContext, SpreadSheetRuntime > { getInfo = () => { const state = this.store.getState(); const result: { cellss: ICell[][]; selectedCellRange: [ID, ID] } = {} as any; if (this.undoContext && !R.isEmpty(this.undoContext)) { const minI = min(this.undoContext.map(it => it.i)); const minJ = min(this.undoContext.map(it => it.j)); const maxI = max(this.undoContext.map(it => it.i)); const maxJ = max(this.undoContext.map(it => it.j)); const firstCell = getCellByij(state, minI, minJ)!; const lastCell = getCellByij(state, maxI, maxJ)!; // lastCell可能是null result.selectedCellRange = [firstCell.id, lastCell ? lastCell.id : firstCell.id]; const isSingle = result.selectedCellRange[0] === result.selectedCellRange[1]; result.cellss = getRangeByIj( state, minI, minJ, isSingle ? minI : maxI, isSingle ? minJ : maxJ, ); } else if (this.params.selectedCellRange) { const startIj = getCellij(state, this.params.selectedCellRange[0]); const endIj = getCellij(state, this.params.selectedCellRange[1]); result.cellss = getRangeByIj(state, startIj.i, startIj.j, endIj.i, endIj.j); result.selectedCellRange = this.params.selectedCellRange; } else { if (state.selectionType !== 'cell' || R.isEmpty(state.selectedCellRange)) { return {} as any; } const startIj = getCellij(state, state.selectedCellRange[0]); const endIj = getCellij(state, state.selectedCellRange[1]); result.cellss = getRangeByIj(state, startIj.i, startIj.j, endIj.i, endIj.j); result.selectedCellRange = state.selectedCellRange; } return result; }; execute = () => { const state = this.store.getState(); const info = this.getInfo(); if (R.isEmpty(info)) return false; const { cellss, selectedCellRange } = info; const firstSelectedCell = cellss[0][0]! as ICellNN; if ( (this.params.selectedCellRange && selectedCellRange[0] === selectedCellRange[1]) || (!this.params.selectedCellRange && selectionIsOneCell(state)) ) { // 1. 单选单元格 if ((firstSelectedCell.rowspan || 1) === 1 && (firstSelectedCell.colspan || 1) === 1) { // 1.1 单个非合并单元格, 不做任何操作 return false; } else { // 1.2 单个合并单元格, 将拆分 const { newState, undoContext } = splitCell(state, firstSelectedCell.id, this.runtime!); this.undoContext = undoContext; this.store.setState(Object.assign(newState, { readyDimensions: true }) as IStoreState); } } else { // 2. 多选单元格, 直接做合并 const { newState, undoContext } = mergeCells(state, selectedCellRange, this.runtime!); this.undoContext = undoContext; this.store.setState(Object.assign(newState, { readyDimensions: true }) as IStoreState); } setTimeout(() => { this.runtime!.setSheetDimensions(); this.runtime!.fsmService.send({ type: 'SELECT.CELL', selectedCell: firstSelectedCell.id }); }); return true; }; undo = () => { const state = this.store.getState(); const newState = placeCells(state, this.undoContext); this.store.setState(Object.assign(newState, { readyDimensions: true })); const minI = min(this.undoContext.map(it => it.i)); const minJ = min(this.undoContext.map(it => it.j)); // 左上角的单元不可能为null const firstCellId = this.undoContext.find(it => it.i === minI && it.j === minJ)!.cell!.id; setTimeout(() => { this.runtime!.setSheetDimensions(); this.runtime!.fsmService.send({ type: 'SELECT.CELL', selectedCell: firstCellId }); }); }; } export default MergeCellCommand;