All files / roosterjs-content-model-core/lib/command/paste createPasteFragment.ts

100% Statements 38/38
88.24% Branches 30/34
100% Functions 3/3
100% Lines 38/38

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 891x     1x 1x 1x         1x           50x 7x     100x 50x   50x         3x 3x 3x 3x 47x 29x 18x 18x 36x           36x 3x     36x           36x   9x 9x 27x   6x         21x         50x               6x 3x   3x 4x 4x 4x 4x 4x   3x    
import { moveChildNodes, wrap } from 'roosterjs-content-model-dom';
import type { ClipboardData, PasteType } from 'roosterjs-content-model-types';
 
const NBSP_HTML = '\u00A0';
const ENSP_HTML = '\u2002';
const TAB_SPACES = 6;
 
/**
 * @internal
 */
export function createPasteFragment(
    document: Document,
    clipboardData: ClipboardData,
    pasteType: PasteType,
    root: HTMLElement | undefined
): DocumentFragment {
    if (!clipboardData.text && pasteType === 'asPlainText' && root) {
        clipboardData.text = root.textContent || clipboardData.text;
    }
 
    const { imageDataUri, text } = clipboardData;
    const fragment = document.createDocumentFragment();
 
    if (
        (pasteType == 'asImage' && imageDataUri) ||
        (pasteType != 'asPlainText' && !text && imageDataUri)
    ) {
        // Paste image
        const img = document.createElement('img');
        img.style.maxWidth = '100%';
        img.src = imageDataUri;
        fragment.appendChild(img);
    } else if (pasteType != 'asPlainText' && root) {
        moveChildNodes(fragment, root);
    } else Eif (text) {
        text.split('\n').forEach((line, index, lines) => {
            line = line
                .replace(/^ /g, NBSP_HTML)
                .replace(/ $/g, NBSP_HTML)
                .replace(/\r/g, '')
                .replace(/ {2}/g, ' ' + NBSP_HTML);
 
            if (line.includes('\t')) {
                line = transformTabCharacters(line);
            }
 
            const textNode = document.createTextNode(line);
 
            // There are 3 scenarios:
            // 1. Single line: Paste as it is
            // 2. Two lines: Add <br> between the lines
            // 3. 3 or More lines, For first and last line, paste as it is. For middle lines, wrap with DIV, and add BR if it is empty line
            if (lines.length == 2 && index == 0) {
                // 1 of 2 lines scenario, add BR
                fragment.appendChild(textNode);
                fragment.appendChild(document.createElement('br'));
            } else if (index > 0 && index < lines.length - 1) {
                // Middle line of >=3 lines scenario, wrap with DIV
                fragment.appendChild(
                    wrap(document, line == '' ? document.createElement('br') : textNode, 'div')
                );
            } else {
                // All others, paste as it is
                fragment.appendChild(textNode);
            }
        });
    }
 
    return fragment;
}
 
/**
 * Transform \t characters into EN SPACE characters
 * @param input string NOT containing \n characters
 * @example t("\thello", 2) => "&ensp;&ensp;&ensp;&ensp;hello"
 */
function transformTabCharacters(input: string, EinitialOffset: number = 0) {
    let line = input;
    let tIndex: number;
    while ((tIndex = line.indexOf('\t')) != -1) {
        const lineBefore = line.slice(0, tIndex);
        const lineAfter = line.slice(tIndex + 1);
        const tabCount = TAB_SPACES - ((lineBefore.length + initialOffset) % TAB_SPACES);
        const tabStr = Array(tabCount).fill(ENSP_HTML).join('');
        line = lineBefore + tabStr + lineAfter;
    }
    return line;
}