All files / roosterjs-content-model-plugins/lib/edit keyboardTab.ts

76.67% Statements 23/30
72.73% Branches 16/22
50% Functions 3/6
76.67% Lines 23/30

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 881x 1x 1x 1x 1x 1x                               1x 24x   24x   24x   24x                   24x                                                         24x         24x   24x 2x 2x 2x 22x   22x 12x 10x 10x        
import { handleTabOnList } from './tabUtils/handleTabOnList';
import { handleTabOnParagraph } from './tabUtils/handleTabOnParagraph';
import { handleTabOnTable } from './tabUtils/handleTabOnTable';
import { handleTabOnTableCell } from './tabUtils/handleTabOnTableCell';
import { setModelIndentation } from 'roosterjs-content-model-api';
import {
    ChangeSource,
    getOperationalBlocks,
    isBlockGroupOfType,
} from 'roosterjs-content-model-dom';
import type {
    ContentModelListItem,
    ContentModelTableCell,
    FormatContentModelContext,
    IEditor,
    ReadonlyContentModelDocument,
} from 'roosterjs-content-model-types';
 
/**
 * @internal
 */
export function keyboardTab(editor: IEditor, rawEvent: KeyboardEvent) {
    const selection = editor.getDOMSelection();
 
    switch (selection?.type) {
        case 'range':
            editor.formatContentModel(
                (model, context) => {
                    return handleTab(model, rawEvent, context);
                },
                {
                    apiName: 'handleTabKey',
                    rawEvent,
                    changeSource: ChangeSource.Keyboard,
                    getChangeData: () => rawEvent.which,
                }
            );
 
            return true;
        case 'table':
            editor.formatContentModel(
                model => {
                    return handleTabOnTable(model, rawEvent);
                },
                {
                    apiName: 'handleTabKey',
                    rawEvent,
                    changeSource: ChangeSource.Keyboard,
                    getChangeData: () => rawEvent.which,
                }
            );
            return true;
    }
}
 
/**
 * If multiple blocks are selected, indent or outdent the selected blocks with setModelIndentation.
 * If only one block is selected:
 * - If it is a table cell, call handleTabOnTableCell to handle the tab key.
 * - If it is a paragraph, call handleTabOnParagraph to handle the tab key.
 * - If it is a list item, call handleTabOnList to handle the tab key.
 */
function handleTab(
    model: ReadonlyContentModelDocument,
    rawEvent: KeyboardEvent,
    context: FormatContentModelContext
) {
    const blocks = getOperationalBlocks<ContentModelListItem | ContentModelTableCell>(
        model,
        ['ListItem', 'TableCell'],
        []
    );
    const block = blocks.length > 0 ? blocks[0].block : undefined;
 
    if (blocks.length > 1) {
        setModelIndentation(model, rawEvent.shiftKey ? 'outdent' : 'indent');
        rawEvent.preventDefault();
        return true;
    } else Iif (isBlockGroupOfType<ContentModelTableCell>(block, 'TableCell')) {
        return handleTabOnTableCell(model, block, rawEvent);
    } else if (block?.blockType === 'Paragraph') {
        return handleTabOnParagraph(model, block, rawEvent, context);
    } else Eif (isBlockGroupOfType<ContentModelListItem>(block, 'ListItem')) {
        return handleTabOnList(model, block, rawEvent, context);
    }
    return false;
}