UNPKG

@atlaskit/editor-plugin-table

Version:

Table plugin for the @atlaskit/editor

195 lines (187 loc) 8.3 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.removeExtraneousColumnWidths = exports.fixTables = exports.fixAutoSizedTable = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _styles = require("@atlaskit/editor-common/styles"); var _editorSharedStyles = require("@atlaskit/editor-shared-styles"); var _columnState = require("../table-resizing/utils/column-state"); var _contentWidth = require("../table-resizing/utils/content-width"); var _misc = require("../table-resizing/utils/misc"); function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } var validateTableCellNodeAttrs = function validateTableCellNodeAttrs(_ref, reportInvalidTableCellSpanAttrs) { var colspan = _ref.colspan, rowspan = _ref.rowspan, tableLocalId = _ref.tableLocalId; if (colspan && colspan < 0) { reportInvalidTableCellSpanAttrs({ nodeType: 'tableCell', attribute: 'colspan', reason: 'negative value', tableLocalId: tableLocalId, spanValue: colspan }); } if (rowspan && rowspan < 0) { reportInvalidTableCellSpanAttrs({ nodeType: 'tableCell', attribute: 'rowspan', reason: 'negative value', tableLocalId: tableLocalId, spanValue: rowspan }); } return; }; // We attempt to patch the document when we have extra, unneeded, column widths // Take this node for example: // // ['td', { colwidth: [100, 100, 100], colspan: 2 }] // // This row only spans two columns, yet it contains widths for 3. // We remove the third width here, assumed duplicate content. var removeExtraneousColumnWidths = exports.removeExtraneousColumnWidths = function removeExtraneousColumnWidths(node, basePos, tr, reportInvalidTableCellSpanAttrs) { var hasProblems = false; tr = replaceCells(tr, node, basePos, function (cell) { var _cell$attrs = cell.attrs, colwidth = _cell$attrs.colwidth, colspan = _cell$attrs.colspan, rowspan = _cell$attrs.rowspan; if (reportInvalidTableCellSpanAttrs) { validateTableCellNodeAttrs({ colspan: colspan, rowspan: rowspan, tableLocalId: node.attrs.localId }, reportInvalidTableCellSpanAttrs); } if (colwidth && colwidth.length > colspan) { hasProblems = true; return cell.type.createChecked(_objectSpread(_objectSpread({}, cell.attrs), {}, { colwidth: colwidth.slice(0, colspan) }), cell.content, cell.marks); } return cell; }); if (hasProblems) { return true; } return false; }; var fixTables = exports.fixTables = function fixTables(tr, reportInvalidTableCellSpanAttrs) { var hasProblems = false; tr.doc.descendants(function (node, pos) { if (node.type.name === 'table') { // in the unlikely event of having to fix multiple tables at the same time hasProblems = removeExtraneousColumnWidths(node, tr.mapping.map(pos), tr, reportInvalidTableCellSpanAttrs); } }); if (hasProblems) { return tr; } }; // When we get a table with an 'auto' attribute, we want to: // 1. render with table-layout: auto // 2. capture the column widths // 3. set the column widths as attributes, and remove the 'auto' attribute, // so the table renders the same, but is now fixed-width // // This can be used to migrate table appearances from other sources that are // usually rendered with 'auto'. // // We use this when migrating TinyMCE tables for Confluence, for example: // https://pug.jira-dev.com/wiki/spaces/AEC/pages/3362882215/How+do+we+map+TinyMCE+tables+to+Fabric+tables var fixAutoSizedTable = exports.fixAutoSizedTable = function fixAutoSizedTable(view, tableNode, tableRef, tablePos, opts) { var tr = view.state.tr; var domAtPos = view.domAtPos.bind(view); var tableStart = tablePos + 1; var colWidths = parseDOMColumnWidths(domAtPos, tableNode, tableStart, tableRef); var totalContentWidth = colWidths.reduce(function (acc, current) { return acc + current; }, 0); var tableLayout = getLayoutBasedOnWidth(totalContentWidth); var maxLayoutSize = (0, _misc.getLayoutSize)(tableLayout, opts.containerWidth, {}); // Content width will generally not meet the constraints of the layout // whether it be below or above, so we scale our columns widths // to meet these requirements var scale = 1; if (totalContentWidth !== maxLayoutSize) { scale = maxLayoutSize / totalContentWidth; } var scaledColumnWidths = colWidths.map(function (width) { return Math.floor(width * scale); }); tr = replaceCells(tr, tableNode, tablePos, function (cell, _rowIndex, colIndex) { var newColWidths = scaledColumnWidths.slice(colIndex, colIndex + cell.attrs.colspan); return cell.type.createChecked(_objectSpread(_objectSpread({}, cell.attrs), {}, { colwidth: newColWidths.length ? newColWidths : null }), cell.content, cell.marks); }); // clear autosizing on the table node return tr.setNodeMarkup(tablePos, undefined, _objectSpread(_objectSpread({}, tableNode.attrs), {}, { layout: tableLayout, __autoSize: false })).setMeta('addToHistory', false); }; var getLayoutBasedOnWidth = function getLayoutBasedOnWidth(totalWidth) { if (totalWidth > _editorSharedStyles.akEditorWideLayoutWidth) { return 'full-width'; } else if (totalWidth > _editorSharedStyles.akEditorDefaultLayoutWidth && totalWidth < _editorSharedStyles.akEditorWideLayoutWidth) { return 'wide'; } else { return 'default'; } }; function parseDOMColumnWidths(domAtPos, tableNode, tableStart, tableRef) { var row = tableRef.querySelector('tr'); if (!row) { return []; } var cols = []; for (var col = 0; col < row.childElementCount; col++) { var currentCol = row.children[col]; var colspan = Number(currentCol.getAttribute('colspan') || 1); for (var span = 0; span < colspan; span++) { var colIdx = col + span; var cells = (0, _columnState.getCellsRefsInColumn)(colIdx, tableNode, tableStart, domAtPos); var colWidth = (0, _columnState.calculateColumnWidth)(cells, function (_, col) { // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting return (0, _contentWidth.contentWidth)(col, tableRef).width; }); cols[colIdx] = Math.max(colWidth, _styles.tableCellMinWidth); } } return cols; } // TODO: ED-26961 - move to prosemirror-utils var replaceCells = function replaceCells(tr, table, tablePos, modifyCell) { var rows = []; var modifiedCells = 0; for (var rowIndex = 0; rowIndex < table.childCount; rowIndex++) { var row = table.child(rowIndex); var cells = []; for (var colIndex = 0; colIndex < row.childCount; colIndex++) { var cell = row.child(colIndex); // TODO: ED-26961 - The rowIndex and colIndex are not accurate in a merged cell scenario // e.g. table with 5 columns might have only one cell in a row, colIndex will be 1, where it should be 4 var node = modifyCell(cell, rowIndex, colIndex); if (node.sameMarkup(cell) === false) { modifiedCells++; } cells.push(node); } if (cells.length) { rows.push(row.type.createChecked(row.attrs, cells, row.marks)); } } // Check if the table has changed before replacing. // If no cells are modified our counter will be zero. if (rows.length && modifiedCells !== 0) { var newTable = table.type.createChecked(table.attrs, rows, table.marks); return tr.replaceWith(tablePos, tablePos + table.nodeSize, newTable); } return tr; };