Skip to content

Commit

Permalink
Port ContentModelEditPlugin to use IStandaloneEditor (#2342)
Browse files Browse the repository at this point in the history
* Port ContentModelEditPlugin to use IStandaloneEditor

* improve
  • Loading branch information
JiuqingSong authored Jan 19, 2024
1 parent 7f27c64 commit 8dc9968
Show file tree
Hide file tree
Showing 18 changed files with 95 additions and 138 deletions.
2 changes: 1 addition & 1 deletion demo/scripts/controls/ContentModelEditorMainPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,6 @@ class ContentModelEditorMainPane extends MainPaneBase<ContentModelMainPaneState>
const plugins = [
...this.toggleablePlugins,
this.contentModelPanePlugin.getInnerRibbonPlugin(),
this.contentModelEditPlugin,
this.pasteOptionPlugin,
this.emojiPlugin,
this.entityDelimiterPlugin,
Expand Down Expand Up @@ -255,6 +254,7 @@ class ContentModelEditorMainPane extends MainPaneBase<ContentModelMainPaneState>
this.contentModelRibbonPlugin,
this.formatPainterPlugin,
this.pastePlugin,
this.contentModelEditPlugin,
]}
defaultSegmentFormat={defaultFormat}
inDarkMode={this.state.isDarkMode}
Expand Down
49 changes: 7 additions & 42 deletions demo/scripts/controls/StandaloneEditorMainPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,15 @@ import ContentModelPanePlugin from './sidePane/contentModel/ContentModelPanePlug
import ContentModelRibbon from './ribbonButtons/contentModel/ContentModelRibbon';
import ContentModelRooster from './contentModel/editor/ContentModelRooster';
import ContentModelSnapshotPlugin from './sidePane/snapshot/ContentModelSnapshotPlugin';
import getToggleablePlugins from './getToggleablePlugins';
import MainPaneBase, { MainPaneBaseState } from './MainPaneBase';
import RibbonPlugin from './ribbonButtons/contentModel/RibbonPlugin';
import SampleEntityPlugin from './sampleEntity/SampleEntityPlugin';
import SidePane from './sidePane/SidePane';
import TitleBar from './titleBar/TitleBar';
import { arrayPush } from 'roosterjs-editor-dom';
import { ContentModelEditPlugin, EntityDelimiterPlugin } from 'roosterjs-content-model-plugins';
import { ContentModelEditPlugin } from 'roosterjs-content-model-plugins';
import { ContentModelRibbonPlugin } from './ribbonButtons/contentModel/ContentModelRibbonPlugin';
import { createEmojiPlugin, createPasteOptionPlugin } from 'roosterjs-react';
import { EditorPlugin, Snapshots } from 'roosterjs-editor-types';
import { getDarkColor } from 'roosterjs-color-utils';
import { PartialTheme } from '@fluentui/react/lib/Theme';
import { Snapshots } from 'roosterjs-editor-types';
import { StandaloneEditor } from 'roosterjs-content-model-core';
import { trustedHTMLHandler } from '../utils/trustedHTMLHandler';
import {
Expand Down Expand Up @@ -99,13 +95,8 @@ class ContentModelEditorMainPane extends MainPaneBase<ContentModelMainPaneState>
private contentModelPanePlugin: ContentModelPanePlugin;
private contentModelEditPlugin: ContentModelEditPlugin;
private contentModelRibbonPlugin: RibbonPlugin;
private pasteOptionPlugin: EditorPlugin;
private emojiPlugin: EditorPlugin;
private snapshotPlugin: ContentModelSnapshotPlugin;
private entityDelimiterPlugin: EntityDelimiterPlugin;
private toggleablePlugins: EditorPlugin[] | null = null;
private formatPainterPlugin: ContentModelFormatPainterPlugin;
private sampleEntityPlugin: SampleEntityPlugin;
private snapshots: Snapshots<Snapshot>;

constructor(props: {}) {
Expand All @@ -127,11 +118,7 @@ class ContentModelEditorMainPane extends MainPaneBase<ContentModelMainPaneState>
this.contentModelPanePlugin = new ContentModelPanePlugin();
this.contentModelEditPlugin = new ContentModelEditPlugin();
this.contentModelRibbonPlugin = new ContentModelRibbonPlugin();
this.pasteOptionPlugin = createPasteOptionPlugin();
this.emojiPlugin = createEmojiPlugin();
this.entityDelimiterPlugin = new EntityDelimiterPlugin();
this.formatPainterPlugin = new ContentModelFormatPainterPlugin();
this.sampleEntityPlugin = new SampleEntityPlugin();
this.state = {
showSidePane: window.location.hash != '',
popoutWindow: null,
Expand Down Expand Up @@ -181,31 +168,7 @@ class ContentModelEditorMainPane extends MainPaneBase<ContentModelMainPaneState>
);
}

getPlugins() {
this.toggleablePlugins =
this.toggleablePlugins || getToggleablePlugins(this.state.initState);

const plugins = [
...this.toggleablePlugins,
this.contentModelPanePlugin.getInnerRibbonPlugin(),
this.contentModelEditPlugin,
this.pasteOptionPlugin,
this.emojiPlugin,
this.entityDelimiterPlugin,
this.sampleEntityPlugin,
];

if (this.state.showSidePane || this.state.popoutWindow) {
arrayPush(plugins, this.getSidePanePlugins());
}

plugins.push(this.updateContentPlugin);

return plugins;
}

resetEditor() {
this.toggleablePlugins = null;
this.setState({
editorCreator: (div: HTMLDivElement, options: StandaloneEditorOptions) =>
new StandaloneEditor(div, {
Expand All @@ -217,7 +180,6 @@ class ContentModelEditorMainPane extends MainPaneBase<ContentModelMainPaneState>

renderEditor() {
const styles = this.getStyles();
const allPlugins = this.getPlugins();
const editorStyles = {
transform: `scale(${this.state.scale})`,
transformOrigin: this.state.isRtl ? 'right top' : 'left top',
Expand Down Expand Up @@ -245,8 +207,11 @@ class ContentModelEditorMainPane extends MainPaneBase<ContentModelMainPaneState>
<ContentModelRooster
id={MainPaneBase.editorDivId}
className={styles.editor}
legacyPlugins={allPlugins}
plugins={[this.contentModelRibbonPlugin, this.formatPainterPlugin]}
plugins={[
this.contentModelRibbonPlugin,
this.formatPainterPlugin,
this.contentModelEditPlugin,
]}
defaultSegmentFormat={defaultFormat}
inDarkMode={this.state.isDarkMode}
getDarkColor={getDarkColor}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { keyboardDelete } from './keyboardDelete';
import { keyboardInput } from './keyboardInput';
import { PluginEventType } from 'roosterjs-editor-types';
import type { IContentModelEditor } from 'roosterjs-content-model-editor';
import type {
EditorPlugin,
IEditor,
IStandaloneEditor,
KeyDownEvent,
PluginEvent,
PluginKeyDownEvent,
} from 'roosterjs-editor-types';
} from 'roosterjs-content-model-types';

/**
* ContentModel edit plugins helps editor to do editing operation on top of content model.
Expand All @@ -16,7 +14,7 @@ import type {
* 2. Backspace Key
*/
export class ContentModelEditPlugin implements EditorPlugin {
private editor: IContentModelEditor | null = null;
private editor: IStandaloneEditor | null = null;

/**
* Get name of this plugin
Expand All @@ -31,9 +29,9 @@ export class ContentModelEditPlugin implements EditorPlugin {
* editor reference so that it can call to any editor method or format API later.
* @param editor The editor object
*/
initialize(editor: IEditor) {
initialize(editor: IStandaloneEditor) {
// TODO: Later we may need a different interface for Content Model editor plugin
this.editor = editor as IContentModelEditor;
this.editor = editor;
}

/**
Expand All @@ -54,18 +52,17 @@ export class ContentModelEditPlugin implements EditorPlugin {
onPluginEvent(event: PluginEvent) {
if (this.editor) {
switch (event.eventType) {
case PluginEventType.KeyDown:
case 'keyDown':
this.handleKeyDownEvent(this.editor, event);
break;
}
}
}

private handleKeyDownEvent(editor: IContentModelEditor, event: PluginKeyDownEvent) {
private handleKeyDownEvent(editor: IStandaloneEditor, event: KeyDownEvent) {
const rawEvent = event.rawEvent;

if (!rawEvent.defaultPrevented && !event.handledByEditFeature) {
// TODO: Consider use ContentEditFeature and need to hide other conflict features that are not based on Content Model
switch (rawEvent.key) {
case 'Backspace':
case 'Delete':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,19 @@ import {
backwardDeleteCollapsedSelection,
forwardDeleteCollapsedSelection,
} from './deleteSteps/deleteCollapsedSelection';
import type { IContentModelEditor } from 'roosterjs-content-model-editor';
import type { DOMSelection, DeleteSelectionStep } from 'roosterjs-content-model-types';
import type {
DOMSelection,
DeleteSelectionStep,
IStandaloneEditor,
} from 'roosterjs-content-model-types';

/**
* @internal
* Do keyboard event handling for DELETE/BACKSPACE key
* @param editor The Content Model Editor
* @param rawEvent DOM keyboard event
*/
export function keyboardDelete(editor: IContentModelEditor, rawEvent: KeyboardEvent) {
export function keyboardDelete(editor: IStandaloneEditor, rawEvent: KeyboardEvent) {
const selection = editor.getDOMSelection();

if (shouldDeleteWithContentModel(selection, rawEvent)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { deleteSelection, isModifierKey } from 'roosterjs-content-model-core';
import { normalizeContentModel } from 'roosterjs-content-model-dom';
import type { IContentModelEditor } from 'roosterjs-content-model-editor';
import type { DOMSelection } from 'roosterjs-content-model-types';
import type { DOMSelection, IStandaloneEditor } from 'roosterjs-content-model-types';

/**
* @internal
*/
export function keyboardInput(editor: IContentModelEditor, rawEvent: KeyboardEvent) {
export function keyboardInput(editor: IStandaloneEditor, rawEvent: KeyboardEvent) {
const selection = editor.getDOMSelection();

if (shouldInputWithContentModel(selection, rawEvent, editor.isInIME())) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import * as keyboardDelete from '../../lib/edit/keyboardDelete';
import * as keyboardInput from '../../lib/edit/keyboardInput';
import { ContentModelEditPlugin } from '../../lib/edit/ContentModelEditPlugin';
import { EntityOperation, PluginEventType } from 'roosterjs-editor-types';
import { IContentModelEditor } from 'roosterjs-content-model-editor';
import { IStandaloneEditor } from 'roosterjs-content-model-types';

describe('ContentModelEditPlugin', () => {
let editor: IContentModelEditor;
let editor: IStandaloneEditor;

beforeEach(() => {
editor = ({
getDOMSelection: () =>
({
type: -1,
} as any), // Force return invalid range to go through content model code
} as any) as IContentModelEditor;
} as any) as IStandaloneEditor;
});

describe('onPluginEvent', () => {
Expand All @@ -32,7 +31,7 @@ describe('ContentModelEditPlugin', () => {
plugin.initialize(editor);

plugin.onPluginEvent({
eventType: PluginEventType.KeyDown,
eventType: 'keyDown',
rawEvent,
});

Expand All @@ -47,7 +46,7 @@ describe('ContentModelEditPlugin', () => {
plugin.initialize(editor);

plugin.onPluginEvent({
eventType: PluginEventType.KeyDown,
eventType: 'keyDown',
rawEvent,
});

Expand All @@ -60,12 +59,12 @@ describe('ContentModelEditPlugin', () => {
const rawEvent = { which: 41, key: 'A' } as any;
const addUndoSnapshotSpy = jasmine.createSpy('addUndoSnapshot');

editor.addUndoSnapshot = addUndoSnapshotSpy;
editor.takeSnapshot = addUndoSnapshotSpy;

plugin.initialize(editor);

plugin.onPluginEvent({
eventType: PluginEventType.KeyDown,
eventType: 'keyDown',
rawEvent,
});

Expand All @@ -79,7 +78,7 @@ describe('ContentModelEditPlugin', () => {

plugin.initialize(editor);
plugin.onPluginEvent({
eventType: PluginEventType.KeyDown,
eventType: 'keyDown',
rawEvent,
});

Expand All @@ -94,16 +93,16 @@ describe('ContentModelEditPlugin', () => {
plugin.initialize(editor);

plugin.onPluginEvent({
eventType: PluginEventType.EntityOperation,
operation: EntityOperation.Overwrite,
eventType: 'entityOperation',
operation: 'overwrite',
rawEvent: {
type: 'keydown',
} as any,
entity: wrapper,
});

plugin.onPluginEvent({
eventType: PluginEventType.KeyDown,
eventType: 'keyDown',
rawEvent: { key: 'Delete' } as any,
});

Expand All @@ -112,7 +111,7 @@ describe('ContentModelEditPlugin', () => {
} as any);

plugin.onPluginEvent({
eventType: PluginEventType.KeyDown,
eventType: 'keyDown',
rawEvent: { key: 'Delete' } as any,
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { IContentModelEditor } from 'roosterjs-content-model-editor';
import {
ContentModelDocument,
ContentModelFormatter,
FormatWithContentModelOptions,
IStandaloneEditor,
} from 'roosterjs-content-model-types';

export function editingTestCommon(
apiName: string,
executionCallback: (editor: IContentModelEditor) => void,
executionCallback: (editor: IStandaloneEditor) => void,
model: ContentModelDocument,
result: ContentModelDocument,
calledTimes: number
Expand All @@ -32,7 +32,7 @@ export function editingTestCommon(
triggerEvent,
getEnvironment: () => ({}),
formatContentModel,
} as any) as IContentModelEditor;
} as any) as IStandaloneEditor;

executionCallback(editor);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import * as normalizeContentModel from 'roosterjs-content-model-dom/lib/modelApi/common/normalizeContentModel';
import { FormatWithContentModelContext } from 'roosterjs-content-model-types';
import { IContentModelEditor } from 'roosterjs-content-model-editor';
import { FormatWithContentModelContext, IStandaloneEditor } from 'roosterjs-content-model-types';
import {
handleKeyboardEventResult,
shouldDeleteAllSegmentsBefore,
shouldDeleteWord,
} from '../../lib/edit/handleKeyboardEventCommon';

describe('handleKeyboardEventResult', () => {
let mockedEditor: IContentModelEditor;
let mockedEditor: IStandaloneEditor;
let mockedEvent: KeyboardEvent;
let cacheContentModel: jasmine.Spy;
let preventDefault: jasmine.Spy;
Expand All @@ -28,7 +27,7 @@ describe('handleKeyboardEventResult', () => {
triggerContentChangedEvent,
triggerEvent,
addUndoSnapshot,
} as any) as IContentModelEditor;
} as any) as IStandaloneEditor;
mockedEvent = ({
preventDefault,
} as any) as KeyboardEvent;
Expand Down
Loading

0 comments on commit 8dc9968

Please sign in to comment.