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             24x   12x     12x     12x 12x   12x   12x 2x 2x 2x   2x     12x   12x           1x             24x   8x 8x   8x           8x   8x 5x   5x 5x   5x 5x     5x 5x       5x   3x     8x         7x          
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,
    };
}