From ac847aa232c6e9d99867c11e4eb399bfdf0f4c34 Mon Sep 17 00:00:00 2001 From: Artem Nistuley Date: Fri, 18 Apr 2025 20:09:46 +0300 Subject: [PATCH] handle table colspan and colgroup --- .../assets/styles/elements/prosemirror.css | 2 +- .../src/core/super-converter/exporter.js | 31 ++++++++++++---- .../v2/importer/tableImporter.js | 30 ++++++++++++++-- .../table/tableHelpers/createColGroup.js | 6 +++- .../src/tests/data/table-merged-cells.docx | Bin 0 -> 13600 bytes .../export/export-helpers/export-helpers.js | 1 + .../src/tests/export/tableExporter.test.js | 25 +++++++++++++ .../src/tests/import/tableImporter.test.js | 34 ++++++++++++++++++ 8 files changed, 117 insertions(+), 12 deletions(-) create mode 100644 packages/super-editor/src/tests/data/table-merged-cells.docx create mode 100644 packages/super-editor/src/tests/export/tableExporter.test.js diff --git a/packages/super-editor/src/assets/styles/elements/prosemirror.css b/packages/super-editor/src/assets/styles/elements/prosemirror.css index 086d09f76b..8bace6caab 100644 --- a/packages/super-editor/src/assets/styles/elements/prosemirror.css +++ b/packages/super-editor/src/assets/styles/elements/prosemirror.css @@ -131,7 +131,7 @@ https://github.com/ProseMirror/prosemirror-tables/blob/master/demo/index.html .ProseMirror .tableWrapper { --table-border-width: 1px; - --offset: 1px; + --offset: 2px; overflow-x: auto; scrollbar-width: thin; diff --git a/packages/super-editor/src/core/super-converter/exporter.js b/packages/super-editor/src/core/super-converter/exporter.js index 0908c3e999..356abeae8b 100644 --- a/packages/super-editor/src/core/super-converter/exporter.js +++ b/packages/super-editor/src/core/super-converter/exporter.js @@ -18,6 +18,8 @@ import { TrackDeleteMarkName, TrackInsertMarkName, TrackFormatMarkName } from '@ import { carbonCopy } from '../utilities/carbonCopy.js'; import { baseBulletList, baseOrderedListDef } from './v2/exporter/helpers/base-list.definitions.js'; import { translateCommentNode } from './v2/exporter/commentsExporter.js'; +import { createColGroup } from '@extensions/table/tableHelpers/createColGroup.js'; + /** * @typedef {Object} ExportParams @@ -808,7 +810,7 @@ function translateTable(params) { params.node = preProcessVerticalMergeCells(params.node, params); const elements = translateChildNodes(params); const tableProperties = generateTableProperties(params.node); - const gridProperties = generateTableGrid(params.node); + const gridProperties = generateTableGrid(params.node, params); elements.unshift(tableProperties); elements.unshift(gridProperties); @@ -992,17 +994,32 @@ function generateTableBorders(node) { * @param {SchemaNode} node * @returns {XmlReadyNode} The table grid properties node */ -function generateTableGrid(node) { - const { gridColumnWidths } = node.attrs; - +function generateTableGrid(node, params) { + const { editorSchema } = params; + + let colgroup = []; + + try { + const pmNode = editorSchema.nodeFromJSON(node); + const cellMinWidth = 25; + const { colgroupValues } = createColGroup( + pmNode, + cellMinWidth, + ); + + colgroup = colgroupValues; + } catch(err) { + colgroup = []; + } + const elements = []; - gridColumnWidths?.forEach((width) => { + colgroup?.forEach((width) => { elements.push({ name: 'w:gridCol', - attributes: { 'w:w': inchesToTwips(width) }, + attributes: { 'w:w': pixelsToTwips(width) }, }); }); - + return { name: 'w:tblGrid', elements, diff --git a/packages/super-editor/src/core/super-converter/v2/importer/tableImporter.js b/packages/super-editor/src/core/super-converter/v2/importer/tableImporter.js index 67aefa6fa7..78b251b1df 100644 --- a/packages/super-editor/src/core/super-converter/v2/importer/tableImporter.js +++ b/packages/super-editor/src/core/super-converter/v2/importer/tableImporter.js @@ -118,6 +118,7 @@ export function handleTableCellNode( columnWidth = null, styleTag, params, + cellIndex, ) { const { docx, nodeListHandler } = params; const tcPr = node.elements.find((el) => el.name === 'w:tcPr'); @@ -159,10 +160,33 @@ export function handleTableCellNode( if (width) { attributes['colwidth'] = [width]; attributes['widthUnit'] = 'px'; + + const defaultColWidths = gridColumnWidths; + const hasDefaultColWidths = gridColumnWidths && gridColumnWidths.length > 0; + const colspanNum = parseInt(colspan, 10); + + if (colspanNum && colspanNum > 1 && hasDefaultColWidths) { + let colwidth = []; + + for (let i = 0; i < colspanNum; i++) { + let colwidthValue = defaultColWidths[cellIndex + i]; + let defaultColwidth = 100; + + if (typeof colwidthValue !== 'undefined') { + colwidth.push(colwidthValue); + } else { + colwidth.push(defaultColwidth); + } + } + + if (colwidth.length) { + attributes['colwidth'] = [...colwidth]; + } + } } if (widthType) attributes['widthType'] = widthType; - if (colspan) attributes['colspan'] = Number(colspan); + if (colspan) attributes['colspan'] = parseInt(colspan, 10); if (background) attributes['background'] = background; if (verticalAlign) attributes['verticalAlign'] = verticalAlign; if (fontSize) attributes['fontSize'] = fontSize; @@ -397,7 +421,7 @@ export function handleTableRowNode(node, table, rowBorders, styleTag, params) { const content = cellNodes?.map((n, index) => { const colWidth = cellNodes.length > 1 ? gridColumnWidths[index] : null; - return handleTableCellNode(n, node, table, borders, colWidth, styleTag, params); + return handleTableCellNode(n, node, table, borders, colWidth, styleTag, params, index); }) || []; const newNode = { @@ -448,6 +472,6 @@ const getGridColumnWidths = (tableNode) => { tblGrid?.elements?.flatMap((el) => { if (el.name !== 'w:gridCol') return []; return twipsToPixels(el.attributes['w:w']); - }) || {} + }) || [] ); }; diff --git a/packages/super-editor/src/extensions/table/tableHelpers/createColGroup.js b/packages/super-editor/src/extensions/table/tableHelpers/createColGroup.js index cd1a46c238..3e0d49277f 100644 --- a/packages/super-editor/src/extensions/table/tableHelpers/createColGroup.js +++ b/packages/super-editor/src/extensions/table/tableHelpers/createColGroup.js @@ -5,6 +5,7 @@ export const createColGroup = (node, cellMinWidth, overrideCol, overrideValue) = let fixedWidth = true; const cols = []; + const colsValues = []; const row = node.firstChild; if (!row) return {}; @@ -18,16 +19,19 @@ export const createColGroup = (node, cellMinWidth, overrideCol, overrideValue) = if (!hasWidth) fixedWidth = false; const [prop, value] = getColStyleDeclaration(cellMinWidth, hasWidth); cols.push(['col', { style: `${prop}: ${value}` }]); + colsValues.push(parseInt(value, 10)); } } const tableWidth = fixedWidth ? `${totalWidth}px` : ''; const tableMinWidth = fixedWidth ? '' : `${totalWidth}px`; const colgroup = ['colgroup', {}, ...cols]; + const colgroupValues = [...colsValues]; return { colgroup, tableWidth, - tableMinWidth, + tableMinWidth, + colgroupValues, }; }; diff --git a/packages/super-editor/src/tests/data/table-merged-cells.docx b/packages/super-editor/src/tests/data/table-merged-cells.docx new file mode 100644 index 0000000000000000000000000000000000000000..86f3f26fdec384c80ae359221093f8175fbefc84 GIT binary patch literal 13600 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 An*aa+ literal 0 HcmV?d00001 diff --git a/packages/super-editor/src/tests/export/export-helpers/export-helpers.js b/packages/super-editor/src/tests/export/export-helpers/export-helpers.js index d2e6d4e3a3..e917af00a6 100644 --- a/packages/super-editor/src/tests/export/export-helpers/export-helpers.js +++ b/packages/super-editor/src/tests/export/export-helpers/export-helpers.js @@ -74,6 +74,7 @@ export const getExportedResult = async (name, comments = []) => { const commentDefinitions = processedComments.map((c, index) => getCommentDefinition(c, index)); const [result, params] = exportSchemaToJson({ + editorSchema: editor.schema, node: schema, bodyNode, relationships: [], diff --git a/packages/super-editor/src/tests/export/tableExporter.test.js b/packages/super-editor/src/tests/export/tableExporter.test.js new file mode 100644 index 0000000000..10e9f4b93b --- /dev/null +++ b/packages/super-editor/src/tests/export/tableExporter.test.js @@ -0,0 +1,25 @@ +import { getExportedResult } from './export-helpers/index.js'; +import { twipsToPixels } from '../../core/super-converter/helpers.js'; + +describe('test table export', async () => { + const fileName = 'table-merged-cells.docx'; + const result = await getExportedResult(fileName); + + const body = {}; + + beforeEach(() => { + Object.assign(body, result.elements?.find((el) => el.name === 'w:body')); + }); + + it('correctly gets w:tblGrid', () => { + const tableGrid = body.elements[0].elements[0].elements; + + const gridCol1 = twipsToPixels(tableGrid[0].attributes['w:w']); + const gridCol2 = twipsToPixels(tableGrid[1].attributes['w:w']); + const gridCol3 = twipsToPixels(tableGrid[2].attributes['w:w']); + + expect(gridCol1).toBe(94); + expect(gridCol2).toBe(331); + expect(gridCol3).toBe(176); + }); +}); diff --git a/packages/super-editor/src/tests/import/tableImporter.test.js b/packages/super-editor/src/tests/import/tableImporter.test.js index 099db470ff..e59dd3adc9 100644 --- a/packages/super-editor/src/tests/import/tableImporter.test.js +++ b/packages/super-editor/src/tests/import/tableImporter.test.js @@ -3,6 +3,7 @@ import { handleTrackChangeNode } from '@converter/v2/importer/trackChangesImport import { defaultNodeListHandler } from '@converter/v2/importer/docxImporter.js'; import { TrackInsertMarkName } from '@extensions/track-changes/constants.js'; import { handleAllTableNodes } from '@converter/v2/importer/tableImporter.js'; +import { getTestDataByFileName } from '@tests/helpers/helpers.js'; describe('table live xml test', () => { const simpleTableStyleXml = ``; @@ -200,3 +201,36 @@ describe('table live xml test', () => { expect(result.nodes[0].content[0].content[0].attrs.cellMargins.right).toBe(8); }); }); + +describe('table tests to check colwidth', () => { + + it('correctly gets colwidth for horizontally merged cells', async () => { + const dataName = 'table-merged-cells.docx'; + const docx = await getTestDataByFileName(dataName); + const documentXml = docx['word/document.xml']; + + const doc = documentXml.elements[0]; + const body = doc.elements[0]; + const content = body.elements; + + const result = handleAllTableNodes({ nodes: [content[0]], docx, nodeListHandler: defaultNodeListHandler() }); + const node = result.nodes[0]; + + expect(node.type).toBe('table'); + + const tr1 = node.content[0]; + const tr2 = node.content[1]; + const tr3 = node.content[2]; + + expect(tr1.content[0].attrs.colspan).toBe(2); + expect(tr1.content[0].attrs.colwidth).toEqual([94, 331]); + expect(tr1.content[1].attrs.colwidth).toEqual([176]) + + expect(tr2.content[0].attrs.colwidth).toEqual([94]); + expect(tr2.content[1].attrs.colwidth).toEqual([331]); + expect(tr2.content[2].attrs.colwidth).toEqual([176]); + + expect(tr3.content[0].attrs.colspan).toBe(3); + expect(tr3.content[0].attrs.colwidth).toEqual([94, 331, 176]); + }); +});