@softwear/latestcollectioncore 1.0.183 → 1.0.184
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/reports.js +21 -0
- package/package.json +1 -1
- package/src/reports.ts +28 -0
- package/test/reports.spec.ts +68 -0
package/dist/reports.js
CHANGED
|
@@ -61,6 +61,26 @@ function containerLoopSource(container, printBuffer) {
|
|
|
61
61
|
return [printBuffer];
|
|
62
62
|
return getProperty(container.source, printBuffer);
|
|
63
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Top-level empty-source containers (invoice “billTo” bands, wrappers) sit beside overflowing repeats.
|
|
66
|
+
* They are not on the nested {@link containerChain}; redraw them whenever we append a continuation page.
|
|
67
|
+
* Omit the overflowing root when it is chain[0] — redrawing it would recurse (e.g. wrapper around lines).
|
|
68
|
+
*/
|
|
69
|
+
function redrawRootDummyBodyContainersOnNewPage(doc, layout, rootPrintBuffer, paperSize, options, context, containerChain) {
|
|
70
|
+
const overflowingRootContainer = containerChain.length > 0 ? containerChain[0].object : undefined;
|
|
71
|
+
layout.objects.forEach((object) => {
|
|
72
|
+
if (object.type !== 'container')
|
|
73
|
+
return;
|
|
74
|
+
if (overflowingRootContainer !== undefined && object === overflowingRootContainer)
|
|
75
|
+
return;
|
|
76
|
+
const c = object;
|
|
77
|
+
if (c.printOnlyAtStart === true || c.printOnlyAtEnd === true)
|
|
78
|
+
return;
|
|
79
|
+
if (!dummyLayoutSource(c.source))
|
|
80
|
+
return;
|
|
81
|
+
addObjectToPDF(0, 0, doc, object, rootPrintBuffer, paperSize, layout, options, rootPrintBuffer, [], context);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
64
84
|
/** jsPDF font style strings. fontStyle bitmask: 0=normal, 1=bold, 2=italic, 3=bold+italic */
|
|
65
85
|
const FONT_STYLES = ['normal', 'bold', 'italic', 'bolditalic'];
|
|
66
86
|
/** Recursively collect used custom fonts from layout objects (text/field with fontFamily) and layout default. */
|
|
@@ -399,6 +419,7 @@ function addPage(originX, originY, doc, layout, rootPrintBuffer, paperSize, opti
|
|
|
399
419
|
}
|
|
400
420
|
if (!context.measureOnly) {
|
|
401
421
|
drawStaticPartOfPage(doc, layout, rootPrintBuffer, paperSize, options, context);
|
|
422
|
+
redrawRootDummyBodyContainersOnNewPage(doc, layout, rootPrintBuffer, paperSize, options, context, containerChain);
|
|
402
423
|
}
|
|
403
424
|
// Bounding box tracked for snap-to-bottom; continuation cursor is ALWAYS the passed-in coords.
|
|
404
425
|
const absoluteLowerRightHandSide = { x: continuationOxTenths / 10, y: continuationOyTenths / 10 };
|
package/package.json
CHANGED
package/src/reports.ts
CHANGED
|
@@ -118,6 +118,33 @@ function containerLoopSource(container: ContainerLayoutObject, printBuffer: any)
|
|
|
118
118
|
return getProperty(container.source as string, printBuffer)
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Top-level empty-source containers (invoice “billTo” bands, wrappers) sit beside overflowing repeats.
|
|
123
|
+
* They are not on the nested {@link containerChain}; redraw them whenever we append a continuation page.
|
|
124
|
+
* Omit the overflowing root when it is chain[0] — redrawing it would recurse (e.g. wrapper around lines).
|
|
125
|
+
*/
|
|
126
|
+
function redrawRootDummyBodyContainersOnNewPage(
|
|
127
|
+
doc: jsPDF,
|
|
128
|
+
layout: Layout,
|
|
129
|
+
rootPrintBuffer: any,
|
|
130
|
+
paperSize: PaperSize,
|
|
131
|
+
options: GenPdfOptions,
|
|
132
|
+
context: RenderContext,
|
|
133
|
+
containerChain: { object: ContainerLayoutObject; printBuffer: any }[]
|
|
134
|
+
): void {
|
|
135
|
+
const overflowingRootContainer =
|
|
136
|
+
containerChain.length > 0 ? (containerChain[0].object as ContainerLayoutObject) : undefined
|
|
137
|
+
|
|
138
|
+
layout.objects.forEach((object) => {
|
|
139
|
+
if (object.type !== 'container') return
|
|
140
|
+
if (overflowingRootContainer !== undefined && object === overflowingRootContainer) return
|
|
141
|
+
const c = object as ContainerLayoutObject
|
|
142
|
+
if (c.printOnlyAtStart === true || c.printOnlyAtEnd === true) return
|
|
143
|
+
if (!dummyLayoutSource(c.source)) return
|
|
144
|
+
addObjectToPDF(0, 0, doc, object, rootPrintBuffer, paperSize, layout, options, rootPrintBuffer, [], context)
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
|
|
121
148
|
/** jsPDF font style strings. fontStyle bitmask: 0=normal, 1=bold, 2=italic, 3=bold+italic */
|
|
122
149
|
const FONT_STYLES = ['normal', 'bold', 'italic', 'bolditalic'] as const
|
|
123
150
|
|
|
@@ -472,6 +499,7 @@ function addPage(
|
|
|
472
499
|
}
|
|
473
500
|
if (!context.measureOnly) {
|
|
474
501
|
drawStaticPartOfPage(doc, layout, rootPrintBuffer, paperSize, options, context)
|
|
502
|
+
redrawRootDummyBodyContainersOnNewPage(doc, layout, rootPrintBuffer, paperSize, options, context, containerChain)
|
|
475
503
|
}
|
|
476
504
|
// Bounding box tracked for snap-to-bottom; continuation cursor is ALWAYS the passed-in coords.
|
|
477
505
|
const absoluteLowerRightHandSide = { x: continuationOxTenths / 10, y: continuationOyTenths / 10 }
|
package/test/reports.spec.ts
CHANGED
|
@@ -263,4 +263,72 @@ describe('genPDF', () => {
|
|
|
263
263
|
expect(pdfText).toContain('ROW_0_MARK')
|
|
264
264
|
expect(pdfText).toContain('ROW_35_MARK')
|
|
265
265
|
})
|
|
266
|
+
|
|
267
|
+
it('redraws top-level empty-source body containers on every continuation page beside an overflowing sibling', async () => {
|
|
268
|
+
const chromeText = {
|
|
269
|
+
type: 'text' as const,
|
|
270
|
+
name: 'chrome-label',
|
|
271
|
+
x: 0,
|
|
272
|
+
y: 0,
|
|
273
|
+
width: 300,
|
|
274
|
+
height: 48,
|
|
275
|
+
active: true,
|
|
276
|
+
text: 'CHROME_EACH_PAGE',
|
|
277
|
+
textAlign: 1 as const,
|
|
278
|
+
fontFamily: 'Helvetica',
|
|
279
|
+
fontSize: 28,
|
|
280
|
+
fontStyle: 0,
|
|
281
|
+
}
|
|
282
|
+
const lineField = {
|
|
283
|
+
type: 'field' as const,
|
|
284
|
+
name: 'ln',
|
|
285
|
+
x: 0,
|
|
286
|
+
y: 0,
|
|
287
|
+
width: 800,
|
|
288
|
+
height: 96,
|
|
289
|
+
active: true,
|
|
290
|
+
source: 'line',
|
|
291
|
+
textAlign: 1 as const,
|
|
292
|
+
fontFamily: 'Helvetica',
|
|
293
|
+
fontSize: 36,
|
|
294
|
+
fontStyle: 0,
|
|
295
|
+
}
|
|
296
|
+
const ITEMS = Array.from({ length: 48 }, (_, i) => ({ line: `SKU_${i}` }))
|
|
297
|
+
const layout: Layout = {
|
|
298
|
+
name: 'sibling-chrome',
|
|
299
|
+
paperSize: { width: 210, height: 297, footerHeight: 20 },
|
|
300
|
+
objects: [
|
|
301
|
+
{
|
|
302
|
+
type: 'container',
|
|
303
|
+
name: 'addressBand',
|
|
304
|
+
x: 60,
|
|
305
|
+
y: 440,
|
|
306
|
+
width: 400,
|
|
307
|
+
height: 280,
|
|
308
|
+
active: true,
|
|
309
|
+
source: '',
|
|
310
|
+
children: [chromeText],
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
type: 'container',
|
|
314
|
+
name: 'lines',
|
|
315
|
+
x: 500,
|
|
316
|
+
y: 440,
|
|
317
|
+
width: 1500,
|
|
318
|
+
height: 200,
|
|
319
|
+
active: true,
|
|
320
|
+
source: 'ITEMS',
|
|
321
|
+
repeatContainer: 'vertical' as const,
|
|
322
|
+
children: [lineField],
|
|
323
|
+
},
|
|
324
|
+
],
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const doc = await genPDF(layout, { ITEMS })
|
|
328
|
+
expect(doc.getNumberOfPages()).toBeGreaterThanOrEqual(2)
|
|
329
|
+
const pdfText = Buffer.from(doc.output('arraybuffer')).toString('latin1')
|
|
330
|
+
const chromeMatches = pdfText.match(/\(CHROME_EACH_PAGE\)/g)
|
|
331
|
+
expect(chromeMatches?.length ?? 0).toBeGreaterThanOrEqual(doc.getNumberOfPages())
|
|
332
|
+
expect(pdfText).toContain('SKU_20')
|
|
333
|
+
})
|
|
266
334
|
})
|