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

Content Model Cache improvement - Step 4: Port "readonly" functions #2643

Merged
merged 49 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
7cc5a1b
Readonly types (3rd try
JiuqingSong May 13, 2024
3ff0779
Improve
JiuqingSong May 14, 2024
950a4ae
fix build
JiuqingSong May 14, 2024
2574fe2
Improve
JiuqingSong May 14, 2024
0180d29
Merge branch 'master' into u/jisong/readonlytype0513
JiuqingSong May 14, 2024
47b21f3
improve
JiuqingSong May 14, 2024
bd6b0cb
Improve
JiuqingSong May 14, 2024
cf3ea78
Add shallow mutable type
JiuqingSong May 14, 2024
e14e506
improve
JiuqingSong May 14, 2024
9a2d449
Improve
JiuqingSong May 14, 2024
719f5ed
improve
JiuqingSong May 14, 2024
caf7ef1
improve
JiuqingSong May 15, 2024
29495db
Merge branch 'master' into u/jisong/readonlytype0513
JiuqingSong May 16, 2024
0230a26
add test
JiuqingSong May 16, 2024
46fbe45
Readonly types step 2
JiuqingSong May 16, 2024
5f9b88b
Readonly types step 3
JiuqingSong May 16, 2024
4fa3138
Merge branch 'u/jisong/readonlytypes_step_2' into u/jisong/readonlyty…
JiuqingSong May 16, 2024
ce2e31a
Readonly type step 4
JiuqingSong May 16, 2024
2afcf38
add test
JiuqingSong May 16, 2024
b2a3f6c
Merge branch 'u/jisong/readonlytypes_step_2' into u/jisong/readonlyty…
JiuqingSong May 16, 2024
adb26a0
Improve
JiuqingSong May 16, 2024
b77e4b0
Merge branch 'u/jisong/readonlytypes_step_2' into u/jisong/readonlyty…
JiuqingSong May 16, 2024
85b50f2
improve
JiuqingSong May 17, 2024
e91e1a8
Merge branch 'master' into u/jisong/readonlytype0513
JiuqingSong May 17, 2024
6dbd78b
improve
JiuqingSong May 17, 2024
d0ee665
Merge branch 'u/jisong/readonlytype0513' into u/jisong/readonlytypes_…
JiuqingSong May 17, 2024
6d7d041
Merge branch 'u/jisong/readonlytype0513' into u/jisong/readonlytypes_…
JiuqingSong May 17, 2024
6c35a70
Merge branch 'u/jisong/readonlytypes_step_2' into u/jisong/readonlyty…
JiuqingSong May 17, 2024
1e157b1
Merge branch 'u/jisong/readonlytypes_step_3' into u/jisong/readonlyty…
JiuqingSong May 17, 2024
f659ca9
Merge branch 'master' into u/jisong/readonlytypes_step_2
JiuqingSong May 19, 2024
acceb1d
improve
JiuqingSong May 19, 2024
d5b159d
Merge branch 'u/jisong/readonlytypes_step_2' into u/jisong/readonlyty…
JiuqingSong May 19, 2024
a69738f
Merge branch 'master' into u/jisong/readonlytype0513
JiuqingSong May 20, 2024
b4ab134
improve
JiuqingSong May 20, 2024
dea9f7f
Merge branch 'u/jisong/readonlytype0513' into u/jisong/readonlytypes_…
JiuqingSong May 20, 2024
6d9fe1e
Merge branch 'u/jisong/readonlytype0513' into u/jisong/readonlytypes_…
JiuqingSong May 20, 2024
124559c
Merge branch 'u/jisong/readonlytypes_step_2' into u/jisong/readonlyty…
JiuqingSong May 20, 2024
df68a71
Merge branch 'u/jisong/readonlytypes_step_3' into u/jisong/readonlyty…
JiuqingSong May 20, 2024
f745036
Merge branch 'master' into u/jisong/readonlytypes_step_2
JiuqingSong May 20, 2024
806a1d3
Improve
JiuqingSong May 20, 2024
fa84daa
Merge branch 'master' into u/jisong/readonlytypes_step_3
JiuqingSong May 20, 2024
de8ca0d
improve
JiuqingSong May 20, 2024
149b315
Merge branch 'u/jisong/readonlytypes_step_2' into u/jisong/readonlyty…
JiuqingSong May 20, 2024
1de55bb
Merge branch 'u/jisong/readonlytypes_step_3' into u/jisong/readonlyty…
JiuqingSong May 20, 2024
7a6b43f
fix test
JiuqingSong May 20, 2024
bd9661d
Merge branch 'u/jisong/readonlytypes_step_2' into u/jisong/readonlyty…
JiuqingSong May 20, 2024
5e72761
improve
JiuqingSong May 20, 2024
3f36928
Merge branch 'u/jisong/readonlytypes_step_2' into u/jisong/readonlyty…
JiuqingSong May 20, 2024
19286c5
Merge branch 'master' into u/jisong/readonlytypes_step_4
JiuqingSong May 22, 2024
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
Expand Up @@ -3,9 +3,9 @@ import { ApiPaneProps } from '../ApiPaneProps';
import { insertEntity } from 'roosterjs-content-model-api';
import { trustedHTMLHandler } from '../../../../utils/trustedHTMLHandler';
import {
ContentModelBlockGroup,
ContentModelEntity,
InsertEntityOptions,
ReadonlyContentModelBlockGroup,
} from 'roosterjs-content-model-types';

const styles = require('./InsertEntityPane.scss');
Expand Down Expand Up @@ -155,7 +155,7 @@ export default class InsertEntityPane extends React.Component<ApiPaneProps, Inse
};
}

