From 3431d234072a5c5c611c15459a186999423db391 Mon Sep 17 00:00:00 2001 From: wpxp123456 Date: Thu, 29 Aug 2024 19:48:34 +0800 Subject: [PATCH 1/6] fix(formula): fix paste --- .../formula-clipboard.controller.ts | 78 ++++++++++++++++--- 1 file changed, 68 insertions(+), 10 deletions(-) diff --git a/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts b/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts index 164d2662954a..ac5690f16638 100644 --- a/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts +++ b/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts @@ -84,26 +84,24 @@ export class FormulaClipboardController extends Disposable { payload: ICopyPastePayload, isSpecialPaste: boolean ) { - const pasteType = payload.pasteType; - // Intercept scenarios where formulas do not need to be processed, and only process default paste and paste formulas only - if (pasteType === PREDEFINED_HOOK_NAME.SPECIAL_PASTE_VALUE || pasteType === PREDEFINED_HOOK_NAME.SPECIAL_PASTE_FORMAT || pasteType === PREDEFINED_HOOK_NAME.SPECIAL_PASTE_COL_WIDTH) { + if ( + [ + PREDEFINED_HOOK_NAME.SPECIAL_PASTE_FORMAT, + PREDEFINED_HOOK_NAME.SPECIAL_PASTE_COL_WIDTH, + PREDEFINED_HOOK_NAME.SPECIAL_PASTE_BESIDES_BORDER, + ].includes(payload.pasteType) + ) { return { undos: [], redos: [], }; } - const copyInfo = { - copyType: payload.copyType || COPY_TYPE.COPY, - copyRange: pasteFrom?.range, - pasteType: payload.pasteType, - }; - const pastedRange = pasteTo.range; - const matrix = data; const workbook = this._currentUniverSheet.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET)!; const unitId = pasteTo.unitId || workbook.getUnitId(); const subUnitId = pasteTo.subUnitId || workbook.getActiveSheet()?.getSheetId(); + if (!unitId || !subUnitId) { return { undos: [], @@ -111,6 +109,14 @@ export class FormulaClipboardController extends Disposable { }; } + const pastedRange = pasteTo.range; + const matrix = data; + const copyInfo = { + copyType: payload.copyType || COPY_TYPE.COPY, + copyRange: pasteFrom?.range, + pasteType: payload.pasteType, + }; + return this._injector.invoke((accessor) => getSetCellFormulaMutations( unitId, subUnitId, @@ -271,6 +277,58 @@ export function getSetCellFormulaMutations( }; } +function getValueMatrix( + unitId: string, + subUnitId: string, + range: IDiscreteRange, + matrix: ObjectMatrix, + accessor: IAccessor, + copyInfo: { + copyType: COPY_TYPE; + copyRange?: IDiscreteRange; + pasteType: string; + }, + lexerTreeBuilder: LexerTreeBuilder, + formulaDataModel: FormulaDataModel, + isSpecialPaste = false, + pasteFrom: ISheetDiscreteRangeLocation | null +) { + if (!pasteFrom) { + return getValueMatrixOfPasteFromIsNull(matrix); + } +} + +function getValueMatrixOfPasteFromIsNull(matrix: ObjectMatrix): ObjectMatrix { + const valueMatrix = new ObjectMatrix(); + + matrix.forValue((row, col, value) => { + if (!isFormulaString(value.v)) { + return false; + } + + const valueObject: ICellDataWithSpanInfo = {}; + valueObject.v = null; + valueObject.f = `${value.v}`; + + valueMatrix.setValue(row, col, valueObject); + }); + + return valueMatrix; +} + +function getPasteValueValueMatrix( + matrix: ObjectMatrix, + formulaDataModel: FormulaDataModel, + pasteFrom: ISheetDiscreteRangeLocation | null +) { + const valueMatrix = new ObjectMatrix(); + const arrayFormulaCellData = formulaDataModel.getArrayFormulaCellData(); + + // matrix.forValue((row, col, value) => { + + // } +} + function getCellRichText(cell: ICellData) { if (cell?.p) { const body = cell?.p.body; From 2b523fadf55aff509e72fd0212ebf7a2babef806 Mon Sep 17 00:00:00 2001 From: wpxp123456 Date: Fri, 30 Aug 2024 10:44:54 +0800 Subject: [PATCH 2/6] fix(formula): fix paste --- .../formula-clipboard.controller.ts | 173 ++++++++++++------ 1 file changed, 117 insertions(+), 56 deletions(-) diff --git a/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts b/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts index ac5690f16638..1cb5301214f1 100644 --- a/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts +++ b/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts @@ -132,7 +132,6 @@ export class FormulaClipboardController extends Disposable { } } -// eslint-disable-next-line max-lines-per-function export function getSetCellFormulaMutations( unitId: string, subUnitId: string, @@ -152,6 +151,63 @@ export function getSetCellFormulaMutations( const redoMutationsInfo: IMutationInfo[] = []; const undoMutationsInfo: IMutationInfo[] = []; + const valueMatrix = getValueMatrix(unitId, subUnitId, range, matrix, copyInfo, lexerTreeBuilder, formulaDataModel, isSpecialPaste, pasteFrom); + + // set cell value and style + const setValuesMutation: ISetRangeValuesMutationParams = { + unitId, + subUnitId, + cellValue: valueMatrix.getData(), + }; + + redoMutationsInfo.push({ + id: SetRangeValuesMutation.id, + params: setValuesMutation, + }); + + // undo + const undoSetValuesMutation: ISetRangeValuesMutationParams = SetRangeValuesUndoMutationFactory( + accessor, + setValuesMutation + ); + + undoMutationsInfo.push({ + id: SetRangeValuesMutation.id, + params: undoSetValuesMutation, + }); + return { + undos: undoMutationsInfo, + redos: redoMutationsInfo, + }; +} + +function getValueMatrix( + unitId: string, + subUnitId: string, + range: IDiscreteRange, + matrix: ObjectMatrix, + copyInfo: { + copyType: COPY_TYPE; + copyRange?: IDiscreteRange; + pasteType: string; + }, + lexerTreeBuilder: LexerTreeBuilder, + formulaDataModel: FormulaDataModel, + isSpecialPaste = false, + pasteFrom: ISheetDiscreteRangeLocation | null +): ObjectMatrix { + if (!pasteFrom) { + return getValueMatrixOfPasteFromIsNull(matrix, range); + } + + if (copyInfo.pasteType === PREDEFINED_HOOK_NAME.SPECIAL_PASTE_VALUE) { + return getPasteValueValueMatrix(unitId, subUnitId, range, matrix, formulaDataModel, pasteFrom); + } + + if (copyInfo.pasteType === PREDEFINED_HOOK_NAME.SPECIAL_PASTE_FORMULA) { + return getPasteFormulaValueMatrix(range, matrix); + } + const valueMatrix = new ObjectMatrix(); const formulaIdMap = new Map(); @@ -249,84 +305,89 @@ export function getSetCellFormulaMutations( valueMatrix.setValue(range.rows[row], range.cols[col], valueObject); }); - // set cell value and style - const setValuesMutation: ISetRangeValuesMutationParams = { - unitId, - subUnitId, - cellValue: valueMatrix.getData(), - }; - redoMutationsInfo.push({ - id: SetRangeValuesMutation.id, - params: setValuesMutation, - }); + return valueMatrix; +} - // undo - const undoSetValuesMutation: ISetRangeValuesMutationParams = SetRangeValuesUndoMutationFactory( - accessor, - setValuesMutation - ); +function getValueMatrixOfPasteFromIsNull(matrix: ObjectMatrix, range: IDiscreteRange): ObjectMatrix { + const valueMatrix = new ObjectMatrix(); - undoMutationsInfo.push({ - id: SetRangeValuesMutation.id, - params: undoSetValuesMutation, + matrix.forValue((row, col, value) => { + const valueObject: ICellDataWithSpanInfo = {}; + valueObject.f = null; + + if (isFormulaString(value.v)) { + valueObject.v = null; + valueObject.f = `${value.v}`; + + valueMatrix.setValue(range.rows[row], range.cols[col], valueObject); + } }); - return { - undos: undoMutationsInfo, - redos: redoMutationsInfo, - }; + + return valueMatrix; } -function getValueMatrix( +function getPasteValueValueMatrix( unitId: string, subUnitId: string, range: IDiscreteRange, matrix: ObjectMatrix, - accessor: IAccessor, - copyInfo: { - copyType: COPY_TYPE; - copyRange?: IDiscreteRange; - pasteType: string; - }, - lexerTreeBuilder: LexerTreeBuilder, formulaDataModel: FormulaDataModel, - isSpecialPaste = false, - pasteFrom: ISheetDiscreteRangeLocation | null -) { - if (!pasteFrom) { - return getValueMatrixOfPasteFromIsNull(matrix); - } -} - -function getValueMatrixOfPasteFromIsNull(matrix: ObjectMatrix): ObjectMatrix { + pasteFrom: ISheetDiscreteRangeLocation +): ObjectMatrix { const valueMatrix = new ObjectMatrix(); + const arrayFormulaCellData = formulaDataModel.getArrayFormulaCellData()?.[unitId]?.[subUnitId]; matrix.forValue((row, col, value) => { - if (!isFormulaString(value.v)) { - return false; + const fromRow = pasteFrom.range.rows[row]; + const fromCol = pasteFrom.range.cols[col]; + const toRow = range.rows[row]; + const toCol = range.cols[col]; + + const formulaString = value.f || ''; + const formulaId = value.si || ''; + + if (isFormulaString(formulaString) || isFormulaId(formulaId)) { + const valueObject: ICellDataWithSpanInfo = {}; + valueObject.v = value.v; + valueObject.f = null; + valueObject.si = null; + + valueMatrix.setValue(toRow, toCol, valueObject); + } else if (arrayFormulaCellData?.[fromRow]?.[fromCol]) { + const cell = arrayFormulaCellData[fromRow][fromCol]; + const valueObject: ICellDataWithSpanInfo = {}; + valueObject.v = cell.v; + valueObject.f = null; + valueObject.si = null; + + valueMatrix.setValue(toRow, toCol, valueObject); } - - const valueObject: ICellDataWithSpanInfo = {}; - valueObject.v = null; - valueObject.f = `${value.v}`; - - valueMatrix.setValue(row, col, valueObject); }); return valueMatrix; } -function getPasteValueValueMatrix( - matrix: ObjectMatrix, - formulaDataModel: FormulaDataModel, - pasteFrom: ISheetDiscreteRangeLocation | null -) { +function getPasteFormulaValueMatrix( + range: IDiscreteRange, + matrix: ObjectMatrix +): ObjectMatrix { const valueMatrix = new ObjectMatrix(); - const arrayFormulaCellData = formulaDataModel.getArrayFormulaCellData(); - // matrix.forValue((row, col, value) => { + matrix.forValue((row, col, value) => { + const formulaString = value.f || ''; + const formulaId = value.si || ''; + + if (isFormulaString(value.f)) { + const valueObject: ICellDataWithSpanInfo = {}; + valueObject.v = null; + valueObject.f = value.f; - // } + valueMatrix.setValue(range.rows[row], range.cols[col], valueObject); + } + }); + + return valueMatrix; } function getCellRichText(cell: ICellData) { From b5a78ac4d8af5075de8977e7f54c797dc406a0b0 Mon Sep 17 00:00:00 2001 From: wpxp123456 Date: Fri, 30 Aug 2024 14:15:06 +0800 Subject: [PATCH 3/6] fix(formula): fix paste --- .../formula-clipboard.controller.ts | 70 +++++++++++++------ 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts b/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts index 1cb5301214f1..58d325b56187 100644 --- a/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts +++ b/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts @@ -196,12 +196,24 @@ function getValueMatrix( isSpecialPaste = false, pasteFrom: ISheetDiscreteRangeLocation | null ): ObjectMatrix { + let copyRowLength = 0; + let copyColumnLength = 0; + + if (copyInfo && copyInfo.copyRange) { + const { copyType, copyRange } = copyInfo; + + if (copyType === COPY_TYPE.COPY && copyRange) { + copyRowLength = copyRange.rows.length; + copyColumnLength = copyRange.cols.length; + } + } + if (!pasteFrom) { - return getValueMatrixOfPasteFromIsNull(matrix, range); + return getValueMatrixOfPasteFromIsNull(unitId, subUnitId, range, matrix, formulaDataModel); } if (copyInfo.pasteType === PREDEFINED_HOOK_NAME.SPECIAL_PASTE_VALUE) { - return getPasteValueValueMatrix(unitId, subUnitId, range, matrix, formulaDataModel, pasteFrom); + return getSpecialPasteValueValueMatrix(unitId, subUnitId, range, matrix, formulaDataModel, pasteFrom); } if (copyInfo.pasteType === PREDEFINED_HOOK_NAME.SPECIAL_PASTE_FORMULA) { @@ -211,17 +223,6 @@ function getValueMatrix( const valueMatrix = new ObjectMatrix(); const formulaIdMap = new Map(); - let copyRowLength = 0; - let copyColumnLength = 0; - - if (copyInfo && copyInfo.copyRange) { - const { copyType, copyRange } = copyInfo; - if (copyType === COPY_TYPE.COPY && copyRange) { - copyRowLength = copyRange.rows.length; - copyColumnLength = copyRange.cols.length; - } - } - // eslint-disable-next-line complexity matrix.forValue((row, col, value) => { const originalFormula = value.f || ''; @@ -309,25 +310,42 @@ function getValueMatrix( return valueMatrix; } -function getValueMatrixOfPasteFromIsNull(matrix: ObjectMatrix, range: IDiscreteRange): ObjectMatrix { +function getValueMatrixOfPasteFromIsNull( + unitId: string, + subUnitId: string, + range: IDiscreteRange, + matrix: ObjectMatrix, + formulaDataModel: FormulaDataModel +): ObjectMatrix { const valueMatrix = new ObjectMatrix(); + const formulaData = formulaDataModel.getFormulaData()?.[unitId]?.[subUnitId]; matrix.forValue((row, col, value) => { + const toRow = range.rows[row]; + const toCol = range.cols[col]; const valueObject: ICellDataWithSpanInfo = {}; - valueObject.f = null; if (isFormulaString(value.v)) { + // If the copy value is a formula valueObject.v = null; valueObject.f = `${value.v}`; - valueMatrix.setValue(range.rows[row], range.cols[col], valueObject); + valueMatrix.setValue(toRow, toCol, valueObject); + } else if (formulaData?.[toRow]?.[toCol]) { + // If the paste location is a formula + valueObject.v = value.v; + valueObject.f = null; + valueObject.f = null; + valueObject.si = null; + + valueMatrix.setValue(toRow, toCol, valueObject); } }); return valueMatrix; } -function getPasteValueValueMatrix( +function getSpecialPasteValueValueMatrix( unitId: string, subUnitId: string, range: IDiscreteRange, @@ -337,30 +355,36 @@ function getPasteValueValueMatrix( ): ObjectMatrix { const valueMatrix = new ObjectMatrix(); const arrayFormulaCellData = formulaDataModel.getArrayFormulaCellData()?.[unitId]?.[subUnitId]; + const formulaData = formulaDataModel.getFormulaData()?.[unitId]?.[subUnitId]; matrix.forValue((row, col, value) => { const fromRow = pasteFrom.range.rows[row]; const fromCol = pasteFrom.range.cols[col]; const toRow = range.rows[row]; const toCol = range.cols[col]; + const valueObject: ICellDataWithSpanInfo = {}; - const formulaString = value.f || ''; - const formulaId = value.si || ''; - - if (isFormulaString(formulaString) || isFormulaId(formulaId)) { - const valueObject: ICellDataWithSpanInfo = {}; + if (isFormulaString(value.f) || isFormulaId(value.si)) { + // If the copy value is a formula valueObject.v = value.v; valueObject.f = null; valueObject.si = null; valueMatrix.setValue(toRow, toCol, valueObject); } else if (arrayFormulaCellData?.[fromRow]?.[fromCol]) { + // If the copy value is an array formula const cell = arrayFormulaCellData[fromRow][fromCol]; - const valueObject: ICellDataWithSpanInfo = {}; valueObject.v = cell.v; valueObject.f = null; valueObject.si = null; + valueMatrix.setValue(toRow, toCol, valueObject); + } else if (formulaData?.[toRow]?.[toCol]) { + // If the paste location is a formula + valueObject.v = value.v; + valueObject.f = null; + valueObject.si = null; + valueMatrix.setValue(toRow, toCol, valueObject); } }); From 91a6a6f6919aefaa82c1e612542155c1b06ebf05 Mon Sep 17 00:00:00 2001 From: wpxp123456 Date: Fri, 30 Aug 2024 17:00:09 +0800 Subject: [PATCH 4/6] fix(formula): fix formula paste --- .../formula-clipboard.controller.ts | 288 +++++++++++------- 1 file changed, 173 insertions(+), 115 deletions(-) diff --git a/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts b/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts index 58d325b56187..2a477fe0903f 100644 --- a/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts +++ b/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts @@ -151,7 +151,7 @@ export function getSetCellFormulaMutations( const redoMutationsInfo: IMutationInfo[] = []; const undoMutationsInfo: IMutationInfo[] = []; - const valueMatrix = getValueMatrix(unitId, subUnitId, range, matrix, copyInfo, lexerTreeBuilder, formulaDataModel, isSpecialPaste, pasteFrom); + const valueMatrix = getValueMatrix(unitId, subUnitId, range, matrix, copyInfo, lexerTreeBuilder, formulaDataModel, pasteFrom); // set cell value and style const setValuesMutation: ISetRangeValuesMutationParams = { @@ -193,21 +193,8 @@ function getValueMatrix( }, lexerTreeBuilder: LexerTreeBuilder, formulaDataModel: FormulaDataModel, - isSpecialPaste = false, pasteFrom: ISheetDiscreteRangeLocation | null ): ObjectMatrix { - let copyRowLength = 0; - let copyColumnLength = 0; - - if (copyInfo && copyInfo.copyRange) { - const { copyType, copyRange } = copyInfo; - - if (copyType === COPY_TYPE.COPY && copyRange) { - copyRowLength = copyRange.rows.length; - copyColumnLength = copyRange.cols.length; - } - } - if (!pasteFrom) { return getValueMatrixOfPasteFromIsNull(unitId, subUnitId, range, matrix, formulaDataModel); } @@ -217,97 +204,10 @@ function getValueMatrix( } if (copyInfo.pasteType === PREDEFINED_HOOK_NAME.SPECIAL_PASTE_FORMULA) { - return getPasteFormulaValueMatrix(range, matrix); + return getSpecialPasteFormulaValueMatrix(unitId, subUnitId, range, matrix, lexerTreeBuilder, formulaDataModel, pasteFrom); } - const valueMatrix = new ObjectMatrix(); - const formulaIdMap = new Map(); - - // eslint-disable-next-line complexity - matrix.forValue((row, col, value) => { - const originalFormula = value.f || ''; - const originalFormulaId = value.si || ''; - - let valueObject: ICellDataWithSpanInfo = {}; - // Paste the formula only, you also need to process some regular values, but style information is not needed - if (isSpecialPaste) { - valueObject = Tools.deepClone(value); - valueObject.s = null; - } - - if (!copyRowLength || !copyColumnLength) { - return; - } - - // Directly reuse when there is a formula id - if (isFormulaId(originalFormulaId)) { - const { unitId: pasteFromUnitId = '', subUnitId: pasteFromSubUnitId = '', range: pasteFromRange } = pasteFrom || {}; - - if (((pasteFromUnitId && unitId !== pasteFromUnitId) || (pasteFromSubUnitId && subUnitId !== pasteFromSubUnitId)) && pasteFromRange?.rows && pasteFromRange?.cols) { - const formulaString = formulaDataModel.getFormulaStringByCell(pasteFromRange.rows[row], pasteFromRange.cols[col], pasteFromSubUnitId, pasteFromUnitId); - - const rowIndex = row % copyRowLength; - const colIndex = col % copyColumnLength; - - const copyX = copyInfo?.copyRange ? copyInfo?.copyRange?.cols[colIndex] : colIndex; - const copyY = copyInfo?.copyRange ? copyInfo?.copyRange?.rows[rowIndex] : rowIndex; - const offsetX = range.cols[col] - copyX; - const offsetY = range.rows[row] - copyY; - const shiftedFormula = lexerTreeBuilder.moveFormulaRefOffset(formulaString || '', offsetX, offsetY); - - valueObject.si = null; - valueObject.f = shiftedFormula; - valueObject.v = null; - valueObject.p = null; - } else { - valueObject.si = originalFormulaId; - valueObject.f = null; - valueObject.v = null; - valueObject.p = null; - } - } else if (isFormulaString(originalFormula)) { - const rowIndex = row % copyRowLength; - const colIndex = col % copyColumnLength; - - const index = `${rowIndex}_${colIndex}`; - let formulaId = formulaIdMap.get(index); - - if (!formulaId) { - formulaId = Tools.generateRandomId(6); - formulaIdMap.set(index, formulaId); - - const copyX = copyInfo?.copyRange ? copyInfo?.copyRange?.cols[colIndex] : colIndex; - const copyY = copyInfo?.copyRange ? copyInfo?.copyRange?.rows[rowIndex] : rowIndex; - const offsetX = range.cols[col] - copyX; - const offsetY = range.rows[row] - copyY; - const shiftedFormula = lexerTreeBuilder.moveFormulaRefOffset(originalFormula, offsetX, offsetY); - - valueObject.si = formulaId; - valueObject.f = shiftedFormula; - valueObject.v = null; - valueObject.p = null; - } else { - // At the beginning of the second formula, set formulaId only - valueObject.si = formulaId; - valueObject.f = null; - valueObject.v = null; - valueObject.p = null; - } - } - - // If there is rich text, remove the style - if (copyInfo.pasteType === PREDEFINED_HOOK_NAME.SPECIAL_PASTE_FORMULA && value.p) { - const richText = getCellRichText(value); - if (richText) { - valueObject.p = null; - valueObject.v = richText; - } - } - - valueMatrix.setValue(range.rows[row], range.cols[col], valueObject); - }); - - return valueMatrix; + return getDefaultPasteValueMatrix(unitId, subUnitId, range, matrix, lexerTreeBuilder, formulaDataModel, pasteFrom); } function getValueMatrixOfPasteFromIsNull( @@ -329,14 +229,16 @@ function getValueMatrixOfPasteFromIsNull( // If the copy value is a formula valueObject.v = null; valueObject.f = `${value.v}`; + valueObject.si = null; + valueObject.p = null; valueMatrix.setValue(toRow, toCol, valueObject); } else if (formulaData?.[toRow]?.[toCol]) { // If the paste location is a formula valueObject.v = value.v; valueObject.f = null; - valueObject.f = null; valueObject.si = null; + valueObject.p = null; valueMatrix.setValue(toRow, toCol, valueObject); } @@ -354,12 +256,12 @@ function getSpecialPasteValueValueMatrix( pasteFrom: ISheetDiscreteRangeLocation ): ObjectMatrix { const valueMatrix = new ObjectMatrix(); - const arrayFormulaCellData = formulaDataModel.getArrayFormulaCellData()?.[unitId]?.[subUnitId]; + const arrayFormulaCellData = formulaDataModel.getArrayFormulaCellData()?.[pasteFrom.unitId]?.[pasteFrom.subUnitId]; const formulaData = formulaDataModel.getFormulaData()?.[unitId]?.[subUnitId]; matrix.forValue((row, col, value) => { - const fromRow = pasteFrom.range.rows[row]; - const fromCol = pasteFrom.range.cols[col]; + const fromRow = pasteFrom.range.rows[row % pasteFrom.range.rows.length]; + const fromCol = pasteFrom.range.cols[col % pasteFrom.range.cols.length]; const toRow = range.rows[row]; const toCol = range.cols[col]; const valueObject: ICellDataWithSpanInfo = {}; @@ -369,6 +271,7 @@ function getSpecialPasteValueValueMatrix( valueObject.v = value.v; valueObject.f = null; valueObject.si = null; + valueObject.p = null; valueMatrix.setValue(toRow, toCol, valueObject); } else if (arrayFormulaCellData?.[fromRow]?.[fromCol]) { @@ -377,6 +280,7 @@ function getSpecialPasteValueValueMatrix( valueObject.v = cell.v; valueObject.f = null; valueObject.si = null; + valueObject.p = null; valueMatrix.setValue(toRow, toCol, valueObject); } else if (formulaData?.[toRow]?.[toCol]) { @@ -384,6 +288,101 @@ function getSpecialPasteValueValueMatrix( valueObject.v = value.v; valueObject.f = null; valueObject.si = null; + valueObject.p = null; + + if (value.p) { + const richText = getCellRichText(value); + if (richText) { + valueObject.v = richText; + } + } + + valueMatrix.setValue(toRow, toCol, valueObject); + } + }); + + return valueMatrix; +} + +function getSpecialPasteFormulaValueMatrix( + unitId: string, + subUnitId: string, + range: IDiscreteRange, + matrix: ObjectMatrix, + lexerTreeBuilder: LexerTreeBuilder, + formulaDataModel: FormulaDataModel, + pasteFrom: ISheetDiscreteRangeLocation +): ObjectMatrix { + const valueMatrix = new ObjectMatrix(); + const formulaIdMap = new Map(); + + matrix.forValue((row, col, value) => { + const toRow = range.rows[row]; + const toCol = range.cols[col]; + const valueObject: ICellDataWithSpanInfo = {}; + + if (isFormulaId(value.si)) { + // If the copy value is a formula + if (pasteFrom.unitId !== unitId || pasteFrom.subUnitId !== subUnitId) { + const formulaString = formulaDataModel.getFormulaStringByCell( + pasteFrom.range.rows[row % pasteFrom.range.rows.length], + pasteFrom.range.cols[col % pasteFrom.range.cols.length], + pasteFrom.subUnitId, + pasteFrom.unitId + ); + const offsetX = range.cols[col] - pasteFrom.range.cols[col % pasteFrom.range.cols.length]; + const offsetY = range.rows[row] - pasteFrom.range.rows[row % pasteFrom.range.rows.length]; + const shiftedFormula = lexerTreeBuilder.moveFormulaRefOffset(formulaString || '', offsetX, offsetY); + + valueObject.si = null; + valueObject.f = shiftedFormula; + } else { + valueObject.si = value.si; + valueObject.f = null; + } + + valueObject.v = null; + valueObject.p = null; + + valueMatrix.setValue(toRow, toCol, valueObject); + } else if (isFormulaString(value.f)) { + // If the copy value is a formula + const index = `${row % pasteFrom.range.rows.length}_${col % pasteFrom.range.cols.length}`; + let formulaId = formulaIdMap.get(index); + + if (!formulaId) { + formulaId = Tools.generateRandomId(6); + formulaIdMap.set(index, formulaId); + + const offsetX = range.cols[col] - pasteFrom.range.cols[col % pasteFrom.range.cols.length]; + const offsetY = range.rows[row] - pasteFrom.range.rows[row % pasteFrom.range.rows.length]; + const shiftedFormula = lexerTreeBuilder.moveFormulaRefOffset(value.f || '', offsetX, offsetY); + + valueObject.si = formulaId; + valueObject.f = shiftedFormula; + } else { + // At the beginning of the second formula, set formulaId only + valueObject.si = formulaId; + valueObject.f = null; + } + + valueObject.v = null; + valueObject.p = null; + + valueMatrix.setValue(toRow, toCol, valueObject); + } else { + // If the paste location is a formula + valueObject.v = value.v; + valueObject.f = null; + valueObject.si = null; + valueObject.p = null; + + if (value.p) { + const richText = getCellRichText(value); + if (richText) { + valueObject.v = richText; + } + } valueMatrix.setValue(toRow, toCol, valueObject); } @@ -392,22 +391,81 @@ function getSpecialPasteValueValueMatrix( return valueMatrix; } -function getPasteFormulaValueMatrix( +function getDefaultPasteValueMatrix( + unitId: string, + subUnitId: string, range: IDiscreteRange, - matrix: ObjectMatrix + matrix: ObjectMatrix, + lexerTreeBuilder: LexerTreeBuilder, + formulaDataModel: FormulaDataModel, + pasteFrom: ISheetDiscreteRangeLocation ): ObjectMatrix { const valueMatrix = new ObjectMatrix(); + const formulaIdMap = new Map(); + const formulaData = formulaDataModel.getFormulaData()?.[unitId]?.[subUnitId]; matrix.forValue((row, col, value) => { - const formulaString = value.f || ''; - const formulaId = value.si || ''; + const toRow = range.rows[row]; + const toCol = range.cols[col]; + const valueObject: ICellDataWithSpanInfo = {}; + + if (isFormulaId(value.si)) { + // If the copy value is a formula + if (pasteFrom.unitId !== unitId || pasteFrom.subUnitId !== subUnitId) { + const formulaString = formulaDataModel.getFormulaStringByCell( + pasteFrom.range.rows[row % pasteFrom.range.rows.length], + pasteFrom.range.cols[col % pasteFrom.range.cols.length], + pasteFrom.subUnitId, + pasteFrom.unitId + ); + const offsetX = range.cols[col] - pasteFrom.range.cols[col % pasteFrom.range.cols.length]; + const offsetY = range.rows[row] - pasteFrom.range.rows[row % pasteFrom.range.rows.length]; + const shiftedFormula = lexerTreeBuilder.moveFormulaRefOffset(formulaString || '', offsetX, offsetY); + + valueObject.si = null; + valueObject.f = shiftedFormula; + } else { + valueObject.si = value.si; + valueObject.f = null; + } + + valueObject.v = null; + valueObject.p = null; + + valueMatrix.setValue(toRow, toCol, valueObject); + } else if (isFormulaString(value.f)) { + // If the copy value is a formula + const index = `${row % pasteFrom.range.rows.length}_${col % pasteFrom.range.cols.length}`; + let formulaId = formulaIdMap.get(index); + + if (!formulaId) { + formulaId = Tools.generateRandomId(6); + formulaIdMap.set(index, formulaId); + + const offsetX = range.cols[col] - pasteFrom.range.cols[col % pasteFrom.range.cols.length]; + const offsetY = range.rows[row] - pasteFrom.range.rows[row % pasteFrom.range.rows.length]; + const shiftedFormula = lexerTreeBuilder.moveFormulaRefOffset(value.f || '', offsetX, offsetY); + + valueObject.si = formulaId; + valueObject.f = shiftedFormula; + } else { + // At the beginning of the second formula, set formulaId only + valueObject.si = formulaId; + valueObject.f = null; + } - if (isFormulaString(value.f)) { - const valueObject: ICellDataWithSpanInfo = {}; valueObject.v = null; - valueObject.f = value.f; + valueObject.p = null; + + valueMatrix.setValue(toRow, toCol, valueObject); + } else if (formulaData?.[toRow]?.[toCol]) { + // If the paste location is a formula + valueObject.v = value.v; + valueObject.f = null; + valueObject.si = null; + valueObject.p = value.p; - valueMatrix.setValue(range.rows[row], range.cols[col], valueObject); + valueMatrix.setValue(toRow, toCol, valueObject); } }); From bd2856a2514e78ffd42639d1637e4ebf0b8a3271 Mon Sep 17 00:00:00 2001 From: wpxp123456 Date: Fri, 30 Aug 2024 19:19:28 +0800 Subject: [PATCH 5/6] fix(formula): fix formula paste --- .../formula-clipboard.controller.spec.ts | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/packages/sheets-formula/src/controllers/__tests__/formula-clipboard.controller.spec.ts b/packages/sheets-formula/src/controllers/__tests__/formula-clipboard.controller.spec.ts index 1f9cb81285be..5404747e665f 100644 --- a/packages/sheets-formula/src/controllers/__tests__/formula-clipboard.controller.spec.ts +++ b/packages/sheets-formula/src/controllers/__tests__/formula-clipboard.controller.spec.ts @@ -101,6 +101,15 @@ describe('Test paste with formula', () => { pasteType: PREDEFINED_HOOK_NAME.DEFAULT_PASTE, }; + const pasteFrom = { + unitId, + subUnitId, + range: { + rows: [0], + cols: [2, 3], + }, + }; + const result = { undos: [ { @@ -110,15 +119,6 @@ describe('Test paste with formula', () => { subUnitId, cellValue: { 12: { - 2: { - custom: null, - s: null, - f: null, - si: null, - p: null, - v: null, - t: null, - }, 3: { custom: null, s: null, @@ -142,7 +142,6 @@ describe('Test paste with formula', () => { subUnitId, cellValue: { 12: { - 2: {}, 3: { f: null, si: '3e4r5t', @@ -166,7 +165,7 @@ describe('Test paste with formula', () => { lexerTreeBuilder, formulaDataModel, false, - null + pasteFrom ); expect(redoUndoList).toStrictEqual(result); @@ -332,6 +331,15 @@ describe('Test paste with formula', () => { pasteType: PREDEFINED_HOOK_NAME.DEFAULT_PASTE, }; + const pasteFrom = { + unitId, + subUnitId, + range: { + rows: [0, 1, 2, 3], + cols: [5, 6, 7, 8], + }, + }; + const result = { undos: [ { @@ -624,7 +632,7 @@ describe('Test paste with formula', () => { lexerTreeBuilder, formulaDataModel, false, - null + pasteFrom ); // Randomly generated id, no comparison is made From a0469ee8dcd09deec434b5d592f77533a8bf162d Mon Sep 17 00:00:00 2001 From: wpxp123456 Date: Sat, 31 Aug 2024 18:41:20 +0800 Subject: [PATCH 6/6] fix(formula): fix paste --- .../src/controllers/formula-clipboard.controller.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts b/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts index 2a477fe0903f..9164d042a1e9 100644 --- a/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts +++ b/packages/sheets-formula/src/controllers/formula-clipboard.controller.ts @@ -85,13 +85,7 @@ export class FormulaClipboardController extends Disposable { isSpecialPaste: boolean ) { // Intercept scenarios where formulas do not need to be processed, and only process default paste and paste formulas only - if ( - [ - PREDEFINED_HOOK_NAME.SPECIAL_PASTE_FORMAT, - PREDEFINED_HOOK_NAME.SPECIAL_PASTE_COL_WIDTH, - PREDEFINED_HOOK_NAME.SPECIAL_PASTE_BESIDES_BORDER, - ].includes(payload.pasteType) - ) { + if ([PREDEFINED_HOOK_NAME.SPECIAL_PASTE_FORMAT, PREDEFINED_HOOK_NAME.SPECIAL_PASTE_COL_WIDTH].includes(payload.pasteType)) { return { undos: [], redos: [],