From aff4a142653f7d2d7773e28177f38277b7ec8d05 Mon Sep 17 00:00:00 2001 From: fe-cj <109814122+fe-cj@users.noreply.github.com> Date: Thu, 5 Sep 2024 08:58:58 +0200 Subject: [PATCH] Fixes issue #1042 (#2778) * Fixes issue #1042 * Fixes unit tests that broke after last commit --------- Co-authored-by: fe-cj --- src/DocumentContext.js | 4 ++-- src/LayoutBuilder.js | 26 ++++++++++++++++++++++---- tests/unit/LayoutBuilder.spec.js | 14 +++++++------- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/DocumentContext.js b/src/DocumentContext.js index 364b0328b..03e2024c5 100644 --- a/src/DocumentContext.js +++ b/src/DocumentContext.js @@ -65,10 +65,10 @@ class DocumentContext extends EventEmitter { } } - markEnding(endingCell, originalXOffset) { + markEnding(endingCell, originalXOffset, discountY) { this.page = endingCell._columnEndingContext.page; this.x = endingCell._columnEndingContext.x + originalXOffset; - this.y = endingCell._columnEndingContext.y; + this.y = endingCell._columnEndingContext.y - discountY; this.availableWidth = endingCell._columnEndingContext.availableWidth; this.availableHeight = endingCell._columnEndingContext.availableHeight; this.lastColumnWidth = endingCell._columnEndingContext.lastColumnWidth; diff --git a/src/LayoutBuilder.js b/src/LayoutBuilder.js index af5e5dd98..05b571d34 100644 --- a/src/LayoutBuilder.js +++ b/src/LayoutBuilder.js @@ -476,7 +476,7 @@ class LayoutBuilder { } ColumnCalculator.buildColumnWidths(columns, availableWidth); - let result = this.processRow(columns, columns, gaps); + let result = this.processRow(false, columns, columns, gaps); addAll(columnNode.positions, result.positions); function gapArray(gap) { @@ -510,7 +510,7 @@ class LayoutBuilder { return null; } - processRow(columns, widths, gaps, tableBody, tableRow, height) { + processRow(dontBreakRows, columns, widths, gaps, tableBody, tableRow, height) { const updatePageBreakData = (page, prevY) => { let pageDesc; // Find page break data for this row and page @@ -571,6 +571,7 @@ class LayoutBuilder { if (endingCell) { // We store a reference of the ending cell in the first cell of the rowspan column._endingCell = endingCell; + column._endingCell._startingRowSpanY = column._startingRowSpanY; } // Check if exists and retrieve the cell that started the rowspan in case we are in the cell just after @@ -588,10 +589,17 @@ class LayoutBuilder { // We pass the endingSpanCell reference to store the context just after processing rowspan cell this.writer.context().beginColumn(width, leftOffset, endingSpanCell); + if (!column._span) { this.processNode(column); addAll(positions, column.positions); } else if (column._columnEndingContext) { + let discountY = 0; + if (dontBreakRows) { + // Calculate how many points we have to discount to Y when dontBreakRows and rowSpan are combined + const ctxBeforeRowSpanLastRow = this.writer.contextStack[this.writer.contextStack.length - 1]; + discountY = ctxBeforeRowSpanLastRow.y - column._startingRowSpanY; + } let originalXOffset = 0; // If context was saved from an unbreakable block and we are not in an unbreakable block anymore // We have to sum the originalX (X before starting unbreakable block) to X @@ -600,7 +608,7 @@ class LayoutBuilder { } // row-span ending // Recover the context after processing the rowspanned cell - this.writer.context().markEnding(column, originalXOffset); + this.writer.context().markEnding(column, originalXOffset, discountY); } } @@ -708,6 +716,16 @@ class LayoutBuilder { let rowHeights = tableNode.table.heights; for (let i = 0, l = tableNode.table.body.length; i < l; i++) { + // if dontBreakRows and row starts a rowspan + // we store the 'y' of the beginning of each rowSpan + if (processor.dontBreakRows) { + tableNode.table.body[i].forEach(cell => { + if (cell.rowSpan && cell.rowSpan > 1) { + cell._startingRowSpanY = this.writer.context().y; + } + }); + } + processor.beginRow(i, this.writer); let height; @@ -723,7 +741,7 @@ class LayoutBuilder { height = undefined; } - let result = this.processRow(tableNode.table.body[i], tableNode.table.widths, tableNode._offsets.offsets, tableNode.table.body, i, height); + let result = this.processRow(processor.dontBreakRows, tableNode.table.body[i], tableNode.table.widths, tableNode._offsets.offsets, tableNode.table.body, i, height); addAll(tableNode.positions, result.positions); processor.endRow(i, this.writer, result.pageBreaks); diff --git a/tests/unit/LayoutBuilder.spec.js b/tests/unit/LayoutBuilder.spec.js index 542b0f51b..13b0e71cc 100644 --- a/tests/unit/LayoutBuilder.spec.js +++ b/tests/unit/LayoutBuilder.spec.js @@ -1679,7 +1679,7 @@ describe('LayoutBuilder', function () { it('should return an empty array if no page breaks occur', function () { var doc = createTable(1, 0); - var result = builder2.processRow(doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0); + var result = builder2.processRow(false, doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0); assert(result.pageBreaks instanceof Array); assert.equal(result.pageBreaks.length, 0); @@ -1687,7 +1687,7 @@ describe('LayoutBuilder', function () { it('on page break should return an entry with ending/starting positions', function () { var doc = createTable(0, 1, 10, 5, 5); - var result = builder2.processRow(doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0); + var result = builder2.processRow(false, doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0); assert(result.pageBreaks instanceof Array); assert.equal(result.pageBreaks.length, 1); @@ -1697,7 +1697,7 @@ describe('LayoutBuilder', function () { it('on page break should return an entry with ending/starting positions 2', function () { var doc = createTable(0, 1, 10, 5); - var result = builder2.processRow(doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0); + var result = builder2.processRow(false, doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0); assert(result.pageBreaks instanceof Array); assert.equal(result.pageBreaks.length, 1); @@ -1708,14 +1708,14 @@ describe('LayoutBuilder', function () { it('on multi-pass page break (columns or table columns) should treat bottom-most page-break as the ending position ', function () { var doc = createTable(0, 1, 10, 5, 7); - var result = builder2.processRow(doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0); + var result = builder2.processRow(false, doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0); assert.equal(result.pageBreaks[0].prevY, 40 + 12 * 7); }); it('on multiple page breaks (more than 2 pages), should return all entries with ending/starting positions', function () { var doc = createTable(0, 1, 100, 90, 90); - var result = builder2.processRow(doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0); + var result = builder2.processRow(false, doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0); assert(result.pageBreaks instanceof Array); assert.equal(result.pageBreaks.length, 2); @@ -1727,7 +1727,7 @@ describe('LayoutBuilder', function () { it('on multiple page breaks (more than 2 pages), should return all entries with ending/starting positions 2', function () { var doc = createTable(0, 1, 100, 90); - var result = builder2.processRow(doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0); + var result = builder2.processRow(false, doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0); assert(result.pageBreaks instanceof Array); assert.equal(result.pageBreaks.length, 2); @@ -1739,7 +1739,7 @@ describe('LayoutBuilder', function () { it('on multiple and multi-pass page breaks should calculate bottom-most endings for every page', function () { var doc = createTable(0, 1, 100, 90, 92); - var result = builder2.processRow(doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0); + var result = builder2.processRow(false, doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0); assert(result.pageBreaks instanceof Array); assert.equal(result.pageBreaks.length, 2);