All files / roosterjs-content-model-core/lib/command/cutCopy getContentForCopy.ts

100% Statements 41/41
93.1% Branches 27/29
100% Functions 3/3
100% Lines 40/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 105 1061x 1x 1x 1x                                           1x 30x 4x   30x 22x   30x                   1x         23x 23x   23x 20x 20x 20x   20x 9x     20x 20x 20x   20x 20x 20x 18x                 18x   18x           5x       18x   18x 6x   6x   6x 6x 12x 4x 4x   8x     18x    
import { adjustImageSelectionOnSafari } from './adjustImageSelectionOnSafari';
import { adjustSelectionForCopyCut } from './adjustSelectionForCopyCut';
import { onCreateCopyEntityNode } from '../../override/pasteCopyBlockEntityParser';
import {
    contentModelToDom,
    contentModelToText,
    createDomToModelContext,
    createModelToDomContext,
    domToContentModel,
    trimModelForSelection,
    isElementOfType,
    isNodeOfType,
    wrap,
} from 'roosterjs-content-model-dom';
import type {
    DOMSelection,
    IEditor,
    OnNodeCreated,
    TextAndHtmlContentForCopy,
} from 'roosterjs-content-model-types';
 
/**
 * @internal
 * Exported only for unit testing
 */
export const onNodeCreated: OnNodeCreated = (modelElement, node): void => {
    if (isNodeOfType(node, 'ELEMENT_NODE') && isElementOfType(node, 'table')) {
        wrap(node.ownerDocument, node, 'div');
    }
    if (isNodeOfType(node, 'ELEMENT_NODE') && !node.isContentEditable) {
        node.removeAttribute('contenteditable');
    }
    onCreateCopyEntityNode(modelElement, node);
};
 
/**
 * Get the content for the copy event
 * @param editor The editor object
 * @param isCut if the event cut the content.
 * @param event the clipboard event that triggered the copy/cut
 * @returns
 */
export function getContentForCopy(
    editor: IEditor,
    isCut: boolean,
    event: ClipboardEvent
): TextAndHtmlContentForCopy | null {
    const selection = editor.getDOMSelection();
    adjustImageSelectionOnSafari(editor, selection);
 
    if (selection && (selection.type !== 'range' || !selection.range.collapsed)) {
        const pasteModel = editor.getContentModelCopy('disconnected');
        const context = createModelToDomContext();
        trimModelForSelection(pasteModel, selection);
 
        if (selection.type === 'range') {
            adjustSelectionForCopyCut(pasteModel);
        }
 
        context.onNodeCreated = onNodeCreated;
        const doc = editor.getDocument();
        const tempDiv = doc.createElement('div');
 
        const selectionForCopy = contentModelToDom(doc, tempDiv, pasteModel, context);
        const newRange = selectionForCopy ? domSelectionToRange(doc, selectionForCopy) : null;
        if (newRange) {
            const { clonedRoot } = editor.triggerEvent('beforeCutCopy', {
                clonedRoot: tempDiv,
                range: newRange,
                rawEvent: event,
                isCut,
            });
 
            // Build the text content from the (possibly modified) cloned root DOM tree so that any
            // changes made by beforeCutCopy event handlers are reflected in the plain text result as well
            const textModel = domToContentModel(clonedRoot, createDomToModelContext());
 
            return {
                htmlContent: clonedRoot,
                textContent: contentModelToText(textModel),
            };
        }
    }
    return null;
}
 
function domSelectionToRange(doc: Document, selection: DOMSelection): Range | null {
    let newRange: Range | null = null;
 
    if (selection.type === 'table') {
        const table = selection.table;
        const elementToSelect =
            table.parentElement?.childElementCount == 1 ? table.parentElement : table;
 
        newRange = doc.createRange();
        newRange.selectNode(elementToSelect);
    } else if (selection.type === 'image') {
        newRange = doc.createRange();
        newRange.selectNode(selection.image);
    } else {
        newRange = selection.range;
    }
 
    return newRange;
}