From f229390a5b007125c203ae67c6d4110df8418353 Mon Sep 17 00:00:00 2001 From: jocs Date: Thu, 31 Oct 2024 15:19:03 +0800 Subject: [PATCH 1/3] fix: default text style in doc --- packages/docs-ui/src/basics/paragraph.ts | 34 ++++++++--- .../commands/commands/ime-input.command.ts | 3 +- packages/docs-ui/src/controllers/menu/menu.ts | 20 +++++-- .../doc-input.controller.ts | 3 +- .../src/services/doc-menu-style.service.ts | 58 +++++++++++++++++-- .../layout/block/paragraph/language-ruler.ts | 6 +- .../layout/block/paragraph/layout-ruler.ts | 30 +++++----- .../block/paragraph/paragraph-layout.ts | 10 ++-- .../docs/layout/block/paragraph/shaping.ts | 14 ++--- 9 files changed, 129 insertions(+), 49 deletions(-) diff --git a/packages/docs-ui/src/basics/paragraph.ts b/packages/docs-ui/src/basics/paragraph.ts index f55c4328ad2..2c3ae741e74 100644 --- a/packages/docs-ui/src/basics/paragraph.ts +++ b/packages/docs-ui/src/basics/paragraph.ts @@ -20,21 +20,39 @@ export function hasParagraphInTable(paragraph: IParagraph, tables: ICustomTable[ return tables.some((table) => paragraph.startIndex > table.startIndex && paragraph.startIndex < table.endIndex); } -export function getTextRunAtPosition(textRuns: ITextRun[], position: number, cacheStyle?: Nullable) { +export function getTextRunAtPosition( + textRuns: ITextRun[], + position: number, + defaultStyle: ITextStyle, + cacheStyle: Nullable +): ITextRun { + const retTextRun: ITextRun = { + st: 0, + ed: 0, + ts: defaultStyle, + }; + for (let i = textRuns.length - 1; i >= 0; i--) { const textRun = textRuns[i]; const { st, ed } = textRun; if (position > st && position <= ed) { - return { - ...textRun, - ts: { - ...textRun.ts, - ...cacheStyle, - }, + retTextRun.st = st; + retTextRun.ed = ed; + + retTextRun.ts = { + ...retTextRun.ts, + ...textRun.ts, }; } } - return cacheStyle ? { ts: cacheStyle } : null; + if (cacheStyle) { + retTextRun.ts = { + ...retTextRun.ts, + ...cacheStyle, + }; + } + + return retTextRun; } diff --git a/packages/docs-ui/src/commands/commands/ime-input.command.ts b/packages/docs-ui/src/commands/commands/ime-input.command.ts index e102244cf90..2809ca5c2a7 100644 --- a/packages/docs-ui/src/commands/commands/ime-input.command.ts +++ b/packages/docs-ui/src/commands/commands/ime-input.command.ts @@ -88,8 +88,9 @@ export const IMEInputCommand: ICommand = { }, }; + const defaultTextStyle = docMenuStyleService.getDefaultStyle(); const styleCache = docMenuStyleService.getStyleCache(); - const curTextRun = getTextRunAtPosition(body.textRuns ?? [], startOffset + oldTextLen, styleCache); + const curTextRun = getTextRunAtPosition(body.textRuns ?? [], startOffset + oldTextLen, defaultTextStyle, styleCache); const textX = new TextX(); const jsonX = JSONX.getInstance(); diff --git a/packages/docs-ui/src/controllers/menu/menu.ts b/packages/docs-ui/src/controllers/menu/menu.ts index a75946be78b..647ee9a74f3 100644 --- a/packages/docs-ui/src/controllers/menu/menu.ts +++ b/packages/docs-ui/src/controllers/menu/menu.ts @@ -20,6 +20,7 @@ import type { Subscription } from 'rxjs'; import { BaselineOffset, BooleanNumber, + DEFAULT_STYLES, DOCS_ZEN_EDITOR_UNIT_ID_KEY, DocumentFlavor, HorizontalAlign, @@ -461,7 +462,7 @@ export function FontFamilySelectorMenuItemFactory(accessor: IAccessor): IMenuSel })), // disabled$: getCurrentSheetDisabled$(accessor), value$: new Observable((subscriber) => { - const defaultValue = FONT_FAMILY_LIST[0].value; + const defaultValue = DEFAULT_STYLES.ff; const disposable = commandService.onCommandExecuted((c) => { const id = c.id; @@ -506,7 +507,7 @@ export function FontSizeSelectorMenuItemFactory(accessor: IAccessor): IMenuSelec selections: FONT_SIZE_LIST, // disabled$, value$: new Observable((subscriber) => { - const DEFAULT_SIZE = 14; + const DEFAULT_SIZE = DEFAULT_STYLES.fs; const disposable = commandService.onCommandExecuted((c) => { const id = c.id; @@ -916,13 +917,18 @@ function getFontStyleAtCursor(accessor: IAccessor) { const textSelectionService = accessor.get(DocSelectionManagerService); const docMenuStyleService = accessor.get(DocMenuStyleService); - const docDataModel = univerInstanceService.getCurrentUniverDocInstance(); + const docDataModel = univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_DOC); const activeTextRange = textSelectionService.getActiveTextRange(); + + const defaultTextStyle = docMenuStyleService.getDefaultStyle(); const cacheStyle = docMenuStyleService.getStyleCache() ?? {}; if (docDataModel == null || activeTextRange == null) { return { - ts: cacheStyle, + ts: { + ...defaultTextStyle, + ...cacheStyle, + }, }; } @@ -932,7 +938,10 @@ function getFontStyleAtCursor(accessor: IAccessor) { if (textRuns == null) { return { - ts: cacheStyle, + ts: { + ...defaultTextStyle, + ...cacheStyle, + }, }; } @@ -950,6 +959,7 @@ function getFontStyleAtCursor(accessor: IAccessor) { return { ...textRun, ts: { + ...defaultTextStyle, ...textRun?.ts, ...cacheStyle, }, diff --git a/packages/docs-ui/src/controllers/render-controllers/doc-input.controller.ts b/packages/docs-ui/src/controllers/render-controllers/doc-input.controller.ts index 9610dbd5cc4..a4c07b8d01b 100644 --- a/packages/docs-ui/src/controllers/render-controllers/doc-input.controller.ts +++ b/packages/docs-ui/src/controllers/render-controllers/doc-input.controller.ts @@ -74,8 +74,9 @@ export class DocInputController extends Disposable implements IRenderModule { const originBody = docDataModel.getSelfOrHeaderFooterModel(segmentId).getBody(); // Insert content's style should follow the text style of the current position. + const defaultTextStyle = this._docMenuStyleService.getDefaultStyle(); const cacheStyle = this._docMenuStyleService.getStyleCache(); - const curTextRun = getTextRunAtPosition(originBody?.textRuns ?? [], activeRange.endOffset, cacheStyle); + const curTextRun = getTextRunAtPosition(originBody?.textRuns ?? [], activeRange.endOffset, defaultTextStyle, cacheStyle); await this._commandService.executeCommand(InsertCommand.id, { unitId, diff --git a/packages/docs-ui/src/services/doc-menu-style.service.ts b/packages/docs-ui/src/services/doc-menu-style.service.ts index ab670bf34c2..9bd371759e6 100644 --- a/packages/docs-ui/src/services/doc-menu-style.service.ts +++ b/packages/docs-ui/src/services/doc-menu-style.service.ts @@ -14,9 +14,23 @@ * limitations under the License. */ -import type { ITextStyle, Nullable } from '@univerjs/core'; -import { Disposable, Inject } from '@univerjs/core'; -import { DocSelectionManagerService } from '@univerjs/docs'; +import type { DocumentDataModel, ITextStyle, Nullable } from '@univerjs/core'; +import { Disposable, Inject, IUniverInstanceService, UniverInstanceType } from '@univerjs/core'; +import { DocSelectionManagerService, DocSkeletonManagerService } from '@univerjs/docs'; +import { DocumentEditArea, IRenderManagerService } from '@univerjs/engine-render'; + +const BODY_DEFAULT_FONTSIZE = 11; +const HEADER_FOOTER_DEFAULT_FONTSIZE = 9; +const DEFAULT_TEXT_STYLE = { + /** + * fontFamily + */ + ff: 'Arial', + /** + * fontSize + */ + fs: BODY_DEFAULT_FONTSIZE, +}; // It is used to cache the styles in the doc menu, which is used for the next input, // and is cleared when the doc range is changed. @@ -24,7 +38,9 @@ export class DocMenuStyleService extends Disposable { private _cacheStyle: Nullable = null; constructor( - @Inject(DocSelectionManagerService) private readonly _textSelectionManagerService: DocSelectionManagerService + @Inject(DocSelectionManagerService) private readonly _textSelectionManagerService: DocSelectionManagerService, + @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, + @IRenderManagerService private readonly _renderManagerService: IRenderManagerService ) { super(); @@ -47,6 +63,40 @@ export class DocMenuStyleService extends Disposable { return this._cacheStyle; } + getDefaultStyle(): ITextStyle { + const docDataModel = this._univerInstanceService + .getCurrentUnitForType(UniverInstanceType.UNIVER_DOC); + + if (docDataModel == null) { + return { + ...DEFAULT_TEXT_STYLE, + }; + } + + const unitId = docDataModel?.getUnitId(); + const docSkeletonManagerService = this._renderManagerService.getRenderById(unitId)?.with(DocSkeletonManagerService); + const docViewModel = docSkeletonManagerService?.getViewModel(); + + if (docViewModel == null) { + return { + ...DEFAULT_TEXT_STYLE, + }; + } + + const editArea = docViewModel.getEditArea(); + + if (editArea === DocumentEditArea.BODY) { + return { + ...DEFAULT_TEXT_STYLE, + }; + } else { + return { + ...DEFAULT_TEXT_STYLE, + fs: HEADER_FOOTER_DEFAULT_FONTSIZE, + }; + } + } + setStyleCache(style: ITextStyle) { this._cacheStyle = { ...this._cacheStyle, diff --git a/packages/engine-render/src/components/docs/layout/block/paragraph/language-ruler.ts b/packages/engine-render/src/components/docs/layout/block/paragraph/language-ruler.ts index 74a1979259a..7d753850b9c 100644 --- a/packages/engine-render/src/components/docs/layout/block/paragraph/language-ruler.ts +++ b/packages/engine-render/src/components/docs/layout/block/paragraph/language-ruler.ts @@ -16,12 +16,12 @@ import type { IParagraph } from '@univerjs/core'; -import { EMOJI_REG, hasArabic, hasSpace, hasTibetan, startWithEmoji } from '../../../../../basics/tools'; -import { createSkeletonLetterGlyph, createSkeletonWordGlyph } from '../../model/glyph'; -import { getFontCreateConfig } from '../../tools'; import type { ISectionBreakConfig } from '../../../../../basics/interfaces'; import type { DataStreamTreeNode } from '../../../view-model/data-stream-tree-node'; import type { DocumentViewModel } from '../../../view-model/document-view-model'; +import { EMOJI_REG, hasArabic, hasSpace, hasTibetan, startWithEmoji } from '../../../../../basics/tools'; +import { createSkeletonLetterGlyph, createSkeletonWordGlyph } from '../../model/glyph'; +import { getFontCreateConfig } from '../../tools'; // Handle English word, English punctuation, number characters. // https://en.wikipedia.org/wiki/CJK_characters diff --git a/packages/engine-render/src/components/docs/layout/block/paragraph/layout-ruler.ts b/packages/engine-render/src/components/docs/layout/block/paragraph/layout-ruler.ts index 5372df67f0f..a75d0efba89 100644 --- a/packages/engine-render/src/components/docs/layout/block/paragraph/layout-ruler.ts +++ b/packages/engine-render/src/components/docs/layout/block/paragraph/layout-ruler.ts @@ -14,8 +14,22 @@ * limitations under the License. */ -import { BooleanNumber, DataStreamTreeTokenType, GridType, ObjectRelativeFromV, PositionedObjectLayoutType, SpacingRule, TableTextWrapType } from '@univerjs/core'; import type { INumberUnit, IParagraphProperties, IParagraphStyle, Nullable } from '@univerjs/core'; +import type { + IDocumentSkeletonColumn, + IDocumentSkeletonDivide, + IDocumentSkeletonDrawing, + IDocumentSkeletonGlyph, + IDocumentSkeletonLine, + IDocumentSkeletonPage, + IDocumentSkeletonSection, + IDocumentSkeletonTable, +} from '../../../../../basics/i-document-skeleton-cached'; +import type { IParagraphConfig, IParagraphTableCache, ISectionBreakConfig } from '../../../../../basics/interfaces'; +import type { + ILayoutContext, +} from '../../tools'; +import { BooleanNumber, DataStreamTreeTokenType, GridType, ObjectRelativeFromV, PositionedObjectLayoutType, SpacingRule, TableTextWrapType } from '@univerjs/core'; import { GlyphType, LineType } from '../../../../../basics/i-document-skeleton-cached'; import { BreakPointType } from '../../line-breaker/break'; import { addGlyphToDivide, createSkeletonBulletGlyph } from '../../model/glyph'; @@ -46,20 +60,6 @@ import { mergeByV, } from '../../tools'; import { getNullTableSkeleton, getTableIdAndSliceIndex, getTableSliceId } from '../table'; -import type { - IDocumentSkeletonColumn, - IDocumentSkeletonDivide, - IDocumentSkeletonDrawing, - IDocumentSkeletonGlyph, - IDocumentSkeletonLine, - IDocumentSkeletonPage, - IDocumentSkeletonSection, - IDocumentSkeletonTable, -} from '../../../../../basics/i-document-skeleton-cached'; -import type { IParagraphConfig, IParagraphTableCache, ISectionBreakConfig } from '../../../../../basics/interfaces'; -import type { - ILayoutContext, -} from '../../tools'; export function layoutParagraph( ctx: ILayoutContext, diff --git a/packages/engine-render/src/components/docs/layout/block/paragraph/paragraph-layout.ts b/packages/engine-render/src/components/docs/layout/block/paragraph/paragraph-layout.ts index fdf03593aba..764e22619af 100644 --- a/packages/engine-render/src/components/docs/layout/block/paragraph/paragraph-layout.ts +++ b/packages/engine-render/src/components/docs/layout/block/paragraph/paragraph-layout.ts @@ -14,17 +14,17 @@ * limitations under the License. */ +import type { IDocumentSkeletonPage } from '../../../../../basics/i-document-skeleton-cached'; +import type { ISectionBreakConfig } from '../../../../../basics/interfaces'; +import type { DataStreamTreeNode } from '../../../view-model/data-stream-tree-node'; +import type { DocumentViewModel } from '../../../view-model/document-view-model'; +import type { ILayoutContext } from '../../tools'; import { DataStreamTreeNodeType } from '@univerjs/core'; import { clearFontCreateConfigCache } from '../../tools'; import { createTableSkeleton } from '../table'; import { lineAdjustment } from './line-adjustment'; import { lineBreaking } from './linebreaking'; import { shaping } from './shaping'; -import type { IDocumentSkeletonPage } from '../../../../../basics/i-document-skeleton-cached'; -import type { ISectionBreakConfig } from '../../../../../basics/interfaces'; -import type { DataStreamTreeNode } from '../../../view-model/data-stream-tree-node'; -import type { DocumentViewModel } from '../../../view-model/document-view-model'; -import type { ILayoutContext } from '../../tools'; export function dealWidthParagraph( ctx: ILayoutContext, diff --git a/packages/engine-render/src/components/docs/layout/block/paragraph/shaping.ts b/packages/engine-render/src/components/docs/layout/block/paragraph/shaping.ts index 9656503f171..02aa052352f 100644 --- a/packages/engine-render/src/components/docs/layout/block/paragraph/shaping.ts +++ b/packages/engine-render/src/components/docs/layout/block/paragraph/shaping.ts @@ -14,8 +14,14 @@ * limitations under the License. */ -import { BooleanNumber, DataStreamTreeTokenType, GridType, PositionedObjectLayoutType } from '@univerjs/core'; import type { IParagraphStyle, Nullable } from '@univerjs/core'; +import type { IDocumentSkeletonGlyph } from '../../../../../basics/i-document-skeleton-cached'; +import type { ISectionBreakConfig } from '../../../../../basics/interfaces'; +import type { DataStreamTreeNode } from '../../../view-model/data-stream-tree-node'; +import type { DocumentViewModel } from '../../../view-model/document-view-model'; +import type { IOpenTypeGlyphInfo } from '../../shaping-engine/text-shaping'; +import type { ILayoutContext } from '../../tools'; +import { BooleanNumber, DataStreamTreeTokenType, GridType, PositionedObjectLayoutType } from '@univerjs/core'; import { hasArabic, hasCJK, hasCJKPunctuation, hasCJKText, hasTibetan, startWithEmoji } from '../../../../../basics/tools'; import { Lang } from '../../hyphenation/lang'; import { LineBreaker } from '../../line-breaker'; @@ -31,12 +37,6 @@ import { textShape } from '../../shaping-engine/text-shaping'; import { prepareParagraphBody } from '../../shaping-engine/utils'; import { getCharSpaceApply, getFontCreateConfig } from '../../tools'; import { ArabicHandler, emojiHandler, otherHandler, TibetanHandler } from './language-ruler'; -import type { IDocumentSkeletonGlyph } from '../../../../../basics/i-document-skeleton-cached'; -import type { ISectionBreakConfig } from '../../../../../basics/interfaces'; -import type { DataStreamTreeNode } from '../../../view-model/data-stream-tree-node'; -import type { DocumentViewModel } from '../../../view-model/document-view-model'; -import type { IOpenTypeGlyphInfo } from '../../shaping-engine/text-shaping'; -import type { ILayoutContext } from '../../tools'; // Now we apply consecutive punctuation adjustment, specified in Chinese Layout // Requirements, section 3.1.6.1 Punctuation Adjustment Space, and Japanese Layout From b21a43041b12d586cd66b5525277a1db7949689f Mon Sep 17 00:00:00 2001 From: jocs Date: Thu, 31 Oct 2024 17:13:49 +0800 Subject: [PATCH 2/3] fix: default text style in doc --- .../commands/commands/break-line.command.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/docs-ui/src/commands/commands/break-line.command.ts b/packages/docs-ui/src/commands/commands/break-line.command.ts index c54aa13613a..ea35f382f9c 100644 --- a/packages/docs-ui/src/commands/commands/break-line.command.ts +++ b/packages/docs-ui/src/commands/commands/break-line.command.ts @@ -14,9 +14,11 @@ * limitations under the License. */ -import type { DocumentDataModel, ICommand, IParagraph } from '@univerjs/core'; +import type { DocumentDataModel, ICommand, IDocumentBody, IParagraph } from '@univerjs/core'; import { BuildTextUtils, CommandType, DataStreamTreeTokenType, ICommandService, IUniverInstanceService, PresetListType, Tools, UniverInstanceType } from '@univerjs/core'; import { DocSelectionManagerService } from '@univerjs/docs'; +import { getTextRunAtPosition } from '../../basics/paragraph'; +import { DocMenuStyleService } from '../../services/doc-menu-style.service'; import { InsertCommand } from './core-editing.command'; import { ToggleCheckListCommand } from './list.command'; @@ -55,10 +57,12 @@ export const BreakLineCommand: ICommand = { type: CommandType.COMMAND, + // eslint-disable-next-line max-lines-per-function handler: async (accessor) => { const docSelectionManagerService = accessor.get(DocSelectionManagerService); const univerInstanceService = accessor.get(IUniverInstanceService); const commandService = accessor.get(ICommandService); + const docMenuStyleService = accessor.get(DocMenuStyleService); const activeTextRange = docSelectionManagerService.getActiveTextRange(); const rectRanges = docSelectionManagerService.getRectRanges(); @@ -97,9 +101,20 @@ export const BreakLineCommand: ICommand = { const prevParagraphIndex = prevParagraph.startIndex; - const insertBody = { + const defaultTextStyle = docMenuStyleService.getDefaultStyle(); + const styleCache = docMenuStyleService.getStyleCache(); + const curTextRun = getTextRunAtPosition(body.textRuns ?? [], endOffset, defaultTextStyle, styleCache); + + const insertBody: IDocumentBody = { dataStream: DataStreamTreeTokenType.PARAGRAPH, paragraphs: generateParagraphs(DataStreamTreeTokenType.PARAGRAPH, prevParagraph), + textRuns: [{ + st: 0, + ed: 1, + ts: { + ...curTextRun.ts, + }, + }], }; const deleteRange = { From f4b020f247a58a1db3ca0267481d1c42143b7709 Mon Sep 17 00:00:00 2001 From: jocs Date: Thu, 31 Oct 2024 20:13:25 +0800 Subject: [PATCH 3/3] fix: find the first possible cursor position --- .../src/commands/commands/ime-input.command.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/docs-ui/src/commands/commands/ime-input.command.ts b/packages/docs-ui/src/commands/commands/ime-input.command.ts index 2809ca5c2a7..bb22a9bac9e 100644 --- a/packages/docs-ui/src/commands/commands/ime-input.command.ts +++ b/packages/docs-ui/src/commands/commands/ime-input.command.ts @@ -53,7 +53,7 @@ export const IMEInputCommand: ICommand = { } const previousActiveRange = imeInputManagerService.getActiveRange(); - if (!previousActiveRange) { + if (previousActiveRange == null) { return false; } @@ -66,7 +66,7 @@ export const IMEInputCommand: ICommand = { const insertRange = BuildTextUtils.selection.getInsertSelection(previousActiveRange, body); Object.assign(previousActiveRange, insertRange); - const { startOffset } = previousActiveRange; + const { startOffset, endOffset } = previousActiveRange; const len = newText.length; @@ -90,7 +90,12 @@ export const IMEInputCommand: ICommand = { const defaultTextStyle = docMenuStyleService.getDefaultStyle(); const styleCache = docMenuStyleService.getStyleCache(); - const curTextRun = getTextRunAtPosition(body.textRuns ?? [], startOffset + oldTextLen, defaultTextStyle, styleCache); + const curTextRun = getTextRunAtPosition( + body.textRuns ?? [], + isCompositionStart ? endOffset : startOffset + oldTextLen, + defaultTextStyle, + styleCache + ); const textX = new TextX(); const jsonX = JSONX.getInstance();