import { IStoreState, IRow, ID, ICell, FormulaManagerConfig } from '../../index.data'; import { IRowWithCell } from '../..'; import { normalizeRows, normalizeCellIdMap } from '../../common/helper'; import { insertBetween, insertIndex, sliceBy, idMap, batchMove } from 'valor-app-utils'; import { recalculate } from './recalculate'; import { restoreCellRefIfNeeded } from '../formula_support/postProcess'; import { getHostRows, getRowi, getRow } from '../selectors'; import { RootNodeId } from 'valor-app-utils/dist/tree/interface'; import * as R from 'rambda'; import { Store } from 'unistore'; // import { getNewRowDimensions } from './row'; import { SpreadSheetRuntime } from '../../RuntimeContext'; export function insertRow( state: IStoreState, baseI: number, rowsToInsert: IRowWithCell[], runtime: SpreadSheetRuntime, ) { const insertAtIndex = baseI + 1; const rowsToInsert_normalized: IRow[] = normalizeRows( { rows: rowsToInsert, columns: state.columns }, insertAtIndex, ); const cellsToInsert_normalized = normalizeCellIdMap( { rows: rowsToInsert, columns: state.columns }, insertAtIndex, ); const newRows = state.rows .slice(0, insertAtIndex) .concat(rowsToInsert_normalized) .concat(state.rows.slice(insertAtIndex)); const affectedRow_ids = inferHostRowsByInsert(state, baseI, rowsToInsert.map(it => it.id)); // console.log(affectedRow_ids, 'affectedRow_ids ', baseI); const newState = { ...state, rows: newRows, cells: Object.assign({}, state.cells, cellsToInsert_normalized), }; return optimizedCalculate( newState, affectedRow_ids, runtime && runtime.formulaManager.config, runtime && runtime.batchMode, ); } export function moveRow(state: IStoreState, type: 'up' | 'down', rowIndexes: number[]) { const [newRows_, moved] = batchMove(state.rows, rowIndexes, type === 'up' ? -1 : 1); const newRows = newRows_ as IRow[]; if (!moved) return null; // const newRowDimensions = getNewRowDimensions(newRows.map(it => it.id), state.rowDimensions); return { rows: newRows, // rowDimensions: newRowDimensions, }; } export function deleteRow( state: IStoreState, fromIndex: number, toIndex: number, runtime: SpreadSheetRuntime, ) { const newRows = state.rows.slice(0, fromIndex).concat(state.rows.slice(toIndex + 1)); const newCellIds = (R.flatten(newRows.map(row => row.cellIds || ([] as ICell[]))) as any) as ID[]; const newCells = idMap(newCellIds.filter(Boolean).map(id => state.cells[id])); const affectedRow_ids = inferHostRowsByDelete(state, fromIndex, toIndex); const newState = { ...state, rows: newRows, cells: newCells, }; // console.log('affectedRow_ids ', affectedRow_ids, affectedRow_ids.map(id => getRowi(state, id))); return optimizedCalculate( newState, affectedRow_ids, runtime && runtime.formulaManager.config, runtime && runtime.batchMode, ); } /** * @params state * @params prevIndex 表示插入行的 前一行 * @params insertIds */ export function inferHostRowsByInsert(state: IStoreState, prevIndex: number, insertIds: ID[]) { const result = inferHostRowsByDelete( state, prevIndex < 0 ? 0 : prevIndex, prevIndex + 1 > state.rows.length - 1 ? prevIndex : prevIndex + 1, ); return R.uniq(result.concat(insertIds)).filter(it => it !== RootNodeId); } export function inferHostRowsByDelete(state: IStoreState, fromIndex: number, toIndex: number) { const result1 = getHostRows(state, fromIndex); const deletedIds = R.range(fromIndex, toIndex + 1) .map(i => (i >= 0 ? state.rows[i].id : null)) .filter(Boolean); const result2 = toIndex <= state.rows.length - 1 ? getHostRows(state, toIndex) : ([] as ID[]); return R.uniq(result1.concat(result2)).filter( it => it !== RootNodeId && deletedIds.indexOf(it) < 0, ); } export function ensureSelectionWhenDelete( store: Store, deleteIds: ID[], runtime: SpreadSheetRuntime, action: any, ) { if (deleteIds.length <= 0) return; runtime!.fsmService.send({ type: 'SELECT.NONE' }); const state = store.getState(); const fromIndex = getRowi(state, deleteIds[0]); const toIndex = getRowi(state, R.last(deleteIds)!); const focusOnRowId = fromIndex > 0 ? state.rows[fromIndex - 1].id : toIndex < state.rows.length - 1 ? state.rows[toIndex + 1].id : null; action(); setTimeout(() => { runtime!.setSheetDimensions(); focusOnRowId && runtime!.fsmService.send({ type: 'SELECT.ROW', selectedRow: focusOnRowId }); }, 0); } export function deleteRowOperation( store: Store, deleteI: number[], runtime: SpreadSheetRuntime, ) { const deleteIds = R.range(deleteI[0], R.last(deleteI)! + 1).map(i => store.getState().rows[i].id); ensureSelectionWhenDelete(store, deleteIds, runtime, () => { const newState = deleteRow(store.getState(), deleteI[0], R.last(deleteI)!, runtime); store.setState(Object.assign(newState, { readyDimensions: true })); }); } function optimizedCalculate( state: IStoreState, affectedRow_ids: ID[], formulaConfig: FormulaManagerConfig, batchMode: boolean, ) { const calculatedStatePatch = batchMode ? Object.assign({}, state) : recalculate(state, { targetRowIds: affectedRow_ids, force: false, config: formulaConfig, }); const cellRefRestored = restoreCellRefIfNeeded(state, calculatedStatePatch); return { ...cellRefRestored, rows: state.rows }; }