@softwear/latestcollectioncore 1.0.178 → 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/reports.js CHANGED
@@ -43,9 +43,21 @@ 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). */
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 (!container.source || container.source === '')
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.repeatOnOverflow)) {
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
- (_a = options.onAlert) === null || _a === void 0 ? void 0 : _a.call(options, { header: 'containernotfound', body: object.source, type: 'warning', timeout: 10000 });
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;
@@ -675,14 +689,14 @@ function genPDF(layout, printBuffer, options = {}) {
675
689
  !object.printOnlyAtEnd &&
676
690
  !object.printOnlyAtStart)
677
691
  .forEach((object) => {
678
- const bump = Math.max(0, measurementTopPrintedStartBottomTenths - object.y);
679
- addObjectToPDF(0, bump, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext);
692
+ measurementContext.pendingRootStartBumpTenths = Math.max(0, measurementTopPrintedStartBottomTenths - object.y);
693
+ addObjectToPDF(0, 0, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext);
680
694
  });
681
695
  layout.objects
682
696
  .filter((object) => object.type == 'container' && object.printOnlyAtEnd)
683
697
  .forEach((object) => {
684
- const bump = Math.max(0, measurementTopPrintedStartBottomTenths - object.y);
685
- addObjectToPDF(0, bump, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext);
698
+ measurementContext.pendingRootStartBumpTenths = Math.max(0, measurementTopPrintedStartBottomTenths - object.y);
699
+ addObjectToPDF(0, 0, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext);
686
700
  });
687
701
  // Get total page count from measurement pass
688
702
  const totalPageCount = measurementContext.currentPageCount || 1;
@@ -714,14 +728,14 @@ function genPDF(layout, printBuffer, options = {}) {
714
728
  !object.printOnlyAtEnd &&
715
729
  !object.printOnlyAtStart)
716
730
  .forEach((object) => {
717
- const bump = Math.max(0, renderTopPrintedStartBottomTenths - object.y);
718
- addObjectToPDF(0, bump, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext);
731
+ renderContext.pendingRootStartBumpTenths = Math.max(0, renderTopPrintedStartBottomTenths - object.y);
732
+ addObjectToPDF(0, 0, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext);
719
733
  });
720
734
  // Draw printOnlyAtEnd containers once at the end (at their layout coordinates on current page)
721
735
  const printOnlyAtEndContainers = layout.objects.filter((object) => object.type == 'container' && object.printOnlyAtEnd);
722
736
  printOnlyAtEndContainers.forEach((object) => {
723
- const bump = Math.max(0, renderTopPrintedStartBottomTenths - object.y);
724
- addObjectToPDF(0, bump, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext);
737
+ renderContext.pendingRootStartBumpTenths = Math.max(0, renderTopPrintedStartBottomTenths - object.y);
738
+ addObjectToPDF(0, 0, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext);
725
739
  });
726
740
  return doc;
727
741
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softwear/latestcollectioncore",
3
- "version": "1.0.178",
3
+ "version": "1.0.179",
4
4
  "description": "Core functions for LatestCollections applications",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
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 over the current buffer when the container is only a visual group (no `source` binding). */
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 (!container.source || container.source === '') return [printBuffer]
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.repeatOnOverflow)) {
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
@@ -801,14 +817,14 @@ export async function genPDF(layout: Layout, printBuffer: any, options: GenPdfOp
801
817
  !(object as ContainerLayoutObject).printOnlyAtStart
802
818
  )
803
819
  .forEach((object) => {
804
- const bump = Math.max(0, measurementTopPrintedStartBottomTenths - object.y)
805
- addObjectToPDF(0, bump, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext)
820
+ measurementContext.pendingRootStartBumpTenths = Math.max(0, measurementTopPrintedStartBottomTenths - object.y)
821
+ addObjectToPDF(0, 0, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext)
806
822
  })
807
823
  layout.objects
808
824
  .filter((object) => object.type == 'container' && (object as ContainerLayoutObject).printOnlyAtEnd)
809
825
  .forEach((object) => {
810
- const bump = Math.max(0, measurementTopPrintedStartBottomTenths - object.y)
811
- addObjectToPDF(0, bump, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext)
826
+ measurementContext.pendingRootStartBumpTenths = Math.max(0, measurementTopPrintedStartBottomTenths - object.y)
827
+ addObjectToPDF(0, 0, measurementDoc, object, printBuffer, paperSize, layout, options, printBuffer, [], measurementContext)
812
828
  })
813
829
 
814
830
  // Get total page count from measurement pass
@@ -847,8 +863,8 @@ export async function genPDF(layout: Layout, printBuffer: any, options: GenPdfOp
847
863
  !(object as ContainerLayoutObject).printOnlyAtStart
848
864
  )
849
865
  .forEach((object) => {
850
- const bump = Math.max(0, renderTopPrintedStartBottomTenths - object.y)
851
- addObjectToPDF(0, bump, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext)
866
+ renderContext.pendingRootStartBumpTenths = Math.max(0, renderTopPrintedStartBottomTenths - object.y)
867
+ addObjectToPDF(0, 0, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext)
852
868
  })
853
869
 
854
870
  // Draw printOnlyAtEnd containers once at the end (at their layout coordinates on current page)
@@ -856,8 +872,8 @@ export async function genPDF(layout: Layout, printBuffer: any, options: GenPdfOp
856
872
  (object) => object.type == 'container' && (object as ContainerLayoutObject).printOnlyAtEnd
857
873
  )
858
874
  printOnlyAtEndContainers.forEach((object) => {
859
- const bump = Math.max(0, renderTopPrintedStartBottomTenths - object.y)
860
- addObjectToPDF(0, bump, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext)
875
+ renderContext.pendingRootStartBumpTenths = Math.max(0, renderTopPrintedStartBottomTenths - object.y)
876
+ addObjectToPDF(0, 0, doc, object, printBuffer, paperSize, layout, options, printBuffer, [], renderContext)
861
877
  })
862
878
  return doc
863
879
  }
@@ -209,4 +209,58 @@ describe('genPDF', () => {
209
209
  expect(iB).toBeGreaterThanOrEqual(0)
210
210
  expect(iH).toBeLessThan(iB)
211
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
+ })
212
266
  })