Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix 335899: Split paragraph by BR before doing block format #2955

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { alignTable } from '../table/alignTable';
import { getOperationalBlocks, mutateBlock } from 'roosterjs-content-model-dom';
import { splitSelectedParagraphByBr } from './splitSelectedParagraphByBr';
import type {
ContentModelListItem,
ReadonlyContentModelDocument,
Expand Down Expand Up @@ -53,6 +54,8 @@ export function setModelAlignment(
model: ReadonlyContentModelDocument,
alignment: 'left' | 'center' | 'right' | 'justify'
) {
splitSelectedParagraphByBr(model);

const paragraphOrListItemOrTable = getOperationalBlocks<ContentModelListItem>(
model,
['ListItem'],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { findListItemsInSameThread } from '../list/findListItemsInSameThread';
import { splitSelectedParagraphByBr } from './splitSelectedParagraphByBr';
import {
applyTableFormat,
getOperationalBlocks,
Expand All @@ -19,6 +20,8 @@ import type {
* @internal
*/
export function setModelDirection(model: ReadonlyContentModelDocument, direction: 'ltr' | 'rtl') {
splitSelectedParagraphByBr(model);

const paragraphOrListItemOrTable = getOperationalBlocks<ContentModelListItem>(
model,
['ListItem'],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { findListItemsInSameThread } from '../list/findListItemsInSameThread';
import { getListAnnounceData } from '../list/getListAnnounceData';
import { splitSelectedParagraphByBr } from './splitSelectedParagraphByBr';
import {
createListLevel,
getOperationalBlocks,
Expand Down Expand Up @@ -33,6 +34,8 @@ export function setModelIndentation(
length: number = IndentStepInPixel,
context?: FormatContentModelContext
) {
splitSelectedParagraphByBr(model);

const paragraphOrListItem = getOperationalBlocks<ContentModelListItem>(
model,
['ListItem'],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {
createParagraph,
getSelectedSegmentsAndParagraphs,
mutateBlock,
} from 'roosterjs-content-model-dom';
import type {
ReadonlyContentModelDocument,
ReadonlyContentModelParagraph,
ShallowMutableContentModelParagraph,
} from 'roosterjs-content-model-types';

/**
* @internal
* For all selected paragraphs, if it has BR in middle of other segments, split the paragraph into multiple paragraphs
* @param model The model to process
*/
export function splitSelectedParagraphByBr(model: ReadonlyContentModelDocument) {
const selections = getSelectedSegmentsAndParagraphs(
model,
false /*includingFormatHolder*/,
false /*includingEntity*/
);

for (const [_, para, path] of selections) {
if (para?.segments.some(s => s.segmentType == 'Br')) {
let currentParagraph = shallowColonParagraph(para);
let hasVisibleSegment = false;
const newParagraphs: ShallowMutableContentModelParagraph[] = [];
const parent = mutateBlock(path[0]);
const index = parent.blocks.indexOf(para);

if (index >= 0) {
for (const segment of mutateBlock(para).segments) {
if (segment.segmentType == 'Br') {
if (!hasVisibleSegment) {
currentParagraph.segments.push(segment);
}

if (currentParagraph.segments.length > 0) {
newParagraphs.push(currentParagraph);
}

currentParagraph = shallowColonParagraph(para);
hasVisibleSegment = false;
} else {
currentParagraph.segments.push(segment);

if (segment.segmentType != 'SelectionMarker') {
hasVisibleSegment = true;
}
}
}

if (currentParagraph.segments.length > 0) {
newParagraphs.push(currentParagraph);
}

parent.blocks.splice(index, 1, ...newParagraphs);
}
}
}
}

function shallowColonParagraph(
para: ReadonlyContentModelParagraph
): ShallowMutableContentModelParagraph {
return createParagraph(false /*isImplicit*/, para.format, para.segmentFormat, para.decorator);
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { splitSelectedParagraphByBr } from './splitSelectedParagraphByBr';
import { wrapBlockStep1, wrapBlockStep2 } from '../common/wrapBlock';
import {
getOperationalBlocks,
Expand Down Expand Up @@ -28,6 +29,8 @@ export function toggleModelBlockQuote(
formatLtr: ContentModelFormatContainerFormat,
formatRtl: ContentModelFormatContainerFormat
): boolean {
splitSelectedParagraphByBr(model);

const paragraphOfQuote = getOperationalBlocks<
ContentModelFormatContainer | ContentModelListItem
>(model, ['FormatContainer', 'ListItem'], ['TableCell'], true /*deepFirst*/);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { splitSelectedParagraphByBr } from '../block/splitSelectedParagraphByBr';
import {
createListItem,
createListLevel,
Expand Down Expand Up @@ -27,6 +28,8 @@ export function setListType(
listType: 'OL' | 'UL',
removeMargins: boolean = false
) {
splitSelectedParagraphByBr(model);

const paragraphOrListItems = getOperationalBlocks<ContentModelListItem>(
model,
['ListItem'],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { getSelectedParagraphs } from 'roosterjs-content-model-dom';
import { splitSelectedParagraphByBr } from '../../modelApi/block/splitSelectedParagraphByBr';
import type { IEditor, ShallowMutableContentModelParagraph } from 'roosterjs-content-model-types';

/**
Expand All @@ -14,6 +15,8 @@ export function formatParagraphWithContentModel(
) {
editor.formatContentModel(
(model, context) => {
splitSelectedParagraphByBr(model);

const paragraphs = getSelectedParagraphs(model, true /*mutate*/);

paragraphs.forEach(setStyleCallback);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as splitSelectedParagraphByBrModule from '../../../lib/modelApi/block/splitSelectedParagraphByBr';
import { ContentModelBlockFormat } from 'roosterjs-content-model-types';
import { setModelAlignment } from '../../../lib/modelApi/block/setModelAlignment';
import {
Expand All @@ -12,6 +13,14 @@ import {

describe('align left', () => {
const mockedCachedElement = 'CACHE' as any;
let splitSelectedParagraphByBrSpy: jasmine.Spy;

beforeEach(() => {
splitSelectedParagraphByBrSpy = spyOn(
splitSelectedParagraphByBrModule,
'splitSelectedParagraphByBr'
).and.callThrough();
});

function createParagraph(isImplicit?: boolean, format?: ContentModelBlockFormat) {
const result = originalCreateParagraph(isImplicit, format);
Expand All @@ -31,6 +40,8 @@ describe('align left', () => {
blocks: [],
});
expect(result).toBeFalse();
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledTimes(1);
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledWith(group);
});

it('Group without selection', () => {
Expand All @@ -45,6 +56,8 @@ describe('align left', () => {
blocks: [para],
});
expect(result).toBeFalse();
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledTimes(1);
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledWith(group);
});

it('Group with selected paragraph', () => {
Expand Down Expand Up @@ -91,6 +104,8 @@ describe('align left', () => {
],
});
expect(result).toBeTrue();
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledTimes(1);
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledWith(group);
});

it('Group with multiple selected paragraph', () => {
Expand Down Expand Up @@ -141,6 +156,8 @@ describe('align left', () => {
],
});
expect(result).toBeTrue();
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledTimes(1);
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledWith(group);
});

it('Group with selected paragraph in RTL', () => {
Expand Down Expand Up @@ -170,6 +187,8 @@ describe('align left', () => {
],
});
expect(result).toBeTrue();
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledTimes(1);
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledWith(group);
});

it('Group with paragraph under OL', () => {
Expand Down Expand Up @@ -214,6 +233,8 @@ describe('align left', () => {
],
});
expect(result).toBeTrue();
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledTimes(1);
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledWith(group);
});

it('align table, list, paragraph left', () => {
Expand Down Expand Up @@ -329,6 +350,8 @@ describe('align left', () => {
],
});
expect(result).toBeTrue();
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledTimes(1);
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledWith(group);
});

it('align table, list, paragraph center', () => {
Expand Down Expand Up @@ -442,6 +465,8 @@ describe('align left', () => {
],
});
expect(result).toBeTrue();
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledTimes(1);
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledWith(group);
});

it('align table, list, paragraph right', () => {
Expand Down Expand Up @@ -555,6 +580,8 @@ describe('align left', () => {
],
});
expect(result).toBeTrue();
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledTimes(1);
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledWith(group);
});

it('[RTL] align table, list, paragraph left', () => {
Expand Down Expand Up @@ -675,6 +702,8 @@ describe('align left', () => {
],
});
expect(result).toBeTrue();
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledTimes(1);
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledWith(group);
});

it('[RTL] align table, list, paragraph center', () => {
Expand Down Expand Up @@ -795,6 +824,8 @@ describe('align left', () => {
],
});
expect(result).toBeTrue();
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledTimes(1);
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledWith(group);
});

it('[RTL] align table, list, paragraph right', () => {
Expand Down Expand Up @@ -916,6 +947,8 @@ describe('align left', () => {
],
});
expect(result).toBeTrue();
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledTimes(1);
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledWith(group);
});

it('align justify paragraph', () => {
Expand All @@ -941,6 +974,8 @@ describe('align left', () => {
],
});
expect(result).toBeTruthy();
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledTimes(1);
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledWith(group);
});

it('align justify list item', () => {
Expand Down Expand Up @@ -985,5 +1020,7 @@ describe('align left', () => {
],
});
expect(result).toBeTruthy();
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledTimes(1);
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledWith(group);
});
});
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as splitSelectedParagraphByBrModule from '../../../lib/modelApi/block/splitSelectedParagraphByBr';
import { ContentModelDocument } from 'roosterjs-content-model-types';
import { setModelDirection } from '../../../lib/modelApi/block/setModelDirection';

Expand All @@ -7,6 +8,7 @@ describe('setModelDirection', () => {
const color = '#AABBCC';
const testBorderString = `${width} ${style} ${color}`;
const mockedCachedElement = 'CACHE' as any;
let splitSelectedParagraphByBrSpy: jasmine.Spy;

function runTest(
model: ContentModelDocument,
Expand All @@ -23,8 +25,17 @@ describe('setModelDirection', () => {
model.blocks[0].dataset = {};
}
expect(model).toEqual(expectedModel);
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledTimes(1);
expect(splitSelectedParagraphByBrSpy).toHaveBeenCalledWith(model);
}

beforeEach(() => {
splitSelectedParagraphByBrSpy = spyOn(
splitSelectedParagraphByBrModule,
'splitSelectedParagraphByBr'
);
});

it('set direction for paragraph', () => {
runTest(
{
Expand Down
Loading
Loading