Skip to content

Commit

Permalink
Content Model: Improve adjustWordSelection (#2087)
Browse files Browse the repository at this point in the history
  • Loading branch information
JiuqingSong authored Sep 21, 2023
1 parent b4ca8e2 commit bee1d42
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 33 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
import { ContentModelSegmentFormat, ContentModelText } from 'roosterjs-content-model-types';
import { addCode, addLink } from '../common/addDecorators';
import {
ContentModelCode,
ContentModelLink,
ContentModelSegmentFormat,
ContentModelText,
} from 'roosterjs-content-model-types';

/**
* Create a ContentModelText model
* @param text Text of this model
* @param format @optional The format of this model
* @param link @optional The link decorator
* @param code @option The code decorator
*/
export function createText(text: string, format?: ContentModelSegmentFormat): ContentModelText {
return {
export function createText(
text: string,
format?: ContentModelSegmentFormat,
link?: ContentModelLink,
code?: ContentModelCode
): ContentModelText {
const result: ContentModelText = {
segmentType: 'Text',
text: text,
format: format ? { ...format } : {},
};

if (link) {
addLink(result, link);
}

if (code) {
addCode(result, code);
}

return result;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { createTable } from '../../../lib/modelApi/creators/createTable';
import { createTableCell } from '../../../lib/modelApi/creators/createTableCell';
import { createText } from '../../../lib/modelApi/creators/createText';
import {
ContentModelCode,
ContentModelLink,
ContentModelListLevel,
ContentModelSegmentFormat,
ContentModelTableCellFormat,
Expand Down Expand Up @@ -188,6 +190,47 @@ describe('Creators', () => {
expect(format).toEqual({ a: 1 });
});

it('createText with decorators', () => {
const format = { a: 1 } as any;
const text = 'test';
const link: ContentModelLink = {
dataset: {},
format: {
href: 'test',
},
};
const code: ContentModelCode = {
format: { fontFamily: 'test' },
};
const result = createText(text, format, link, code);

expect(result).toEqual({
segmentType: 'Text',
format: { a: 1 } as any,
text: text,
link,
code,
});
expect(result.link).not.toBe(link);
expect(result.code).not.toBe(code);

result.link!.dataset.a = 'b';
result.link!.format.href = 'test2';

expect(link).toEqual({
dataset: {},
format: {
href: 'test',
},
});

result.code!.format.fontFamily = 'test2';

expect(code).toEqual({
format: { fontFamily: 'test' },
});
});

it('createTable', () => {
const tableModel = createTable(2);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,48 +25,54 @@ export function adjustWordSelection(
return true;
});

if (markerBlock) {
const tempSegments = markerBlock ? [...markerBlock.segments] : undefined;

if (tempSegments && markerBlock) {
const segments: ContentModelSegment[] = [];
let markerSelectionIndex = markerBlock.segments.indexOf(marker);
let markerSelectionIndex = tempSegments.indexOf(marker);
for (let i = markerSelectionIndex - 1; i >= 0; i--) {
const currentSegment = markerBlock.segments[i];
const currentSegment = tempSegments[i];
if (currentSegment.segmentType == 'Text') {
const found = findDelimiter(currentSegment, false /*moveRightward*/);
if (found > -1) {
if (found == currentSegment.text.length) {
break;
}
splitTextSegment(markerBlock.segments, currentSegment, i, found);
segments.push(markerBlock.segments[i + 1]);

splitTextSegment(tempSegments, currentSegment, i, found);

segments.push(tempSegments[i + 1]);

break;
} else {
segments.push(markerBlock.segments[i]);
segments.push(tempSegments[i]);
}
} else {
break;
}
}
markerSelectionIndex = markerBlock.segments.indexOf(marker);

markerSelectionIndex = tempSegments.indexOf(marker);
segments.push(marker);

// Marker is at start of word
if (segments.length <= 1) {
return segments;
}

for (let i = markerSelectionIndex + 1; i < markerBlock.segments.length; i++) {
const currentSegment = markerBlock.segments[i];
for (let i = markerSelectionIndex + 1; i < tempSegments.length; i++) {
const currentSegment = tempSegments[i];
if (currentSegment.segmentType == 'Text') {
const found = findDelimiter(currentSegment, true /*moveRightward*/);
if (found > -1) {
if (found == 0) {
break;
}
splitTextSegment(markerBlock.segments, currentSegment, i, found);
segments.push(markerBlock.segments[i]);
splitTextSegment(tempSegments, currentSegment, i, found);
segments.push(tempSegments[i]);
break;
} else {
segments.push(markerBlock.segments[i]);
segments.push(tempSegments[i]);
}
} else {
break;
Expand All @@ -78,6 +84,7 @@ export function adjustWordSelection(
return [marker];
}

markerBlock.segments = tempSegments;
return segments;
} else {
return [marker];
Expand Down Expand Up @@ -123,26 +130,22 @@ function findDelimiter(segment: ContentModelText, moveRightward: boolean): numbe

function splitTextSegment(
segments: ContentModelSegment[],
textSegment: ContentModelText,
textSegment: Readonly<ContentModelText>,
index: number,
found: number
) {
const text = textSegment.text;
const newSegment = createText(text.substring(0, found), segments[index].format);

if (textSegment.code) {
newSegment.code = {
format: { ...textSegment.code.format },
};
}

if (textSegment.link) {
newSegment.link = {
format: { ...textSegment.link.format },
dataset: { ...textSegment.link.dataset },
};
}

textSegment.text = text.substring(found, text.length);
segments.splice(index, 0, newSegment);
const newSegmentLeft = createText(
text.substring(0, found),
textSegment.format,
textSegment.link,
textSegment.code
);
const newSegmentRight = createText(
text.substring(found, text.length),
textSegment.format,
textSegment.link,
textSegment.code
);
segments.splice(index, 1, newSegmentLeft, newSegmentRight);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { adjustWordSelection } from '../../../lib/modelApi/selection/adjustWordSelection';
import {
createContentModelDocument,
createParagraph,
createSelectionMarker,
createText,
} from 'roosterjs-content-model-dom';
import {
ContentModelBlock,
ContentModelDocument,
Expand Down Expand Up @@ -885,4 +891,84 @@ describe('adjustWordSelection', () => {
);
});
});

it('Do not modify segments array if no word is selected: marker before text', () => {
const text = createText('Word1 Word2');
const marker = createSelectionMarker();
const paragraph = createParagraph();
const model = createContentModelDocument();

paragraph.segments.push(marker, text);
model.blocks.push(paragraph);

adjustWordSelection(model, marker);

expect(model).toEqual({
blockGroupType: 'Document',
blocks: [
{
blockType: 'Paragraph',
segments: [marker, text],
format: {},
},
],
});
expect(model.blocks[0]).toBe(paragraph);
expect(paragraph.segments[0]).toBe(marker);
expect(paragraph.segments[1]).toBe(text);
});

it('Do not modify segments array if no word is selected: marker after text', () => {
const text = createText('Word1 Word2');
const marker = createSelectionMarker();
const paragraph = createParagraph();
const model = createContentModelDocument();

paragraph.segments.push(text, marker);
model.blocks.push(paragraph);

adjustWordSelection(model, marker);

expect(model).toEqual({
blockGroupType: 'Document',
blocks: [
{
blockType: 'Paragraph',
segments: [text, marker],
format: {},
},
],
});
expect(model.blocks[0]).toBe(paragraph);
expect(paragraph.segments[0]).toBe(text);
expect(paragraph.segments[1]).toBe(marker);
});

it('Do not modify segments array if no word is selected: marker between text', () => {
const text1 = createText('Word1 ');
const text2 = createText(' Word2');
const marker = createSelectionMarker();
const paragraph = createParagraph();
const model = createContentModelDocument();

paragraph.segments.push(text1, marker, text2);
model.blocks.push(paragraph);

adjustWordSelection(model, marker);

expect(model).toEqual({
blockGroupType: 'Document',
blocks: [
{
blockType: 'Paragraph',
segments: [text1, marker, text2],
format: {},
},
],
});
expect(model.blocks[0]).toBe(paragraph);
expect(paragraph.segments[0]).toBe(text1);
expect(paragraph.segments[1]).toBe(marker);
expect(paragraph.segments[2]).toBe(text2);
});
});

0 comments on commit bee1d42

Please sign in to comment.