UNPKG

@atlaskit/editor-plugin-table

Version:

Table plugin for the @atlaskit/editor

133 lines (131 loc) 5.12 kB
import { mapChildren } from '@atlaskit/editor-common/utils'; import { TableMap } from '@atlaskit/editor-tables/table-map'; import { findTable } from '@atlaskit/editor-tables/utils'; import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals'; export const isIsolating = node => { return !!node.type.spec.isolating; }; export const containsHeaderColumn = table => { const map = TableMap.get(table); // Get cell positions for first column. const cellPositions = map.cellsInRect({ left: 0, top: 0, right: 1, bottom: map.height }); for (let i = 0; i < cellPositions.length; i++) { try { const cell = table.nodeAt(cellPositions[i]); if (cell && cell.type !== table.type.schema.nodes.tableHeader) { return false; } } catch { return false; } } return true; }; export const containsHeaderRow = table => { const map = TableMap.get(table); for (let i = 0; i < map.width; i++) { const cell = table.nodeAt(map.map[i]); if (cell && cell.type !== table.type.schema.nodes.tableHeader) { return false; } } return true; }; export const checkIfHeaderColumnEnabled = selection => filterNearSelection(selection, findTable, containsHeaderColumn, false); export const checkIfHeaderRowEnabled = selection => filterNearSelection(selection, findTable, containsHeaderRow, false); export const checkIfNumberColumnEnabled = selection => filterNearSelection(selection, findTable, table => !!table.attrs.isNumberColumnEnabled, false); export const getTableWidth = node => { return getTableWidths(node).reduce((acc, current) => acc + current, 0); }; export const tablesHaveDifferentColumnWidths = (currentTable, previousTable) => { const currentTableWidths = getTableWidths(currentTable); const previousTableWidths = getTableWidths(previousTable); if (currentTableWidths.length !== previousTableWidths.length) { return true; } const sameWidths = currentTableWidths.every((value, index) => { return value === previousTableWidths[index]; }); return sameWidths === false; }; export const tablesHaveDifferentNoOfColumns = (currentTable, previousTable) => { const prevMap = TableMap.get(previousTable); const currentMap = TableMap.get(currentTable); return prevMap.width !== currentMap.width; }; export const tablesHaveDifferentNoOfRows = (currentTable, previousTable) => { const prevMap = TableMap.get(previousTable); const currentMap = TableMap.get(currentTable); return prevMap.height !== currentMap.height; }; function filterNearSelection(selection, findNode, predicate, defaultValue) { const found = findNode(selection); if (!found) { return defaultValue; } return predicate(found.node, found.pos); } function getTableWidths(node) { if (!node.content.firstChild) { return []; } const tableWidths = []; node.content.firstChild.content.forEach(cell => { if (Array.isArray(cell.attrs.colwidth)) { const colspan = cell.attrs.colspan || 1; tableWidths.push(...cell.attrs.colwidth.slice(0, colspan)); } }); return tableWidths; } export const isTableNested = (state, tablePos = 0) => { const $tablePos = state.doc.resolve(tablePos); return $tablePos.depth > 0; }; export const isTableNestedInMoreThanOneNode = (state, tablePos = 0) => { return state.doc.resolve(tablePos).depth > 2; }; /** * True when the table sits under a bodiedSyncBlock ancestor. * Used to prefer DOM-measured wrapper width over getParentNodeWidth() for stable scaling. */ export const isTableNestedUnderBodiedSyncBlock = (state, tablePos) => { const bodiedSyncBlock = state.schema.nodes.bodiedSyncBlock; if (!bodiedSyncBlock) { return false; } const $pos = state.doc.resolve(tablePos); for (let d = $pos.depth; d > 0; d--) { if ($pos.node(d).type === bodiedSyncBlock) { return true; } } return false; }; const anyChildCellMergedAcrossRow = node => mapChildren(node, child => child.attrs.rowspan || 0).some(rowspan => rowspan > 1); const anyChildCellMergedAcrossColumn = node => mapChildren(node, child => child.attrs.colspan || 0).some(colspan => colspan > 1); /** * Check if a given node is a header row with this definition: * - all children are tableHeader cells * - no table cells have been merged with other table row cells (rowspan > 1) * - no table cells have been merged with other table column cells (colspan > 1), * (colspan check gated behind platform_editor_fix_sticky_header_malfunction) * * @param node ProseMirror node * @returns boolean if it meets definition */ export const supportedHeaderRow = node => { const allHeaders = mapChildren(node, child => child.type.name === 'tableHeader').every(Boolean); if (expValEquals('platform_editor_fix_sticky_header_malfunction', 'isEnabled', true)) { const someMergedAcrossRow = anyChildCellMergedAcrossRow(node); const someMergedAcrossColumn = anyChildCellMergedAcrossColumn(node); return allHeaders && !someMergedAcrossRow && !someMergedAcrossColumn; } const someMerged = anyChildCellMergedAcrossRow(node); return allHeaders && !someMerged; };