@atlaskit/editor-plugin-table
Version:
Table plugin for the @atlaskit/editor
107 lines (106 loc) • 4.17 kB
JavaScript
import { mapChildren } from '@atlaskit/editor-common/utils';
import { TableMap } from '@atlaskit/editor-tables/table-map';
import { findTable } from '@atlaskit/editor-tables/utils';
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 (e) {
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 parent = state.doc.resolve(tablePos).parent;
const nodeTypes = state.schema.nodes;
return parent.type === nodeTypes.layoutColumn || parent.type === nodeTypes.expand || parent.type === nodeTypes.bodiedExtension || parent.type === nodeTypes.extensionFrame || parent.type === nodeTypes.tableHeader || parent.type === nodeTypes.tableCell;
};
export const isTableNestedInMoreThanOneNode = (state, tablePos = 0) => {
return state.doc.resolve(tablePos).depth > 2;
};
const anyChildCellMergedAcrossRow = node => mapChildren(node, child => child.attrs.rowspan || 0).some(rowspan => rowspan > 1);
/**
* Check if a given node is a header row with this definition:
* - all children are tableHeader cells
* - no table cells have been have merged with other table row cells
*
* @param node ProseMirror node
* @return boolean if it meets definition
*/
export const supportedHeaderRow = node => {
const allHeaders = mapChildren(node, child => child.type.name === 'tableHeader').every(Boolean);
const someMerged = anyChildCellMergedAcrossRow(node);
return allHeaders && !someMerged;
};