Skip to content

Commit

Permalink
Content Model code improvement 2: Decouple DomToModelContext and edit…
Browse files Browse the repository at this point in the history
…or (#1923)

* Content Model code improvement 1

* fix build

* fix build

* Remove unnecessary isDarkMode

* improve 2

* Fix test

* improve

* improve
  • Loading branch information
JiuqingSong authored Jul 1, 2023
1 parent 9807ed1 commit 55b2135
Show file tree
Hide file tree
Showing 45 changed files with 808 additions and 855 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,24 @@ import { defaultFormatParsers, getFormatParsers } from '../../formatHandlers/def
import { defaultProcessorMap } from './defaultProcessors';
import { defaultStyleMap } from '../../formatHandlers/utils/defaultStyles';
import { DomToModelContext, DomToModelOption, EditorContext } from 'roosterjs-content-model-types';
import { SelectionRangeTypes } from 'roosterjs-editor-types';
import { SelectionRangeEx } from 'roosterjs-editor-types';

/**
* Create context object form DOM to Content Model conversion
* @param editorContext Context of editor
* @param options Options for this context
* @param selection Selection that already exists in content
*/
export function createDomToModelContext(
editorContext?: EditorContext,
options?: DomToModelOption
options?: DomToModelOption,
selection?: SelectionRangeEx
): DomToModelContext {
const context: DomToModelContext = {
...editorContext,

blockFormat: {},
segmentFormat: {},
zoomScaleFormat: {},
isInSelection: false,

listFormat: {
Expand Down Expand Up @@ -57,46 +58,12 @@ export function createDomToModelContext(
allowCacheElement: !options?.disableCacheElement,
};

const range = options?.selectionRange;
let selectionRoot: Node | undefined;

switch (range?.type) {
case SelectionRangeTypes.Normal:
const regularRange = range.ranges[0];
if (regularRange) {
selectionRoot = regularRange.commonAncestorContainer;
context.regularSelection = {
startContainer: regularRange.startContainer,
startOffset: regularRange.startOffset,
endContainer: regularRange.endContainer,
endOffset: regularRange.endOffset,
isSelectionCollapsed: regularRange.collapsed,
};
}
break;

case SelectionRangeTypes.TableSelection:
if (range.coordinates && range.table) {
selectionRoot = range.table;
context.tableSelection = {
table: range.table,
firstCell: { ...range.coordinates.firstCell },
lastCell: { ...range.coordinates.lastCell },
};
}

break;

case SelectionRangeTypes.ImageSelection:
selectionRoot = range.image;
context.imageSelection = {
image: range.image,
};
break;
if (editorContext?.isRootRtl) {
context.blockFormat.direction = 'rtl';
}

if (selectionRoot) {
context.selectionRootNode = selectionRoot;
if (selection) {
context.rangeEx = selection;
}

return context;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import { createContentModelDocument } from '../modelApi/creators/createContentModelDocument';
import { createDomToModelContext } from './context/createDomToModelContext';
import { isNodeOfType } from '../domUtils/isNodeOfType';
import { NodeType } from 'roosterjs-editor-types';
import { normalizeContentModel } from '../modelApi/common/normalizeContentModel';
import { parseFormat } from './utils/parseFormat';
import { rootDirectionFormatHandler } from '../formatHandlers/root/rootDirectionFormatHandler';
import { zoomScaleFormatHandler } from '../formatHandlers/root/zoomScaleFormatHandler';
import { SelectionRangeEx } from 'roosterjs-editor-types';
import {
ContentModelDocument,
DomToModelOption,
Expand All @@ -15,25 +11,19 @@ import {
/**
* Create Content Model from DOM tree in this editor
* @param root Root element of DOM tree to create Content Model from
* @param editorContext Context of content model editor
* @param option The option to customize the behavior of DOM to Content Model conversion
* @param editorContext Context of content model editor
* @param selection Existing selection range in editor
* @returns A ContentModelDocument object that contains all the models created from the give root element
*/
export function domToContentModel(
root: HTMLElement | DocumentFragment,
option?: DomToModelOption,
editorContext?: EditorContext,
option?: DomToModelOption
selection?: SelectionRangeEx
): ContentModelDocument {
const model = createContentModelDocument(editorContext?.defaultFormat);
const context = createDomToModelContext(editorContext, option);

if (isNodeOfType(root, NodeType.Element)) {
// Need to calculate direction (ltr or rtl), use it as initial value
parseFormat(root, [rootDirectionFormatHandler.parse], context.blockFormat, context);

// Need to calculate zoom scale value from root element, use this value to calculate sizes for elements
parseFormat(root, [zoomScaleFormatHandler.parse], context.zoomScaleFormat, context);
}
const context = createDomToModelContext(editorContext, option, selection);

context.elementProcessors.child(model, root, context);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { addSelectionMarker } from '../utils/addSelectionMarker';
import { getRegularSelectionOffsets } from '../utils/getRegularSelectionOffsets';
import { isNodeOfType } from '../../domUtils/isNodeOfType';
import { NodeType } from 'roosterjs-editor-types';
import { NodeType, SelectionRangeTypes } from 'roosterjs-editor-types';
import {
ContentModelBlockGroup,
DomToModelContext,
Expand Down Expand Up @@ -73,8 +73,8 @@ export function handleRegularSelection(
addSelectionMarker(group, context);
}

if (index == nodeEndOffset) {
if (!context.regularSelection!.isSelectionCollapsed) {
if (index == nodeEndOffset && context.rangeEx?.type == SelectionRangeTypes.Normal) {
if (!context.rangeEx.areAllCollapsed) {
addSelectionMarker(group, context);
}
context.isInSelection = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { addSegment } from '../../modelApi/common/addSegment';
import { ContentModelImageFormat, ElementProcessor } from 'roosterjs-content-model-types';
import { createImage } from '../../modelApi/creators/createImage';
import { parseFormat } from '../utils/parseFormat';
import { SelectionRangeTypes } from 'roosterjs-editor-types';
import { stackFormat } from '../utils/stackFormat';

/**
Expand Down Expand Up @@ -32,7 +33,10 @@ export const imageProcessor: ElementProcessor<HTMLImageElement> = (group, elemen
if (context.isInSelection) {
image.isSelected = true;
}
if (context.imageSelection?.image == element) {
if (
context.rangeEx?.type == SelectionRangeTypes.ImageSelection &&
context.rangeEx.image == element
) {
image.isSelectedAsImageSelection = true;
image.isSelected = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { createTable } from '../../modelApi/creators/createTable';
import { createTableCell } from '../../modelApi/creators/createTableCell';
import { getBoundingClientRect } from '../utils/getBoundingClientRect';
import { parseFormat } from '../utils/parseFormat';
import { SelectionRangeTypes } from 'roosterjs-editor-types';
import { stackFormat } from '../utils/stackFormat';
import {
ContentModelTableCellFormat,
Expand Down Expand Up @@ -39,8 +40,16 @@ export const tableProcessor: ElementProcessor<HTMLTableElement> = (
parseFormat(tableElement, context.formatParsers.block, context.blockFormat, context);

const table = createTable(tableElement.rows.length, context.blockFormat);
const { table: selectedTable, firstCell, lastCell } = context.tableSelection || {};
const hasTableSelection = selectedTable == tableElement && !!firstCell && !!lastCell;
const tableSelection =
context.rangeEx?.type == SelectionRangeTypes.TableSelection
? context.rangeEx
: null;
const selectedTable = tableSelection?.table;
const coordinates = tableSelection?.coordinates;
const hasTableSelection =
selectedTable == tableElement &&
!!coordinates?.firstCell &&
!!coordinates?.lastCell;

if (context.allowCacheElement) {
table.cachedElement = tableElement;
Expand All @@ -59,7 +68,7 @@ export const tableProcessor: ElementProcessor<HTMLTableElement> = (

const columnPositions: number[] = [0];
const rowPositions: number[] = [0];
const zoomScale = context.zoomScaleFormat.zoomScale || 1;
const zoomScale = context.zoomScale || 1;

for (let row = 0; row < tableElement.rows.length; row++) {
const tr = tableElement.rows[row];
Expand Down Expand Up @@ -213,10 +222,10 @@ export const tableProcessor: ElementProcessor<HTMLTableElement> = (
if (
(hasSelectionBeforeCell && hasSelectionAfterCell) ||
(hasTableSelection &&
row >= firstCell.y &&
row <= lastCell.y &&
targetCol >= firstCell.x &&
targetCol <= lastCell.x)
row >= coordinates.firstCell.y &&
row <= coordinates.lastCell.y &&
targetCol >= coordinates.firstCell.x &&
targetCol <= coordinates.lastCell.x)
) {
cell.isSelected = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import { addDecorators } from '../../modelApi/common/addDecorators';
import { addSegment } from '../../modelApi/common/addSegment';
import { addSelectionMarker } from '../utils/addSelectionMarker';
import { areSameFormats } from '../utils/areSameFormats';
import { createText } from '../../modelApi/creators/createText';
import { getRegularSelectionOffsets } from '../utils/getRegularSelectionOffsets';
import { hasSpacesOnly } from '../../domUtils/stringUtil';
import {
ContentModelBlockGroup,
DomToModelContext,
ElementProcessor,
} from 'roosterjs-content-model-types';
import { createText } from '../../modelApi/creators/createText';
import { getRegularSelectionOffsets } from '../utils/getRegularSelectionOffsets';
import { hasSpacesOnly } from '../../domUtils/stringUtil';

/**
* @internal
Expand All @@ -35,7 +35,7 @@ export const textProcessor: ElementProcessor<Text> = (
if (txtEndOffset >= 0) {
addTextSegment(group, txt.substring(0, txtEndOffset), context);

if (!context.regularSelection!.isSelectionCollapsed) {
if (context.rangeEx && !context.rangeEx.areAllCollapsed) {
addSelectionMarker(group, context);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DomToModelContext } from 'roosterjs-content-model-types';
import { SelectionRangeTypes } from 'roosterjs-editor-types';

/**
* Get offset numbers of a regular (range based) selection.
Expand All @@ -11,14 +12,11 @@ export function getRegularSelectionOffsets(
context: DomToModelContext,
currentContainer: Node
): [number, number] {
let startOffset =
context.regularSelection?.startContainer == currentContainer
? context.regularSelection.startOffset!
: -1;
let endOffset =
context.regularSelection?.endContainer == currentContainer
? context.regularSelection.endOffset!
: -1;
const range =
context.rangeEx?.type == SelectionRangeTypes.Normal ? context.rangeEx.ranges[0] : null;

let startOffset = range?.startContainer == currentContainer ? range.startOffset : -1;
let endOffset = range?.endContainer == currentContainer ? range.endOffset! : -1;

return [startOffset, endOffset];
}

This file was deleted.

This file was deleted.

Loading

0 comments on commit 55b2135

Please sign in to comment.