All files / roosterjs-content-model-core/lib/coreApi/setDOMSelection setTableCellsStyle.ts

100% Statements 34/34
94.12% Branches 32/34
100% Functions 7/7
100% Lines 32/32

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 106 107 108 109 110 111 112 113 114 115 116 117 118 1191x 1x     1x 1x             1x 4x                       1x             29x 29x 29x         29x             29x                                     18x   18x 18x     41x         24x           24x 24x     18x 51x   80x 51x   51x       51x 118x   118x 117x   117x           40x   40x           18x    
import { ensureUniqueId } from '../setEditorStyle/ensureUniqueId';
import { getSafeIdSelector, isNodeOfType, toArray } from 'roosterjs-content-model-dom';
import type { EditorCore, ParsedTable, TableCellCoordinate } from 'roosterjs-content-model-types';
 
const DOM_SELECTION_CSS_KEY = '_DOMSelection';
const TABLE_ID = 'table';
 
/**
 * @internal
 * Remove table cell selection styles
 * @param core The EditorCore object
 */
export function removeTableCellsStyle(core: EditorCore) {
    core.api.setEditorStyle(core, DOM_SELECTION_CSS_KEY, '');
}
 
/**
 * @internal
 * Set style for table cells in the selection
 * @param core The EditorCore object
 * @param table The HTML table element
 * @param parsedTable The parsed table structure
 * @param firstCell The coordinates of the first selected cell
 * @param lastCell The coordinates of the last selected cell
 */
export function setTableCellsStyle(
    core: EditorCore,
    table: HTMLTableElement,
    parsedTable: ParsedTable,
    firstCell: TableCellCoordinate,
    lastCell: TableCellCoordinate
) {
    const tableId = ensureUniqueId(table, TABLE_ID);
    const tableSelector = getSafeIdSelector(tableId);
    const tableSelectionColor = core.lifecycle.isDarkMode
        ? core.selection.tableCellSelectionBackgroundColorDark
        : core.selection.tableCellSelectionBackgroundColor;
 
    const tableSelectors =
        firstCell.row == 0 &&
        firstCell.col == 0 &&
        lastCell.row == parsedTable.length - 1 &&
        lastCell.col == (parsedTable[lastCell.row]?.length ?? 0) - 1
            ? [tableSelector, `${tableSelector} *`]
            : buildTableSelectors(parsedTable, tableSelector, table, firstCell, lastCell);
 
    core.api.setEditorStyle(
        core,
        DOM_SELECTION_CSS_KEY,
        `background-color:${tableSelectionColor}!important;`,
        tableSelectors
    );
}
 
/**
 * @internal
 * Build CSS selectors for table cells within the selection range
 */
function buildTableSelectors(
    parsedTable: ParsedTable,
    tableSelector: string,
    table: HTMLTableElement,
    firstCell: TableCellCoordinate,
    lastCell: TableCellCoordinate
): string[] {
    const selectors: string[] = [];
 
    let cont = 0;
    const indexes = toArray(table.childNodes)
        .filter(
            (node): node is HTMLTableSectionElement =>
                ['THEAD', 'TBODY', 'TFOOT'].indexOf(
                    isNodeOfType(node, 'ELEMENT_NODE') ? node.tagName : ''
                ) > -1
        )
        .map(node => {
            const result = {
                el: node.tagName,
                start: cont,
                end: node.childNodes.length + cont,
            };
 
            cont = result.end;
            return result;
        });
 
    parsedTable.forEach((row, rowIndex) => {
        let tdCount = 0;
 
        const midElement = indexes.filter(ind => ind.start <= rowIndex && ind.end > rowIndex)[0];
        const middleElSelector = midElement ? '>' + midElement.el + '>' : '>';
        const currentRow =
            midElement && rowIndex + 1 >= midElement.start
                ? rowIndex + 1 - midElement.start
                : rowIndex + 1;
 
        for (let cellIndex = 0; cellIndex < row.length; cellIndex++) {
            const cell = row[cellIndex];
 
            if (typeof cell == 'object') {
                tdCount++;
 
                if (
                    rowIndex >= firstCell.row &&
                    rowIndex <= lastCell.row &&
                    cellIndex >= firstCell.col &&
                    cellIndex <= lastCell.col
                ) {
                    const selector = `${tableSelector}${middleElSelector} tr:nth-child(${currentRow})>${cell.tagName}:nth-child(${tdCount})`;
 
                    selectors.push(selector, selector + ' *');
                }
            }
        }
    });
 
    return selectors;
}