@softwear/latestcollectioncore 1.0.177 → 1.0.179
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/dist/pdf.d.ts +1 -1
- package/dist/reports.js +30 -8
- package/package.json +1 -1
- package/src/pdf.ts +1 -1
- package/src/reports.ts +31 -7
- package/test/reports.spec.ts +127 -2
package/dist/pdf.d.ts
CHANGED
|
@@ -54,7 +54,7 @@ export interface ContainerLayoutObject extends BaseLayoutObject {
|
|
|
54
54
|
minHeightBeforeBreak?: number;
|
|
55
55
|
/** When true, container and children are drawn only once at the end of the report, not on every page */
|
|
56
56
|
printOnlyAtEnd?: boolean;
|
|
57
|
-
/**
|
|
57
|
+
/** Only effective on top-level `layout.objects` (PDF engine ignores this flag on nested containers). */
|
|
58
58
|
printOnlyAtStart?: boolean;
|
|
59
59
|
}
|
|
60
60
|
export type LayoutObject = TextLayoutObject | FieldLayoutObject | RectangleLayoutObject | ImageLayoutObject | ContainerLayoutObject;
|
package/dist/reports.js
CHANGED
|
@@ -43,9 +43,21 @@ function getProperty(propertyName, object) {
|
|
|
43
43
|
}
|
|
44
44
|
return property;
|
|
45
45
|
}
|
|
46
|
-
/** Repeat once
|
|
46
|
+
/** Repeat once when the container has no data binding (`source` empty / whitespace-only). */
|
|
47
|
+
function dummyLayoutSource(source) {
|
|
48
|
+
return source === undefined || String(source).trim() === '';
|
|
49
|
+
}
|
|
50
|
+
/** Like repeatOnOverflow: redraw after a page break so nested overflowing content can proceed. */
|
|
51
|
+
function containerRedrawsAfterContinuationPage(child) {
|
|
52
|
+
if (child.type !== 'container')
|
|
53
|
+
return false;
|
|
54
|
+
const c = child;
|
|
55
|
+
if (c.repeatOnOverflow)
|
|
56
|
+
return true;
|
|
57
|
+
return dummyLayoutSource(c.source);
|
|
58
|
+
}
|
|
47
59
|
function containerLoopSource(container, printBuffer) {
|
|
48
|
-
if (
|
|
60
|
+
if (dummyLayoutSource(container.source))
|
|
49
61
|
return [printBuffer];
|
|
50
62
|
return getProperty(container.source, printBuffer);
|
|
51
63
|
}
|
|
@@ -368,6 +380,7 @@ function drawSimpleObject(x, y, doc, object, printBuffer, width, height, options
|
|
|
368
380
|
}
|
|
369
381
|
}
|
|
370
382
|
function addPage(originX, originY, doc, layout, rootPrintBuffer, paperSize, options, containerChain, context) {
|
|
383
|
+
context.pendingRootStartBumpTenths = 0;
|
|
371
384
|
if (context.mode === 'measurement') {
|
|
372
385
|
// Track page count in measurement mode
|
|
373
386
|
if (context.currentPageCount === undefined) {
|
|
@@ -392,7 +405,7 @@ function addPage(originX, originY, doc, layout, rootPrintBuffer, paperSize, opti
|
|
|
392
405
|
absoluteLowerRightHandSide.y = originY / 10;
|
|
393
406
|
containerChain.forEach((link) => {
|
|
394
407
|
link.object.children.forEach((child) => {
|
|
395
|
-
if (!child.snapToBottom && (child.type != 'container' || child
|
|
408
|
+
if (!child.snapToBottom && (child.type != 'container' || containerRedrawsAfterContinuationPage(child))) {
|
|
396
409
|
const childLowerRightHandSide = addObjectToPDF(originX, originY, doc, child, link.printBuffer, paperSize, layout, options, rootPrintBuffer, [], context);
|
|
397
410
|
absoluteLowerRightHandSide.x = Math.max(absoluteLowerRightHandSide.x, childLowerRightHandSide.x);
|
|
398
411
|
absoluteLowerRightHandSide.y = Math.max(absoluteLowerRightHandSide.y, childLowerRightHandSide.y);
|
|
@@ -441,9 +454,10 @@ function drawBottomDwellers(object, originX, originY, absoluteLowerRightHandSide
|
|
|
441
454
|
* Use originX,originY as origin to displace the object's own x,y coordinates
|
|
442
455
|
*/
|
|
443
456
|
addObjectToPDF = function (originX, originY, doc, object, printBuffer, paperSize, layout, options, rootPrintBuffer, containerChain, context) {
|
|
444
|
-
var _a;
|
|
457
|
+
var _a, _b;
|
|
458
|
+
const rootBump = containerChain.length === 0 ? (_a = context.pendingRootStartBumpTenths) !== null && _a !== void 0 ? _a : 0 : 0;
|
|
445
459
|
const x = (originX + object.x) / 10;
|
|
446
|
-
const y = (originY + object.y) / 10;
|
|
460
|
+
const y = (originY + object.y + rootBump) / 10;
|
|
447
461
|
const width = object.width / 10;
|
|
448
462
|
const height = object.height / 10;
|
|
449
463
|
// Keep track of the lower righthandside of all objects in this container
|
|
@@ -458,7 +472,7 @@ addObjectToPDF = function (originX, originY, doc, object, printBuffer, paperSize
|
|
|
458
472
|
let originX = x * 10, originY = y * 10;
|
|
459
473
|
const source = containerLoopSource(object, printBuffer);
|
|
460
474
|
if (source === undefined) {
|
|
461
|
-
(
|
|
475
|
+
(_b = options.onAlert) === null || _b === void 0 ? void 0 : _b.call(options, { header: 'containernotfound', body: object.source, type: 'warning', timeout: 10000 });
|
|
462
476
|
return absoluteLowerRightHandSide;
|
|
463
477
|
}
|
|
464
478
|
const nrContainers = source.length;
|
|
@@ -663,21 +677,25 @@ function genPDF(layout, printBuffer, options = {}) {
|
|
|
663
677
|
}
|
|
664
678
|
drawStaticPartOfPage(measurementDoc, layout, printBuffer, paperSize, options, measurementContext);
|
|
665
679
|
// Draw containers in measurement mode (same order as render)
|
|
680
|
+
let measurementTopPrintedStartBottomTenths = 0;
|
|
666
681
|
layout.objects
|
|
667
682
|
.filter((object) => object.type == 'container' && object.printOnlyAtStart)
|
|
668
683
|
.forEach((object) => {
|
|
669
|
-
addObjectToPDF(0, 0, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext);
|
|
684
|
+
const lh = addObjectToPDF(0, 0, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext);
|
|
685
|
+
measurementTopPrintedStartBottomTenths = Math.max(measurementTopPrintedStartBottomTenths, lh.y * 10);
|
|
670
686
|
});
|
|
671
687
|
layout.objects
|
|
672
688
|
.filter((object) => object.type == 'container' &&
|
|
673
689
|
!object.printOnlyAtEnd &&
|
|
674
690
|
!object.printOnlyAtStart)
|
|
675
691
|
.forEach((object) => {
|
|
692
|
+
measurementContext.pendingRootStartBumpTenths = Math.max(0, measurementTopPrintedStartBottomTenths - object.y);
|
|
676
693
|
addObjectToPDF(0, 0, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext);
|
|
677
694
|
});
|
|
678
695
|
layout.objects
|
|
679
696
|
.filter((object) => object.type == 'container' && object.printOnlyAtEnd)
|
|
680
697
|
.forEach((object) => {
|
|
698
|
+
measurementContext.pendingRootStartBumpTenths = Math.max(0, measurementTopPrintedStartBottomTenths - object.y);
|
|
681
699
|
addObjectToPDF(0, 0, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext);
|
|
682
700
|
});
|
|
683
701
|
// Get total page count from measurement pass
|
|
@@ -697,10 +715,12 @@ function genPDF(layout, printBuffer, options = {}) {
|
|
|
697
715
|
defaultFontFamily: layout.defaultFontFamily,
|
|
698
716
|
};
|
|
699
717
|
drawStaticPartOfPage(doc, layout, printBuffer, paperSize, options, renderContext);
|
|
718
|
+
let renderTopPrintedStartBottomTenths = 0;
|
|
700
719
|
layout.objects
|
|
701
720
|
.filter((object) => object.type == 'container' && object.printOnlyAtStart)
|
|
702
721
|
.forEach((object) => {
|
|
703
|
-
addObjectToPDF(0, 0, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext);
|
|
722
|
+
const lh = addObjectToPDF(0, 0, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext);
|
|
723
|
+
renderTopPrintedStartBottomTenths = Math.max(renderTopPrintedStartBottomTenths, lh.y * 10);
|
|
704
724
|
});
|
|
705
725
|
// Draw containers in rendering mode (body containers after printOnlyAtStart)
|
|
706
726
|
layout.objects
|
|
@@ -708,11 +728,13 @@ function genPDF(layout, printBuffer, options = {}) {
|
|
|
708
728
|
!object.printOnlyAtEnd &&
|
|
709
729
|
!object.printOnlyAtStart)
|
|
710
730
|
.forEach((object) => {
|
|
731
|
+
renderContext.pendingRootStartBumpTenths = Math.max(0, renderTopPrintedStartBottomTenths - object.y);
|
|
711
732
|
addObjectToPDF(0, 0, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext);
|
|
712
733
|
});
|
|
713
734
|
// Draw printOnlyAtEnd containers once at the end (at their layout coordinates on current page)
|
|
714
735
|
const printOnlyAtEndContainers = layout.objects.filter((object) => object.type == 'container' && object.printOnlyAtEnd);
|
|
715
736
|
printOnlyAtEndContainers.forEach((object) => {
|
|
737
|
+
renderContext.pendingRootStartBumpTenths = Math.max(0, renderTopPrintedStartBottomTenths - object.y);
|
|
716
738
|
addObjectToPDF(0, 0, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext);
|
|
717
739
|
});
|
|
718
740
|
return doc;
|
package/package.json
CHANGED
package/src/pdf.ts
CHANGED
|
@@ -61,7 +61,7 @@ export interface ContainerLayoutObject extends BaseLayoutObject {
|
|
|
61
61
|
minHeightBeforeBreak?: number
|
|
62
62
|
/** When true, container and children are drawn only once at the end of the report, not on every page */
|
|
63
63
|
printOnlyAtEnd?: boolean
|
|
64
|
-
/**
|
|
64
|
+
/** Only effective on top-level `layout.objects` (PDF engine ignores this flag on nested containers). */
|
|
65
65
|
printOnlyAtStart?: boolean
|
|
66
66
|
}
|
|
67
67
|
|
package/src/reports.ts
CHANGED
|
@@ -46,6 +46,8 @@ interface RenderContext {
|
|
|
46
46
|
imageAssets?: Map<string, PdfImageAsset>
|
|
47
47
|
/** Layout default font used when object.fontFamily is undefined */
|
|
48
48
|
defaultFontFamily?: string
|
|
49
|
+
/** Vertical pad for root draws after printOnlyAtStart; set per root container; addPage resets to 0 after each page break. */
|
|
50
|
+
pendingRootStartBumpTenths?: number
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
// We have to declare some functions that will be called by other functions but also have to call those other functions
|
|
@@ -92,10 +94,22 @@ function getProperty(propertyName: string, object: any): any {
|
|
|
92
94
|
return property
|
|
93
95
|
}
|
|
94
96
|
|
|
95
|
-
/** Repeat once
|
|
97
|
+
/** Repeat once when the container has no data binding (`source` empty / whitespace-only). */
|
|
98
|
+
function dummyLayoutSource(source?: string): boolean {
|
|
99
|
+
return source === undefined || String(source).trim() === ''
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Like repeatOnOverflow: redraw after a page break so nested overflowing content can proceed. */
|
|
103
|
+
function containerRedrawsAfterContinuationPage(child: LayoutObject): boolean {
|
|
104
|
+
if (child.type !== 'container') return false
|
|
105
|
+
const c = child as ContainerLayoutObject
|
|
106
|
+
if (c.repeatOnOverflow) return true
|
|
107
|
+
return dummyLayoutSource(c.source)
|
|
108
|
+
}
|
|
109
|
+
|
|
96
110
|
function containerLoopSource(container: ContainerLayoutObject, printBuffer: any): any {
|
|
97
|
-
if (
|
|
98
|
-
return getProperty(container.source, printBuffer)
|
|
111
|
+
if (dummyLayoutSource(container.source)) return [printBuffer]
|
|
112
|
+
return getProperty(container.source as string, printBuffer)
|
|
99
113
|
}
|
|
100
114
|
|
|
101
115
|
/** jsPDF font style strings. fontStyle bitmask: 0=normal, 1=bold, 2=italic, 3=bold+italic */
|
|
@@ -433,6 +447,7 @@ function addPage(
|
|
|
433
447
|
containerChain: { object: ContainerLayoutObject; printBuffer: any }[],
|
|
434
448
|
context: RenderContext
|
|
435
449
|
): { originX: number; originY: number; x: number; y: number } {
|
|
450
|
+
context.pendingRootStartBumpTenths = 0
|
|
436
451
|
if (context.mode === 'measurement') {
|
|
437
452
|
// Track page count in measurement mode
|
|
438
453
|
if (context.currentPageCount === undefined) {
|
|
@@ -456,7 +471,7 @@ function addPage(
|
|
|
456
471
|
absoluteLowerRightHandSide.y = originY / 10
|
|
457
472
|
containerChain.forEach((link) => {
|
|
458
473
|
link.object.children.forEach((child) => {
|
|
459
|
-
if (!child.snapToBottom && (child.type != 'container' || child
|
|
474
|
+
if (!child.snapToBottom && (child.type != 'container' || containerRedrawsAfterContinuationPage(child))) {
|
|
460
475
|
const childLowerRightHandSide = addObjectToPDF(originX, originY, doc, child, link.printBuffer, paperSize, layout, options, rootPrintBuffer, [], context)
|
|
461
476
|
absoluteLowerRightHandSide.x = Math.max(absoluteLowerRightHandSide.x, childLowerRightHandSide.x)
|
|
462
477
|
absoluteLowerRightHandSide.y = Math.max(absoluteLowerRightHandSide.y, childLowerRightHandSide.y)
|
|
@@ -529,8 +544,9 @@ addObjectToPDF = function (
|
|
|
529
544
|
containerChain: { object: ContainerLayoutObject; printBuffer: any }[],
|
|
530
545
|
context: RenderContext
|
|
531
546
|
): { x: number; y: number } {
|
|
547
|
+
const rootBump = containerChain.length === 0 ? context.pendingRootStartBumpTenths ?? 0 : 0
|
|
532
548
|
const x = (originX + object.x) / 10
|
|
533
|
-
const y = (originY + object.y) / 10
|
|
549
|
+
const y = (originY + object.y + rootBump) / 10
|
|
534
550
|
const width = object.width / 10
|
|
535
551
|
const height = object.height / 10
|
|
536
552
|
// Keep track of the lower righthandside of all objects in this container
|
|
@@ -786,10 +802,12 @@ export async function genPDF(layout: Layout, printBuffer: any, options: GenPdfOp
|
|
|
786
802
|
drawStaticPartOfPage(measurementDoc, layout, printBuffer, paperSize, options, measurementContext)
|
|
787
803
|
|
|
788
804
|
// Draw containers in measurement mode (same order as render)
|
|
805
|
+
let measurementTopPrintedStartBottomTenths = 0
|
|
789
806
|
layout.objects
|
|
790
807
|
.filter((object) => object.type == 'container' && (object as ContainerLayoutObject).printOnlyAtStart)
|
|
791
808
|
.forEach((object) => {
|
|
792
|
-
addObjectToPDF(0, 0, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext)
|
|
809
|
+
const lh = addObjectToPDF(0, 0, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext)
|
|
810
|
+
measurementTopPrintedStartBottomTenths = Math.max(measurementTopPrintedStartBottomTenths, lh.y * 10)
|
|
793
811
|
})
|
|
794
812
|
layout.objects
|
|
795
813
|
.filter(
|
|
@@ -799,11 +817,13 @@ export async function genPDF(layout: Layout, printBuffer: any, options: GenPdfOp
|
|
|
799
817
|
!(object as ContainerLayoutObject).printOnlyAtStart
|
|
800
818
|
)
|
|
801
819
|
.forEach((object) => {
|
|
820
|
+
measurementContext.pendingRootStartBumpTenths = Math.max(0, measurementTopPrintedStartBottomTenths - object.y)
|
|
802
821
|
addObjectToPDF(0, 0, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext)
|
|
803
822
|
})
|
|
804
823
|
layout.objects
|
|
805
824
|
.filter((object) => object.type == 'container' && (object as ContainerLayoutObject).printOnlyAtEnd)
|
|
806
825
|
.forEach((object) => {
|
|
826
|
+
measurementContext.pendingRootStartBumpTenths = Math.max(0, measurementTopPrintedStartBottomTenths - object.y)
|
|
807
827
|
addObjectToPDF(0, 0, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext)
|
|
808
828
|
})
|
|
809
829
|
|
|
@@ -826,10 +846,12 @@ export async function genPDF(layout: Layout, printBuffer: any, options: GenPdfOp
|
|
|
826
846
|
}
|
|
827
847
|
drawStaticPartOfPage(doc, layout, printBuffer, paperSize, options, renderContext)
|
|
828
848
|
|
|
849
|
+
let renderTopPrintedStartBottomTenths = 0
|
|
829
850
|
layout.objects
|
|
830
851
|
.filter((object) => object.type == 'container' && (object as ContainerLayoutObject).printOnlyAtStart)
|
|
831
852
|
.forEach((object) => {
|
|
832
|
-
addObjectToPDF(0, 0, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext)
|
|
853
|
+
const lh = addObjectToPDF(0, 0, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext)
|
|
854
|
+
renderTopPrintedStartBottomTenths = Math.max(renderTopPrintedStartBottomTenths, lh.y * 10)
|
|
833
855
|
})
|
|
834
856
|
|
|
835
857
|
// Draw containers in rendering mode (body containers after printOnlyAtStart)
|
|
@@ -841,6 +863,7 @@ export async function genPDF(layout: Layout, printBuffer: any, options: GenPdfOp
|
|
|
841
863
|
!(object as ContainerLayoutObject).printOnlyAtStart
|
|
842
864
|
)
|
|
843
865
|
.forEach((object) => {
|
|
866
|
+
renderContext.pendingRootStartBumpTenths = Math.max(0, renderTopPrintedStartBottomTenths - object.y)
|
|
844
867
|
addObjectToPDF(0, 0, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext)
|
|
845
868
|
})
|
|
846
869
|
|
|
@@ -849,6 +872,7 @@ export async function genPDF(layout: Layout, printBuffer: any, options: GenPdfOp
|
|
|
849
872
|
(object) => object.type == 'container' && (object as ContainerLayoutObject).printOnlyAtEnd
|
|
850
873
|
)
|
|
851
874
|
printOnlyAtEndContainers.forEach((object) => {
|
|
875
|
+
renderContext.pendingRootStartBumpTenths = Math.max(0, renderTopPrintedStartBottomTenths - object.y)
|
|
852
876
|
addObjectToPDF(0, 0, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext)
|
|
853
877
|
})
|
|
854
878
|
return doc
|
package/test/reports.spec.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest'
|
|
2
2
|
import { genPDF } from '../src/reports'
|
|
3
3
|
import type { Layout } from '../src/pdf'
|
|
4
|
-
// import fs from 'fs'
|
|
5
4
|
|
|
5
|
+
/** Tiny valid JPEG as data URL — avoids flaky network-dependent image fetch in CI/sandbox. */
|
|
6
|
+
function offlineJpegFixture(): string {
|
|
7
|
+
const b64 =
|
|
8
|
+
'/9j/4AAQSkZJRgABAQIAASABIAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAKAAoDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAb/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHhAP/EABQQAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQEAAQkCf//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQMBAT8B/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAgMBPwF//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAQYPAj//xAAVEAEAAAAAAAAAAAAAAAAAAAAAAP/aAAgBAQBPCQ//Z'
|
|
9
|
+
return `data:image/jpeg;base64,${b64}`
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// URL still used so collectImageUrlsFromLayout resolves the layout object
|
|
6
13
|
const imageUrl = 'https://upload.wikimedia.org/wikipedia/commons/thumb/7/79/Phillips_PM5538.jpg/500px-Phillips_PM5538.jpg'
|
|
7
14
|
|
|
8
15
|
describe('genPDF', () => {
|
|
@@ -59,7 +66,14 @@ describe('genPDF', () => {
|
|
|
59
66
|
title: 'Minimal PDF',
|
|
60
67
|
}
|
|
61
68
|
|
|
62
|
-
const doc = await genPDF(layout, printBuffer
|
|
69
|
+
const doc = await genPDF(layout, printBuffer, {
|
|
70
|
+
loadImage: async () => ({
|
|
71
|
+
dataUrl: offlineJpegFixture(),
|
|
72
|
+
format: 'JPEG',
|
|
73
|
+
width: 500,
|
|
74
|
+
height: 375,
|
|
75
|
+
}),
|
|
76
|
+
})
|
|
63
77
|
const pdf = doc.output('arraybuffer')
|
|
64
78
|
const pdfText = Buffer.from(pdf).toString('latin1')
|
|
65
79
|
|
|
@@ -138,4 +152,115 @@ describe('genPDF', () => {
|
|
|
138
152
|
expect(iStart).toBeLessThan(iMid)
|
|
139
153
|
expect(iMid).toBeLessThan(iEnd)
|
|
140
154
|
})
|
|
155
|
+
|
|
156
|
+
it('stacks top-level body containers below printOnlyAtStart when they share the same layout y', async () => {
|
|
157
|
+
const text = (name: string, label: string, y = 0, fontSize = 80) =>
|
|
158
|
+
({
|
|
159
|
+
type: 'text' as const,
|
|
160
|
+
name,
|
|
161
|
+
x: 20,
|
|
162
|
+
y,
|
|
163
|
+
width: 900,
|
|
164
|
+
height: 400,
|
|
165
|
+
active: true,
|
|
166
|
+
text: label,
|
|
167
|
+
textAlign: 1 as const,
|
|
168
|
+
fontFamily: 'Helvetica',
|
|
169
|
+
fontSize,
|
|
170
|
+
fontStyle: 0,
|
|
171
|
+
}) as const
|
|
172
|
+
|
|
173
|
+
const sharedY = 400
|
|
174
|
+
const layout: Layout = {
|
|
175
|
+
name: 'same-y-stack',
|
|
176
|
+
paperSize: { width: 210, height: 297, footerHeight: 20 },
|
|
177
|
+
objects: [
|
|
178
|
+
{
|
|
179
|
+
type: 'container',
|
|
180
|
+
x: 0,
|
|
181
|
+
y: sharedY,
|
|
182
|
+
width: 1000,
|
|
183
|
+
height: 900,
|
|
184
|
+
active: true,
|
|
185
|
+
source: '',
|
|
186
|
+
printOnlyAtStart: true,
|
|
187
|
+
children: [text('h', 'PAGE1_HEADER_BLOCK')],
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
type: 'container',
|
|
191
|
+
x: 0,
|
|
192
|
+
y: sharedY,
|
|
193
|
+
width: 1000,
|
|
194
|
+
height: 500,
|
|
195
|
+
active: true,
|
|
196
|
+
source: '',
|
|
197
|
+
children: [text('b', 'BODY_AFTER_STACK', 0, 32)],
|
|
198
|
+
},
|
|
199
|
+
],
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const doc = await genPDF(layout, {})
|
|
203
|
+
const pdfText = Buffer.from(doc.output('arraybuffer')).toString('latin1')
|
|
204
|
+
expect(pdfText).toContain('(PAGE1_HEADER_BLOCK)')
|
|
205
|
+
expect(pdfText).toContain('(BODY_AFTER_STACK)')
|
|
206
|
+
const iH = pdfText.indexOf('(PAGE1_HEADER_BLOCK)')
|
|
207
|
+
const iB = pdfText.indexOf('(BODY_AFTER_STACK)')
|
|
208
|
+
expect(iH).toBeGreaterThanOrEqual(0)
|
|
209
|
+
expect(iB).toBeGreaterThanOrEqual(0)
|
|
210
|
+
expect(iH).toBeLessThan(iB)
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
it('redraws empty-source wrapper so inner vertical repeat spans multiple pages', async () => {
|
|
214
|
+
const rowField = {
|
|
215
|
+
type: 'field' as const,
|
|
216
|
+
name: 'ln',
|
|
217
|
+
x: 0,
|
|
218
|
+
y: 0,
|
|
219
|
+
width: 1600,
|
|
220
|
+
height: 80,
|
|
221
|
+
active: true,
|
|
222
|
+
source: 'line',
|
|
223
|
+
textAlign: 1 as const,
|
|
224
|
+
fontFamily: 'Helvetica',
|
|
225
|
+
fontSize: 36,
|
|
226
|
+
fontStyle: 0,
|
|
227
|
+
}
|
|
228
|
+
const ROWS = Array.from({ length: 40 }, (_, i) => ({ line: `ROW_${i}_MARK` }))
|
|
229
|
+
const layout: Layout = {
|
|
230
|
+
name: 'wrapper-overflow',
|
|
231
|
+
paperSize: { width: 210, height: 297, footerHeight: 20 },
|
|
232
|
+
objects: [
|
|
233
|
+
{
|
|
234
|
+
type: 'container',
|
|
235
|
+
name: 'wrap',
|
|
236
|
+
x: 50,
|
|
237
|
+
y: 100,
|
|
238
|
+
width: 1900,
|
|
239
|
+
height: 2800,
|
|
240
|
+
active: true,
|
|
241
|
+
source: '',
|
|
242
|
+
children: [
|
|
243
|
+
{
|
|
244
|
+
type: 'container',
|
|
245
|
+
name: 'rows',
|
|
246
|
+
x: 0,
|
|
247
|
+
y: 0,
|
|
248
|
+
width: 1800,
|
|
249
|
+
height: 120,
|
|
250
|
+
active: true,
|
|
251
|
+
source: 'ROWS',
|
|
252
|
+
repeatContainer: 'vertical' as const,
|
|
253
|
+
children: [rowField],
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
},
|
|
257
|
+
],
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const doc = await genPDF(layout, { ROWS })
|
|
261
|
+
expect(doc.getNumberOfPages()).toBeGreaterThanOrEqual(2)
|
|
262
|
+
const pdfText = Buffer.from(doc.output('arraybuffer')).toString('latin1')
|
|
263
|
+
expect(pdfText).toContain('ROW_0_MARK')
|
|
264
|
+
expect(pdfText).toContain('ROW_35_MARK')
|
|
265
|
+
})
|
|
141
266
|
})
|