function findAllEntities(group: ContentModelBlockGroup, result: ContentModelEntity[]) {
function findAllEntities(group: ReadonlyContentModelBlockGroup, result: ContentModelEntity[]) {
group.blocks.forEach(block => {
switch (block.blockType) {
case 'BlockGroup':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@ import { findListItemsInSameThread } from './findListItemsInSameThread';
import {
getAutoListStyleType,
getClosestAncestorBlockGroupIndex,
getListMetadata,
getOrderedListNumberStr,
updateListMetadata,
} from 'roosterjs-content-model-dom';
import type {
AnnounceData,
ContentModelBlockGroup,
ContentModelListItem,
ReadonlyContentModelBlockGroup,
ReadonlyContentModelListItem,
} from 'roosterjs-content-model-types';

/**
* Get announce data for list item
* @param path Content model path that include the list item
* @returns Announce data of current list item if any, or null
*/
export function getListAnnounceData(path: ContentModelBlockGroup[]): AnnounceData | null {
export function getListAnnounceData(path: ReadonlyContentModelBlockGroup[]): AnnounceData | null {
const index = getClosestAncestorBlockGroupIndex(path, ['ListItem'], ['TableCell']);

if (index >= 0) {
Expand All @@ -27,7 +28,7 @@ export function getListAnnounceData(path: ContentModelBlockGroup[]): AnnounceDat
return null;
} else if (level.listType == 'OL') {
const listNumber = getListNumber(path, listItem);
const metadata = updateListMetadata(level);
const metadata = getListMetadata(level);
const listStyle = getAutoListStyleType(
'OL',
metadata ?? {},
Expand All @@ -51,7 +52,10 @@ export function getListAnnounceData(path: ContentModelBlockGroup[]): AnnounceDat
}
}

function getListNumber(path: ContentModelBlockGroup[], listItem: ContentModelListItem) {
function getListNumber(
path: ReadonlyContentModelBlockGroup[],
listItem: ReadonlyContentModelListItem
) {
const items = findListItemsInSameThread(path[path.length - 1], listItem);
let listNumber = 0;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { ContentModelTableRow } from 'roosterjs-content-model-types';
import type { ReadonlyContentModelTableRow } from 'roosterjs-content-model-types';

/**
* @internal
*/
export function canMergeCells(
rows: ContentModelTableRow[],
rows: ReadonlyContentModelTableRow[],
firstRow: number,
firstCol: number,
lastRow: number,
Expand Down Expand Up @@ -40,7 +40,11 @@ export function canMergeCells(
return noSpanAbove && noSpanLeft && noDifferentBelowSpan && noDifferentRightSpan;
}

function getBelowSpanCount(rows: ContentModelTableRow[], rowIndex: number, colIndex: number) {
function getBelowSpanCount(
rows: ReadonlyContentModelTableRow[],
rowIndex: number,
colIndex: number
) {
let spanCount = 0;

for (let row = rowIndex + 1; row < rows.length; row++) {
Expand All @@ -54,7 +58,11 @@ function getBelowSpanCount(rows: ContentModelTableRow[], rowIndex: number, colIn
return spanCount;
}

function getRightSpanCount(rows: ContentModelTableRow[], rowIndex: number, colIndex: number) {
function getRightSpanCount(
rows: ReadonlyContentModelTableRow[],
rowIndex: number,
colIndex: number
) {
let spanCount = 0;

for (let col = colIndex + 1; col < rows[rowIndex]?.cells.length; col++) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { formatImageWithContentModel } from '../utils/formatImageWithContentModel';
import { readFile, updateImageMetadata } from 'roosterjs-content-model-dom';
import { getImageMetadata, readFile } from 'roosterjs-content-model-dom';
import type { ContentModelImage, IEditor } from 'roosterjs-content-model-types';

/**
Expand All @@ -14,7 +14,7 @@ export function changeImage(editor: IEditor, file: File) {
readFile(file, dataUrl => {
if (dataUrl && !editor.isDisposed() && selection?.type === 'image') {
formatImageWithContentModel(editor, 'changeImage', (image: ContentModelImage) => {
const originalSrc = updateImageMetadata(image)?.src ?? '';
const originalSrc = getImageMetadata(image)?.src ?? '';
const previousSrc = image.src;

image.src = dataUrl;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type {
ContentModelSegmentFormat,
IEditor,
MergeModelOption,
ReadonlyContentModelDocument,
} from 'roosterjs-content-model-types';

const EmptySegmentFormat: Required<ContentModelSegmentFormat> = {
Expand All @@ -38,7 +39,7 @@ const CloneOption: CloneModelOptions = {
/**
* @internal
*/
export function cloneModelForPaste(model: ContentModelDocument) {
export function cloneModelForPaste(model: ReadonlyContentModelDocument) {
return cloneModel(model, CloneOption);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { ChangedEntity, ContentModelBlockGroup } from 'roosterjs-content-model-types';
import type { ChangedEntity, ReadonlyContentModelBlockGroup } from 'roosterjs-content-model-types';

/**
* @internal
*/
export function findAllEntities(group: ContentModelBlockGroup, entities: ChangedEntity[]) {
export function findAllEntities(group: ReadonlyContentModelBlockGroup, entities: ChangedEntity[]) {
group.blocks.forEach(block => {
switch (block.blockType) {
case 'BlockGroup':
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type {
ContentModelBlock,
ShallowMutableContentModelBlock,
ShallowMutableContentModelBlockGroup,
} from 'roosterjs-content-model-types';

Expand All @@ -8,6 +8,9 @@ import type {
* @param group The block group to add block into
* @param block The block to add
*/
export function addBlock(group: ShallowMutableContentModelBlockGroup, block: ContentModelBlock) {
export function addBlock(
group: ShallowMutableContentModelBlockGroup,
block: ShallowMutableContentModelBlock
) {
group.blocks.push(block);
}
32 changes: 16 additions & 16 deletions packages/roosterjs-content-model-dom/lib/modelApi/common/isEmpty.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import type {
ContentModelBlock,
ContentModelBlockGroup,
ContentModelSegment,
ReadonlyContentModelBlock,
ReadonlyContentModelBlockGroup,
ReadonlyContentModelSegment,
} from 'roosterjs-content-model-types';

/**
* @internal
*/
export function isBlockEmpty(block: ContentModelBlock): boolean {
export function isBlockEmpty(block: ReadonlyContentModelBlock): boolean {
switch (block.blockType) {
case 'Paragraph':
return block.segments.length == 0;
Expand All @@ -29,7 +29,7 @@ export function isBlockEmpty(block: ContentModelBlock): boolean {
/**
* @internal
*/
export function isBlockGroupEmpty(group: ContentModelBlockGroup): boolean {
export function isBlockGroupEmpty(group: ReadonlyContentModelBlockGroup): boolean {
switch (group.blockGroupType) {
case 'FormatContainer':
// Format Container of DIV is a container for style, so we always treat it as not empty
Expand All @@ -51,7 +51,7 @@ export function isBlockGroupEmpty(group: ContentModelBlockGroup): boolean {
/**
* @internal
*/
export function isSegmentEmpty(segment: ContentModelSegment): boolean {
export function isSegmentEmpty(segment: ReadonlyContentModelSegment): boolean {
switch (segment.segmentType) {
case 'Text':
return !segment.text;
Expand All @@ -69,7 +69,7 @@ export function isSegmentEmpty(segment: ContentModelSegment): boolean {
* @returns true if the model is empty.
*/
export function isEmpty(
model: ContentModelBlock | ContentModelBlockGroup | ContentModelSegment
model: ReadonlyContentModelBlock | ReadonlyContentModelBlockGroup | ReadonlyContentModelSegment
): boolean {
if (isBlockGroup(model)) {
return isBlockGroupEmpty(model);
Expand All @@ -83,19 +83,19 @@ export function isEmpty(
}

function isSegment(
model: ContentModelBlock | ContentModelBlockGroup | ContentModelSegment
): model is ContentModelSegment {
return typeof (<ContentModelSegment>model).segmentType === 'string';
model: ReadonlyContentModelBlock | ReadonlyContentModelBlockGroup | ReadonlyContentModelSegment
): model is ReadonlyContentModelSegment {
return typeof (<ReadonlyContentModelSegment>model).segmentType === 'string';
}

function isBlock(
model: ContentModelBlock | ContentModelBlockGroup | ContentModelSegment
): model is ContentModelBlock {
return typeof (<ContentModelBlock>model).blockType === 'string';
model: ReadonlyContentModelBlock | ReadonlyContentModelBlockGroup | ReadonlyContentModelSegment
): model is ReadonlyContentModelBlock {
return typeof (<ReadonlyContentModelBlock>model).blockType === 'string';
}

function isBlockGroup(
model: ContentModelBlock | ContentModelBlockGroup | ContentModelSegment
): model is ContentModelBlockGroup {
return typeof (<ContentModelBlockGroup>model).blockGroupType === 'string';
model: ReadonlyContentModelBlock | ReadonlyContentModelBlockGroup | ReadonlyContentModelSegment
): model is ReadonlyContentModelBlockGroup {
return typeof (<ReadonlyContentModelBlockGroup>model).blockGroupType === 'string';
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import type { ContentModelSegment, ContentModelSegmentFormat } from 'roosterjs-content-model-types';
import type {
ContentModelSegmentFormat,
ReadonlyContentModelSegment,
} from 'roosterjs-content-model-types';

/**
* Get the text format of a segment, this function will return only format that is applicable to text
* @param segment The segment to get format from
* @returns
*/
export function getSegmentTextFormat(segment: ContentModelSegment): ContentModelSegmentFormat {
export function getSegmentTextFormat(
segment: ReadonlyContentModelSegment
): ContentModelSegmentFormat {
const { fontFamily, fontSize, textColor, backgroundColor, letterSpacing, lineHeight } =
segment?.format ?? {};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { extractBorderValues } from '../../domUtils/style/borderValues';
import { getClosestAncestorBlockGroupIndex } from './getClosestAncestorBlockGroupIndex';
import { getTableMetadata } from '../metadata/updateTableMetadata';
import { isBold } from '../../domUtils/style/isBold';
import { iterateSelections } from '../selection/iterateSelections';
import { parseValueWithUnit } from '../../formatHandlers/utils/parseValueWithUnit';
import { updateTableMetadata } from '../metadata/updateTableMetadata';
import type {
ContentModelFormatState,
ContentModelBlock,
ContentModelBlockGroup,
ContentModelDocument,
ContentModelFormatContainer,
ContentModelImage,
ContentModelListItem,
ContentModelParagraph,
ContentModelSegmentFormat,
TableSelectionContext,
ReadonlyContentModelBlockGroup,
ReadonlyContentModelBlock,
ReadonlyContentModelImage,
ReadonlyTableSelectionContext,
ReadonlyContentModelParagraph,
ReadonlyContentModelFormatContainer,
ReadonlyContentModelListItem,
ReadonlyContentModelDocument,
} from 'roosterjs-content-model-types';

/**
Expand All @@ -24,12 +24,12 @@ import type {
* @param formatState Existing format state object, used for receiving the result
*/
export function retrieveModelFormatState(
model: ContentModelDocument,
model: ReadonlyContentModelDocument,
pendingFormat: ContentModelSegmentFormat | null,
formatState: ContentModelFormatState
) {
let firstTableContext: TableSelectionContext | undefined;
let firstBlock: ContentModelBlock | undefined;
let firstTableContext: ReadonlyTableSelectionContext | undefined;
let firstBlock: ReadonlyContentModelBlock | undefined;
let isFirst = true;
let isFirstImage = true;
let isFirstSegment = true;
Expand All @@ -56,10 +56,11 @@ export function retrieveModelFormatState(
// Segment formats
segments?.forEach(segment => {
if (isFirstSegment || segment.segmentType != 'SelectionMarker') {
const modelFormat = Object.assign({}, model.format);
delete modelFormat?.italic;
delete modelFormat?.underline;
delete modelFormat?.fontWeight;
const modelFormat = { ...model.format };

delete modelFormat.italic;
delete modelFormat.underline;
delete modelFormat.fontWeight;

retrieveSegmentFormat(
formatState,
Expand Down Expand Up @@ -165,7 +166,7 @@ function retrieveSegmentFormat(

function retrieveParagraphFormat(
result: ContentModelFormatState,
paragraph: ContentModelParagraph,
paragraph: ReadonlyContentModelParagraph,
isFirst: boolean
) {
const headingLevel = parseInt((paragraph.decorator?.tagName || '').substring(1));
Expand All @@ -180,14 +181,14 @@ function retrieveParagraphFormat(

function retrieveStructureFormat(
result: ContentModelFormatState,
path: ContentModelBlockGroup[],
path: ReadonlyContentModelBlockGroup[],
isFirst: boolean
) {
const listItemIndex = getClosestAncestorBlockGroupIndex(path, ['ListItem'], []);
const containerIndex = getClosestAncestorBlockGroupIndex(path, ['FormatContainer'], []);

if (listItemIndex >= 0) {
const listItem = path[listItemIndex] as ContentModelListItem;
const listItem = path[listItemIndex] as ReadonlyContentModelListItem;
const listType = listItem?.levels[listItem.levels.length - 1]?.listType;

mergeValue(result, 'isBullet', listType == 'UL', isFirst);
Expand All @@ -198,13 +199,16 @@ function retrieveStructureFormat(
result,
'isBlockQuote',
containerIndex >= 0 &&
(path[containerIndex] as ContentModelFormatContainer)?.tagName == 'blockquote',
(path[containerIndex] as ReadonlyContentModelFormatContainer)?.tagName == 'blockquote',
isFirst
);
}

function retrieveTableFormat(tableContext: TableSelectionContext, result: ContentModelFormatState) {
const tableFormat = updateTableMetadata(tableContext.table);
function retrieveTableFormat(
tableContext: ReadonlyTableSelectionContext,
result: ContentModelFormatState
) {
const tableFormat = getTableMetadata(tableContext.table);

result.isInTable = true;
result.tableHasHeader = tableContext.table.rows.some(row =>
Expand All @@ -216,7 +220,7 @@ function retrieveTableFormat(tableContext: TableSelectionContext, result: Conten
}
}

function retrieveImageFormat(image: ContentModelImage, result: ContentModelFormatState) {
function retrieveImageFormat(image: ReadonlyContentModelImage, result: ContentModelFormatState) {
const { format } = image;
const borderKey = 'borderTop';
const extractedBorder = extractBorderValues(format[borderKey]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { hasSelectionInBlockGroup } from '../selection/hasSelectionInBlockGroup';
import type { ContentModelTable, TableSelectionCoordinates } from 'roosterjs-content-model-types';
import type {
ReadonlyContentModelTable,
TableSelectionCoordinates,
} from 'roosterjs-content-model-types';

/**
* Get selection coordinates of a table. If there is no selection, return null
* @param table The table model to get selection from
*/
export function getSelectedCells(table: ContentModelTable): TableSelectionCoordinates | null {
export function getSelectedCells(
table: ReadonlyContentModelTable
): TableSelectionCoordinates | null {
let firstRow = -1;
let firstColumn = -1;
let lastRow = -1;
Expand Down
Loading
Loading