Skip to content

Commit

Permalink
Merge branch 'master' into u/xiameng/add-background-for-copilot-treat…
Browse files Browse the repository at this point in the history
…ment
  • Loading branch information
JiuqingSong authored May 22, 2024
2 parents a8a7ef6 + ecdb478 commit 4b76be2
Show file tree
Hide file tree
Showing 89 changed files with 2,841 additions and 383 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { cloneModel } from 'roosterjs-content-model-dom';
import { ContentModelPane, ContentModelPaneProps } from './ContentModelPane';
import { createRibbonPlugin, RibbonButton, RibbonPlugin } from '../../roosterjsReact/ribbon';
import { getRefreshButton } from './buttons/refreshButton';
Expand Down Expand Up @@ -70,8 +71,9 @@ export class ContentModelPanePlugin extends SidePanePluginImpl<
this.getComponent(component => {
this.editor.formatContentModel(
model => {
component.setContentModel(model);
setCurrentContentModel(model);
const clonedModel = cloneModel(model);
component.setContentModel(clonedModel);
setCurrentContentModel(clonedModel);

return false;
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import * as React from 'react';
import { ContentModelWithDataset } from 'roosterjs-content-model-types';
import { FormatRenderer } from './utils/FormatRenderer';
import {
ContentModelWithDataset,
ShallowMutableContentModelWithDataset,
} from 'roosterjs-content-model-types';

const styles = require('./FormatView.scss');

export function MetadataView<T>(props: {
model: ContentModelWithDataset<T>;
renderers: FormatRenderer<T>[];
updater: (model: ContentModelWithDataset<T>, callback: (format: T | null) => T | null) => void;
updater: (
model: ShallowMutableContentModelWithDataset<T>,
callback: (format: T | null) => T | null
) => void;
}) {
const { model, renderers, updater } = props;
const metadata = React.useRef<T>(null);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,45 @@
import type { ContentModelBlockGroup, ContentModelListItem } from 'roosterjs-content-model-types';
import type {
ContentModelBlockGroup,
ContentModelListItem,
ReadonlyContentModelBlockGroup,
ReadonlyContentModelListItem,
} from 'roosterjs-content-model-types';

/**
* Search for all list items in the same thread as the current list item
* @param model The content model
* @param currentItem The current list item
* Search for all list items in the same thread as the current list item
*/
export function findListItemsInSameThread(
group: ContentModelBlockGroup,
currentItem: ContentModelListItem
): ContentModelListItem[] {
): ContentModelListItem[];

/**
* Search for all list items in the same thread as the current list item (Readonly)
* @param model The content model
* @param currentItem The current list item
*/
export function findListItemsInSameThread(
group: ReadonlyContentModelBlockGroup,
currentItem: ReadonlyContentModelListItem
): ReadonlyContentModelListItem[];

export function findListItemsInSameThread(
group: ReadonlyContentModelBlockGroup,
currentItem: ReadonlyContentModelListItem
): ReadonlyContentModelListItem[] {
const items: (ContentModelListItem | null)[] = [];

findListItems(group, items);

return filterListItems(items, currentItem);
}

function findListItems(group: ContentModelBlockGroup, result: (ContentModelListItem | null)[]) {
function findListItems(
group: ReadonlyContentModelBlockGroup,
result: (ReadonlyContentModelListItem | null)[]
) {
group.blocks.forEach(block => {
switch (block.blockType) {
case 'BlockGroup':
Expand Down Expand Up @@ -56,7 +79,7 @@ function findListItems(group: ContentModelBlockGroup, result: (ContentModelListI
});
}

function pushNullIfNecessary(result: (ContentModelListItem | null)[]) {
function pushNullIfNecessary(result: (ReadonlyContentModelListItem | null)[]) {
const last = result[result.length - 1];

if (!last || last !== null) {
Expand All @@ -65,10 +88,10 @@ function pushNullIfNecessary(result: (ContentModelListItem | null)[]) {
}

function filterListItems(
items: (ContentModelListItem | null)[],
currentItem: ContentModelListItem
items: (ReadonlyContentModelListItem | null)[],
currentItem: ReadonlyContentModelListItem
) {
const result: ContentModelListItem[] = [];
const result: ReadonlyContentModelListItem[] = [];
const currentIndex = items.indexOf(currentItem);
const levelLength = currentItem.levels.length;
const isOrderedList = currentItem.levels[levelLength - 1]?.listType == 'OL';
Expand Down Expand Up @@ -131,7 +154,7 @@ function filterListItems(
}

function areListTypesCompatible(
listItems: (ContentModelListItem | null)[],
listItems: (ReadonlyContentModelListItem | null)[],
currentIndex: number,
compareToIndex: number
): boolean {
Expand All @@ -146,7 +169,7 @@ function areListTypesCompatible(
);
}

function hasStartNumberOverride(item: ContentModelListItem, levelLength: number): boolean {
function hasStartNumberOverride(item: ReadonlyContentModelListItem, levelLength: number): boolean {
return item.levels
.slice(0, levelLength)
.some(level => level.format.startNumberOverride !== undefined);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as domToContentModel from 'roosterjs-content-model-dom/lib/domToModel/d
import * as updateCachedSelection from '../../../lib/corePlugin/cache/updateCachedSelection';
import { createContentModel } from '../../../lib/coreApi/createContentModel/createContentModel';
import {
ContentModelDocument,
DomToModelContext,
DomToModelOptionForCreateModel,
EditorCore,
Expand Down Expand Up @@ -362,7 +363,9 @@ describe('createContentModel and cache management', () => {
},
} as any;

cloneModelSpy = spyOn(cloneModel, 'cloneModel').and.callFake(x => x);
cloneModelSpy = spyOn(cloneModel, 'cloneModel').and.callFake(
x => x as ContentModelDocument
);

spyOn(domToContentModel, 'domToContentModel').and.returnValue(mockedNewModel);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,9 @@ describe('Editor', () => {
mockedModel
);

const cloneModelSpy = spyOn(cloneModel, 'cloneModel').and.callFake(x => x);
const cloneModelSpy = spyOn(cloneModel, 'cloneModel').and.callFake(
x => x as ContentModelDocument
);

const model = editor.getContentModelCopy('clean');
expect(model).toBe(mockedModel);
Expand Down
19 changes: 14 additions & 5 deletions packages/roosterjs-content-model-dom/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export { areSameFormats } from './domToModel/utils/areSameFormats';
export { isBlockElement } from './domToModel/utils/isBlockElement';
export { buildSelectionMarker } from './domToModel/utils/buildSelectionMarker';

export { updateMetadata, hasMetadata } from './modelApi/metadata/updateMetadata';
export { updateMetadata, getMetadata, hasMetadata } from './modelApi/metadata/updateMetadata';
export { isNodeOfType } from './domUtils/isNodeOfType';
export { isElementOfType } from './domUtils/isElementOfType';
export { getObjectKeys } from './domUtils/getObjectKeys';
Expand Down Expand Up @@ -54,7 +54,9 @@ export { createEntity } from './modelApi/creators/createEntity';
export { createDivider } from './modelApi/creators/createDivider';
export { createListLevel } from './modelApi/creators/createListLevel';
export { createEmptyModel } from './modelApi/creators/createEmptyModel';
export { createTableRow } from './modelApi/creators/createTableRow';

export { mutateBlock, mutateSegments, mutateSegment } from './modelApi/common/mutate';
export { addBlock } from './modelApi/common/addBlock';
export { addCode } from './modelApi/common/addDecorators';
export { addLink } from './modelApi/common/addDecorators';
Expand Down Expand Up @@ -129,10 +131,17 @@ export { retrieveModelFormatState } from './modelApi/editing/retrieveModelFormat
export { getListStyleTypeFromString } from './modelApi/editing/getListStyleTypeFromString';
export { getSegmentTextFormat } from './modelApi/editing/getSegmentTextFormat';

export { updateImageMetadata } from './modelApi/metadata/updateImageMetadata';
export { updateTableCellMetadata } from './modelApi/metadata/updateTableCellMetadata';
export { updateTableMetadata } from './modelApi/metadata/updateTableMetadata';
export { updateListMetadata, ListMetadataDefinition } from './modelApi/metadata/updateListMetadata';
export { updateImageMetadata, getImageMetadata } from './modelApi/metadata/updateImageMetadata';
export {
updateTableCellMetadata,
getTableCellMetadata,
} from './modelApi/metadata/updateTableCellMetadata';
export { updateTableMetadata, getTableMetadata } from './modelApi/metadata/updateTableMetadata';
export {
updateListMetadata,
getListMetadata,
ListMetadataDefinition,
} from './modelApi/metadata/updateListMetadata';

export { ChangeSource } from './constants/ChangeSource';
export { BulletListType } from './constants/BulletListType';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import type { ContentModelBlock, ContentModelBlockGroup } from 'roosterjs-content-model-types';
import type {
ContentModelBlock,
ShallowMutableContentModelBlockGroup,
} from 'roosterjs-content-model-types';

/**
* Add a given block to block group
* @param group The block group to add block into
* @param block The block to add
*/
export function addBlock(group: ContentModelBlockGroup, block: ContentModelBlock) {
export function addBlock(group: ShallowMutableContentModelBlockGroup, block: ContentModelBlock) {
group.blocks.push(block);
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import type {
ContentModelCode,
ContentModelLink,
ContentModelSegment,
DomToModelDecoratorContext,
ReadonlyContentModelCode,
ReadonlyContentModelLink,
ShallowMutableContentModelSegment,
} from 'roosterjs-content-model-types';

/**
* @internal
*/
export function addLink(segment: ContentModelSegment, link: ContentModelLink) {
export function addLink(
segment: ShallowMutableContentModelSegment,
link: ReadonlyContentModelLink
) {
if (link.format.href) {
segment.link = {
format: { ...link.format },
Expand All @@ -22,7 +25,10 @@ export function addLink(segment: ContentModelSegment, link: ContentModelLink) {
* @param segment The segment to add decorator to
* @param code The code decorator to add
*/
export function addCode(segment: ContentModelSegment, code: ContentModelCode) {
export function addCode(
segment: ShallowMutableContentModelSegment,
code: ReadonlyContentModelCode
) {
if (code.format.fontFamily) {
segment.code = {
format: { ...code.format },
Expand All @@ -33,7 +39,10 @@ export function addCode(segment: ContentModelSegment, code: ContentModelCode) {
/**
* @internal
*/
export function addDecorators(segment: ContentModelSegment, context: DomToModelDecoratorContext) {
export function addDecorators(
segment: ShallowMutableContentModelSegment,
context: DomToModelDecoratorContext
) {
addLink(segment, context.link);
addCode(segment, context.code);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import type {
ContentModelParagraph,
ContentModelSegment,
ContentModelSegmentFormat,
ShallowMutableContentModelBlockGroup,
ShallowMutableContentModelParagraph,
} from 'roosterjs-content-model-types';

/**
Expand All @@ -19,7 +21,28 @@ export function addSegment(
newSegment: ContentModelSegment,
blockFormat?: ContentModelBlockFormat,
segmentFormat?: ContentModelSegmentFormat
): ContentModelParagraph {
): ContentModelParagraph;

/**
* Add a given segment into a paragraph from its parent group. If the last block of the given group is not paragraph, create a new paragraph. (Shallow mutable)
* @param group The parent block group of the paragraph to add segment into
* @param newSegment The segment to add
* @param blockFormat The block format used for creating a new paragraph when need
* @returns The parent paragraph where the segment is added to
*/
export function addSegment(
group: ShallowMutableContentModelBlockGroup,
newSegment: ContentModelSegment,
blockFormat?: ContentModelBlockFormat,
segmentFormat?: ContentModelSegmentFormat
): ShallowMutableContentModelParagraph;

export function addSegment(
group: ShallowMutableContentModelBlockGroup,
newSegment: ContentModelSegment,
blockFormat?: ContentModelBlockFormat,
segmentFormat?: ContentModelSegmentFormat
): ShallowMutableContentModelParagraph {
const paragraph = ensureParagraph(group, blockFormat, segmentFormat);
const lastSegment = paragraph.segments[paragraph.segments.length - 1];

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { addBlock } from './addBlock';
import { createParagraph } from '../creators/createParagraph';
import { mutateBlock } from './mutate';
import type {
ContentModelBlockFormat,
ContentModelBlockGroup,
ContentModelParagraph,
ContentModelSegmentFormat,
ShallowMutableContentModelBlockGroup,
ShallowMutableContentModelParagraph,
} from 'roosterjs-content-model-types';

/**
Expand All @@ -17,11 +20,29 @@ export function ensureParagraph(
group: ContentModelBlockGroup,
blockFormat?: ContentModelBlockFormat,
segmentFormat?: ContentModelSegmentFormat
): ContentModelParagraph {
): ContentModelParagraph;

/**
* @internal
* Ensure there is a Paragraph that can insert segments in a Content Model Block Group (Shallow mutable)
* @param group The parent block group of the target paragraph
* @param blockFormat Format of the paragraph. This is only used if we need to create a new paragraph
*/
export function ensureParagraph(
group: ShallowMutableContentModelBlockGroup,
blockFormat?: ContentModelBlockFormat,
segmentFormat?: ContentModelSegmentFormat
): ShallowMutableContentModelParagraph;

export function ensureParagraph(
group: ShallowMutableContentModelBlockGroup,
blockFormat?: ContentModelBlockFormat,
segmentFormat?: ContentModelSegmentFormat
): ShallowMutableContentModelParagraph {
const lastBlock = group.blocks[group.blocks.length - 1];

if (lastBlock?.blockType == 'Paragraph') {
return lastBlock;
return mutateBlock(lastBlock);
} else {
const paragraph = createParagraph(true, blockFormat, segmentFormat);
addBlock(group, paragraph);
Expand Down
Loading

0 comments on commit 4b76be2

Please sign in to comment.