From 0431c1f3964b251377ab584011d4c1c5610e5d82 Mon Sep 17 00:00:00 2001 From: ybzky Date: Mon, 26 Aug 2024 15:44:09 +0800 Subject: [PATCH] fix: modify the rich text judgment logic (#3178) --- .../__tests__/end-edit.controller.spec.ts | 139 +++++++++++++++++- .../editor/editing.render-controller.ts | 47 +++++- 2 files changed, 180 insertions(+), 6 deletions(-) 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 409ec85b27c..fa86e86095f 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 @@ -149,7 +149,7 @@ describe('Test EndEditController', () => { }; const cellData = getCellDataByInputCell(cell, inputCell); - expect(cellData).toEqual({ v: '2', f: null, si: null, p: null }); + expect(cellData).toEqual({ v: '2', t: CellValueType.NUMBER, f: null, si: null, p: null }); }); it('Rich text cell', () => { const cell = { @@ -272,7 +272,7 @@ describe('Test EndEditController', () => { it('test isRichText util', () => { const cellBody = { - dataStream: '11111111\r\n', + dataStream: 'qqqqqq\r\n', textRuns: [ { ts: { @@ -297,10 +297,143 @@ describe('Test EndEditController', () => { // textRuns acts on the entire string expect(isRichTextRes).toBe(false); const anotherCellBody = Tools.deepClone(cellBody); - anotherCellBody.dataStream = `111${anotherCellBody.dataStream}`; + anotherCellBody.dataStream = `${anotherCellBody.dataStream}qqq`; // textRuns works on parts of strings const isRichTextRes2 = isRichText(anotherCellBody); expect(isRichTextRes2).toBe(true); }); + + it('test number can not set style', () => { + const dataStreamOnlyHaveNumber = { + id: '__INTERNAL_EDITOR__DOCS_NORMAL', + documentStyle: { + pageSize: { + width: 320.4903259277344, + }, + marginTop: 0, + marginBottom: 1, + 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 311f46b3d2f..65a6834c7c6 100644 --- a/packages/sheets-ui/src/controllers/editor/editing.render-controller.ts +++ b/packages/sheets-ui/src/controllers/editor/editing.render-controller.ts @@ -16,7 +16,7 @@ /* eslint-disable max-lines-per-function */ -import type { DocumentDataModel, ICellData, ICommandInfo, IDisposable, IDocumentBody, IDocumentData, IPosition, Nullable, Workbook } from '@univerjs/core'; +import type { DocumentDataModel, ICellData, ICommandInfo, IDisposable, IDocumentBody, IDocumentData, IPosition, IStyleData, Nullable, Workbook } from '@univerjs/core'; import { CellValueType, DEFAULT_EMPTY_DOCUMENT_VALUE, Direction, Disposable, DisposableCollection, DOCS_FORMULA_BAR_EDITOR_UNIT_ID_KEY, EDITOR_ACTIVATED, FOCUSING_EDITOR_BUT_HIDDEN, @@ -34,6 +34,7 @@ import { IUndoRedoService, IUniverInstanceService, LocaleService, + numfmt, toDisposable, Tools, UniverInstanceType, @@ -1068,6 +1069,13 @@ export function getCellDataByInput( cellData.si = null; cellData.p = null; cellData.t = CellValueType.FORCE_STRING; + } else if (numfmt.parseValue(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 (isRichText(body)) { if (body.dataStream === '\r\n') { cellData.v = ''; @@ -1089,21 +1097,54 @@ export function getCellDataByInput( cellData.f = null; cellData.si = null; cellData.p = null; + // If the style length in textRun.ts is equal to the content length, it should be set as the cell style + const style = getCellStyleBySnapshot(snapshot); + if (style) { + cellData.s = style; + } } return cellData; } -export function isRichText(body: IDocumentBody) { +export function isRichText(body: IDocumentBody): boolean { const { textRuns = [], paragraphs = [], customRanges, customBlocks = [] } = body; const bodyNoLineBreak = body.dataStream.replace('\r\n', ''); + // 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) => textRun.ts && (textRun.st !== 0 || textRun.ed !== bodyNoLineBreak.length)) || + textRuns.some((textRun) => { + const hasRichTextStyle = Boolean(textRun.ts && Object.keys(textRun.ts).some((property) => { + return richTextStyle.includes(property); + })); + return hasRichTextStyle || (textRun.ts && (textRun.ed - textRun.st < bodyNoLineBreak.length)); + }) || paragraphs.some((paragraph) => paragraph.bullet) || paragraphs.length >= 2 || Boolean(customRanges?.length) || customBlocks.length > 0 ); } + +export function getCellStyleBySnapshot(snapshot: IDocumentData): Nullable { + const { body } = snapshot; + if (!body) return null; + const { textRuns = [] } = body; + + let style = {}; + const bodyNoLineBreak = body.dataStream.replace('\r\n', ''); + textRuns.forEach((textRun) => { + const { st, ed, ts } = textRun; + if (ed - st >= bodyNoLineBreak.length) { + style = { ...style, ...ts }; + } + }); + if (Object.keys(style).length) { + return style; + } + return null; +} +