diff --git a/packages/sheets-numfmt-ui/src/controllers/__tests__/editor.controller.spec.ts b/packages/sheets-numfmt-ui/src/controllers/__tests__/editor.controller.spec.ts index 0f8ac1932a1a..f8f31a05531e 100644 --- a/packages/sheets-numfmt-ui/src/controllers/__tests__/editor.controller.spec.ts +++ b/packages/sheets-numfmt-ui/src/controllers/__tests__/editor.controller.spec.ts @@ -160,4 +160,162 @@ describe('test editor', () => { // The date-time drop is a numeric value, not a literal string expect(result?.v).toBe(0.5231712962962963); }); + + it('edit number will throw style in this editing', () => { + const sheetInterceptorService = testBed.get(SheetInterceptorService); + const cellData = { + p: { + id: '__INTERNAL_EDITOR__DOCS_NORMAL', + documentStyle: { + pageSize: { + width: 230.41758728027344, + }, + marginTop: 6, + marginBottom: 2, + marginRight: 2, + marginLeft: 2, + renderConfig: { + verticalAlign: 0, + horizontalAlign: 0, + wrapStrategy: 0, + background: {}, + centerAngle: 0, + vertexAngle: 0, + }, + }, + body: { + dataStream: '2022-11-11\r\n', + textRuns: [ + { + st: 0, + ed: 2, + ts: { + ff: 'Arial', + fs: 11, + }, + }, + { + st: 2, + ed: 10, + ts: { + ff: 'Arial', + fs: 11, + bl: 1, + }, + }, + ], + paragraphs: [ + { + startIndex: 10, + paragraphStyle: { + horizontalAlign: 0, + }, + }, + ], + customRanges: [], + customDecorations: [], + }, + drawings: {}, + drawingsOrder: [], + settings: { + zoomRatio: 1, + }, + }, + v: null, + f: null, + si: null, + }; + const location = { + workbook, + worksheet, + unitId, + subUnitId, + row: 0, + col: 0, + origin: cellData, + }; + + const result = sheetInterceptorService.writeCellInterceptor.fetchThroughInterceptors(AFTER_CELL_EDIT)(cellData, location); + expect(result?.s).toBeFalsy(); + expect(result?.p).toBeFalsy(); + expect(result?.v).toBe(44876); + }); + + it('edit number with bullet should keep rich text', () => { + const sheetInterceptorService = testBed.get(SheetInterceptorService); + const richTextParams = { + id: '__INTERNAL_EDITOR__ZEN_EDITOR', + documentStyle: { + pageSize: { + width: 595, + }, + documentFlavor: 0, + marginTop: 0, + marginBottom: 0, + marginRight: 0, + marginLeft: 0, + renderConfig: { + vertexAngle: 0, + centerAngle: 0, + }, + }, + drawings: {}, + drawingsOrder: [], + body: { + dataStream: '123123123\r\n', + textRuns: [ + { + st: 0, + ed: 9, + ts: { + ff: 'Arial', + fs: 11, + }, + }, + ], + paragraphs: [ + { + startIndex: 9, + paragraphStyle: { + horizontalAlign: 0, + }, + bullet: { + nestingLevel: 0, + textStyle: { + fs: 20, + }, + listType: 'CHECK_LIST', + listId: 'xIECkc', + }, + }, + ], + sectionBreaks: [ + { + startIndex: 10, + }, + ], + customRanges: [], + customDecorations: [], + }, + }; + const cellData = { + p: richTextParams, + v: null, + f: null, + si: null, + }; + const location = { + workbook, + worksheet, + unitId, + subUnitId, + row: 0, + col: 0, + origin: cellData, + }; + + const result = sheetInterceptorService.writeCellInterceptor.fetchThroughInterceptors(AFTER_CELL_EDIT)(cellData, location); + expect(result?.p).toEqual(richTextParams); + expect(result?.v).toBeFalsy(); + }); }); diff --git a/packages/sheets-numfmt-ui/src/controllers/numfmt.editor.controller.ts b/packages/sheets-numfmt-ui/src/controllers/numfmt.editor.controller.ts index 7c034609a379..2edd1e697acb 100644 --- a/packages/sheets-numfmt-ui/src/controllers/numfmt.editor.controller.ts +++ b/packages/sheets-numfmt-ui/src/controllers/numfmt.editor.controller.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { IRange, Nullable, Workbook } from '@univerjs/core'; +import type { IDocumentBody, IRange, Nullable, Workbook } from '@univerjs/core'; import type { INumfmtItemWithCache, IRemoveNumfmtMutationParams, @@ -144,9 +144,11 @@ export class NumfmtEditorController extends Disposable { toDisposable( this._sheetInterceptorService.writeCellInterceptor.intercept(AFTER_CELL_EDIT, { + // eslint-disable-next-line complexity handler: (value, context, next) => { // clear the effect this._collectEffectMutation.clean(); + const { worksheet, row, col } = context; const currentNumfmtValue = this._numfmtService.getValue( context.unitId, context.subUnitId, @@ -164,19 +166,33 @@ export class NumfmtEditorController extends Disposable { null ); }; - - // if the value is empty or the current numfmt is text format, return the value directly - if (!value?.v || currentNumfmtValue?.pattern === DEFAULT_TEXT_FORMAT) { + if (!value?.v && !value?.p) { return next(value); } - const content = String(value.v); + if (currentNumfmtValue?.pattern === DEFAULT_TEXT_FORMAT) { + return next(value); + } + const body = value.p?.body; + const content = value?.p?.body?.dataStream ? value.p.body.dataStream.replace(/\r\n$/, '') : String(value.v); const numfmtInfo = numfmt.parseDate(content) || numfmt.parseTime(content) || numfmt.parseNumber(content); + if (body) { + if (!canConvertRichTextToNumfmt(body)) { + return next(value); + } else { + const { dataStream } = body; + const dataStreamWithoutEnd = dataStream.replace(/\r\n$/, ''); + const num = Number(dataStreamWithoutEnd); + if (Number.isNaN(num) && !numfmtInfo) { + return next(value); + } + } + } + if (numfmtInfo) { if (numfmtInfo.z) { - const v = Number(numfmtInfo.v); this._collectEffectMutation.add( context.unitId, context.subUnitId, @@ -186,12 +202,12 @@ export class NumfmtEditorController extends Disposable { pattern: numfmtInfo.z, } ); - return { ...value, v, t: CellValueType.NUMBER }; } - } else if ( - ['date', 'time', 'datetime', 'percent'].includes(currentNumfmtType) || - !isNumeric(content) - ) { + const v = Number(numfmtInfo.v); + // The format needs to discard the current style settings + const originStyle = worksheet.getCellStyleOnly(row, col)?.s; + return { ...value, v, p: null, s: originStyle, t: CellValueType.NUMBER }; + } else if (['date', 'time', 'datetime', 'percent'].includes(currentNumfmtType) || !isNumeric(content)) { clean(); } return next(value); @@ -282,3 +298,23 @@ export class NumfmtEditorController extends Disposable { function isNumeric(str: string) { return /^-?\d+(\.\d+)?$/.test(str); } + +function canConvertRichTextToNumfmt(body: IDocumentBody): boolean { + const { textRuns = [], paragraphs = [], customRanges, customBlocks = [] } = body; + + // Some styles are unique to rich text. When this style appears, we consider the value to be rich text. + const richTextStyle = ['va']; + + return !( + textRuns.some((textRun) => { + const hasRichTextStyle = Boolean(textRun.ts && Object.keys(textRun.ts).some((property) => { + return richTextStyle.includes(property); + })); + return hasRichTextStyle; + }) || + paragraphs.some((paragraph) => paragraph.bullet) || + paragraphs.length >= 2 || + Boolean(customRanges?.length) || + customBlocks.length > 0 + ); +} diff --git a/packages/sheets-ui/src/controllers/editor/__tests__/end-edit.controller.spec.ts b/packages/sheets-ui/src/controllers/editor/__tests__/end-edit.controller.spec.ts index 1fac1af46a6f..1880e2d6ec24 100644 --- a/packages/sheets-ui/src/controllers/editor/__tests__/end-edit.controller.spec.ts +++ b/packages/sheets-ui/src/controllers/editor/__tests__/end-edit.controller.spec.ts @@ -161,7 +161,7 @@ describe('Test EndEditController', () => { }; const cellData = getCellDataByInputCell(cell, inputCell); - const target = { v: '2', t: CellValueType.NUMBER, f: null, si: null, p: null }; + const target = { v: '2', f: null, si: null, p: null }; expect(cellData).toEqual({ ...target, @@ -460,138 +460,5 @@ describe('Test EndEditController', () => { const isRichTextWithCellBody2 = isRichText(cellBody2); expect(isRichTextWithCellBody2).toBe(false); }); - - it('test number can not set style', () => { - const dataStreamOnlyHaveNumber = { - id: '__INTERNAL_EDITOR__DOCS_NORMAL', - documentStyle: { - pageSize: { - width: 320.4903259277344, - }, - marginTop: 0, - marginBottom: 2, - marginRight: 2, - marginLeft: 2, - renderConfig: { - verticalAlign: 0, - horizontalAlign: 0, - wrapStrategy: 0, - background: {}, - centerAngle: 0, - vertexAngle: 0, - }, - }, - body: { - dataStream: '111111111111111\r\n', - textRuns: [ - { - st: 0, - ed: 15, - ts: { - fs: 28, - }, - }, - ], - paragraphs: [ - { - startIndex: 15, - paragraphStyle: { - horizontalAlign: 0, - }, - }, - ], - customRanges: [], - customDecorations: [], - }, - drawings: {}, - drawingsOrder: [], - settings: { - zoomRatio: 1, - }, - resources: [ - { - name: 'SHEET_THREAD_COMMENT_PLUGIN', - data: '{}', - }, - { - name: 'DOC_HYPER_LINK_PLUGIN', - data: '{"links":[]}', - }, - { - name: 'SHEET_AuthzIoMockService_PLUGIN', - data: '{}', - }, - ], - }; - const res = getCellDataByInputCell({}, { p: dataStreamOnlyHaveNumber }); - // Because the previous cell had no style, and the value set now can be converted to a number, the style set this time is not retained. - expect(res?.s).toBeUndefined(); - - const dataStreamHaveString = { - id: '__INTERNAL_EDITOR__DOCS_NORMAL', - documentStyle: { - pageSize: { - width: 220.712890625, - }, - marginTop: 0, - marginBottom: 1, - marginRight: 2, - marginLeft: 2, - renderConfig: { - verticalAlign: 0, - horizontalAlign: 0, - wrapStrategy: 0, - background: {}, - centerAngle: 0, - vertexAngle: 0, - }, - }, - body: { - dataStream: 'qqqqqwwww\r\n', - textRuns: [ - { - st: 0, - ed: 9, - ts: { - fs: 28, - }, - }, - ], - paragraphs: [ - { - startIndex: 9, - paragraphStyle: { - horizontalAlign: 0, - }, - }, - ], - customRanges: [], - customDecorations: [], - }, - drawings: {}, - drawingsOrder: [], - settings: { - zoomRatio: 1, - }, - resources: [ - { - name: 'SHEET_THREAD_COMMENT_PLUGIN', - data: '{}', - }, - { - name: 'DOC_HYPER_LINK_PLUGIN', - data: '{"links":[]}', - }, - { - name: 'SHEET_AuthzIoMockService_PLUGIN', - data: '{}', - }, - ], - }; - const res2 = getCellDataByInputCell({}, { p: dataStreamHaveString }); - expect(res2?.s).toStrictEqual({ - fs: 28, - }); - }); }); }); diff --git a/packages/sheets-ui/src/controllers/editor/editing.render-controller.ts b/packages/sheets-ui/src/controllers/editor/editing.render-controller.ts index f7e894905f76..b99704636d8d 100644 --- a/packages/sheets-ui/src/controllers/editor/editing.render-controller.ts +++ b/packages/sheets-ui/src/controllers/editor/editing.render-controller.ts @@ -36,7 +36,6 @@ import { IUndoRedoService, IUniverInstanceService, LocaleService, - numfmt, toDisposable, Tools, UniverInstanceType, @@ -729,7 +728,6 @@ export class EditingRenderController extends Disposable implements IRenderModule } } -// eslint-disable-next-line export function getCellDataByInput( cellData: ICellData, documentDataModel: Nullable, @@ -802,13 +800,6 @@ export function getCellDataByInput( cellData.f = null; cellData.si = null; } - } else if (numfmt.parseDate(newDataStream) || numfmt.parseNumber(newDataStream) || numfmt.parseTime(newDataStream)) { - // If it can be converted to a number and is not forced to be a string, then the style should keep prev style. - cellData.v = newDataStream; - cellData.f = null; - cellData.si = null; - cellData.p = null; - cellData.t = CellValueType.NUMBER; } else { // If the data is empty, the data is set to null. if (newDataStream === '' && cellData.v == null && cellData.p == null) {