All files / roosterjs-content-model-api/lib/modelApi/common queryContentModelBlocks.ts

100% Statements 32/32
100% Branches 18/18
100% Functions 3/3
100% Lines 25/25

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                            1x           50x 50x 81x 7x   74x   74x       56x 13x   56x   9x 3x   9x 9x 9x   9x 4x   11x 17x 17x           17x     9x     43x               74x             74x    
import type {
    ContentModelBlockType,
    ReadonlyContentModelBlock,
    ReadonlyContentModelBlockBase,
    ReadonlyContentModelBlockGroup,
} from 'roosterjs-content-model-types';
 
/**
 * Query content model blocks
 * @param group The block group to query
 * @param type The type of block to query
 * @param filter Optional selector to filter the blocks
 * @param findFirstOnly True to return the first block only, false to return all blocks
 */
export function queryContentModelBlocks<T extends ReadonlyContentModelBlock>(
    group: ReadonlyContentModelBlockGroup,
    type: T extends ReadonlyContentModelBlockBase<infer U> ? U : never,
    filter?: (element: T) => element is T,
    findFirstOnly?: boolean
): T[] {
    const elements: T[] = [];
    for (let i = 0; i < group.blocks.length; i++) {
        if (findFirstOnly && elements.length > 0) {
            return elements;
        }
        const block = group.blocks[i];
 
        switch (block.blockType) {
            case 'Paragraph':
            case 'Divider':
            case 'Entity':
                if (isExpectedBlockType(block, type, filter)) {
                    elements.push(block);
                }
                break;
            case 'BlockGroup':
                if (isExpectedBlockType(block, type, filter)) {
                    elements.push(block);
                }
                const results = queryContentModelBlocks<T>(block, type, filter, findFirstOnly);
                elements.push(...results);
                break;
            case 'Table':
                if (isExpectedBlockType(block, type, filter)) {
                    elements.push(block);
                }
                for (const row of block.rows) {
                    for (const cell of row.cells) {
                        const results = queryContentModelBlocks<T>(
                            cell,
                            type,
                            filter,
                            findFirstOnly
                        );
                        elements.push(...results);
                    }
                }
                break;
        }
    }
    return elements;
}
 
function isExpectedBlockType<T extends ReadonlyContentModelBlock>(
    block: ReadonlyContentModelBlock,
    type: ContentModelBlockType,
    filter?: (element: T) => element is T
): block is T {
    return isBlockType<T>(block, type) && (!filter || filter(block));
}
 
function isBlockType<T extends ReadonlyContentModelBlock>(
    block: ReadonlyContentModelBlock,
    type: ContentModelBlockType
): block is T {
    return block.blockType == type;
}