@flowaccount/pdfmake 1.0.7-staging.1 → 1.0.7-staging.4
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.
- package/build/pdfmake.js +726 -496
- package/build/pdfmake.min.js +2 -2
- package/build/pdfmake.min.js.map +1 -1
- package/package.json +1 -1
- package/src/layoutBuilder.js +244 -14
- package/src/tableProcessor.js +9 -3
- package/src/textTools.js +1 -1
package/package.json
CHANGED
package/src/layoutBuilder.js
CHANGED
|
@@ -538,13 +538,32 @@ LayoutBuilder.prototype.processNode = function (node) {
|
|
|
538
538
|
startY: ctx.y,
|
|
539
539
|
startPage: ctx.page,
|
|
540
540
|
availableHeight: ctx.availableHeight,
|
|
541
|
-
itemCount: currentPage ? currentPage.items.length : 0
|
|
541
|
+
itemCount: currentPage ? currentPage.items.length : 0,
|
|
542
|
+
x: ctx.x,
|
|
543
|
+
summaryRenderedPage: null
|
|
542
544
|
};
|
|
543
545
|
}
|
|
544
546
|
|
|
545
547
|
// Process the stack
|
|
546
548
|
self.processVerticalContainer(node);
|
|
547
549
|
|
|
550
|
+
// Track which page summary was rendered on (summary is first item, unbreakable)
|
|
551
|
+
if (preRenderState && node.stack && node.stack[0]) {
|
|
552
|
+
var summaryNode = node.stack[0];
|
|
553
|
+
if (summaryNode.summary || summaryNode.unbreakable) {
|
|
554
|
+
// Summary is unbreakable, check if it was pushed to a new page
|
|
555
|
+
// by comparing its height with available space at startPage
|
|
556
|
+
var summaryHeight = Math.abs(summaryNode._height || 0);
|
|
557
|
+
if (summaryHeight <= preRenderState.availableHeight) {
|
|
558
|
+
// Summary fit on startPage
|
|
559
|
+
preRenderState.summaryRenderedPage = preRenderState.startPage;
|
|
560
|
+
} else {
|
|
561
|
+
// Summary was pushed to next page
|
|
562
|
+
preRenderState.summaryRenderedPage = preRenderState.startPage + 1;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
548
567
|
// Post-render repositioning
|
|
549
568
|
if (footerGapEnabled && preRenderState) {
|
|
550
569
|
var ctx = self.writer.context();
|
|
@@ -683,6 +702,132 @@ LayoutBuilder.prototype.processNode = function (node) {
|
|
|
683
702
|
// Intermediate pages (remark only) should not be repositioned
|
|
684
703
|
var pageIdx = ctx.page;
|
|
685
704
|
if (pageIdx > preRenderState.startPage) {
|
|
705
|
+
// Also reposition items on the START page (where summary might be)
|
|
706
|
+
var startPage = pages[preRenderState.startPage];
|
|
707
|
+
if (startPage && startPage.items && startPage.items.length > 0) {
|
|
708
|
+
var startPageHeight = startPage.pageSize.height;
|
|
709
|
+
var startPageBottom = startPageHeight - pageMargins.bottom;
|
|
710
|
+
|
|
711
|
+
// Find content bottom on start page
|
|
712
|
+
var startContentBottom = 0;
|
|
713
|
+
for (var si = 0; si < startPage.items.length; si++) {
|
|
714
|
+
var sItem = startPage.items[si];
|
|
715
|
+
var sItemBottom = 0;
|
|
716
|
+
if (sItem.item) {
|
|
717
|
+
if (typeof sItem.item.y === 'number') {
|
|
718
|
+
var sh = 0;
|
|
719
|
+
// Line items have getHeight() method
|
|
720
|
+
if (sItem.type === 'line' && typeof sItem.item.getHeight === 'function') {
|
|
721
|
+
sh = sItem.item.getHeight();
|
|
722
|
+
} else {
|
|
723
|
+
sh = sItem.item.h || sItem.item.height || 0;
|
|
724
|
+
}
|
|
725
|
+
sItemBottom = sItem.item.y + sh;
|
|
726
|
+
}
|
|
727
|
+
if (typeof sItem.item.y2 === 'number' && sItem.item.y2 > sItemBottom) {
|
|
728
|
+
sItemBottom = sItem.item.y2;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
if (sItemBottom > startContentBottom) {
|
|
732
|
+
startContentBottom = sItemBottom;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
// Calculate gap and move items on start page
|
|
737
|
+
var startGapHeight = startPageBottom - startContentBottom;
|
|
738
|
+
if (startGapHeight > 0) {
|
|
739
|
+
var startStackStartY = preRenderState.startY;
|
|
740
|
+
for (var si = 0; si < startPage.items.length; si++) {
|
|
741
|
+
var sItem = startPage.items[si];
|
|
742
|
+
var sItemY = null;
|
|
743
|
+
if (sItem.item && typeof sItem.item.y1 === 'number') {
|
|
744
|
+
sItemY = sItem.item.y1;
|
|
745
|
+
} else if (sItem.item && typeof sItem.item.y === 'number') {
|
|
746
|
+
sItemY = sItem.item.y;
|
|
747
|
+
} else if (sItem.item && sItem.item.points && Array.isArray(sItem.item.points) && sItem.item.points.length > 0) {
|
|
748
|
+
// For polylines, use the first point's Y
|
|
749
|
+
sItemY = sItem.item.points[0].y;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// Skip items fully above footer start
|
|
753
|
+
if (sItemY === null || sItemY < startStackStartY) continue;
|
|
754
|
+
|
|
755
|
+
// Move item down
|
|
756
|
+
if (sItem.item && typeof sItem.item.y === 'number') {
|
|
757
|
+
sItem.item.y += startGapHeight;
|
|
758
|
+
}
|
|
759
|
+
if (sItem.item && typeof sItem.item.y1 === 'number') {
|
|
760
|
+
sItem.item.y1 += startGapHeight;
|
|
761
|
+
}
|
|
762
|
+
if (sItem.item && typeof sItem.item.y2 === 'number') {
|
|
763
|
+
sItem.item.y2 += startGapHeight;
|
|
764
|
+
}
|
|
765
|
+
// Handle polylines (points array)
|
|
766
|
+
if (sItem.item && sItem.item.points && Array.isArray(sItem.item.points)) {
|
|
767
|
+
for (var spi = 0; spi < sItem.item.points.length; spi++) {
|
|
768
|
+
if (typeof sItem.item.points[spi].y === 'number') {
|
|
769
|
+
sItem.item.points[spi].y += startGapHeight;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// MULTI-PAGE: Draw guide lines in the gap area (same as single-page)
|
|
776
|
+
var colSpec = node._footerGapOption && node._footerGapOption.columns ? node._footerGapOption.columns : (self._footerGapOption && self._footerGapOption.columns);
|
|
777
|
+
if (colSpec) {
|
|
778
|
+
var rawWidths = colSpec.content && colSpec.content.vLines ? colSpec.content.vLines : [];
|
|
779
|
+
if (rawWidths && rawWidths.length > 1) {
|
|
780
|
+
var style = (colSpec.style || {});
|
|
781
|
+
var lw = style.lineWidth != null ? style.lineWidth : 0.5;
|
|
782
|
+
var lc = style.color || '#000000';
|
|
783
|
+
var dashCfg = style.dash;
|
|
784
|
+
var includeOuter = colSpec.includeOuter !== false;
|
|
785
|
+
var startIndex = includeOuter ? 0 : 1;
|
|
786
|
+
var endIndex = includeOuter ? rawWidths.length : rawWidths.length - 1;
|
|
787
|
+
var pageX = preRenderState.x || pageMargins.left;
|
|
788
|
+
|
|
789
|
+
for (var ci = startIndex; ci < endIndex; ci++) {
|
|
790
|
+
var xGuide = pageX + rawWidths[ci] - 0.25;
|
|
791
|
+
// Extend first and last vertical lines to content bottom after moving
|
|
792
|
+
var isFirstOrLast = (ci === 0) || (ci === rawWidths.length - 1);
|
|
793
|
+
var vLineY2 = isFirstOrLast ? (startContentBottom + startGapHeight) : (startStackStartY + startGapHeight);
|
|
794
|
+
startPage.items.push({
|
|
795
|
+
type: 'vector',
|
|
796
|
+
item: {
|
|
797
|
+
type: 'line',
|
|
798
|
+
x1: xGuide,
|
|
799
|
+
y1: startStackStartY,
|
|
800
|
+
x2: xGuide,
|
|
801
|
+
y2: vLineY2,
|
|
802
|
+
lineWidth: lw,
|
|
803
|
+
lineColor: lc,
|
|
804
|
+
dash: dashCfg ? {
|
|
805
|
+
length: dashCfg.length,
|
|
806
|
+
space: dashCfg.space != null ? dashCfg.space : dashCfg.gap
|
|
807
|
+
} : undefined,
|
|
808
|
+
_footerGuideLine: true
|
|
809
|
+
}
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
// Remove existing horizontal line at startStackStartY (drawn by tableProcessor)
|
|
814
|
+
// It's at wrong position now - we'll draw new one at bottom of gap
|
|
815
|
+
for (var ri = startPage.items.length - 1; ri >= 0; ri--) {
|
|
816
|
+
var rItem = startPage.items[ri];
|
|
817
|
+
if (rItem.type === 'vector' && rItem.item && rItem.item.type === 'line') {
|
|
818
|
+
// Check if it's a horizontal line at startStackStartY
|
|
819
|
+
if (Math.abs(rItem.item.y1 - startStackStartY) < 1 &&
|
|
820
|
+
Math.abs(rItem.item.y2 - startStackStartY) < 1) {
|
|
821
|
+
startPage.items.splice(ri, 1);
|
|
822
|
+
break;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
|
|
686
831
|
var page = pages[pageIdx];
|
|
687
832
|
if (page && page.items && page.items.length > 0) {
|
|
688
833
|
var pageHeight = page.pageSize.height;
|
|
@@ -703,19 +848,35 @@ LayoutBuilder.prototype.processNode = function (node) {
|
|
|
703
848
|
if (typeof item.item.y2 === 'number' && item.item.y2 > itemBottom) {
|
|
704
849
|
itemBottom = item.item.y2;
|
|
705
850
|
}
|
|
851
|
+
// Handle polylines (points array)
|
|
852
|
+
if (item.item.points && Array.isArray(item.item.points)) {
|
|
853
|
+
for (var pi = 0; pi < item.item.points.length; pi++) {
|
|
854
|
+
if (typeof item.item.points[pi].y === 'number' && item.item.points[pi].y > itemBottom) {
|
|
855
|
+
itemBottom = item.item.points[pi].y;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
}
|
|
706
859
|
}
|
|
707
860
|
if (itemBottom > contentBottom) {
|
|
708
861
|
contentBottom = itemBottom;
|
|
709
862
|
}
|
|
710
863
|
}
|
|
711
864
|
|
|
712
|
-
//
|
|
713
|
-
var
|
|
865
|
+
// Check if summary is on the last page
|
|
866
|
+
var summaryOnLastPage = (preRenderState.summaryRenderedPage === pageIdx);
|
|
714
867
|
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
//
|
|
868
|
+
var stackStartY;
|
|
869
|
+
if (summaryOnLastPage) {
|
|
870
|
+
// Summary is on this page - move all: summary + remark + footer together
|
|
871
|
+
// Calculate header threshold for this page
|
|
872
|
+
var repeatableHeaderHeight = 0;
|
|
873
|
+
for (var ri = 0; ri < self.writer.repeatables.length; ri++) {
|
|
874
|
+
repeatableHeaderHeight += self.writer.repeatables[ri].height;
|
|
875
|
+
}
|
|
876
|
+
var headerThreshold = pageMargins.top + repeatableHeaderHeight;
|
|
877
|
+
|
|
878
|
+
// Find minimum Y of all items below header threshold
|
|
879
|
+
stackStartY = contentBottom;
|
|
719
880
|
for (var i = 0; i < page.items.length; i++) {
|
|
720
881
|
var item = page.items[i];
|
|
721
882
|
var itemY = null;
|
|
@@ -724,23 +885,92 @@ LayoutBuilder.prototype.processNode = function (node) {
|
|
|
724
885
|
} else if (item.item && typeof item.item.y === 'number') {
|
|
725
886
|
itemY = item.item.y;
|
|
726
887
|
} else if (item.item && item.item.points && Array.isArray(item.item.points) && item.item.points.length > 0) {
|
|
727
|
-
// For polylines, use the first point's Y
|
|
728
888
|
itemY = item.item.points[0].y;
|
|
729
889
|
}
|
|
890
|
+
if (itemY !== null && itemY >= headerThreshold && itemY < stackStartY) {
|
|
891
|
+
stackStartY = itemY;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
730
894
|
|
|
731
|
-
|
|
732
|
-
|
|
895
|
+
// Draw guide lines in the gap area (same as single-page)
|
|
896
|
+
var gapHeightForLines = pageBottom - contentBottom;
|
|
897
|
+
if (gapHeightForLines > 0) {
|
|
898
|
+
var colSpec = node._footerGapOption && node._footerGapOption.columns ? node._footerGapOption.columns : (self._footerGapOption && self._footerGapOption.columns);
|
|
899
|
+
if (colSpec) {
|
|
900
|
+
var rawWidths = colSpec.content && colSpec.content.vLines ? colSpec.content.vLines : [];
|
|
901
|
+
if (rawWidths && rawWidths.length > 1) {
|
|
902
|
+
var style = (colSpec.style || {});
|
|
903
|
+
var lw = style.lineWidth != null ? style.lineWidth : 0.5;
|
|
904
|
+
var lc = style.color || '#000000';
|
|
905
|
+
var dashCfg = style.dash;
|
|
906
|
+
var includeOuter = colSpec.includeOuter !== false;
|
|
907
|
+
var startIndex = includeOuter ? 0 : 1;
|
|
908
|
+
var endIndex = includeOuter ? rawWidths.length : rawWidths.length - 1;
|
|
909
|
+
var pageX = preRenderState.x || pageMargins.left;
|
|
910
|
+
|
|
911
|
+
for (var ci = startIndex; ci < endIndex; ci++) {
|
|
912
|
+
var xGuide = pageX + rawWidths[ci] - 0.25;
|
|
913
|
+
page.items.push({
|
|
914
|
+
type: 'vector',
|
|
915
|
+
item: {
|
|
916
|
+
type: 'line',
|
|
917
|
+
x1: xGuide,
|
|
918
|
+
y1: stackStartY,
|
|
919
|
+
x2: xGuide,
|
|
920
|
+
y2: stackStartY + gapHeightForLines,
|
|
921
|
+
lineWidth: lw,
|
|
922
|
+
lineColor: lc,
|
|
923
|
+
dash: dashCfg ? {
|
|
924
|
+
length: dashCfg.length,
|
|
925
|
+
space: dashCfg.space != null ? dashCfg.space : dashCfg.gap
|
|
926
|
+
} : undefined,
|
|
927
|
+
_footerGuideLine: true
|
|
928
|
+
}
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
} else {
|
|
935
|
+
// Summary is NOT on this page - move only footer
|
|
936
|
+
stackStartY = contentBottom - stackHeight;
|
|
937
|
+
}
|
|
733
938
|
|
|
734
|
-
|
|
735
|
-
|
|
939
|
+
// Calculate gap: how much to move footer stack down
|
|
940
|
+
var gapHeight = pageBottom - contentBottom;
|
|
941
|
+
if (gapHeight > 0) {
|
|
942
|
+
// Calculate header threshold if not already calculated
|
|
943
|
+
if (typeof headerThreshold === 'undefined') {
|
|
736
944
|
var repeatableHeaderHeight = 0;
|
|
737
945
|
for (var ri = 0; ri < self.writer.repeatables.length; ri++) {
|
|
738
946
|
repeatableHeaderHeight += self.writer.repeatables[ri].height;
|
|
739
947
|
}
|
|
740
|
-
|
|
948
|
+
headerThreshold = pageMargins.top + repeatableHeaderHeight;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
// Move all items that are part of footer stack (Y >= stackStartY)
|
|
952
|
+
for (var i = 0; i < page.items.length; i++) {
|
|
953
|
+
var item = page.items[i];
|
|
954
|
+
|
|
955
|
+
// Skip guide lines (they're already positioned correctly)
|
|
956
|
+
if (item.item && item.item._footerGuideLine) continue;
|
|
957
|
+
|
|
958
|
+
var itemY = null;
|
|
959
|
+
if (item.item && typeof item.item.y1 === 'number') {
|
|
960
|
+
itemY = item.item.y1;
|
|
961
|
+
} else if (item.item && typeof item.item.y === 'number') {
|
|
962
|
+
itemY = item.item.y;
|
|
963
|
+
} else if (item.item && item.item.points && Array.isArray(item.item.points) && item.item.points.length > 0) {
|
|
964
|
+
itemY = item.item.points[0].y;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// Skip items above footer stack
|
|
968
|
+
if (itemY === null || itemY < stackStartY) continue;
|
|
969
|
+
|
|
970
|
+
// Skip items in header area (repeated headers)
|
|
741
971
|
if (itemY < headerThreshold) continue;
|
|
742
972
|
|
|
743
|
-
// Move footer item down
|
|
973
|
+
// Move footer stack item down
|
|
744
974
|
if (item.item && typeof item.item.y === 'number') {
|
|
745
975
|
item.item.y += gapHeight;
|
|
746
976
|
}
|
package/src/tableProcessor.js
CHANGED
|
@@ -560,11 +560,13 @@ TableProcessor.prototype.endRow = function (rowIndex, writer, pageBreaks, nextRo
|
|
|
560
560
|
var ctx = writer.context();
|
|
561
561
|
var currentPage = ctx.getCurrentPage && ctx.getCurrentPage();
|
|
562
562
|
var pageHeight = currentPage ? (currentPage.pageSize.height - ctx.pageMargins.bottom) : 0;
|
|
563
|
-
|
|
563
|
+
var footerGapOptBreak = ctx._footerGapOption;
|
|
564
|
+
var hLineY = (footerGapOptBreak && footerGapOptBreak.enabled) ? pageHeight - 0.25 : y2;
|
|
564
565
|
if (willBreak && this.layout.hLineWhenBroken !== false) {
|
|
565
566
|
// Check if we're at the true page bottom
|
|
566
567
|
var isAtTruePageBottom = (pageHeight - y2) <= nearBottomThreshold;
|
|
567
|
-
|
|
568
|
+
// Use pageHeight for footer gap tables, y2 for normal tables
|
|
569
|
+
this.drawHorizontalLine(rowIndex + 1, writer, hLineY, true, null, isAtTruePageBottom);
|
|
568
570
|
}
|
|
569
571
|
if (rowBreakWithoutHeader && this.layout.hLineWhenBroken !== false) {
|
|
570
572
|
// Check if previous segment ended at true page bottom
|
|
@@ -573,6 +575,10 @@ TableProcessor.prototype.endRow = function (rowIndex, writer, pageBreaks, nextRo
|
|
|
573
575
|
this.drawHorizontalLine(rowIndex, writer, y1, true, null, prevWasAtPageBottom);
|
|
574
576
|
}
|
|
575
577
|
|
|
578
|
+
// vLineY: ONLY use hLineY when BOTH willBreak AND footerGapOptBreak.enabled are true
|
|
579
|
+
// Otherwise use y2 (original behavior) to avoid NaN errors
|
|
580
|
+
var vLineY = (willBreak && footerGapOptBreak && footerGapOptBreak.enabled) ? hLineY : y2;
|
|
581
|
+
|
|
576
582
|
for (i = 0, l = xs.length; i < l; i++) {
|
|
577
583
|
var leftCellBorder = false;
|
|
578
584
|
var rightCellBorder = false;
|
|
@@ -599,7 +605,7 @@ TableProcessor.prototype.endRow = function (rowIndex, writer, pageBreaks, nextRo
|
|
|
599
605
|
}
|
|
600
606
|
|
|
601
607
|
if (leftCellBorder) {
|
|
602
|
-
this.drawVerticalLine(xs[i].x, y1 - hzLineOffset,
|
|
608
|
+
this.drawVerticalLine(xs[i].x, y1 - hzLineOffset, vLineY + this.bottomLineWidth, xs[i].index, writer, rowIndex, xs[i - 1] ? xs[i - 1].index : null);
|
|
603
609
|
}
|
|
604
610
|
|
|
605
611
|
if (i < l - 1) {
|
package/src/textTools.js
CHANGED
|
@@ -317,7 +317,7 @@ function getStyleProperty(item, styleContextStack, property, defaultValue) {
|
|
|
317
317
|
}
|
|
318
318
|
|
|
319
319
|
if(property === 'bold' && (item.text === '' || item.text === '\u200B')) {
|
|
320
|
-
return false
|
|
320
|
+
return false;
|
|
321
321
|
}
|
|
322
322
|
|
|
323
323
|
if (value !== null && value !== undefined) {
|