@softwear/latestcollectioncore 1.0.176 → 1.0.177
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 +2 -0
- package/dist/reports.js +26 -7
- package/package.json +1 -1
- package/src/pdf.ts +2 -0
- package/src/reports.ts +37 -9
- package/test/reports.spec.ts +67 -0
package/dist/pdf.d.ts
CHANGED
|
@@ -54,6 +54,8 @@ 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
|
+
/** When true, container and children are drawn only once before other body containers (first page header block) */
|
|
58
|
+
printOnlyAtStart?: boolean;
|
|
57
59
|
}
|
|
58
60
|
export type LayoutObject = TextLayoutObject | FieldLayoutObject | RectangleLayoutObject | ImageLayoutObject | ContainerLayoutObject;
|
|
59
61
|
export interface Layout {
|
package/dist/reports.js
CHANGED
|
@@ -43,6 +43,12 @@ function getProperty(propertyName, object) {
|
|
|
43
43
|
}
|
|
44
44
|
return property;
|
|
45
45
|
}
|
|
46
|
+
/** Repeat once over the current buffer when the container is only a visual group (no `source` binding). */
|
|
47
|
+
function containerLoopSource(container, printBuffer) {
|
|
48
|
+
if (!container.source || container.source === '')
|
|
49
|
+
return [printBuffer];
|
|
50
|
+
return getProperty(container.source, printBuffer);
|
|
51
|
+
}
|
|
46
52
|
/** jsPDF font style strings. fontStyle bitmask: 0=normal, 1=bold, 2=italic, 3=bold+italic */
|
|
47
53
|
const FONT_STYLES = ['normal', 'bold', 'italic', 'bolditalic'];
|
|
48
54
|
/** Recursively collect used custom fonts from layout objects (text/field with fontFamily) and layout default. */
|
|
@@ -160,7 +166,7 @@ function collectImageUrlsFromLayout(layout, printBuffer) {
|
|
|
160
166
|
}
|
|
161
167
|
if (object.type !== 'container')
|
|
162
168
|
return;
|
|
163
|
-
const source =
|
|
169
|
+
const source = containerLoopSource(object, currentPrintBuffer);
|
|
164
170
|
if (!Array.isArray(source))
|
|
165
171
|
return;
|
|
166
172
|
source.forEach((containerPrintBuffer) => walk(object.children, containerPrintBuffer));
|
|
@@ -450,8 +456,7 @@ addObjectToPDF = function (originX, originY, doc, object, printBuffer, paperSize
|
|
|
450
456
|
// Recursively draw all child objects from a container object
|
|
451
457
|
if (object.type == 'container') {
|
|
452
458
|
let originX = x * 10, originY = y * 10;
|
|
453
|
-
const
|
|
454
|
-
const source = isPrintOnlyAtEnd && (!object.source || object.source === '') ? [printBuffer] : getProperty(object.source, printBuffer);
|
|
459
|
+
const source = containerLoopSource(object, printBuffer);
|
|
455
460
|
if (source === undefined) {
|
|
456
461
|
(_a = options.onAlert) === null || _a === void 0 ? void 0 : _a.call(options, { header: 'containernotfound', body: object.source, type: 'warning', timeout: 10000 });
|
|
457
462
|
return absoluteLowerRightHandSide;
|
|
@@ -657,9 +662,16 @@ function genPDF(layout, printBuffer, options = {}) {
|
|
|
657
662
|
yield embedFontsInDoc(measurementDoc, usedFonts, options);
|
|
658
663
|
}
|
|
659
664
|
drawStaticPartOfPage(measurementDoc, layout, printBuffer, paperSize, options, measurementContext);
|
|
660
|
-
// Draw containers in measurement mode (same order as render
|
|
665
|
+
// Draw containers in measurement mode (same order as render)
|
|
666
|
+
layout.objects
|
|
667
|
+
.filter((object) => object.type == 'container' && object.printOnlyAtStart)
|
|
668
|
+
.forEach((object) => {
|
|
669
|
+
addObjectToPDF(0, 0, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext);
|
|
670
|
+
});
|
|
661
671
|
layout.objects
|
|
662
|
-
.filter((object) => object.type == 'container' &&
|
|
672
|
+
.filter((object) => object.type == 'container' &&
|
|
673
|
+
!object.printOnlyAtEnd &&
|
|
674
|
+
!object.printOnlyAtStart)
|
|
663
675
|
.forEach((object) => {
|
|
664
676
|
addObjectToPDF(0, 0, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext);
|
|
665
677
|
});
|
|
@@ -685,9 +697,16 @@ function genPDF(layout, printBuffer, options = {}) {
|
|
|
685
697
|
defaultFontFamily: layout.defaultFontFamily,
|
|
686
698
|
};
|
|
687
699
|
drawStaticPartOfPage(doc, layout, printBuffer, paperSize, options, renderContext);
|
|
688
|
-
// Draw containers in rendering mode (normal containers first)
|
|
689
700
|
layout.objects
|
|
690
|
-
.filter((object) => object.type == 'container' &&
|
|
701
|
+
.filter((object) => object.type == 'container' && object.printOnlyAtStart)
|
|
702
|
+
.forEach((object) => {
|
|
703
|
+
addObjectToPDF(0, 0, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext);
|
|
704
|
+
});
|
|
705
|
+
// Draw containers in rendering mode (body containers after printOnlyAtStart)
|
|
706
|
+
layout.objects
|
|
707
|
+
.filter((object) => object.type == 'container' &&
|
|
708
|
+
!object.printOnlyAtEnd &&
|
|
709
|
+
!object.printOnlyAtStart)
|
|
691
710
|
.forEach((object) => {
|
|
692
711
|
addObjectToPDF(0, 0, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext);
|
|
693
712
|
});
|
package/package.json
CHANGED
package/src/pdf.ts
CHANGED
|
@@ -61,6 +61,8 @@ 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
|
+
/** When true, container and children are drawn only once before other body containers (first page header block) */
|
|
65
|
+
printOnlyAtStart?: boolean
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
export type LayoutObject = TextLayoutObject | FieldLayoutObject | RectangleLayoutObject | ImageLayoutObject | ContainerLayoutObject
|
package/src/reports.ts
CHANGED
|
@@ -92,6 +92,12 @@ function getProperty(propertyName: string, object: any): any {
|
|
|
92
92
|
return property
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
/** Repeat once over the current buffer when the container is only a visual group (no `source` binding). */
|
|
96
|
+
function containerLoopSource(container: ContainerLayoutObject, printBuffer: any): any {
|
|
97
|
+
if (!container.source || container.source === '') return [printBuffer]
|
|
98
|
+
return getProperty(container.source, printBuffer)
|
|
99
|
+
}
|
|
100
|
+
|
|
95
101
|
/** jsPDF font style strings. fontStyle bitmask: 0=normal, 1=bold, 2=italic, 3=bold+italic */
|
|
96
102
|
const FONT_STYLES = ['normal', 'bold', 'italic', 'bolditalic'] as const
|
|
97
103
|
|
|
@@ -222,7 +228,7 @@ function collectImageUrlsFromLayout(layout: Layout, printBuffer: any): string[]
|
|
|
222
228
|
|
|
223
229
|
if (object.type !== 'container') return
|
|
224
230
|
|
|
225
|
-
const source = (object as
|
|
231
|
+
const source = containerLoopSource(object as ContainerLayoutObject, currentPrintBuffer)
|
|
226
232
|
if (!Array.isArray(source)) return
|
|
227
233
|
source.forEach((containerPrintBuffer) => walk(object.children, containerPrintBuffer))
|
|
228
234
|
})
|
|
@@ -539,8 +545,7 @@ addObjectToPDF = function (
|
|
|
539
545
|
let originX = x * 10,
|
|
540
546
|
originY = y * 10
|
|
541
547
|
|
|
542
|
-
const
|
|
543
|
-
const source = isPrintOnlyAtEnd && (!object.source || object.source === '') ? [printBuffer] : getProperty(object.source, printBuffer)
|
|
548
|
+
const source = containerLoopSource(object as ContainerLayoutObject, printBuffer)
|
|
544
549
|
if (source === undefined) {
|
|
545
550
|
options.onAlert?.({ header: 'containernotfound', body: object.source, type: 'warning', timeout: 10000 })
|
|
546
551
|
return absoluteLowerRightHandSide
|
|
@@ -780,14 +785,24 @@ export async function genPDF(layout: Layout, printBuffer: any, options: GenPdfOp
|
|
|
780
785
|
}
|
|
781
786
|
drawStaticPartOfPage(measurementDoc, layout, printBuffer, paperSize, options, measurementContext)
|
|
782
787
|
|
|
783
|
-
// Draw containers in measurement mode (same order as render
|
|
788
|
+
// Draw containers in measurement mode (same order as render)
|
|
789
|
+
layout.objects
|
|
790
|
+
.filter((object) => object.type == 'container' && (object as ContainerLayoutObject).printOnlyAtStart)
|
|
791
|
+
.forEach((object) => {
|
|
792
|
+
addObjectToPDF(0, 0, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext)
|
|
793
|
+
})
|
|
784
794
|
layout.objects
|
|
785
|
-
.filter(
|
|
795
|
+
.filter(
|
|
796
|
+
(object) =>
|
|
797
|
+
object.type == 'container' &&
|
|
798
|
+
!(object as ContainerLayoutObject).printOnlyAtEnd &&
|
|
799
|
+
!(object as ContainerLayoutObject).printOnlyAtStart
|
|
800
|
+
)
|
|
786
801
|
.forEach((object) => {
|
|
787
802
|
addObjectToPDF(0, 0, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext)
|
|
788
803
|
})
|
|
789
804
|
layout.objects
|
|
790
|
-
.filter((object) => object.type == 'container' && (object as
|
|
805
|
+
.filter((object) => object.type == 'container' && (object as ContainerLayoutObject).printOnlyAtEnd)
|
|
791
806
|
.forEach((object) => {
|
|
792
807
|
addObjectToPDF(0, 0, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext)
|
|
793
808
|
})
|
|
@@ -811,15 +826,28 @@ export async function genPDF(layout: Layout, printBuffer: any, options: GenPdfOp
|
|
|
811
826
|
}
|
|
812
827
|
drawStaticPartOfPage(doc, layout, printBuffer, paperSize, options, renderContext)
|
|
813
828
|
|
|
814
|
-
// Draw containers in rendering mode (normal containers first)
|
|
815
829
|
layout.objects
|
|
816
|
-
.filter((object) => object.type == 'container' &&
|
|
830
|
+
.filter((object) => object.type == 'container' && (object as ContainerLayoutObject).printOnlyAtStart)
|
|
831
|
+
.forEach((object) => {
|
|
832
|
+
addObjectToPDF(0, 0, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext)
|
|
833
|
+
})
|
|
834
|
+
|
|
835
|
+
// Draw containers in rendering mode (body containers after printOnlyAtStart)
|
|
836
|
+
layout.objects
|
|
837
|
+
.filter(
|
|
838
|
+
(object) =>
|
|
839
|
+
object.type == 'container' &&
|
|
840
|
+
!(object as ContainerLayoutObject).printOnlyAtEnd &&
|
|
841
|
+
!(object as ContainerLayoutObject).printOnlyAtStart
|
|
842
|
+
)
|
|
817
843
|
.forEach((object) => {
|
|
818
844
|
addObjectToPDF(0, 0, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext)
|
|
819
845
|
})
|
|
820
846
|
|
|
821
847
|
// Draw printOnlyAtEnd containers once at the end (at their layout coordinates on current page)
|
|
822
|
-
const printOnlyAtEndContainers = layout.objects.filter(
|
|
848
|
+
const printOnlyAtEndContainers = layout.objects.filter(
|
|
849
|
+
(object) => object.type == 'container' && (object as ContainerLayoutObject).printOnlyAtEnd
|
|
850
|
+
)
|
|
823
851
|
printOnlyAtEndContainers.forEach((object) => {
|
|
824
852
|
addObjectToPDF(0, 0, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext)
|
|
825
853
|
})
|
package/test/reports.spec.ts
CHANGED
|
@@ -71,4 +71,71 @@ describe('genPDF', () => {
|
|
|
71
71
|
expect(pdfText).toContain(printBuffer.title)
|
|
72
72
|
// fs.writeFileSync('test.pdf', Buffer.from(pdf))
|
|
73
73
|
})
|
|
74
|
+
|
|
75
|
+
it('draws printOnlyAtStart before body containers and printOnlyAtEnd after', async () => {
|
|
76
|
+
const textChild = (name: string, y: number, label: string) =>
|
|
77
|
+
({
|
|
78
|
+
type: 'text' as const,
|
|
79
|
+
name,
|
|
80
|
+
x: 20,
|
|
81
|
+
y,
|
|
82
|
+
width: 400,
|
|
83
|
+
height: 40,
|
|
84
|
+
active: true,
|
|
85
|
+
text: label,
|
|
86
|
+
textAlign: 1 as const,
|
|
87
|
+
fontFamily: 'Helvetica',
|
|
88
|
+
fontSize: 24,
|
|
89
|
+
fontStyle: 0,
|
|
90
|
+
}) as const
|
|
91
|
+
|
|
92
|
+
const layout: Layout = {
|
|
93
|
+
name: 'order-test',
|
|
94
|
+
paperSize: { width: 210, height: 297, footerHeight: 20 },
|
|
95
|
+
objects: [
|
|
96
|
+
{
|
|
97
|
+
type: 'container',
|
|
98
|
+
x: 0,
|
|
99
|
+
y: 40,
|
|
100
|
+
width: 500,
|
|
101
|
+
height: 80,
|
|
102
|
+
active: true,
|
|
103
|
+
source: '',
|
|
104
|
+
printOnlyAtStart: true,
|
|
105
|
+
children: [textChild('start', 0, 'START_ONLY')],
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
type: 'container',
|
|
109
|
+
x: 0,
|
|
110
|
+
y: 120,
|
|
111
|
+
width: 500,
|
|
112
|
+
height: 80,
|
|
113
|
+
active: true,
|
|
114
|
+
source: '',
|
|
115
|
+
children: [textChild('mid', 0, 'BODY_MIDDLE')],
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
type: 'container',
|
|
119
|
+
x: 0,
|
|
120
|
+
y: 200,
|
|
121
|
+
width: 500,
|
|
122
|
+
height: 80,
|
|
123
|
+
active: true,
|
|
124
|
+
source: '',
|
|
125
|
+
printOnlyAtEnd: true,
|
|
126
|
+
children: [textChild('end', 0, 'END_ONLY')],
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
}
|
|
130
|
+
const doc = await genPDF(layout, {})
|
|
131
|
+
const pdfText = Buffer.from(doc.output('arraybuffer')).toString('latin1')
|
|
132
|
+
const iStart = pdfText.indexOf('(START_ONLY)')
|
|
133
|
+
const iMid = pdfText.indexOf('(BODY_MIDDLE)')
|
|
134
|
+
const iEnd = pdfText.indexOf('(END_ONLY)')
|
|
135
|
+
expect(iStart).toBeGreaterThanOrEqual(0)
|
|
136
|
+
expect(iMid).toBeGreaterThanOrEqual(0)
|
|
137
|
+
expect(iEnd).toBeGreaterThanOrEqual(0)
|
|
138
|
+
expect(iStart).toBeLessThan(iMid)
|
|
139
|
+
expect(iMid).toBeLessThan(iEnd)
|
|
140
|
+
})
|
|
74
141
|
})
|