diff --git a/src/documentContext.js b/src/documentContext.js index 2f0d2f4a0..3f5bf082d 100644 --- a/src/documentContext.js +++ b/src/documentContext.js @@ -28,7 +28,7 @@ function DocumentContext(pageSize, pageMargins) { this.addPage(pageSize); } -DocumentContext.prototype.beginColumnGroup = function () { +DocumentContext.prototype.beginColumnGroup = function ({ type }) { this.snapshots.push({ x: this.x, y: this.y, @@ -43,7 +43,8 @@ DocumentContext.prototype.beginColumnGroup = function () { page: this.page }, endingCell: this.endingCell, - lastColumnWidth: this.lastColumnWidth + lastColumnWidth: this.lastColumnWidth, + type, }); this.lastColumnWidth = 0; @@ -95,7 +96,6 @@ DocumentContext.prototype.saveContextInEndingCell = function (endingCell) { DocumentContext.prototype.completeColumnGroup = function (height) { var saved = this.snapshots.pop(); - if (saved.overflowed) this.snapshots.pop(); this.calculateBottomMost(saved); @@ -226,55 +226,87 @@ var getPageSize = function (currentPage, newPageOrientation) { // FIXME: Complete the function // Write a moveToNextColumn method that will move to the next column in the current page, or the first column of the next page if the current page is full DocumentContext.prototype.moveToNextColumn = function () { + + const pageSnapshot = this.pageSnapshot(); + const currentSnapshot = this.snapshots[this.snapshots.length - 1]; + const isTable = currentSnapshot.type == 'table'; + let tableWidth; + let tableOffset; + if (isTable) { + tableWidth = this.availableWidth; + // TODO: default offset must be replace with set value + tableOffset = 5 + this.completeColumnGroup(); + } + const pageAvailableWidth = pageSnapshot.availableWidth; + const nextColumnWidth = this.x + this.availableWidth; + const pageOverflow = nextColumnWidth > pageAvailableWidth + if (pageOverflow) { + if (isTable) { + this.beginColumnGroup({ type: 'table' }); + this.beginColumn(tableWidth, tableOffset, this.endingCell); + } + return false + }; + var prevY = this.y; + var prevX = this.x; - var newSnapshots = this.snapshots.flatMap((originalSnapshot, i, allSnapshots) => { - //if (i === 0) return [originalSnapshot]; - - var newSnapshot = Object.assign({}, originalSnapshot); - newSnapshot.overflowed = true; // IMPORTANT - - // FIXME: Calculate "x" and "availableWidth" properly - //newSnapshot.x += this.availableWidth - this.pageMargins.left; // for basic text - newSnapshot.x += originalSnapshot.availableWidth; // for tables - newSnapshot.y = allSnapshots[0].y; // 40 or 43 ??? - newSnapshot.page = originalSnapshot.page; - newSnapshot.availableHeight = allSnapshots[0].availableHeight; // -6 - newSnapshot.availableWidth = this.availableWidth; - - newSnapshot.bottomMost = { - x: newSnapshot.x, - y: newSnapshot.y, - page: newSnapshot.page, - availableHeight: newSnapshot.availableHeight, - availableWidth5: newSnapshot.availableWidth, - }; - newSnapshot.endingCell = originalSnapshot.endingCell; - newSnapshot.lastColumnWidth = originalSnapshot.lastColumnWidth; // Flexible width? + this.beginColumn(this.availableWidth, undefined, this.endingCell) + + if (isTable) { + this.beginColumnGroup({ type: 'table' }); + this.beginColumn(tableWidth, tableOffset, this.endingCell); + } + + // var newSnapshots = this.snapshots.flatMap((originalSnapshot, i, allSnapshots) => { + // //if (i === 0) return [originalSnapshot]; + + // var newSnapshot = Object.assign({}, originalSnapshot); + // newSnapshot.overflowed = true; // IMPORTANT + + // // FIXME: Calculate "x" and "availableWidth" properly + // //newSnapshot.x += this.availableWidth - this.pageMargins.left; // for basic text + // newSnapshot.x += originalSnapshot.availableWidth; // for tables + // newSnapshot.y = allSnapshots[0].y; // 40 or 43 ??? + // newSnapshot.page = originalSnapshot.page; + // newSnapshot.availableHeight = allSnapshots[0].availableHeight; // -6 + // newSnapshot.availableWidth = this.availableWidth; + + // newSnapshot.bottomMost = { + // x: newSnapshot.x, + // y: newSnapshot.y, + // page: newSnapshot.page, + // availableHeight: newSnapshot.availableHeight, + // availableWidth5: newSnapshot.availableWidth, + // }; + // newSnapshot.endingCell = originalSnapshot.endingCell; + // newSnapshot.lastColumnWidth = originalSnapshot.lastColumnWidth; // Flexible width? + + // return [originalSnapshot, newSnapshot]; + // }); + + // this.snapshots = newSnapshots; + + // // FIXME: Replace hardcoded values with proper variables + // var yOffset = 0; // 0 for text, 3 for tables, -5 for tables with repeatble headers + // var colLeftOffset = 0; // default = 0 for tables, 5 in LayoutBuilder + + // this.x += this.snapshots.at(-1).x + colLeftOffset; + // this.y = this.snapshots.at(-1).y + yOffset; + // //this.page = this.snapshots.at(-1).page; + // this.availableHeight = this.snapshots.at(-1).availableHeight - (yOffset * 2); + // this.availableWidth = this.snapshots.at(-1).availableWidth; + // //this.lastColumnWidth = this.snapshots.at(-1).lastColumnWidth; + // //this.endingCell = this.snapshots.at(-1).endingCell; - return [originalSnapshot, newSnapshot]; - }); - - this.snapshots = newSnapshots; - - // FIXME: Replace hardcoded values with proper variables - var yOffset = 0; // 0 for text, 3 for tables, -5 for tables with repeatble headers - var colLeftOffset = 0; // default = 0 for tables, 5 in LayoutBuilder - - this.x += this.snapshots.at(-1).x + colLeftOffset; - this.y = this.snapshots.at(-1).y + yOffset; - //this.page = this.snapshots.at(-1).page; - this.availableHeight = this.snapshots.at(-1).availableHeight - (yOffset * 2); - this.availableWidth = this.snapshots.at(-1).availableWidth; - //this.lastColumnWidth = this.snapshots.at(-1).lastColumnWidth; - //this.endingCell = this.snapshots.at(-1).endingCell; - return { - containerX: this.snapshots.at(-1).x, - containerY: this.snapshots.at(-1).y, + containerX: pageSnapshot.x, + containerY: pageSnapshot.y, contentX: this.x, contentY: this.y, prevY: prevY, + prevX: prevX, }; }; diff --git a/src/layoutBuilder.js b/src/layoutBuilder.js index c7e44ed2e..0dbb1a6c5 100644 --- a/src/layoutBuilder.js +++ b/src/layoutBuilder.js @@ -516,11 +516,16 @@ LayoutBuilder.prototype.processRow = function (columns, widths, gaps, tableBody, var pageBreaks = [], columnBreaks = [], positions = []; // FIXME: Currently the `TraversalTracker.auto` method only supports ONE event and ONE callback, maybe expand to add support for multiple events and callbacks - //this.tracker.auto('pageChanged', storePageBreakData, function () { - this.tracker.auto('columnChanged', storeColumnBreakData, function () { + // this.tracker.auto('pageChanged', storePageBreakData, newFuncProcess); + this.tracker.auto('columnChanged', storeColumnBreakData, newFuncProcess); + + return { pageBreaks: pageBreaks, positions: positions, columnBreaks: columnBreaks }; + + function newFuncProcess() { widths = widths || columns; - self.writer.context().beginColumnGroup(); + const columnType = tableBody ? 'table' : 'column'; + self.writer.context().beginColumnGroup({ type: columnType }); for (var i = 0, l = columns.length; i < l; i++) { var column = columns[i]; @@ -544,9 +549,7 @@ LayoutBuilder.prototype.processRow = function (columns, widths, gaps, tableBody, } self.writer.context().completeColumnGroup(height); - }); - - return { pageBreaks: pageBreaks, positions: positions, columnBreaks: columnBreaks }; + } function storeColumnBreakData(data) { columnBreaks.push(data); diff --git a/src/pageElementWriter.js b/src/pageElementWriter.js index b4a9665e9..a61d80926 100644 --- a/src/pageElementWriter.js +++ b/src/pageElementWriter.js @@ -21,39 +21,81 @@ function PageElementWriter(context, tracker) { function fitOnPage(self, addFct) { var position = addFct(self); + const sneakyColumn = true; if (!position) { - // TODO: Swap the hardcoded boolean check below with an option flag inside columns - // eslint-disable-next-line no-constant-condition - if (true) { - if (!self.writer.context.snapshots.at(-1).overflowed) { + if (sneakyColumn) { + const nextColumn = self.moveToNextColumn(); + if (nextColumn === false) { + const context = self.writer.context; + // TODO: offset have to calculate from page snapshot, if offset set in + // document definition column then in new column don't be applied. + const offset = undefined; + + const currentSnapshot = context.snapshots[context.snapshots.length - 1]; + const isTable = currentSnapshot.type == 'table'; + let tableWidth; + let tableOffset; + if (isTable) { + tableWidth = context.availableWidth; + tableOffset = 5 + context.completeColumnGroup(); + } + + const columnWidth = context.availableWidth; + const endingCell = context.endingCell; - // BUG: Only works with table columns - self.moveToNextColumn(); + context.completeColumnGroup(); + self.moveToNextPage(); + context.beginColumnGroup({ type: 'column' }); + context.beginColumn(columnWidth, offset, endingCell); + if (isTable) { + context.beginColumnGroup({ type: 'table' }); + context.beginColumn(tableWidth, tableOffset, endingCell); + } position = addFct(self); } else { position = addFct(self); } - } - - - if (!position) { - while (self.writer.context.snapshots.at(-1).overflowed) { - var popped = self.writer.context.snapshots.pop(); - - var snap = self.writer.context.snapshots.at(-1); - self.writer.context.x = snap.x; - self.writer.context.y = snap.y; - self.writer.context.availableHeight = snap.availableHeight; - self.writer.context.availableWidth = popped.availableWidth; - self.writer.context.lastColumnWidth = snap.lastColumnWidth; - self.writer.context.endingCell = snap.endingCell; - //self.writer.context.page = snap.page; - } + } else { self.moveToNextPage(); position = addFct(self); } } + + // if (!position) { + // // TODO: Swap the hardcoded boolean check below with an option flag inside columns + // // eslint-disable-next-line no-constant-condition + // if (false) { + // if (!self.writer.context.snapshots.at(-1).overflowed) { + + // // BUG: Only works with table columns + // self.moveToNextColumn(); + + // position = addFct(self); + // } else { + // position = addFct(self); + // } + // } + + + // if (!position) { + // // while (self.writer.context.snapshots.at(-1).overflowed) { + // // var popped = self.writer.context.snapshots.pop(); + + // // var snap = self.writer.context.snapshots.at(-1); + // // self.writer.context.x = snap.x; + // // self.writer.context.y = snap.y; + // // self.writer.context.availableHeight = snap.availableHeight; + // // self.writer.context.availableWidth = popped.availableWidth; + // // self.writer.context.lastColumnWidth = snap.lastColumnWidth; + // // self.writer.context.endingCell = snap.endingCell; + // // //self.writer.context.page = snap.page; + // // } + // self.moveToNextPage(); + // position = addFct(self); + // } + // } return position; } @@ -105,21 +147,23 @@ PageElementWriter.prototype.addFragment = function (fragment, useBlockXOffset, u }; PageElementWriter.prototype.moveToNextColumn = function () { - var nextColumn = this.writer.context.moveToNextColumn(); - this.repeatables.forEach(function (rep) { - rep.xOffset = nextColumn.containerX; - rep.yOffset = nextColumn.containerY; - // FIXME: This number is currently set based on limited trial and error. Try to set it dynamically. - rep.height -= 1; - if (isUndefined(rep.insertedOnPages[this.writer.context.page])) { - // FIXME: Make sure the line below can be removed safely without affecting the functionality of repeatables such as table header rows. - //rep.insertedOnPages[this.writer.context.page] = true; - this.writer.addFragment(rep, true, true); - } else { - this.writer.context.moveDown(rep.height); - } - }, this); + var nextColumn = this.writer.context.moveToNextColumn(); + if (nextColumn == false) return nextColumn; + + // this.repeatables.forEach(function (rep) { + // rep.xOffset = nextColumn.containerX; + // rep.yOffset = nextColumn.containerY; + // // FIXME: This number is currently set based on limited trial and error. Try to set it dynamically. + // rep.height -= 1; + // if (isUndefined(rep.insertedOnPages[this.writer.context.page])) { + // // FIXME: Make sure the line below can be removed safely without affecting the functionality of repeatables such as table header rows. + // //rep.insertedOnPages[this.writer.context.page] = true; + // this.writer.addFragment(rep, true, true); + // } else { + // this.writer.context.moveDown(rep.height); + // } + // }, this); this.writer.tracker.emit('columnChanged', { containerX: nextColumn.containerX, @@ -127,6 +171,7 @@ PageElementWriter.prototype.moveToNextColumn = function () { contentX: nextColumn.contentX, contentY: nextColumn.contentY, prevY: nextColumn.prevY, + prevX: nextColumn.prevX, }); }; diff --git a/src/tableProcessor.js b/src/tableProcessor.js index 4ad093f92..380c69879 100644 --- a/src/tableProcessor.js +++ b/src/tableProcessor.js @@ -135,6 +135,7 @@ TableProcessor.prototype.beginRow = function (rowIndex, writer) { this.rowCallback = this.onRowBreak(rowIndex, writer); writer.tracker.startTracking('pageChanged', this.rowCallback); + writer.tracker.startTracking('columnChanged', this.rowCallback); if (this.dontBreakRows) { writer.beginUnbreakableBlock(); } @@ -341,6 +342,7 @@ TableProcessor.prototype.endRow = function (rowIndex, writer, pageBreaks, column var l, i; var self = this; writer.tracker.stopTracking('pageChanged', this.rowCallback); + writer.tracker.stopTracking('columnChanged', this.rowCallback); writer.context().moveDown(this.layout.paddingBottom(rowIndex, this.tableNode)); writer.context().availableHeight += this.reservedAtBottom; @@ -362,7 +364,7 @@ TableProcessor.prototype.endRow = function (rowIndex, writer, pageBreaks, column if (hasColumnBreaks) { ys[ys.length - 1].y1 = columnBreaks[0].prevY; - ys.push({ y0: columnBreaks[0][this.headerRows > 0 ? 'contentY' : 'containerY'], page: ys[0].page }); + ys.push({ y0: columnBreaks[0].contentY, page: ys[0].page }); } if (hasPageBreaks) {