Skip to content

Commit

Permalink
standalone editor: Remove dependencies (#2115)
Browse files Browse the repository at this point in the history
  • Loading branch information
JiuqingSong authored Sep 30, 2023
1 parent 3520947 commit ac0a912
Show file tree
Hide file tree
Showing 12 changed files with 48 additions and 52 deletions.
1 change: 1 addition & 0 deletions demo/scripts/controls/BuildInPluginState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export default interface BuildInPluginState {
experimentalFeatures: ExperimentalFeatures[];
forcePreserveRatio: boolean;
isRtl: boolean;
cacheModel?: boolean;
tableFeaturesContainerSelector: string;
}

Expand Down
5 changes: 4 additions & 1 deletion demo/scripts/controls/ContentModelEditorMainPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,10 @@ class ContentModelEditorMainPane extends MainPaneBase {
this.toggleablePlugins = null;
this.setState({
editorCreator: (div: HTMLDivElement, options: EditorOptions) =>
new ContentModelEditor(div, options),
new ContentModelEditor(div, {
...options,
cacheModel: this.state.initState.cacheModel,
}),
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import BuildInPluginState, { BuildInPluginProps, UrlPlaceholder } from '../../Bu
import ContentModelOptionsPane from './ContentModelOptionsPane';
import getDefaultContentEditFeatureSettings from './getDefaultContentEditFeatureSettings';
import SidePanePluginImpl from '../SidePanePluginImpl';
import { ExperimentalFeatures } from 'roosterjs-editor-types';
import { SidePaneElementProps } from '../SidePaneElement';

const initialState: BuildInPluginState = {
Expand All @@ -28,8 +27,9 @@ const initialState: BuildInPluginState = {
linkTitle: 'Ctrl+Click to follow the link:' + UrlPlaceholder,
watermarkText: 'Type content here ...',
forcePreserveRatio: false,
experimentalFeatures: [ExperimentalFeatures.ReusableContentModelV2],
experimentalFeatures: [],
isRtl: false,
cacheModel: true,
tableFeaturesContainerSelector: '#' + 'EditorContainer',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ const FeatureNames: Partial<Record<ExperimentalFeatures, string>> = {
[ExperimentalFeatures.DeleteTableWithBackspace]:
'Delete a table selected with the table selector pressing Backspace key',
[ExperimentalFeatures.DisableListChain]: 'Disable list chain functionality',
[ExperimentalFeatures.ReusableContentModelV2]:
'Reuse existing DOM structure if possible, and update the model when content or selection is changed',
};

export default class ContentModelExperimentalFeaturesPane extends React.Component<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export default class ContentModelOptionsPane extends React.Component<
private exportForm = React.createRef<HTMLFormElement>();
private exportData = React.createRef<HTMLInputElement>();
private rtl = React.createRef<HTMLInputElement>();
private cacheModel = React.createRef<HTMLInputElement>();

constructor(props: BuildInPluginProps) {
super(props);
Expand Down Expand Up @@ -96,6 +97,16 @@ export default class ContentModelOptionsPane extends React.Component<
/>
<label htmlFor="pageRtl">Show controls from right to left</label>
</div>
<div>
<input
id="cacheModel"
type="checkbox"
checked={this.state.cacheModel}
onChange={this.onToggleCacheModel}
ref={this.cacheModel}
/>
<label htmlFor="cacheModel">Use Content Model Cache</label>
</div>
<hr />
<details>
<summary>
Expand Down Expand Up @@ -138,6 +149,7 @@ export default class ContentModelOptionsPane extends React.Component<
experimentalFeatures: this.state.experimentalFeatures,
forcePreserveRatio: this.state.forcePreserveRatio,
isRtl: this.state.isRtl,
cacheModel: this.state.cacheModel,
tableFeaturesContainerSelector: this.state.tableFeaturesContainerSelector,
};

Expand Down Expand Up @@ -173,6 +185,12 @@ export default class ContentModelOptionsPane extends React.Component<
MainPaneBase.getInstance().setPageDirection(isRtl);
};

private onToggleCacheModel = () => {
this.resetState(state => {
state.cacheModel = this.cacheModel.current.checked;
}, true);
};

private getHtml() {
return `${htmlStart}${htmlButtons}${darkButton}${htmlEnd}`;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { createContentModelEditorCore } from './createContentModelEditorCore';
import { EditorBase } from 'roosterjs-editor-core';
import { ExperimentalFeatures } from 'roosterjs-editor-types';
import type { ContentModelEditorCore } from '../publicTypes/ContentModelEditorCore';
import type {
ContentModelEditorOptions,
Expand Down Expand Up @@ -29,7 +28,7 @@ export default class ContentModelEditor
constructor(contentDiv: HTMLDivElement, options: ContentModelEditorOptions = {}) {
super(contentDiv, options, createContentModelEditorCore);

if (this.isFeatureEnabled(ExperimentalFeatures.ReusableContentModelV2)) {
if (options.cacheModel) {
// Create an initial content model to cache
// TODO: Once we have standalone editor and get rid of `ensureTypeInContainer` function, we can set init content
// using content model and cache the model directly
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import { createContentModelEditPlugin } from './corePlugins/ContentModelEditPlug
import { createContentModelFormatPlugin } from './corePlugins/ContentModelFormatPlugin';
import { createDomToModelConfig, createModelToDomConfig } from 'roosterjs-content-model-dom';
import { createEditorContext } from './coreApi/createEditorContext';
import { createEditorCore, isFeatureEnabled } from 'roosterjs-editor-core';
import { ExperimentalFeatures } from 'roosterjs-editor-types';
import { createEditorCore } from 'roosterjs-editor-core';
import { getDOMSelection } from './coreApi/getDOMSelection';
import { setContentModel } from './coreApi/setContentModel';
import { setDOMSelection } from './coreApi/setDOMSelection';
Expand Down Expand Up @@ -108,12 +107,7 @@ function getPluginState(options: ContentModelEditorOptions): ContentModelPluginS
const format = options.defaultFormat || {};
return {
cache: {
domIndexer: isFeatureEnabled(
options.experimentalFeatures,
ExperimentalFeatures.ReusableContentModelV2
)
? contentModelDomIndexer
: undefined,
domIndexer: options.cacheModel ? contentModelDomIndexer : undefined,
},
copyPaste: {
allowedCustomPasteType: options.allowedCustomPasteType || [],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { isGeneralSegment } from 'roosterjs-content-model-dom';
import type { Coordinates } from 'roosterjs-editor-types';
import type {
ContentModelBlock,
ContentModelBlockGroup,
Expand Down Expand Up @@ -102,17 +101,16 @@ function setSelectionToTable(
start: Selectable | null,
end: Selectable | null
): boolean {
const notFoundCo: Coordinates = { x: -1, y: -1 };
const startCo = findCell(table, start);
const { x: firstX, y: firstY } = startCo ?? notFoundCo;
const { x: lastX, y: lastY } = (end ? findCell(table, end) : startCo) ?? notFoundCo;
const first = findCell(table, start);
const last = end ? findCell(table, end) : first;

if (!isInSelection) {
for (let row = 0; row < table.rows.length; row++) {
const currentRow = table.rows[row];
for (let col = 0; col < currentRow.cells.length; col++) {
const currentCell = table.rows[row].cells[col];
const isSelected = row >= firstY && row <= lastY && col >= firstX && col <= lastX;
const isSelected =
row >= first.row && row <= last.row && col >= first.col && col <= last.col;

setIsSelected(currentCell, isSelected);

Expand All @@ -137,22 +135,13 @@ function setSelectionToTable(
return isInSelection;
}

function findCell(table: ContentModelTable, cell: Selectable | null): Coordinates | undefined {
let x = -1;
let y = -1;
function findCell(table: ContentModelTable, cell: Selectable | null): { row: number; col: number } {
let col = -1;
const row = cell
? table.rows.findIndex(row => (col = (row.cells as Selectable[]).indexOf(cell)) >= 0)
: -1;

if (cell) {
for (let row = 0; y < 0 && row < table.rows.length; row++) {
for (let col = 0; x < 0 && col < table.rows[row].cells.length; col++) {
if (table.rows[row].cells[col] == cell) {
x = col;
y = row;
}
}
}
}

return x >= 0 && y >= 0 ? { x, y } : undefined;
return { row, col };
}

function setSelectionToSegment(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,9 @@ export interface ContentModelEditorOptions extends EditorOptions {
* Default options used for Content Model to DOM conversion
*/
defaultModelToDomOptions?: ModelToDomOption;

/**
* Reuse existing DOM structure if possible, and update the model when content or selection is changed
*/
cacheModel?: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import * as ContentModelFormatPlugin from '../../lib/editor/corePlugins/ContentM
import * as createDomToModelContext from 'roosterjs-content-model-dom/lib/domToModel/context/createDomToModelContext';
import * as createEditorCore from 'roosterjs-editor-core/lib/editor/createEditorCore';
import * as createModelToDomContext from 'roosterjs-content-model-dom/lib/modelToDom/context/createModelToDomContext';
import * as isFeatureEnabled from 'roosterjs-editor-core/lib/editor/isFeatureEnabled';
import ContentModelTypeInContainerPlugin from '../../lib/editor/corePlugins/ContentModelTypeInContainerPlugin';
import { contentModelDomIndexer } from '../../lib/editor/utils/contentModelDomIndexer';
import { ContentModelEditorOptions } from '../../lib/publicTypes/IContentModelEditor';
import { createContentModel } from '../../lib/editor/coreApi/createContentModel';
import { createContentModelEditorCore } from '../../lib/editor/createContentModelEditorCore';
import { createEditorContext } from '../../lib/editor/coreApi/createEditorContext';
import { ExperimentalFeatures } from 'roosterjs-editor-types';
import { getDOMSelection } from '../../lib/editor/coreApi/getDOMSelection';
import { setContentModel } from '../../lib/editor/coreApi/setContentModel';
import { setDOMSelection } from '../../lib/editor/coreApi/setDOMSelection';
Expand Down Expand Up @@ -350,18 +349,13 @@ describe('createContentModelEditorCore', () => {
});

it('Allow dom indexer', () => {
mockedCore.lifecycle.experimentalFeatures.push(ExperimentalFeatures.ReusableContentModelV2);

const options = {
const options: ContentModelEditorOptions = {
corePluginOverride: {
copyPaste: copyPastePlugin,
},
cacheModel: true,
};

spyOn(isFeatureEnabled, 'isFeatureEnabled').and.callFake(
(features, feature) => feature == ExperimentalFeatures.ReusableContentModelV2
);

const core = createContentModelEditorCore(contentDiv, options);

expect(createEditorCoreSpy).toHaveBeenCalledWith(contentDiv, {
Expand All @@ -370,10 +364,11 @@ describe('createContentModelEditorCore', () => {
typeInContainer: new ContentModelTypeInContainerPlugin(),
copyPaste: copyPastePlugin,
},
cacheModel: true,
});
expect(core).toEqual({
lifecycle: {
experimentalFeatures: [ExperimentalFeatures.ReusableContentModelV2],
experimentalFeatures: [],
},
api: {
switchShadowEdit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,6 @@ describe('ContentModelCopyPastePlugin |', () => {
let clipboardData = <ClipboardData>{};

it('Handle', () => {
editor.isFeatureEnabled = () => true;
spyOn(PasteFile, 'default').and.callFake(() => {});
const preventDefaultSpy = jasmine.createSpy('preventDefaultPaste');
let clipboardEvent = <ClipboardEvent>{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,4 @@ export const enum ExperimentalFeatures {
* Disable list chain functionality
*/
DisableListChain = 'DisableListChain',

/**
* Reuse existing DOM structure if possible, and update the model when content or selection is changed
*/
ReusableContentModelV2 = 'ReusableContentModelV2',
}

0 comments on commit ac0a912

Please sign in to comment.