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

Standalone Editor: Port EntityPlugin #2223

Merged
merged 15 commits into from
Nov 28, 2023
Merged
5 changes: 4 additions & 1 deletion demo/scripts/controls/ContentModelEditorMainPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import SidePane from './sidePane/SidePane';
import SnapshotPlugin from './sidePane/snapshot/SnapshotPlugin';
import TitleBar from './titleBar/TitleBar';
import { arrayPush } from 'roosterjs-editor-dom';
import { ContentModelEditPlugin } from 'roosterjs-content-model-plugins';
import { ContentModelEditPlugin, EntityDelimiterPlugin } from 'roosterjs-content-model-plugins';
import { ContentModelRibbonPlugin } from './ribbonButtons/contentModel/ContentModelRibbonPlugin';
import { ContentModelSegmentFormat } from 'roosterjs-content-model-types';
import { createEmojiPlugin, createPasteOptionPlugin, RibbonPlugin } from 'roosterjs-react';
Expand Down Expand Up @@ -98,6 +98,7 @@ class ContentModelEditorMainPane extends MainPaneBase<ContentModelMainPaneState>
private contentModelRibbonPlugin: RibbonPlugin;
private pasteOptionPlugin: EditorPlugin;
private emojiPlugin: EditorPlugin;
private entityDelimiterPlugin: EntityDelimiterPlugin;
private toggleablePlugins: EditorPlugin[] | null = null;
private formatPainterPlugin: ContentModelFormatPainterPlugin;
private sampleEntityPlugin: SampleEntityPlugin;
Expand All @@ -115,6 +116,7 @@ class ContentModelEditorMainPane extends MainPaneBase<ContentModelMainPaneState>
this.contentModelRibbonPlugin = new ContentModelRibbonPlugin();
this.pasteOptionPlugin = createPasteOptionPlugin();
this.emojiPlugin = createEmojiPlugin();
this.entityDelimiterPlugin = new EntityDelimiterPlugin();
this.formatPainterPlugin = new ContentModelFormatPainterPlugin();
this.sampleEntityPlugin = new SampleEntityPlugin();
this.state = {
Expand Down Expand Up @@ -177,6 +179,7 @@ class ContentModelEditorMainPane extends MainPaneBase<ContentModelMainPaneState>
this.contentModelEditPlugin,
this.pasteOptionPlugin,
this.emojiPlugin,
this.entityDelimiterPlugin,
this.formatPainterPlugin,
this.sampleEntityPlugin,
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ describe('insertLink', () => {
},
contentModel: jasmine.anything(),
selection: jasmine.anything(),
changedEntities: [],
});

document.body.removeChild(div);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { ChangeSource } from '../constants/ChangeSource';
import { ColorTransformDirection, EntityOperation, PluginEventType } from 'roosterjs-editor-types';
import type { Entity } from 'roosterjs-editor-types';
import { PluginEventType } from 'roosterjs-editor-types';
import type {
ChangedEntity,
ContentModelContentChangedEvent,
DOMSelection,
EntityRemovalOperation,
FormatContentModel,
FormatWithContentModelContext,
StandaloneEditorCore,
Expand Down Expand Up @@ -35,8 +34,6 @@ export const formatContentModel: FormatContentModel = (core, formatter, options)

if (formatter(model, context)) {
const writeBack = () => {
handleNewEntities(core, context);
handleDeletedEntities(core, context);
handleImages(core, context);

selection =
Expand Down Expand Up @@ -69,6 +66,21 @@ export const formatContentModel: FormatContentModel = (core, formatter, options)
additionalData: {
formatApiName: apiName,
},
changedEntities: context.newEntities
.map(
(entity): ChangedEntity => ({
entity,
operation: 'newEntity',
rawEvent,
})
)
.concat(
context.deletedEntities.map(entry => ({
entity: entry.entity,
operation: entry.operation,
rawEvent,
}))
),
};
core.api.triggerEvent(core, eventData, true /*broadcast*/);
} else {
Expand All @@ -81,64 +93,6 @@ export const formatContentModel: FormatContentModel = (core, formatter, options)
}
};

function handleNewEntities(core: StandaloneEditorCore, context: FormatWithContentModelContext) {
// TODO: Ideally we can trigger NewEntity event here. But to be compatible with original editor code, we don't do it here for now.
// Once Content Model Editor can be standalone, we can change this behavior to move triggering NewEntity event code
// from EntityPlugin to here

if (core.lifecycle.isDarkMode) {
context.newEntities.forEach(entity => {
core.api.transformColor(
core,
entity.wrapper,
true /*includeSelf*/,
null /*callback*/,
ColorTransformDirection.LightToDark
);
});
}
}

// This is only used for compatibility with old editor
// TODO: Remove this map once we have standalone editor
const EntityOperationMap: Record<EntityRemovalOperation, EntityOperation> = {
overwrite: EntityOperation.Overwrite,
removeFromEnd: EntityOperation.RemoveFromEnd,
removeFromStart: EntityOperation.RemoveFromStart,
};

function handleDeletedEntities(core: StandaloneEditorCore, context: FormatWithContentModelContext) {
context.deletedEntities.forEach(
({
entity: {
wrapper,
entityFormat: { id, entityType, isReadonly },
},
operation,
}) => {
if (id && entityType) {
// TODO: Revisit this entity parameter for standalone editor, we may just directly pass ContentModelEntity object instead
const entity: Entity = {
id,
type: entityType,
isReadonly: !!isReadonly,
wrapper,
};
core.api.triggerEvent(
core,
{
eventType: PluginEventType.EntityOperation,
entity,
operation: EntityOperationMap[operation],
rawEvent: context.rawEvent,
},
false /*broadcast*/
);
}
}
);
}

function handleImages(core: StandaloneEditorCore, context: FormatWithContentModelContext) {
if (context.newImages.length > 0) {
const viewport = core.api.getVisibleViewport(core);
Expand Down
Loading
Loading