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

Content Model code improvement 2: Decouple DomToModelContext and editor #1923

Merged
merged 13 commits into from
Jul 1, 2023
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