pdfmake 0.3.0-beta.10 → 0.3.0-beta.12
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/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/.idea/misc.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/pdfmake.iml +11 -0
- package/.idea/vcs.xml +6 -0
- package/CHANGELOG.md +13 -0
- package/build/pdfmake.js +44815 -44689
- package/build/pdfmake.js.map +1 -1
- package/build/pdfmake.min.js +2 -2
- package/build/pdfmake.min.js.map +1 -1
- package/build/vfs_fonts.js +6 -5
- package/eslint.config.mjs +52 -52
- package/js/DocumentContext.js +12 -1
- package/js/ElementWriter.js +4 -1
- package/js/LayoutBuilder.js +206 -81
- package/js/PageElementWriter.js +2 -2
- package/js/Printer.js +6 -0
- package/js/Renderer.js +17 -0
- package/js/TableProcessor.js +37 -13
- package/package.json +14 -14
- package/src/3rd-party/svg-to-pdfkit/LICENSE +9 -9
- package/src/DocumentContext.js +13 -1
- package/src/ElementWriter.js +4 -1
- package/src/LayoutBuilder.js +211 -79
- package/src/PageElementWriter.js +2 -2
- package/src/Printer.js +6 -0
- package/src/Renderer.js +11 -0
- package/src/TableProcessor.js +37 -15
package/eslint.config.mjs
CHANGED
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
import jsdoc from "eslint-plugin-jsdoc";
|
|
2
|
-
import globals from "globals";
|
|
3
|
-
import js from "@eslint/js";
|
|
4
|
-
|
|
5
|
-
export default [
|
|
6
|
-
{
|
|
7
|
-
ignores: ["src/3rd-party/svg-to-pdfkit/*"],
|
|
8
|
-
},
|
|
9
|
-
|
|
10
|
-
js.configs.recommended,
|
|
11
|
-
|
|
12
|
-
{
|
|
13
|
-
plugins: {
|
|
14
|
-
jsdoc,
|
|
15
|
-
},
|
|
16
|
-
|
|
17
|
-
languageOptions: {
|
|
18
|
-
globals: {
|
|
19
|
-
...globals.browser,
|
|
20
|
-
...globals.node,
|
|
21
|
-
...globals.mocha,
|
|
22
|
-
},
|
|
23
|
-
|
|
24
|
-
ecmaVersion: 9,
|
|
25
|
-
sourceType: "module",
|
|
26
|
-
},
|
|
27
|
-
|
|
28
|
-
rules: {
|
|
29
|
-
semi: 2,
|
|
30
|
-
"no-throw-literal": 2,
|
|
31
|
-
"no-prototype-builtins": 0,
|
|
32
|
-
"jsdoc/check-examples": 0,
|
|
33
|
-
"jsdoc/check-param-names": 1,
|
|
34
|
-
"jsdoc/check-tag-names": 1,
|
|
35
|
-
"jsdoc/check-types": 1,
|
|
36
|
-
"jsdoc/no-undefined-types": 1,
|
|
37
|
-
"jsdoc/require-description": 0,
|
|
38
|
-
"jsdoc/require-description-complete-sentence": 0,
|
|
39
|
-
"jsdoc/require-example": 0,
|
|
40
|
-
"jsdoc/require-hyphen-before-param-description": 0,
|
|
41
|
-
"jsdoc/require-param": 1,
|
|
42
|
-
"jsdoc/require-param-description": 0,
|
|
43
|
-
"jsdoc/require-param-name": 1,
|
|
44
|
-
"jsdoc/require-param-type": 1,
|
|
45
|
-
"jsdoc/require-returns": 1,
|
|
46
|
-
"jsdoc/require-returns-check": 1,
|
|
47
|
-
"jsdoc/require-returns-description": 0,
|
|
48
|
-
"jsdoc/require-returns-type": 1,
|
|
49
|
-
"jsdoc/valid-types": 1,
|
|
50
|
-
},
|
|
51
|
-
}
|
|
52
|
-
];
|
|
1
|
+
import jsdoc from "eslint-plugin-jsdoc";
|
|
2
|
+
import globals from "globals";
|
|
3
|
+
import js from "@eslint/js";
|
|
4
|
+
|
|
5
|
+
export default [
|
|
6
|
+
{
|
|
7
|
+
ignores: ["src/3rd-party/svg-to-pdfkit/*"],
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
js.configs.recommended,
|
|
11
|
+
|
|
12
|
+
{
|
|
13
|
+
plugins: {
|
|
14
|
+
jsdoc,
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
languageOptions: {
|
|
18
|
+
globals: {
|
|
19
|
+
...globals.browser,
|
|
20
|
+
...globals.node,
|
|
21
|
+
...globals.mocha,
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
ecmaVersion: 9,
|
|
25
|
+
sourceType: "module",
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
rules: {
|
|
29
|
+
semi: 2,
|
|
30
|
+
"no-throw-literal": 2,
|
|
31
|
+
"no-prototype-builtins": 0,
|
|
32
|
+
"jsdoc/check-examples": 0,
|
|
33
|
+
"jsdoc/check-param-names": 1,
|
|
34
|
+
"jsdoc/check-tag-names": 1,
|
|
35
|
+
"jsdoc/check-types": 1,
|
|
36
|
+
"jsdoc/no-undefined-types": 1,
|
|
37
|
+
"jsdoc/require-description": 0,
|
|
38
|
+
"jsdoc/require-description-complete-sentence": 0,
|
|
39
|
+
"jsdoc/require-example": 0,
|
|
40
|
+
"jsdoc/require-hyphen-before-param-description": 0,
|
|
41
|
+
"jsdoc/require-param": 1,
|
|
42
|
+
"jsdoc/require-param-description": 0,
|
|
43
|
+
"jsdoc/require-param-name": 1,
|
|
44
|
+
"jsdoc/require-param-type": 1,
|
|
45
|
+
"jsdoc/require-returns": 1,
|
|
46
|
+
"jsdoc/require-returns-check": 1,
|
|
47
|
+
"jsdoc/require-returns-description": 0,
|
|
48
|
+
"jsdoc/require-returns-type": 1,
|
|
49
|
+
"jsdoc/valid-types": 1,
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
];
|
package/js/DocumentContext.js
CHANGED
|
@@ -21,13 +21,14 @@ class DocumentContext extends _events.EventEmitter {
|
|
|
21
21
|
this.backgroundLength = [];
|
|
22
22
|
this.addPage(pageSize);
|
|
23
23
|
}
|
|
24
|
-
beginColumnGroup(marginXTopParent) {
|
|
24
|
+
beginColumnGroup(marginXTopParent, bottomByPage = {}) {
|
|
25
25
|
this.snapshots.push({
|
|
26
26
|
x: this.x,
|
|
27
27
|
y: this.y,
|
|
28
28
|
availableHeight: this.availableHeight,
|
|
29
29
|
availableWidth: this.availableWidth,
|
|
30
30
|
page: this.page,
|
|
31
|
+
bottomByPage: bottomByPage ? bottomByPage : {},
|
|
31
32
|
bottomMost: {
|
|
32
33
|
x: this.x,
|
|
33
34
|
y: this.y,
|
|
@@ -42,6 +43,15 @@ class DocumentContext extends _events.EventEmitter {
|
|
|
42
43
|
this.marginXTopParent = marginXTopParent;
|
|
43
44
|
}
|
|
44
45
|
}
|
|
46
|
+
updateBottomByPage() {
|
|
47
|
+
const lastSnapshot = this.snapshots[this.snapshots.length - 1];
|
|
48
|
+
const lastPage = this.page;
|
|
49
|
+
let previousBottom = -Number.MIN_VALUE;
|
|
50
|
+
if (lastSnapshot.bottomByPage[lastPage]) {
|
|
51
|
+
previousBottom = lastSnapshot.bottomByPage[lastPage];
|
|
52
|
+
}
|
|
53
|
+
lastSnapshot.bottomByPage[lastPage] = Math.max(previousBottom, this.y);
|
|
54
|
+
}
|
|
45
55
|
resetMarginXTopParent() {
|
|
46
56
|
this.marginXTopParent = null;
|
|
47
57
|
}
|
|
@@ -102,6 +112,7 @@ class DocumentContext extends _events.EventEmitter {
|
|
|
102
112
|
this.availableHeight -= y - saved.bottomMost.y;
|
|
103
113
|
}
|
|
104
114
|
this.lastColumnWidth = saved.lastColumnWidth;
|
|
115
|
+
return saved.bottomByPage;
|
|
105
116
|
}
|
|
106
117
|
addMargin(left, right) {
|
|
107
118
|
this.x += left;
|
package/js/ElementWriter.js
CHANGED
|
@@ -204,9 +204,12 @@ class ElementWriter extends _events.EventEmitter {
|
|
|
204
204
|
});
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
|
-
addVector(vector, ignoreContextX, ignoreContextY, index) {
|
|
207
|
+
addVector(vector, ignoreContextX, ignoreContextY, index, forcePage) {
|
|
208
208
|
let context = this.context();
|
|
209
209
|
let page = context.getCurrentPage();
|
|
210
|
+
if ((0, _variableType.isNumber)(forcePage)) {
|
|
211
|
+
page = context.pages[forcePage];
|
|
212
|
+
}
|
|
210
213
|
let position = this.getCurrentPositionOnPage();
|
|
211
214
|
if (page) {
|
|
212
215
|
(0, _tools.offsetVector)(vector, ignoreContextX ? 0 : context.x, ignoreContextY ? 0 : context.y);
|
package/js/LayoutBuilder.js
CHANGED
|
@@ -472,7 +472,16 @@ class LayoutBuilder {
|
|
|
472
472
|
return gaps;
|
|
473
473
|
}
|
|
474
474
|
}
|
|
475
|
-
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Searches for a cell in the same row that starts a rowspan and is positioned immediately before the current cell.
|
|
478
|
+
* Alternatively, it finds a cell where the colspan initiating the rowspan extends to the cell just before the current one.
|
|
479
|
+
*
|
|
480
|
+
* @param {Array<object>} arr - An array representing cells in a row.
|
|
481
|
+
* @param {number} i - The index of the current cell to search backward from.
|
|
482
|
+
* @returns {object|null} The starting cell of the rowspan if found; otherwise, `null`.
|
|
483
|
+
*/
|
|
484
|
+
_findStartingRowSpanCell(arr, i) {
|
|
476
485
|
let requiredColspan = 1;
|
|
477
486
|
for (let index = i - 1; index >= 0; index--) {
|
|
478
487
|
if (!arr[index]._span) {
|
|
@@ -486,6 +495,140 @@ class LayoutBuilder {
|
|
|
486
495
|
}
|
|
487
496
|
return null;
|
|
488
497
|
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Retrieves a page break description for a specified page from a list of page breaks.
|
|
501
|
+
*
|
|
502
|
+
* @param {Array<object>} pageBreaks - An array of page break descriptions, each containing `prevPage` properties.
|
|
503
|
+
* @param {number} page - The page number to find the associated page break for.
|
|
504
|
+
* @returns {object|undefined} The page break description object for the specified page if found; otherwise, `undefined`.
|
|
505
|
+
*/
|
|
506
|
+
_getPageBreak(pageBreaks, page) {
|
|
507
|
+
return pageBreaks.find(desc => desc.prevPage === page);
|
|
508
|
+
}
|
|
509
|
+
_getPageBreakListBySpan(tableNode, page, rowIndex) {
|
|
510
|
+
if (!tableNode || !tableNode._breaksBySpan) {
|
|
511
|
+
return null;
|
|
512
|
+
}
|
|
513
|
+
const breaksList = tableNode._breaksBySpan.filter(desc => desc.prevPage === page && rowIndex <= desc.rowIndexOfSpanEnd);
|
|
514
|
+
let y = Number.MAX_VALUE,
|
|
515
|
+
prevY = Number.MIN_VALUE;
|
|
516
|
+
breaksList.forEach(b => {
|
|
517
|
+
prevY = Math.max(b.prevY, prevY);
|
|
518
|
+
y = Math.min(b.y, y);
|
|
519
|
+
});
|
|
520
|
+
return {
|
|
521
|
+
prevPage: page,
|
|
522
|
+
prevY: prevY,
|
|
523
|
+
y: y
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
_findSameRowPageBreakByRowSpanData(breaksBySpan, page, rowIndex) {
|
|
527
|
+
if (!breaksBySpan) {
|
|
528
|
+
return null;
|
|
529
|
+
}
|
|
530
|
+
return breaksBySpan.find(desc => desc.prevPage === page && rowIndex === desc.rowIndexOfSpanEnd);
|
|
531
|
+
}
|
|
532
|
+
_updatePageBreaksData(pageBreaks, tableNode, rowIndex) {
|
|
533
|
+
Object.keys(tableNode._bottomByPage).forEach(p => {
|
|
534
|
+
const page = Number(p);
|
|
535
|
+
const pageBreak = this._getPageBreak(pageBreaks, page);
|
|
536
|
+
if (pageBreak) {
|
|
537
|
+
pageBreak.prevY = Math.max(pageBreak.prevY, tableNode._bottomByPage[page]);
|
|
538
|
+
}
|
|
539
|
+
if (tableNode._breaksBySpan && tableNode._breaksBySpan.length > 0) {
|
|
540
|
+
const breaksBySpanList = tableNode._breaksBySpan.filter(pb => pb.prevPage === page && rowIndex <= pb.rowIndexOfSpanEnd);
|
|
541
|
+
if (breaksBySpanList && breaksBySpanList.length > 0) {
|
|
542
|
+
breaksBySpanList.forEach(b => {
|
|
543
|
+
b.prevY = Math.max(b.prevY, tableNode._bottomByPage[page]);
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Resolves the Y-coordinates for a target object by comparing two break points.
|
|
552
|
+
*
|
|
553
|
+
* @param {object} break1 - The first break point with `prevY` and `y` properties.
|
|
554
|
+
* @param {object} break2 - The second break point with `prevY` and `y` properties.
|
|
555
|
+
* @param {object} target - The target object to be updated with resolved Y-coordinates.
|
|
556
|
+
* @property {number} target.prevY - Updated to the maximum `prevY` value between `break1` and `break2`.
|
|
557
|
+
* @property {number} target.y - Updated to the minimum `y` value between `break1` and `break2`.
|
|
558
|
+
*/
|
|
559
|
+
_resolveBreakY(break1, break2, target) {
|
|
560
|
+
target.prevY = Math.max(break1.prevY, break2.prevY);
|
|
561
|
+
target.y = Math.min(break1.y, break2.y);
|
|
562
|
+
}
|
|
563
|
+
_storePageBreakData(data, startsRowSpan, pageBreaks, tableNode) {
|
|
564
|
+
if (!startsRowSpan) {
|
|
565
|
+
let pageDesc = this._getPageBreak(pageBreaks, data.prevPage);
|
|
566
|
+
let pageDescBySpan = this._getPageBreakListBySpan(tableNode, data.prevPage, data.rowIndex);
|
|
567
|
+
if (!pageDesc) {
|
|
568
|
+
pageDesc = {
|
|
569
|
+
...data
|
|
570
|
+
};
|
|
571
|
+
pageBreaks.push(pageDesc);
|
|
572
|
+
}
|
|
573
|
+
if (pageDescBySpan) {
|
|
574
|
+
this._resolveBreakY(pageDesc, pageDescBySpan, pageDesc);
|
|
575
|
+
}
|
|
576
|
+
this._resolveBreakY(pageDesc, data, pageDesc);
|
|
577
|
+
} else {
|
|
578
|
+
const breaksBySpan = tableNode && tableNode._breaksBySpan || null;
|
|
579
|
+
let pageDescBySpan = this._findSameRowPageBreakByRowSpanData(breaksBySpan, data.prevPage, data.rowIndex);
|
|
580
|
+
if (!pageDescBySpan) {
|
|
581
|
+
pageDescBySpan = {
|
|
582
|
+
...data,
|
|
583
|
+
rowIndexOfSpanEnd: data.rowIndex + data.rowSpan - 1
|
|
584
|
+
};
|
|
585
|
+
if (!tableNode._breaksBySpan) {
|
|
586
|
+
tableNode._breaksBySpan = [];
|
|
587
|
+
}
|
|
588
|
+
tableNode._breaksBySpan.push(pageDescBySpan);
|
|
589
|
+
}
|
|
590
|
+
pageDescBySpan.prevY = Math.max(pageDescBySpan.prevY, data.prevY);
|
|
591
|
+
pageDescBySpan.y = Math.min(pageDescBySpan.y, data.y);
|
|
592
|
+
let pageDesc = this._getPageBreak(pageBreaks, data.prevPage);
|
|
593
|
+
if (pageDesc) {
|
|
594
|
+
this._resolveBreakY(pageDesc, pageDescBySpan, pageDesc);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Calculates the left offset for a column based on the specified gap values.
|
|
600
|
+
*
|
|
601
|
+
* @param {number} i - The index of the column for which the offset is being calculated.
|
|
602
|
+
* @param {Array<number>} gaps - An array of gap values for each column.
|
|
603
|
+
* @returns {number} The left offset for the column. Returns `gaps[i]` if it exists, otherwise `0`.
|
|
604
|
+
*/
|
|
605
|
+
_colLeftOffset(i, gaps) {
|
|
606
|
+
if (gaps && gaps.length > i) {
|
|
607
|
+
return gaps[i];
|
|
608
|
+
}
|
|
609
|
+
return 0;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Retrieves the ending cell for a row span in case it exists in a specified table column.
|
|
614
|
+
*
|
|
615
|
+
* @param {Array<Array<object>>} tableBody - The table body, represented as a 2D array of cell objects.
|
|
616
|
+
* @param {number} rowIndex - The index of the starting row for the row span.
|
|
617
|
+
* @param {object} column - The column object containing row span information.
|
|
618
|
+
* @param {number} columnIndex - The index of the column within the row.
|
|
619
|
+
* @returns {object|null} The cell at the end of the row span if it exists; otherwise, `null`.
|
|
620
|
+
* @throws {Error} If the row span extends beyond the total row count.
|
|
621
|
+
*/
|
|
622
|
+
_getRowSpanEndingCell(tableBody, rowIndex, column, columnIndex) {
|
|
623
|
+
if (column.rowSpan && column.rowSpan > 1) {
|
|
624
|
+
let endingRow = rowIndex + column.rowSpan - 1;
|
|
625
|
+
if (endingRow >= tableBody.length) {
|
|
626
|
+
throw new Error(`Row span for column ${columnIndex} (with indexes starting from 0) exceeded row count`);
|
|
627
|
+
}
|
|
628
|
+
return tableBody[endingRow][columnIndex];
|
|
629
|
+
}
|
|
630
|
+
return null;
|
|
631
|
+
}
|
|
489
632
|
processRow({
|
|
490
633
|
marginX = [0, 0],
|
|
491
634
|
dontBreakRows = false,
|
|
@@ -493,108 +636,94 @@ class LayoutBuilder {
|
|
|
493
636
|
cells,
|
|
494
637
|
widths,
|
|
495
638
|
gaps,
|
|
639
|
+
tableNode,
|
|
496
640
|
tableBody,
|
|
497
641
|
rowIndex,
|
|
498
642
|
height
|
|
499
643
|
}) {
|
|
500
|
-
const updatePageBreakData = (page, prevY) => {
|
|
501
|
-
let pageDesc;
|
|
502
|
-
// Find page break data for this row and page
|
|
503
|
-
for (let i = 0, l = pageBreaks.length; i < l; i++) {
|
|
504
|
-
let desc = pageBreaks[i];
|
|
505
|
-
if (desc.prevPage === page) {
|
|
506
|
-
pageDesc = desc;
|
|
507
|
-
break;
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
// If row has page break in this page, update prevY
|
|
511
|
-
if (pageDesc) {
|
|
512
|
-
pageDesc.prevY = Math.max(pageDesc.prevY, prevY);
|
|
513
|
-
}
|
|
514
|
-
};
|
|
515
|
-
const storePageBreakData = data => {
|
|
516
|
-
let pageDesc;
|
|
517
|
-
for (let i = 0, l = pageBreaks.length; i < l; i++) {
|
|
518
|
-
let desc = pageBreaks[i];
|
|
519
|
-
if (desc.prevPage === data.prevPage) {
|
|
520
|
-
pageDesc = desc;
|
|
521
|
-
break;
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
if (!pageDesc) {
|
|
525
|
-
pageDesc = data;
|
|
526
|
-
pageBreaks.push(pageDesc);
|
|
527
|
-
}
|
|
528
|
-
pageDesc.prevY = Math.max(pageDesc.prevY, data.prevY);
|
|
529
|
-
pageDesc.y = Math.min(pageDesc.y, data.y);
|
|
530
|
-
};
|
|
531
644
|
const isUnbreakableRow = dontBreakRows || rowIndex <= rowsWithoutPageBreak - 1;
|
|
532
645
|
let pageBreaks = [];
|
|
646
|
+
let pageBreaksByRowSpan = [];
|
|
533
647
|
let positions = [];
|
|
534
648
|
let willBreakByHeight = false;
|
|
535
|
-
|
|
649
|
+
widths = widths || cells;
|
|
536
650
|
|
|
537
651
|
// Check if row should break by height
|
|
538
652
|
if (!isUnbreakableRow && height > this.writer.context().availableHeight) {
|
|
539
653
|
willBreakByHeight = true;
|
|
540
654
|
}
|
|
541
|
-
|
|
655
|
+
|
|
542
656
|
// Use the marginX if we are in a top level table/column (not nested)
|
|
543
657
|
const marginXParent = this.nestedLevel === 1 ? marginX : null;
|
|
544
|
-
|
|
658
|
+
const _bottomByPage = tableNode ? tableNode._bottomByPage : null;
|
|
659
|
+
this.writer.context().beginColumnGroup(marginXParent, _bottomByPage);
|
|
545
660
|
for (let i = 0, l = cells.length; i < l; i++) {
|
|
546
|
-
let
|
|
661
|
+
let cell = cells[i];
|
|
662
|
+
|
|
663
|
+
// Page change handler
|
|
664
|
+
const storePageBreakClosure = data => {
|
|
665
|
+
const startsRowSpan = cell.rowSpan && cell.rowSpan > 1;
|
|
666
|
+
if (startsRowSpan) {
|
|
667
|
+
data.rowSpan = cell.rowSpan;
|
|
668
|
+
}
|
|
669
|
+
data.rowIndex = rowIndex;
|
|
670
|
+
this._storePageBreakData(data, startsRowSpan, pageBreaks, tableNode);
|
|
671
|
+
};
|
|
672
|
+
this.writer.addListener('pageChanged', storePageBreakClosure);
|
|
547
673
|
let width = widths[i]._calcWidth;
|
|
548
|
-
let leftOffset =
|
|
549
|
-
if
|
|
550
|
-
|
|
674
|
+
let leftOffset = this._colLeftOffset(i, gaps);
|
|
675
|
+
// Check if exists and retrieve the cell that started the rowspan in case we are in the cell just after
|
|
676
|
+
let startingSpanCell = this._findStartingRowSpanCell(cells, i);
|
|
677
|
+
if (cell.colSpan && cell.colSpan > 1) {
|
|
678
|
+
for (let j = 1; j < cell.colSpan; j++) {
|
|
551
679
|
width += widths[++i]._calcWidth + gaps[i];
|
|
552
680
|
}
|
|
553
681
|
}
|
|
554
682
|
|
|
555
683
|
// if rowspan starts in this cell, we retrieve the last cell affected by the rowspan
|
|
556
|
-
const
|
|
557
|
-
if (
|
|
684
|
+
const rowSpanEndingCell = this._getRowSpanEndingCell(tableBody, rowIndex, cell, i);
|
|
685
|
+
if (rowSpanEndingCell) {
|
|
558
686
|
// We store a reference of the ending cell in the first cell of the rowspan
|
|
559
|
-
|
|
560
|
-
|
|
687
|
+
cell._endingCell = rowSpanEndingCell;
|
|
688
|
+
cell._endingCell._startingRowSpanY = cell._startingRowSpanY;
|
|
561
689
|
}
|
|
562
690
|
|
|
563
|
-
//
|
|
564
|
-
let
|
|
565
|
-
let endingSpanCell = null;
|
|
691
|
+
// If we are after a cell that started a rowspan
|
|
692
|
+
let endOfRowSpanCell = null;
|
|
566
693
|
if (startingSpanCell && startingSpanCell._endingCell) {
|
|
567
694
|
// Reference to the last cell of the rowspan
|
|
568
|
-
|
|
695
|
+
endOfRowSpanCell = startingSpanCell._endingCell;
|
|
569
696
|
// Store if we are in an unbreakable block when we save the context and the originalX
|
|
570
697
|
if (this.writer.transactionLevel > 0) {
|
|
571
|
-
|
|
572
|
-
|
|
698
|
+
endOfRowSpanCell._isUnbreakableContext = true;
|
|
699
|
+
endOfRowSpanCell._originalXOffset = this.writer.originalX;
|
|
573
700
|
}
|
|
574
701
|
}
|
|
575
702
|
|
|
576
703
|
// We pass the endingSpanCell reference to store the context just after processing rowspan cell
|
|
577
|
-
this.writer.context().beginColumn(width, leftOffset,
|
|
578
|
-
if (!
|
|
579
|
-
this.processNode(
|
|
580
|
-
|
|
581
|
-
|
|
704
|
+
this.writer.context().beginColumn(width, leftOffset, endOfRowSpanCell);
|
|
705
|
+
if (!cell._span) {
|
|
706
|
+
this.processNode(cell);
|
|
707
|
+
this.writer.context().updateBottomByPage();
|
|
708
|
+
addAll(positions, cell.positions);
|
|
709
|
+
} else if (cell._columnEndingContext) {
|
|
582
710
|
let discountY = 0;
|
|
583
711
|
if (dontBreakRows) {
|
|
584
712
|
// Calculate how many points we have to discount to Y when dontBreakRows and rowSpan are combined
|
|
585
713
|
const ctxBeforeRowSpanLastRow = this.writer.contextStack[this.writer.contextStack.length - 1];
|
|
586
|
-
discountY = ctxBeforeRowSpanLastRow.y -
|
|
714
|
+
discountY = ctxBeforeRowSpanLastRow.y - cell._startingRowSpanY;
|
|
587
715
|
}
|
|
588
716
|
let originalXOffset = 0;
|
|
589
717
|
// If context was saved from an unbreakable block and we are not in an unbreakable block anymore
|
|
590
718
|
// We have to sum the originalX (X before starting unbreakable block) to X
|
|
591
|
-
if (
|
|
592
|
-
originalXOffset =
|
|
719
|
+
if (cell._isUnbreakableContext && !this.writer.transactionLevel) {
|
|
720
|
+
originalXOffset = cell._originalXOffset;
|
|
593
721
|
}
|
|
594
722
|
// row-span ending
|
|
595
723
|
// Recover the context after processing the rowspanned cell
|
|
596
|
-
this.writer.context().markEnding(
|
|
724
|
+
this.writer.context().markEnding(cell, originalXOffset, discountY);
|
|
597
725
|
}
|
|
726
|
+
this.writer.removeListener('pageChanged', storePageBreakClosure);
|
|
598
727
|
}
|
|
599
728
|
|
|
600
729
|
// Check if last cell is part of a span
|
|
@@ -607,7 +736,7 @@ class LayoutBuilder {
|
|
|
607
736
|
// Previous column cell is part of a span
|
|
608
737
|
} else if (lastColumn._span === true) {
|
|
609
738
|
// We get the cell that started the span where we set a reference to the ending cell
|
|
610
|
-
const startingSpanCell = this.
|
|
739
|
+
const startingSpanCell = this._findStartingRowSpanCell(cells, cells.length);
|
|
611
740
|
if (startingSpanCell) {
|
|
612
741
|
// Context will be stored here (ending cell)
|
|
613
742
|
endingSpanCell = startingSpanCell._endingCell;
|
|
@@ -620,36 +749,22 @@ class LayoutBuilder {
|
|
|
620
749
|
}
|
|
621
750
|
}
|
|
622
751
|
|
|
623
|
-
// If there are page breaks in this row, update data with prevY of last cell
|
|
624
|
-
updatePageBreakData(this.writer.context().page, this.writer.context().y);
|
|
625
|
-
|
|
626
752
|
// If content did not break page, check if we should break by height
|
|
627
|
-
if (!isUnbreakableRow && pageBreaks.length === 0
|
|
753
|
+
if (willBreakByHeight && !isUnbreakableRow && pageBreaks.length === 0) {
|
|
628
754
|
this.writer.context().moveDown(this.writer.context().availableHeight);
|
|
629
755
|
this.writer.moveToNextPage();
|
|
630
756
|
}
|
|
631
|
-
this.writer.context().completeColumnGroup(height, endingSpanCell);
|
|
632
|
-
|
|
757
|
+
const bottomByPage = this.writer.context().completeColumnGroup(height, endingSpanCell);
|
|
758
|
+
if (tableNode) {
|
|
759
|
+
tableNode._bottomByPage = bottomByPage;
|
|
760
|
+
// If there are page breaks in this row, update data with prevY of last cell
|
|
761
|
+
this._updatePageBreaksData(pageBreaks, tableNode, rowIndex);
|
|
762
|
+
}
|
|
633
763
|
return {
|
|
764
|
+
pageBreaksBySpan: pageBreaksByRowSpan,
|
|
634
765
|
pageBreaks: pageBreaks,
|
|
635
766
|
positions: positions
|
|
636
767
|
};
|
|
637
|
-
function colLeftOffset(i) {
|
|
638
|
-
if (gaps && gaps.length > i) {
|
|
639
|
-
return gaps[i];
|
|
640
|
-
}
|
|
641
|
-
return 0;
|
|
642
|
-
}
|
|
643
|
-
function getEndingCell(column, columnIndex) {
|
|
644
|
-
if (column.rowSpan && column.rowSpan > 1) {
|
|
645
|
-
let endingRow = rowIndex + column.rowSpan - 1;
|
|
646
|
-
if (endingRow >= tableBody.length) {
|
|
647
|
-
throw new Error(`Row span for column ${columnIndex} (with indexes starting from 0) exceeded row count`);
|
|
648
|
-
}
|
|
649
|
-
return tableBody[endingRow][columnIndex];
|
|
650
|
-
}
|
|
651
|
-
return null;
|
|
652
|
-
}
|
|
653
768
|
}
|
|
654
769
|
|
|
655
770
|
// lists
|
|
@@ -715,6 +830,7 @@ class LayoutBuilder {
|
|
|
715
830
|
if (height === 'auto') {
|
|
716
831
|
height = undefined;
|
|
717
832
|
}
|
|
833
|
+
const pageBeforeProcessing = this.writer.context().page;
|
|
718
834
|
let result = this.processRow({
|
|
719
835
|
marginX: tableNode._margin ? [tableNode._margin[0], tableNode._margin[2]] : [0, 0],
|
|
720
836
|
dontBreakRows: processor.dontBreakRows,
|
|
@@ -723,10 +839,19 @@ class LayoutBuilder {
|
|
|
723
839
|
widths: tableNode.table.widths,
|
|
724
840
|
gaps: tableNode._offsets.offsets,
|
|
725
841
|
tableBody: tableNode.table.body,
|
|
842
|
+
tableNode,
|
|
726
843
|
rowIndex: i,
|
|
727
844
|
height
|
|
728
845
|
});
|
|
729
846
|
addAll(tableNode.positions, result.positions);
|
|
847
|
+
if (!result.pageBreaks || result.pageBreaks.length === 0) {
|
|
848
|
+
const breaksBySpan = tableNode && tableNode._breaksBySpan || null;
|
|
849
|
+
const breakBySpanData = this._findSameRowPageBreakByRowSpanData(breaksBySpan, pageBeforeProcessing, i);
|
|
850
|
+
if (breakBySpanData) {
|
|
851
|
+
const finalBreakBySpanData = this._getPageBreakListBySpan(tableNode, breakBySpanData.prevPage, i);
|
|
852
|
+
result.pageBreaks.push(finalBreakBySpanData);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
730
855
|
processor.endRow(i, this.writer, result.pageBreaks);
|
|
731
856
|
}
|
|
732
857
|
processor.endTable(this.writer);
|
package/js/PageElementWriter.js
CHANGED
|
@@ -36,8 +36,8 @@ class PageElementWriter extends _ElementWriter.default {
|
|
|
36
36
|
addAttachment(attachment, index) {
|
|
37
37
|
return this._fitOnPage(() => super.addAttachment(attachment, index));
|
|
38
38
|
}
|
|
39
|
-
addVector(vector, ignoreContextX, ignoreContextY, index) {
|
|
40
|
-
return super.addVector(vector, ignoreContextX, ignoreContextY, index);
|
|
39
|
+
addVector(vector, ignoreContextX, ignoreContextY, index, forcePage) {
|
|
40
|
+
return super.addVector(vector, ignoreContextX, ignoreContextY, index, forcePage);
|
|
41
41
|
}
|
|
42
42
|
beginClip(width, height) {
|
|
43
43
|
return super.beginClip(width, height);
|
package/js/Printer.js
CHANGED
|
@@ -50,6 +50,9 @@ class PdfPrinter {
|
|
|
50
50
|
this.resolveUrls(docDefinition).then(() => {
|
|
51
51
|
try {
|
|
52
52
|
docDefinition.version = docDefinition.version || '1.3';
|
|
53
|
+
docDefinition.subset = docDefinition.subset || undefined;
|
|
54
|
+
docDefinition.tagged = typeof docDefinition.tagged === 'boolean' ? docDefinition.tagged : false;
|
|
55
|
+
docDefinition.displayTitle = typeof docDefinition.displayTitle === 'boolean' ? docDefinition.displayTitle : false;
|
|
53
56
|
docDefinition.compress = typeof docDefinition.compress === 'boolean' ? docDefinition.compress : true;
|
|
54
57
|
docDefinition.images = docDefinition.images || {};
|
|
55
58
|
docDefinition.attachments = docDefinition.attachments || {};
|
|
@@ -59,6 +62,9 @@ class PdfPrinter {
|
|
|
59
62
|
let pdfOptions = {
|
|
60
63
|
size: [pageSize.width, pageSize.height],
|
|
61
64
|
pdfVersion: docDefinition.version,
|
|
65
|
+
subset: docDefinition.subset,
|
|
66
|
+
tagged: docDefinition.tagged,
|
|
67
|
+
displayTitle: docDefinition.displayTitle,
|
|
62
68
|
compress: docDefinition.compress,
|
|
63
69
|
userPassword: docDefinition.userPassword,
|
|
64
70
|
ownerPassword: docDefinition.ownerPassword,
|
package/js/Renderer.js
CHANGED
|
@@ -329,6 +329,23 @@ class Renderer {
|
|
|
329
329
|
return fontFile;
|
|
330
330
|
};
|
|
331
331
|
(0, _svgToPdfkit.default)(this.pdfDocument, svg.svg, svg.x, svg.y, options);
|
|
332
|
+
if (svg.link) {
|
|
333
|
+
this.pdfDocument.link(svg.x, svg.y, svg._width, svg._height, svg.link);
|
|
334
|
+
}
|
|
335
|
+
if (svg.linkToPage) {
|
|
336
|
+
this.pdfDocument.ref({
|
|
337
|
+
Type: 'Action',
|
|
338
|
+
S: 'GoTo',
|
|
339
|
+
D: [svg.linkToPage, 0, 0]
|
|
340
|
+
}).end();
|
|
341
|
+
this.pdfDocument.annotate(svg.x, svg.y, svg._width, svg._height, {
|
|
342
|
+
Subtype: 'Link',
|
|
343
|
+
Dest: [svg.linkToPage - 1, 'XYZ', null, null, null]
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
if (svg.linkToDestination) {
|
|
347
|
+
this.pdfDocument.goTo(svg.x, svg.y, svg._width, svg._height, svg.linkToDestination);
|
|
348
|
+
}
|
|
332
349
|
}
|
|
333
350
|
renderAttachment(attachment) {
|
|
334
351
|
const file = this.pdfDocument.provideAttachment(attachment.attachment);
|