Skip to content

Commit

Permalink
Clean up core API (#2481)
Browse files Browse the repository at this point in the history
* Clean up core API

* fix build

* fix build

* fix test
  • Loading branch information
JiuqingSong authored Mar 8, 2024
1 parent 0296491 commit be79cb0
Show file tree
Hide file tree
Showing 46 changed files with 531 additions and 574 deletions.
6 changes: 3 additions & 3 deletions demo/scripts/controlsV2/demoButtons/pasteButton.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { extractClipboardItems } from 'roosterjs-content-model-core';
import { RibbonButton } from '../roosterjsReact/ribbon';
import { extractClipboardItems, paste } from 'roosterjs-content-model-core';
import type { RibbonButton } from '../roosterjsReact/ribbon';

/**
* @internal
Expand All @@ -19,7 +19,7 @@ export const pasteButton: RibbonButton<'buttonNamePaste'> = {
createDataTransferItems(clipboardItems)
);
const clipboardData = await extractClipboardItems(dataTransferItems);
editor.pasteFromClipboard(clipboardData);
paste(editor, clipboardData);
} catch {}
}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import { ButtonKeys, Buttons } from '../utils/buttons';
import { ChangeSource } from 'roosterjs-content-model-core';
import { ChangeSource, paste } from 'roosterjs-content-model-core';
import { ClipboardData, IEditor, PluginEvent } from 'roosterjs-content-model-types';
import { showPasteOptionPane } from '../component/showPasteOptionPane';
import type { PasteOptionPane } from '../component/showPasteOptionPane';
Expand Down Expand Up @@ -130,18 +130,18 @@ class PasteOptionPlugin implements ReactEditorPlugin {

switch (key) {
case 'pasteOptionPasteAsIs':
this.editor.pasteFromClipboard(this.clipboardData);
paste(this.editor, this.clipboardData);
break;

case 'pasteOptionPasteText':
this.editor.pasteFromClipboard(this.clipboardData, 'asPlainText');
paste(this.editor, this.clipboardData, 'asPlainText');
break;

case 'pasteOptionMergeFormat':
this.editor.pasteFromClipboard(this.clipboardData, 'mergeFormat');
paste(this.editor, this.clipboardData, 'mergeFormat');
break;
case 'pasteOptionPasteAsImage':
this.editor.pasteFromClipboard(this.clipboardData, 'asImage');
paste(this.editor, this.clipboardData, 'asImage');
}

this.pasteOptionRef.current?.setSelectedKey(key);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,10 @@ export const createContentModel: CreateContentModel = (core, option, selectionOv
: selectionOverride || core.api.getDOMSelection(core) || undefined;
const saveIndex = !option && !selectionOverride;
const editorContext = core.api.createEditorContext(core, saveIndex);
const settings = core.environment.domToModelSettings;
const domToModelContext = option
? createDomToModelContext(
editorContext,
core.domToModelSettings.builtIn,
core.domToModelSettings.customized,
option
)
: createDomToModelContextWithConfig(core.domToModelSettings.calculated, editorContext);
? createDomToModelContext(editorContext, settings.builtIn, settings.customized, option)
: createDomToModelContextWithConfig(settings.calculated, editorContext);

const model = domToContentModel(core.logicalRoot, domToModelContext, selection);

Expand Down
6 changes: 3 additions & 3 deletions packages/roosterjs-content-model-core/lib/coreApi/focus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import type { Focus } from 'roosterjs-content-model-types';
*/
export const focus: Focus = core => {
if (!core.lifecycle.shadowEditFragment) {
const { api, selection } = core;
const { api, domHelper, selection } = core;

if (!api.hasFocus(core) && selection.selection?.type == 'range') {
if (!domHelper.hasFocus() && selection.selection?.type == 'range') {
api.setDOMSelection(core, selection.selection, true /*skipSelectionChangedEvent*/);
}

// fallback, in case editor still have no focus
if (!core.api.hasFocus(core)) {
if (!domHelper.hasFocus()) {
core.logicalRoot.focus();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const formatContentModel: FormatContentModel = (core, formatter, options)
newImages: [],
};

const hasFocus = core.api.hasFocus(core);
const hasFocus = core.domHelper.hasFocus();

const changed = formatter(model, context);
const { skipUndoSnapshot, clearModelCache, entityStates, canUndoByBackspace } = context;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const getDOMSelection: GetDOMSelection = core => {
} else {
const selection = core.selection.selection;

return selection && (selection.type != 'range' || !core.api.hasFocus(core))
return selection && (selection.type != 'range' || !core.domHelper.hasFocus())
? selection
: getNewSelection(core);
}
Expand Down
12 changes: 0 additions & 12 deletions packages/roosterjs-content-model-core/lib/coreApi/hasFocus.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ export const setContentModel: SetContentModel = (core, model, option, onNodeCrea
const modelToDomContext = option
? createModelToDomContext(
editorContext,
core.modelToDomSettings.builtIn,
core.modelToDomSettings.customized,
core.environment.modelToDomSettings.builtIn,
core.environment.modelToDomSettings.customized,
option
)
: createModelToDomContextWithConfig(core.modelToDomSettings.calculated, editorContext);
: createModelToDomContextWithConfig(
core.environment.modelToDomSettings.calculated,
editorContext
);

modelToDomContext.onNodeCreated = onNodeCreated;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const setDOMSelection: SetDOMSelection = (core, selection, skipSelectionC
case 'range':
addRangeToSelection(doc, selection.range, selection.isReverted);

core.selection.selection = core.api.hasFocus(core) ? null : selection;
core.selection.selection = core.domHelper.hasFocus() ? null : selection;
break;

default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { extractClipboardItems } from '../utils/extractClipboardItems';
import { getSelectedCells } from '../publicApi/table/getSelectedCells';
import { iterateSelections } from '../publicApi/selection/iterateSelections';
import { onCreateCopyEntityNode } from '../override/pasteCopyBlockEntityParser';
import { paste } from '../publicApi/paste/paste';

import {
contentModelToDom,
Expand Down Expand Up @@ -200,7 +201,7 @@ class CopyPastePlugin implements PluginWithState<CopyPastePluginState> {
this.state.allowedCustomPasteType
).then((clipboardData: ClipboardData) => {
if (!editor.isDisposed()) {
editor.pasteFromClipboard(clipboardData, this.state.defaultPasteType);
paste(editor, clipboardData, this.state.defaultPasteType);
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ class DOMHelperImpl implements DOMHelper {
? closestElement
: null;
}

hasFocus(): boolean {
const activeElement = this.contentDiv.ownerDocument.activeElement;
return !!(activeElement && this.contentDiv.contains(activeElement));
}
}

/**
Expand Down
17 changes: 2 additions & 15 deletions packages/roosterjs-content-model-core/lib/editor/Editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import { createEditorCore } from './createEditorCore';
import { createEmptyModel, tableProcessor } from 'roosterjs-content-model-dom';
import { reducedModelChildProcessor } from '../override/reducedModelChildProcessor';
import { transformColor } from '../publicApi/color/transformColor';
import type { CachedElementHandler } from '../publicApi/model/cloneModel';
import type {
ClipboardData,
ContentModelDocument,
ContentModelFormatter,
ContentModelSegmentFormat,
Expand All @@ -17,7 +15,6 @@ import type {
EditorEnvironment,
FormatContentModelOptions,
IEditor,
PasteType,
PluginEventData,
PluginEventFromType,
PluginEventType,
Expand All @@ -28,6 +25,7 @@ import type {
TrustedHTMLHandler,
Rect,
EntityState,
CachedElementHandler,
} from 'roosterjs-content-model-types';

/**
Expand Down Expand Up @@ -231,7 +229,7 @@ export class Editor implements IEditor {
*/
hasFocus(): boolean {
const core = this.getCore();
return core.api.hasFocus(core);
return core.domHelper.hasFocus();
}

/**
Expand Down Expand Up @@ -342,17 +340,6 @@ export class Editor implements IEditor {
core.api.switchShadowEdit(core, false /*isOn*/);
}

/**
* Paste into editor using a clipboardData object
* @param clipboardData Clipboard data retrieved from clipboard
* @param pasteType Type of paste
*/
pasteFromClipboard(clipboardData: ClipboardData, pasteType: PasteType = 'normal') {
const core = this.getCore();

core.api.paste(core, clipboardData, pasteType);
}

/**
* Get a color manager object for this editor.
*/
Expand Down
14 changes: 7 additions & 7 deletions packages/roosterjs-content-model-core/lib/editor/coreApiMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import { focus } from '../coreApi/focus';
import { formatContentModel } from '../coreApi/formatContentModel';
import { getDOMSelection } from '../coreApi/getDOMSelection';
import { getVisibleViewport } from '../coreApi/getVisibleViewport';
import { hasFocus } from '../coreApi/hasFocus';
import { paste } from '../coreApi/paste';
import { restoreUndoSnapshot } from '../coreApi/restoreUndoSnapshot';
import { setContentModel } from '../coreApi/setContentModel';
import { setDOMSelection } from '../coreApi/setDOMSelection';
Expand All @@ -23,16 +21,18 @@ export const coreApiMap: CoreApiMap = {
createContentModel: createContentModel,
createEditorContext: createEditorContext,
formatContentModel: formatContentModel,
getDOMSelection: getDOMSelection,
setContentModel: setContentModel,

getDOMSelection: getDOMSelection,
setDOMSelection: setDOMSelection,
switchShadowEdit: switchShadowEdit,
getVisibleViewport: getVisibleViewport,
focus: focus,
hasFocus: hasFocus,

addUndoSnapshot: addUndoSnapshot,
restoreUndoSnapshot: restoreUndoSnapshot,

attachDomEvent: attachDomEvent,
triggerEvent: triggerEvent,
paste: paste,

switchShadowEdit: switchShadowEdit,
getVisibleViewport: getVisibleViewport,
};
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { coreApiMap } from './coreApiMap';
import { createDarkColorHandler } from './DarkColorHandlerImpl';
import { createDOMHelper } from './DOMHelperImpl';
import { createEditorCorePlugins } from '../corePlugin/createEditorCorePlugins';
import { createDomToModelSettings, createModelToDomSettings } from './createEditorDefaultSettings';
import { createEditorCorePlugins } from '../corePlugin/createEditorCorePlugins';
import type {
EditorEnvironment,
PluginState,
Expand Down Expand Up @@ -36,27 +36,30 @@ export function createEditorCore(contentDiv: HTMLDivElement, options: EditorOpti
corePlugins.contextMenu,
corePlugins.lifecycle,
],
environment: createEditorEnvironment(contentDiv),
environment: createEditorEnvironment(contentDiv, options),
darkColorHandler: createDarkColorHandler(
contentDiv,
options.getDarkColor ?? getDarkColorFallback,
options.knownColors
),
trustedHTMLHandler: options.trustedHTMLHandler || defaultTrustHtmlHandler,
domToModelSettings: createDomToModelSettings(options),
modelToDomSettings: createModelToDomSettings(options),
domHelper: createDOMHelper(contentDiv),
...getPluginState(corePlugins),
disposeErrorHandler: options.disposeErrorHandler,
};
}

function createEditorEnvironment(contentDiv: HTMLElement): EditorEnvironment {
function createEditorEnvironment(
contentDiv: HTMLElement,
options: EditorOptions
): EditorEnvironment {
const navigator = contentDiv.ownerDocument.defaultView?.navigator;
const userAgent = navigator?.userAgent ?? '';
const appVersion = navigator?.appVersion ?? '';

return {
domToModelSettings: createDomToModelSettings(options),
modelToDomSettings: createModelToDomSettings(options),
isMac: appVersion.indexOf('Mac') != -1,
isAndroid: /android/i.test(userAgent),
isSafari:
Expand Down
3 changes: 2 additions & 1 deletion packages/roosterjs-content-model-core/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { CachedElementHandler, CloneModelOptions, cloneModel } from './publicApi/model/cloneModel';
export { cloneModel } from './publicApi/model/cloneModel';
export { mergeModel, MergeModelOption } from './publicApi/model/mergeModel';
export { isBlockGroupOfType } from './publicApi/model/isBlockGroupOfType';
export {
Expand Down Expand Up @@ -47,6 +47,7 @@ export { cacheGetEventData } from './publicApi/domUtils/cacheGetEventData';

export { undo } from './publicApi/undo/undo';
export { redo } from './publicApi/undo/redo';
export { paste } from './publicApi/paste/paste';
export { transformColor } from './publicApi/color/transformColor';

export { retrieveModelFormatState } from './publicApi/format/retrieveModelFormatState';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,36 +25,9 @@ import type {
ContentModelText,
ContentModelTableRow,
ContentModelListLevel,
CloneModelOptions,
} from 'roosterjs-content-model-types';

/**
* Function type used for cloneModel API to specify how to handle cached element when clone a model
* @param node The cached node
* @param type Type of the node, it can be
* - general: DOM element of ContentModelGeneralSegment or ContentModelGeneralBlock
* - entity: Wrapper element in ContentModelEntity
* - cache: Cached node in other model element that supports cache
*/
export type CachedElementHandler = (
node: HTMLElement,
type: 'general' | 'entity' | 'cache'
) => HTMLElement | undefined;

/**
*
* Options for cloneModel API
*/
export interface CloneModelOptions {
/**
* Specify how to deal with cached element, including cached block element, element in General Model, and wrapper element in Entity
* - True: Cloned model will have the same reference to the cached element
* - False/Not passed: For cached block element, cached element will be undefined. For General Model and Entity, the element will have deep clone and assign to the cloned model
* - A callback: invoke the callback with the source cached element and a string to specify model type, let the callback return the expected value of cached element.
* For General Model and Entity, the callback must return a valid element, otherwise there will be exception thrown.
*/
includeCachedElement?: boolean | CachedElementHandler;
}

/**
* Clone a content model
* @param model The content model to clone
Expand Down
Loading

0 comments on commit be79cb0

Please sign in to comment.