@flowaccount/pdfmake 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -310,6 +310,72 @@ TableProcessor.prototype.drawHorizontalLine = function (lineIndex, writer, overr
310
310
  }
311
311
  };
312
312
 
313
+
314
+ /**
315
+ * Draws vertical lines to fill the gap when a row is forced to the next page.
316
+ * This prevents missing vertical lines at the bottom of the page.
317
+ * @param {number} rowIndex - The index of the row being forced to next page
318
+ * @param {object} writer - The document writer
319
+ * @param {number} y0 - Starting Y position
320
+ * @param {number} y1 - Ending Y position (page break point)
321
+ */
322
+ TableProcessor.prototype.drawVerticalLinesForForcedPageBreak = function (rowIndex, writer, y0, y1) {
323
+ if (!this.rowSpanData || rowIndex <= 0) {
324
+ return;
325
+ }
326
+
327
+ var body = this.tableNode.table.body;
328
+ var prevRowIndex = rowIndex - 1; // Use previous row for cell border detection
329
+
330
+ // Get X positions for vertical lines (similar logic to endRow's getLineXs)
331
+ var xs = [];
332
+ var cols = 0;
333
+
334
+ for (var i = 0, l = body[prevRowIndex].length; i < l; i++) {
335
+ if (!cols) {
336
+ xs.push({ x: this.rowSpanData[i].left, index: i });
337
+ var item = body[prevRowIndex][i];
338
+ cols = (item._colSpan || item.colSpan || 0);
339
+ }
340
+ if (cols > 0) {
341
+ cols--;
342
+ }
343
+ }
344
+ xs.push({ x: this.rowSpanData[this.rowSpanData.length - 1].left, index: this.rowSpanData.length - 1 });
345
+
346
+ // Draw vertical lines for each column position
347
+ for (var xi = 0, xl = xs.length; xi < xl; xi++) {
348
+ var leftCellBorder = false;
349
+ var colIndex = xs[xi].index;
350
+
351
+ // Check if we need to draw a vertical line at this position
352
+ // based on cell borders from the previous row
353
+ var cell;
354
+ if (colIndex < body[prevRowIndex].length) {
355
+ cell = body[prevRowIndex][colIndex];
356
+ leftCellBorder = cell.border ? cell.border[0] : this.layout.defaultBorder;
357
+ }
358
+
359
+ // Check cell before
360
+ if (colIndex > 0 && !leftCellBorder) {
361
+ cell = body[prevRowIndex][colIndex - 1];
362
+ leftCellBorder = cell.border ? cell.border[2] : this.layout.defaultBorder;
363
+ }
364
+
365
+ if (leftCellBorder) {
366
+ this.drawVerticalLine(
367
+ xs[xi].x,
368
+ y0,
369
+ y1,
370
+ xs[xi].index,
371
+ writer,
372
+ prevRowIndex,
373
+ xi > 0 ? xs[xi - 1].index : null
374
+ );
375
+ }
376
+ }
377
+ };
378
+
313
379
  TableProcessor.prototype.drawVerticalLine = function (x, y0, y1, vLineColIndex, writer, vLineRowIndex, beforeVLineColIndex) {
314
380
  var width = this.layout.vLineWidth(vLineColIndex, this.tableNode);
315
381
  if (width === 0) {
@@ -409,9 +475,11 @@ TableProcessor.prototype.endTable = function (writer) {
409
475
  }
410
476
  };
411
477
 
412
- TableProcessor.prototype.endRow = function (rowIndex, writer, pageBreaks) {
478
+ TableProcessor.prototype.endRow = function (rowIndex, writer, pageBreaks, nextRowCells, layoutBuilder) {
413
479
  var l, i;
414
480
  var self = this;
481
+ var tableLayout = this.tableNode && this.tableNode._layout;
482
+ var nearBottomThreshold = (tableLayout && tableLayout.nearBottomThreshold) || 20;
415
483
 
416
484
  writer.tracker.stopTracking('pageChanged', this.rowCallback);
417
485
  writer.context().moveDown(this.layout.paddingBottom(rowIndex, this.tableNode));
@@ -437,7 +505,7 @@ TableProcessor.prototype.endRow = function (rowIndex, writer, pageBreaks) {
437
505
  var pageBreak = pageBreaks[i];
438
506
  ys[ys.length - 1].y1 = pageBreak.prevY;
439
507
 
440
- ys.push({ y0: pageBreak.y, page: pageBreak.prevPage + 1 });
508
+ ys.push({ y0: pageBreak.y, page: pageBreak.prevPage + 1, forced: pageBreak.forced });
441
509
  }
442
510
  }
443
511
 
@@ -473,11 +541,21 @@ TableProcessor.prototype.endRow = function (rowIndex, writer, pageBreaks) {
473
541
  }
474
542
 
475
543
  // Draw horizontal lines before the vertical lines so they are not overridden
544
+ // Only set isPageBreak=true when at TRUE page bottom (not just forced breaks)
545
+ var ctx = writer.context();
546
+ var currentPage = ctx.getCurrentPage && ctx.getCurrentPage();
547
+ var pageHeight = currentPage ? (currentPage.pageSize.height - ctx.pageMargins.bottom) : 0;
548
+
476
549
  if (willBreak && this.layout.hLineWhenBroken !== false) {
477
- this.drawHorizontalLine(rowIndex + 1, writer, y2, true, null, true);
550
+ // Check if we're at the true page bottom
551
+ var isAtTruePageBottom = (pageHeight - y2) <= nearBottomThreshold;
552
+ this.drawHorizontalLine(rowIndex + 1, writer, y2, true, null, isAtTruePageBottom);
478
553
  }
479
554
  if (rowBreakWithoutHeader && this.layout.hLineWhenBroken !== false) {
480
- this.drawHorizontalLine(rowIndex, writer, y1, true, null, true);
555
+ // Check if previous segment ended at true page bottom
556
+ var prevSegmentY = (yi > 0) ? ys[yi - 1].y1 : 0;
557
+ var prevWasAtPageBottom = (pageHeight - prevSegmentY) <= nearBottomThreshold;
558
+ this.drawHorizontalLine(rowIndex, writer, y1, true, null, prevWasAtPageBottom);
481
559
  }
482
560
 
483
561
  for (i = 0, l = xs.length; i < l; i++) {
@@ -596,7 +674,57 @@ TableProcessor.prototype.endRow = function (rowIndex, writer, pageBreaks) {
596
674
  }
597
675
  }
598
676
 
599
- this.drawHorizontalLine(rowIndex + 1, writer);
677
+ // Look ahead: Check if next row will cause a page break
678
+ // If yes, skip drawing the horizontal line at the end of current row
679
+ // This feature is OPT-IN: only enabled when forcePageBreakForAllRows === true
680
+ var shouldSkipHorizontalLine = false;
681
+
682
+ if (nextRowCells && layoutBuilder) {
683
+ // Only perform look-ahead if forcePageBreakForAllRows is explicitly enabled
684
+ // This prevents affecting existing PDFs that don't use this feature
685
+ if (tableLayout && tableLayout.forcePageBreakForAllRows === true) {
686
+ var nextRowEstimatedHeight = 0;
687
+
688
+ // Try to get maximum cell height from next row's measured content
689
+ if (layoutBuilder._getMaxCellHeight) {
690
+ var maxNextCellHeight = layoutBuilder._getMaxCellHeight(nextRowCells);
691
+ if (maxNextCellHeight > 0) {
692
+ nextRowEstimatedHeight = maxNextCellHeight + 10; // Add padding
693
+ }
694
+ }
695
+
696
+ // Fallback: use minRowHeight from table layout
697
+ if (nextRowEstimatedHeight === 0) {
698
+ var footerGapOpt = writer.context()._footerGapOption;
699
+ nextRowEstimatedHeight = (tableLayout && tableLayout.minRowHeight) || (footerGapOpt && footerGapOpt.minRowHeight) || 80;
700
+ }
701
+
702
+ // Check current available height (after current row has been processed)
703
+ var currentAvailableHeight = writer.context().availableHeight;
704
+
705
+ // Skip drawing the horizontal line if EITHER:
706
+ // 1. Next row won't fit (will cause page break), OR
707
+ // 2. We're very close to page bottom (remaining space <= threshold)
708
+ // This prevents duplicate/orphaned lines at page boundaries
709
+ if (nextRowEstimatedHeight > currentAvailableHeight || currentAvailableHeight <= nearBottomThreshold) {
710
+ // Exception: Check if this line should always be drawn (critical boundary)
711
+ // Allow layout to specify via alwaysDrawHLine callback
712
+ var shouldAlwaysDrawLine = false;
713
+ if (typeof tableLayout.alwaysDrawHLine === 'function') {
714
+ shouldAlwaysDrawLine = tableLayout.alwaysDrawHLine(rowIndex + 1, this.tableNode, writer);
715
+ }
716
+
717
+ if (!shouldAlwaysDrawLine) {
718
+ shouldSkipHorizontalLine = true;
719
+ }
720
+ }
721
+ }
722
+ }
723
+
724
+ // Draw horizontal line at the end of the row, unless next row will cause a page break
725
+ if (!shouldSkipHorizontalLine) {
726
+ this.drawHorizontalLine(rowIndex + 1, writer);
727
+ }
600
728
 
601
729
  if (this.headerRows && rowIndex === this.headerRows - 1) {
602
730
  this.headerRepeatable = writer.currentBlockToRepeatable();