All files / roosterjs-content-model-dom/lib/modelToDom/handlers handleEntity.ts

95.45% Statements 42/44
76.74% Branches 33/43
100% Functions 3/3
95% Lines 38/40

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 1051x 1x 1x 1x 1x                 1x         1x             26x   13x     13x     13x 13x   13x   13x 3x 3x 3x   3x     13x   13x           1x             24x   8x 8x   8x           8x   8x 5x   5x 5x   5x 5x     5x 5x       5x   3x     8x         8x          
import { addDelimiters } from '../../domUtils/entityUtils';
import { applyFormat } from '../utils/applyFormat';
import { getObjectKeys } from '../../domUtils/getObjectKeys';
import { reuseCachedElement } from '../../domUtils/reuseCachedElement';
import { wrap } from '../../domUtils/wrap';
import type {
    ContentModelBlockHandler,
    ContentModelEntity,
    ContentModelSegmentFormat,
    ContentModelSegmentHandler,
    ModelToDomContext,
} from 'roosterjs-content-model-types';
 
const BlockEntityContainer = '_E_EBlockEntityContainer';
 
/**
 * @internal
 */
export const handleEntityBlock: ContentModelBlockHandler<ContentModelEntity> = (
    doc,
    parent,
    entityModel,
    context,
    refNode
) => {
    const { entityFormat, wrapper } = entityModel;
 
    applyFormat(wrapper, context.formatAppliers.entity, entityFormat, context);
 
    const isCursorAroundEntity =
        context.addDelimiterForEntity &&
        wrapper.style.display == 'inline-block' &&
        wrapper.style.width == '100%';
    const isContained = wrapper.parentElement?.classList.contains(BlockEntityContainer);
    const elementToReuse = isContained && isCursorAroundEntity ? wrapper.parentElement! : wrapper;
 
    refNode = reuseCachedElement(parent, elementToReuse, refNode, context.rewriteFromModel);
 
    if (isCursorAroundEntity) {
        Eif (!isContained) {
            const element = wrap(doc, wrapper, 'div');
            element.classList.add(BlockEntityContainer);
        }
        addDelimiters(doc, wrapper, getSegmentFormat(context), context);
    }
 
    context.onNodeCreated?.(entityModel, wrapper);
 
    return refNode;
};
 
/**
 * @internal
 */
export const handleEntitySegment: ContentModelSegmentHandler<ContentModelEntity> = (
    doc,
    parent,
    entityModel,
    context,
    newSegments
) => {
    const { entityFormat, wrapper, format } = entityModel;
 
    parent.appendChild(wrapper);
    newSegments?.push(wrapper);
 
    Iif (getObjectKeys(format).length > 0) {
        const span = wrap(doc, wrapper, 'span');
 
        applyFormat(span, context.formatAppliers.segment, format, context);
    }
 
    applyFormat(wrapper, context.formatAppliers.entity, entityFormat, context);
 
    if (context.addDelimiterForEntity && entityFormat.isReadonly) {
        const [after, before] = addDelimiters(doc, wrapper, getSegmentFormat(context), context);
 
        Eif (newSegments) {
            newSegments.push(after, before);
 
            Eif (after.firstChild) {
                newSegments.push(after.firstChild);
            }
 
            Eif (before.firstChild) {
                newSegments.push(before.firstChild);
            }
        }
 
        context.regularSelection.current.segment = after;
    } else {
        context.regularSelection.current.segment = wrapper;
    }
 
    context.onNodeCreated?.(entityModel, wrapper);
};
function getSegmentFormat(
    context: ModelToDomContext
): ContentModelSegmentFormat | null | undefined {
    return {
        ...context.pendingFormat?.format,
        ...context.defaultFormat,
    };
}