@ind-rcg/plugins-printengine 246.1010.0
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/LICENSE.md +37 -0
- package/README.md +7 -0
- package/dist/dev/fonts/LICENSE.txt +202 -0
- package/dist/dev/fonts/Roboto-Italic.ttf +0 -0
- package/dist/dev/fonts/Roboto-Medium.ttf +0 -0
- package/dist/dev/fonts/Roboto-MediumItalic.ttf +0 -0
- package/dist/dev/fonts/Roboto-Regular.ttf +0 -0
- package/dist/dev/printEngine.js +589 -0
- package/dist/dev/src/contractToIntermediateJSONClass.js +1659 -0
- package/dist/dev/src/formatClass.js +156 -0
- package/dist/dev/src/index.js +110 -0
- package/dist/dev/src/localizationClass.js +89 -0
- package/dist/dev/src/logClass.js +38 -0
- package/dist/dev/src/macroHandlerClass.js +132 -0
- package/dist/dev/src/pdfConverterClass.js +1123 -0
- package/dist/dev/src/printEngineParams.js +124 -0
- package/dist/dev/src/tableCellIdentifier.js +116 -0
- package/dist/dev/src/togglesClass.js +61 -0
- package/dist/prod/printEngine.js +2 -0
- package/dist/prod/printEngine.js.LICENSE.txt +50 -0
- package/package.json +79 -0
|
@@ -0,0 +1,1123 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* FILE_HEADER
|
|
3
|
+
*/
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
const _ = require('lodash');
|
|
7
|
+
const PdfPrinter = require('pdfmake');
|
|
8
|
+
const Format = require('./formatClass');
|
|
9
|
+
const TableCellIdentifier = require('./tableCellIdentifier');
|
|
10
|
+
|
|
11
|
+
// required for webpack include (browser impl), used in conjunction with BrowserFonts definition
|
|
12
|
+
const BrowserFontsVfs = require('pdfmake/build/vfs_fonts.js');
|
|
13
|
+
|
|
14
|
+
// => use 'Roboto' font (pdfMake default) due to licensing (Apache 2.0)
|
|
15
|
+
// https://fonts.google.com/specimen/Roboto || https://en.wikipedia.org/wiki/Roboto
|
|
16
|
+
const ServerFonts = {
|
|
17
|
+
Roboto: {
|
|
18
|
+
normal: './fonts/Roboto-Regular.ttf',
|
|
19
|
+
bold: './fonts/Roboto-Medium.ttf',
|
|
20
|
+
italics: './fonts/Roboto-Italic.ttf',
|
|
21
|
+
bolditalics: './fonts/Roboto-MediumItalic.ttf'
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const BrowserFonts = {
|
|
26
|
+
Roboto: {
|
|
27
|
+
normal: 'Roboto-Regular.ttf',
|
|
28
|
+
bold: 'Roboto-Medium.ttf',
|
|
29
|
+
italics: 'Roboto-Italic.ttf',
|
|
30
|
+
bolditalics: 'Roboto-MediumItalic.ttf'
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const TableLayouts = {
|
|
35
|
+
lightHorizontalLinesMainItemsOnly: {
|
|
36
|
+
hLineWidth: function (i, node) {
|
|
37
|
+
// no frame for the table
|
|
38
|
+
if (i === 0 || i === node.table.body.length) {
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
// bold seperator between header and body
|
|
42
|
+
if (i === node.table.headerRows) {
|
|
43
|
+
return 2;
|
|
44
|
+
}
|
|
45
|
+
// get first cell id for row ...
|
|
46
|
+
let row = node.table.body[i];
|
|
47
|
+
if (!_.isNil(row)) {
|
|
48
|
+
let cellId = null;
|
|
49
|
+
_.forEach(row, cell =>{
|
|
50
|
+
if(_.has(cell, 'id')) {
|
|
51
|
+
cellId = cell.id;
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
// seperator for between main rows (+ their child rows)
|
|
56
|
+
let tcid = TableCellIdentifier.fromString(cellId);
|
|
57
|
+
if (!_.isNil(tcid)) {
|
|
58
|
+
if (tcid.isKnown() && tcid.belongsToMainRow()) {
|
|
59
|
+
// seperator between main rows
|
|
60
|
+
return 1;
|
|
61
|
+
} else if (!tcid.isKnown()) {
|
|
62
|
+
// seperator for 'unknown row'
|
|
63
|
+
return 1;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// no seperator for all other cases, e.g. child rows
|
|
68
|
+
return 0;
|
|
69
|
+
},
|
|
70
|
+
vLineWidth: function () {
|
|
71
|
+
return 0;
|
|
72
|
+
},
|
|
73
|
+
hLineColor: function (i, node) {
|
|
74
|
+
return i === node.table.headerRows ? 'black' : 'gray';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const STYLE_HEADING1 = "heading1";
|
|
80
|
+
const STYLE_HEADING2 = "heading2";
|
|
81
|
+
const STYLE_PARAGRAPH = "paragraph";
|
|
82
|
+
|
|
83
|
+
const EXPORT_TYPE = {
|
|
84
|
+
"BASE_64" : "BASE_64",
|
|
85
|
+
"DATA_URL" : "DATA_URL",
|
|
86
|
+
"BLOB" : "BLOB"
|
|
87
|
+
};
|
|
88
|
+
Object.freeze(EXPORT_TYPE);
|
|
89
|
+
|
|
90
|
+
class PdfConverter {
|
|
91
|
+
constructor() {
|
|
92
|
+
this.__pdfMake = null;
|
|
93
|
+
if(typeof pdfMake !== "undefined")
|
|
94
|
+
{
|
|
95
|
+
this.__pdfMake = pdfMake;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
this.__format = new Format();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
__applyPageBreakData(pdfDefinition) {
|
|
102
|
+
if (!_.isUndefined(pdfDefinition.dynamicPageBreak) && pdfDefinition.dynamicPageBreak &&
|
|
103
|
+
!_.isUndefined(pdfDefinition.dynamicPageBreakData) && _.isArray(pdfDefinition.dynamicPageBreakData) && pdfDefinition.dynamicPageBreakData.length > 0) {
|
|
104
|
+
// let table = pdfDefinition.content[0].table;
|
|
105
|
+
let dynamicPageBreakData = pdfDefinition.dynamicPageBreakData;
|
|
106
|
+
|
|
107
|
+
// handle tables in body
|
|
108
|
+
let tables = _.filter(pdfDefinition.content, {style: 'tableBody'});
|
|
109
|
+
this.__applyPageBreakDataToTables(tables, dynamicPageBreakData);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
__applyPageBreakDataToTables(tables, dynamicPageBreakData) {
|
|
114
|
+
|
|
115
|
+
if (!_.isNil(tables) && _.isArray(tables) && tables.length > 0 && !_.isNil(dynamicPageBreakData)) {
|
|
116
|
+
for (let i = 0; i < tables.length; i++) {
|
|
117
|
+
// get table
|
|
118
|
+
let table = tables[i].table;
|
|
119
|
+
if (!_.isNil(table) && !_.isUndefined(table.dynamicPageBreak) && table.dynamicPageBreak) {
|
|
120
|
+
// loop rows
|
|
121
|
+
let row = null;
|
|
122
|
+
let cell = null;
|
|
123
|
+
let breakRow = false;
|
|
124
|
+
for (let j = 0; j < table.body.length; j++) {
|
|
125
|
+
row = table.body[j];
|
|
126
|
+
breakRow = false;
|
|
127
|
+
// loop columns
|
|
128
|
+
for (let k = 0; k < row.length; k++) {
|
|
129
|
+
cell = row[k];
|
|
130
|
+
// apply manual pageBreaks instead of dynamic ones
|
|
131
|
+
if (!breakRow && _.has(cell, 'id')) {
|
|
132
|
+
breakRow = _.includes(dynamicPageBreakData, cell.id);
|
|
133
|
+
if (breakRow) {
|
|
134
|
+
cell.pageBreak = 'before';
|
|
135
|
+
}
|
|
136
|
+
} else if (breakRow && _.has(cell, 'id')) {
|
|
137
|
+
cell.pageBreak = 'before';
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
__initializePdfDefinition() {
|
|
148
|
+
this.__definition = {
|
|
149
|
+
"content": [],
|
|
150
|
+
pageSize: 'A4',
|
|
151
|
+
pageMargins: [ 40, 60, 40, 60 ],
|
|
152
|
+
defaultStyle: {
|
|
153
|
+
font: 'Roboto', //'Helvetica'
|
|
154
|
+
},
|
|
155
|
+
styles: {
|
|
156
|
+
tableBody: {
|
|
157
|
+
fontSize: 10,
|
|
158
|
+
margin: [0, 5, 0, 15]
|
|
159
|
+
},
|
|
160
|
+
tableHeader: {
|
|
161
|
+
fontSize: 10,
|
|
162
|
+
bold: true
|
|
163
|
+
},
|
|
164
|
+
heading1: {
|
|
165
|
+
fontSize: 18,
|
|
166
|
+
bold: true,
|
|
167
|
+
margin: [0, 0, 0, 10]
|
|
168
|
+
},
|
|
169
|
+
heading2: {
|
|
170
|
+
fontSize: 14,
|
|
171
|
+
bold: true,
|
|
172
|
+
margin: [0, 10, 0, 5]
|
|
173
|
+
},
|
|
174
|
+
paragraph: {
|
|
175
|
+
fontSize: 10,
|
|
176
|
+
bold: false,
|
|
177
|
+
italics: false
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
this.__automaticPageBreak = false;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
__getThOrTdContent(thTdNode, settings) {
|
|
185
|
+
let result = {};
|
|
186
|
+
let text = "";
|
|
187
|
+
|
|
188
|
+
if(!_.isNil(thTdNode.elements)){
|
|
189
|
+
_.forEach(thTdNode.elements, childElement => {
|
|
190
|
+
if(childElement.type === "text") {
|
|
191
|
+
text = text + childElement.text;
|
|
192
|
+
} else if (childElement.type === "element" && childElement.name === "pageNumber" && !_.isNil(settings.currentPage)) {
|
|
193
|
+
text = text + settings.currentPage;
|
|
194
|
+
} else if (childElement.type === "element" && childElement.name === "img") {
|
|
195
|
+
result.image = this.__getImageDefinition(childElement, false);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
result.text = text;
|
|
200
|
+
|
|
201
|
+
return result;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
__getHeadingDefinition(headingNode, headingStyle) {
|
|
205
|
+
return this.__createHeadingOrParagraphText(headingNode, headingNode.elements[0].text, headingStyle);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
__getParagraphDefinition(paragraphNode, paragraphStyle) {
|
|
209
|
+
return this.__createHeadingOrParagraphText(paragraphNode, paragraphNode.elements[0].text, paragraphStyle);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
__getImageDefinition(imageNode, useAlignment) {
|
|
213
|
+
let img = {};
|
|
214
|
+
|
|
215
|
+
if (!_.isNil(imageNode)){
|
|
216
|
+
let atr = imageNode.attributes;
|
|
217
|
+
let imageId = atr.id;
|
|
218
|
+
let mimeType = atr.mimeType;
|
|
219
|
+
|
|
220
|
+
if (!_.isNil(imageId) && this.__isImageCached(imageId)) {
|
|
221
|
+
// => png / jpeg image already in cache => simply (re)use it ...
|
|
222
|
+
img = {image: imageId};
|
|
223
|
+
|
|
224
|
+
} else {
|
|
225
|
+
|
|
226
|
+
if (mimeType === "image/svg+xml") {
|
|
227
|
+
// => svg image handling (vector graphics)
|
|
228
|
+
let src = atr.src.split(",");
|
|
229
|
+
let data = src[1];
|
|
230
|
+
let txt;
|
|
231
|
+
|
|
232
|
+
if ((typeof window === 'object') && (typeof window.atob === 'function')) {
|
|
233
|
+
// we do expect an utf8 string
|
|
234
|
+
txt = decodeURIComponent(encodeURIComponent(window.atob(data)));
|
|
235
|
+
} else {
|
|
236
|
+
let buf = Buffer.from(data, 'base64');
|
|
237
|
+
txt = buf.toString('utf8');
|
|
238
|
+
}
|
|
239
|
+
img = {svg: txt};
|
|
240
|
+
|
|
241
|
+
} else {
|
|
242
|
+
// => png / jpeg image handling (raster graphics)
|
|
243
|
+
// add image to cache
|
|
244
|
+
this.__addImageToCache(imageId, atr.src);
|
|
245
|
+
img = {image: imageId};
|
|
246
|
+
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (!_.isNil(atr.width)) {
|
|
251
|
+
img.width = parseInt(atr.width, 10);
|
|
252
|
+
}
|
|
253
|
+
if (!_.isNil(atr.height)) {
|
|
254
|
+
img.height = parseInt(atr.height, 10);
|
|
255
|
+
}
|
|
256
|
+
if (!_.isNil(atr.fit)) {
|
|
257
|
+
let fit = atr.fit.split(',');
|
|
258
|
+
let w = parseInt(fit[0], 10);
|
|
259
|
+
let h = parseInt(fit[1], 10);
|
|
260
|
+
img.fit = [w,h];
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (!_.isNil(atr.alignment) && (true === useAlignment)) {
|
|
264
|
+
let alignmentAttribute = this.__checkEnumAttribute(imageNode, 'alignment', ["left", "center", "right"], null);
|
|
265
|
+
|
|
266
|
+
if (!_.isNil(alignmentAttribute)) {
|
|
267
|
+
img.alignment = alignmentAttribute;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return img;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
__addImageToCache(imageId, imageData) {
|
|
276
|
+
// init image cache if required
|
|
277
|
+
if (!_.has(this.__definition, 'images')) {
|
|
278
|
+
_.assign(this.__definition, {
|
|
279
|
+
images: {}
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// add image to cache
|
|
284
|
+
if (!_.has(this.__definition.images, imageId)) {
|
|
285
|
+
this.__definition.images[imageId] = imageData;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
__isImageCached(imageId) {
|
|
290
|
+
return (_.has(this.__definition, 'images') && _.has(this.__definition.images, imageId));
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
__checkSpansAndColumns(pdfTableDefinition) {
|
|
294
|
+
let rows = 0;
|
|
295
|
+
let columns = 0;
|
|
296
|
+
|
|
297
|
+
let rowCount = pdfTableDefinition.table.body.length;
|
|
298
|
+
let columnCount = pdfTableDefinition.table.widths.length;
|
|
299
|
+
|
|
300
|
+
for (rows=0; rows<rowCount; rows++) {
|
|
301
|
+
let row = pdfTableDefinition.table.body[rows];
|
|
302
|
+
|
|
303
|
+
if (row.length > columnCount) {
|
|
304
|
+
row.length = columnCount;
|
|
305
|
+
} else if (row.length < columnCount) {
|
|
306
|
+
do {
|
|
307
|
+
row.push("");
|
|
308
|
+
} while(row.length < columnCount);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
let maxRowSpan = rowCount-rows;
|
|
312
|
+
|
|
313
|
+
for (columns=0; columns<columnCount; columns++) {
|
|
314
|
+
let column = row[columns];
|
|
315
|
+
let maxColSpan = columnCount-columns;
|
|
316
|
+
|
|
317
|
+
if (!_.isString(column)) {
|
|
318
|
+
if (!_.isNil(column["colSpan"])) {
|
|
319
|
+
if (column.colSpan > maxColSpan) {
|
|
320
|
+
column.colSpan = maxColSpan;
|
|
321
|
+
}
|
|
322
|
+
if (column.colSpan < 2) {
|
|
323
|
+
delete column.colSpan;
|
|
324
|
+
}
|
|
325
|
+
if ((Object.keys(column).length === 1) && !_.isNil(column["text"])) {
|
|
326
|
+
row[columns] = column.text;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if (!_.isNil(column["rowSpan"])) {
|
|
330
|
+
if (column.rowSpan > maxRowSpan) {
|
|
331
|
+
column.rowSpan = maxRowSpan;
|
|
332
|
+
}
|
|
333
|
+
if (column.rowSpan < 2) {
|
|
334
|
+
delete column.rowSpan;
|
|
335
|
+
}
|
|
336
|
+
if ((Object.keys(column).length === 1) && !_.isNil(column["text"])) {
|
|
337
|
+
row[columns] = column.text;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
__checkIntegerAttribute(element, attributeName, allowedStrings, onlyPositiveNumbers, defaultValue) {
|
|
346
|
+
let bElement = !_.isNil(element) && _.isObject(element.attributes);
|
|
347
|
+
let bAttribute = bElement && _.isString(attributeName) && (attributeName !== "") && !_.isNil(element.attributes[attributeName]);
|
|
348
|
+
let bAllowedStrings = !_.isNil(allowedStrings) && _.isArray(allowedStrings) && (allowedStrings.length > 0);
|
|
349
|
+
let bPositiveNumbers = !_.isNil(onlyPositiveNumbers) && _.isBoolean(onlyPositiveNumbers) && (onlyPositiveNumbers === true);
|
|
350
|
+
|
|
351
|
+
if (bAttribute) {
|
|
352
|
+
let attribute = element.attributes[attributeName];
|
|
353
|
+
let i = 0;
|
|
354
|
+
|
|
355
|
+
if (bAllowedStrings && _.isString(attribute)){
|
|
356
|
+
for (i=0; i<allowedStrings.length; i++) {
|
|
357
|
+
if (attribute === allowedStrings[i]) {
|
|
358
|
+
return attribute;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
let parsed = parseInt(attribute, 10);
|
|
364
|
+
|
|
365
|
+
if(!isNaN(parsed)) {
|
|
366
|
+
if (bPositiveNumbers && (parsed < 0))
|
|
367
|
+
{
|
|
368
|
+
return defaultValue;
|
|
369
|
+
} else {
|
|
370
|
+
return parsed;
|
|
371
|
+
}
|
|
372
|
+
} else {
|
|
373
|
+
return defaultValue;
|
|
374
|
+
}
|
|
375
|
+
} else {
|
|
376
|
+
return defaultValue;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
__checkBooleanAttribute(element, attributeName,defaultValue) {
|
|
381
|
+
let bElement = !_.isNil(element) && _.isObject(element.attributes);
|
|
382
|
+
let bAttribute = bElement && _.isString(attributeName) && (attributeName !== "") && !_.isNil(element.attributes[attributeName]);
|
|
383
|
+
|
|
384
|
+
if(bAttribute) {
|
|
385
|
+
let attributeValue = element.attributes[attributeName];
|
|
386
|
+
if (attributeValue === "true") {
|
|
387
|
+
return true;
|
|
388
|
+
} else if (attributeValue === "false") {
|
|
389
|
+
return false;
|
|
390
|
+
} else {
|
|
391
|
+
return defaultValue;
|
|
392
|
+
}
|
|
393
|
+
} else {
|
|
394
|
+
return defaultValue;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
__checkEnumAttribute(element, attributeName,allowedEnumValues ,defaultValue) {
|
|
399
|
+
let bElement = !_.isNil(element) && _.isObject(element.attributes);
|
|
400
|
+
let bAttribute = bElement && _.isString(attributeName) && (attributeName !== "") && !_.isNil(element.attributes[attributeName]);
|
|
401
|
+
|
|
402
|
+
if(bAttribute) {
|
|
403
|
+
let attributeValue = element.attributes[attributeName];
|
|
404
|
+
if(allowedEnumValues.includes(attributeValue)){
|
|
405
|
+
return attributeValue;
|
|
406
|
+
} else {
|
|
407
|
+
return defaultValue;
|
|
408
|
+
}
|
|
409
|
+
} else {
|
|
410
|
+
return defaultValue;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
__checkStringAttribute(element, attributeName, defaultValue) {
|
|
415
|
+
let bElement = !_.isNil(element) && _.isObject(element.attributes);
|
|
416
|
+
let bAttribute = bElement && _.isString(attributeName) && (attributeName !== "") && !_.isNil(element.attributes[attributeName]);
|
|
417
|
+
|
|
418
|
+
if(bAttribute) {
|
|
419
|
+
let attributeValue = element.attributes[attributeName];
|
|
420
|
+
if(_.isString(attributeValue)){
|
|
421
|
+
return attributeValue;
|
|
422
|
+
} else {
|
|
423
|
+
return defaultValue;
|
|
424
|
+
}
|
|
425
|
+
} else {
|
|
426
|
+
return defaultValue;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
__applyNumberFormatAttribute(element, value) {
|
|
431
|
+
let bElement = !_.isNil(element) && _.isObject(element.attributes);
|
|
432
|
+
let bAttribute = bElement && !_.isNil(element.attributes.numberFormat) && !_.isNil(element.attributes.decimalSeparator) && !_.isNil(element.attributes.thousandSeparator);
|
|
433
|
+
|
|
434
|
+
if (bAttribute) {
|
|
435
|
+
return this.__format.formatDecimalV2(value, element.attributes.numberFormat, element.attributes.decimalSeparator, element.attributes.thousandSeparator);
|
|
436
|
+
} else {
|
|
437
|
+
return value;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
__createHeadingOrParagraphText(currentNode, text, style) {
|
|
442
|
+
let result = { "text": text };
|
|
443
|
+
|
|
444
|
+
let boldAttribute = this.__checkBooleanAttribute(currentNode, 'bold', null);
|
|
445
|
+
let italicsAttribute = this.__checkBooleanAttribute(currentNode, 'italics', null);
|
|
446
|
+
let alignmentAttribute = this.__checkEnumAttribute(currentNode, 'alignment', ["left", "center", "right"], null);
|
|
447
|
+
|
|
448
|
+
if (_.isNil(boldAttribute) && _.isNil(italicsAttribute) && _.isNil(alignmentAttribute)) {
|
|
449
|
+
result.style = style;
|
|
450
|
+
} else {
|
|
451
|
+
let styleJson = this.__definition.styles[style];
|
|
452
|
+
|
|
453
|
+
if (!_.isNil(styleJson.fontSize)) {
|
|
454
|
+
result.fontSize = styleJson.fontSize;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if (!_.isNil(styleJson.bold)) {
|
|
458
|
+
result.bold = styleJson.bold;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
if (!_.isNil(styleJson.italics)) {
|
|
462
|
+
result.italics = styleJson.italics;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (!_.isNil(styleJson.margin)) {
|
|
466
|
+
result.margin = styleJson.margin;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (!_.isNil(boldAttribute)) {
|
|
470
|
+
result.bold = boldAttribute;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (!_.isNil(italicsAttribute)) {
|
|
474
|
+
result.italics = italicsAttribute;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
if (!_.isNil(alignmentAttribute)) {
|
|
478
|
+
result.alignment = alignmentAttribute;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
return result;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
__createTableColumn(content, style, colSpan, rowSpan, alignment, bold, italics, cellId) {
|
|
486
|
+
let bTextOnly = _.isNil(content.image) && _.isNil(style) && _.isNil(colSpan) && _.isNil(rowSpan)
|
|
487
|
+
&& _.isNil(alignment) && _.isNil(bold) && _.isNil(italics) && _.isNil(cellId);
|
|
488
|
+
|
|
489
|
+
if (bTextOnly) {
|
|
490
|
+
return content.text;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
let column = {};
|
|
494
|
+
|
|
495
|
+
//Image wins over text if both are defined.
|
|
496
|
+
if (!_.isNil(content.image)) {
|
|
497
|
+
column = content.image;
|
|
498
|
+
} else {
|
|
499
|
+
column.text = content.text;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (!_.isNil(style)) {
|
|
503
|
+
column.style = style;
|
|
504
|
+
}
|
|
505
|
+
if (!_.isNil(colSpan)) {
|
|
506
|
+
column.colSpan = colSpan;
|
|
507
|
+
}
|
|
508
|
+
if (!_.isNil(rowSpan)) {
|
|
509
|
+
column.rowSpan = rowSpan;
|
|
510
|
+
}
|
|
511
|
+
if (!_.isNil(alignment)) {
|
|
512
|
+
column.alignment = alignment;
|
|
513
|
+
}
|
|
514
|
+
if (!_.isNil(bold)) {
|
|
515
|
+
column.bold = bold;
|
|
516
|
+
}
|
|
517
|
+
if (!_.isNil(italics)) {
|
|
518
|
+
column.italics = italics;
|
|
519
|
+
}
|
|
520
|
+
if (!_.isNil(cellId)) {
|
|
521
|
+
column.id = cellId;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
return column;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
__getTableCellAttributes(thOrTdNode){
|
|
528
|
+
let colSpanAttributeValue = this.__checkIntegerAttribute(thOrTdNode, 'colSpan', [], true, null);
|
|
529
|
+
let rowSpanAttributeValue = this.__checkIntegerAttribute(thOrTdNode, 'rowSpan', [], true, null);
|
|
530
|
+
let boldAttribute = this.__checkBooleanAttribute(thOrTdNode, 'bold', null);
|
|
531
|
+
let italicsAttribute = this.__checkBooleanAttribute(thOrTdNode, 'italics', null);
|
|
532
|
+
let alignmentAttribute = this.__checkEnumAttribute(thOrTdNode, 'alignment', ["left", "center", "right"], null);
|
|
533
|
+
let cellId = this.__checkStringAttribute(thOrTdNode, 'id', null);
|
|
534
|
+
|
|
535
|
+
return [colSpanAttributeValue, rowSpanAttributeValue, alignmentAttribute, boldAttribute, italicsAttribute, cellId];
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
__evaluateTableDefinitionRowBreak(tableNode, dynamicPageBreak) {
|
|
539
|
+
let dontBreakRows = this.__checkBooleanAttribute(tableNode, "dontBreakRows", true);
|
|
540
|
+
// deactivate automatic row breaks for tables requiring dynamic page breaks
|
|
541
|
+
if (dynamicPageBreak) {
|
|
542
|
+
dontBreakRows = false;
|
|
543
|
+
}
|
|
544
|
+
return dontBreakRows;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
__evaluateTableDefinitionDynamicPageBreak(tableNode) {
|
|
548
|
+
let automaticPageBreak = this.__automaticPageBreak; // => coming from PrintV2 action configuration
|
|
549
|
+
let dynamicPageBreak = (automaticPageBreak && this.__checkBooleanAttribute(tableNode, "dynamicPageBreak", false));
|
|
550
|
+
if (dynamicPageBreak) {
|
|
551
|
+
this.__configurePdfDefinitionForDynamicPageBreak();
|
|
552
|
+
}
|
|
553
|
+
return dynamicPageBreak;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
__configurePdfDefinitionForDynamicPageBreak() {
|
|
557
|
+
if (!_.has(this.__definition, 'pageBreakBefore')) {
|
|
558
|
+
_.assign(this.__definition, {
|
|
559
|
+
pageBreakBefore: this.__calculatePageBreakBefore.bind(this)
|
|
560
|
+
});
|
|
561
|
+
this.__definition.dynamicPageBreak = true;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
__getTableDefinition(tableNode, settings) {
|
|
566
|
+
if(_.isNil(settings)) {settings = {};}
|
|
567
|
+
|
|
568
|
+
let dynamicPageBreak = this.__evaluateTableDefinitionDynamicPageBreak(tableNode);
|
|
569
|
+
let dontBreakRows = this.__evaluateTableDefinitionRowBreak(tableNode, dynamicPageBreak);
|
|
570
|
+
let pdfTableDefinition = {
|
|
571
|
+
style: "tableBody",
|
|
572
|
+
table: {
|
|
573
|
+
dontBreakRows: dontBreakRows,
|
|
574
|
+
headerRows: 0,
|
|
575
|
+
body: [],
|
|
576
|
+
widths: []
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
if (dynamicPageBreak) {
|
|
580
|
+
pdfTableDefinition.table.dynamicPageBreak = true;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
if(!_.isNil(settings.layout)) {
|
|
584
|
+
pdfTableDefinition.layout = settings.layout;
|
|
585
|
+
}
|
|
586
|
+
if(!_.isNil(tableNode.attributes) && !_.isNil(tableNode.attributes.tableLayout)){
|
|
587
|
+
pdfTableDefinition.layout = tableNode.attributes.tableLayout;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
let bNoWidths = false;
|
|
591
|
+
let theadNode = _.find(tableNode.elements, {name: 'thead'});
|
|
592
|
+
let tbodyNode = _.find(tableNode.elements, {name: 'tbody'});
|
|
593
|
+
|
|
594
|
+
if(!_.isNil(theadNode)) {
|
|
595
|
+
_.forEach(theadNode.elements, headerTrNode=> {
|
|
596
|
+
let row = [];
|
|
597
|
+
_.forEach(headerTrNode.elements, value => {
|
|
598
|
+
let attributeValues = this.__getTableCellAttributes(value);
|
|
599
|
+
|
|
600
|
+
if (pdfTableDefinition.table.headerRows === 0) {
|
|
601
|
+
let widthAttributeValue = this.__checkIntegerAttribute(value, 'width', ['*', 'auto'], true, 'auto');
|
|
602
|
+
pdfTableDefinition.table.widths.push(widthAttributeValue);
|
|
603
|
+
}
|
|
604
|
+
let content = this.__getThOrTdContent(value, settings);
|
|
605
|
+
row.push(this.__createTableColumn(content, 'tableHeader', ...attributeValues));
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
pdfTableDefinition.table.body.push(row);
|
|
609
|
+
pdfTableDefinition.table.headerRows += 1;
|
|
610
|
+
});
|
|
611
|
+
} else if(!_.isNil(tbodyNode)) {
|
|
612
|
+
bNoWidths = true;
|
|
613
|
+
} else {
|
|
614
|
+
pdfTableDefinition.table.widths = ['auto'];
|
|
615
|
+
pdfTableDefinition.table.body = [['']];
|
|
616
|
+
|
|
617
|
+
return pdfTableDefinition;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
if(!_.isNil(tbodyNode)) {
|
|
621
|
+
_.forEach(tbodyNode.elements, tbodyTrNode=> {
|
|
622
|
+
let row = [];
|
|
623
|
+
_.forEach(tbodyTrNode.elements, value => {
|
|
624
|
+
let attributeValues = this.__getTableCellAttributes(value);
|
|
625
|
+
|
|
626
|
+
if ((bNoWidths === true)) {
|
|
627
|
+
let widthAttributeValue = this.__checkIntegerAttribute(value, 'width', ['*', 'auto'], true, 'auto');
|
|
628
|
+
pdfTableDefinition.table.widths.push(widthAttributeValue);
|
|
629
|
+
}
|
|
630
|
+
let content = this.__getThOrTdContent(value, settings);
|
|
631
|
+
content.text = this.__applyNumberFormatAttribute(value, content.text);
|
|
632
|
+
|
|
633
|
+
row.push(this.__createTableColumn(content, null, ...attributeValues));
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
bNoWidths = false;
|
|
637
|
+
pdfTableDefinition.table.body.push(row);
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
this.__checkSpansAndColumns(pdfTableDefinition);
|
|
642
|
+
|
|
643
|
+
return pdfTableDefinition;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
__addBody(definition, json) {
|
|
647
|
+
|
|
648
|
+
_.forEach(json.elements, contractElement => {
|
|
649
|
+
if(contractElement.name === 'table') {
|
|
650
|
+
let tableDefintion = this.__getTableDefinition(contractElement);
|
|
651
|
+
definition.content.push(tableDefintion);
|
|
652
|
+
} else if (contractElement.name === 'h1') {
|
|
653
|
+
let h1Defintion = this.__getHeadingDefinition(contractElement, STYLE_HEADING1);
|
|
654
|
+
definition.content.push(h1Defintion);
|
|
655
|
+
} else if (contractElement.name === 'h2') {
|
|
656
|
+
let h2Defintion = this.__getHeadingDefinition(contractElement, STYLE_HEADING2);
|
|
657
|
+
definition.content.push(h2Defintion);
|
|
658
|
+
} else if (contractElement.name === 'p') {
|
|
659
|
+
let paragraphDefintion = this.__getParagraphDefinition(contractElement, STYLE_PARAGRAPH);
|
|
660
|
+
definition.content.push(paragraphDefintion);
|
|
661
|
+
} else if (contractElement.name === 'img' || contractElement.name === 'signature') {
|
|
662
|
+
let imageDefintion = this.__getImageDefinition(contractElement, true);
|
|
663
|
+
definition.content.push(imageDefintion);
|
|
664
|
+
}
|
|
665
|
+
});
|
|
666
|
+
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
__addHeader(definition, json) {
|
|
670
|
+
let headerNode = _.find(json.elements, {name:"header"});
|
|
671
|
+
|
|
672
|
+
if(!_.isNil(headerNode)) {
|
|
673
|
+
let imageNode = _.find(headerNode.elements, {name:"img"});
|
|
674
|
+
let tableNode = _.find(headerNode.elements, {name:"table"});
|
|
675
|
+
|
|
676
|
+
//The coverage report only works correctly when isWriteDataEnabled() returns true in the Unit Tests.
|
|
677
|
+
definition.header = (currentPage/*, pageCount, pageSize*/) => {
|
|
678
|
+
let imageDefinition = (!_.isNil(imageNode)) ? this.__getImageDefinition(imageNode, true) : null;
|
|
679
|
+
let tableDefinition = (!_.isNil(tableNode)) ? this.__getTableDefinition(tableNode, {"layout": "noBorders", "currentPage": currentPage}) : null;
|
|
680
|
+
|
|
681
|
+
if (!_.isNil(imageDefinition) && !_.isNil(tableDefinition)) {
|
|
682
|
+
return [imageDefinition, tableDefinition];
|
|
683
|
+
} else if (!_.isNil(tableDefinition)) {
|
|
684
|
+
return tableDefinition;
|
|
685
|
+
} else if (!_.isNil(imageDefinition)) {
|
|
686
|
+
return imageDefinition;
|
|
687
|
+
} else {
|
|
688
|
+
return null;
|
|
689
|
+
}
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
__addFooter(definition, json) {
|
|
695
|
+
let footerNode = _.find(json.elements, {name:"footer"});
|
|
696
|
+
if(!_.isNil(footerNode)) {
|
|
697
|
+
let tableNode = _.find(footerNode.elements, {name:"table"});
|
|
698
|
+
let bTableNode = !_.isNil(tableNode);
|
|
699
|
+
|
|
700
|
+
//The coverage report only works correctly when isWriteDataEnabled() returns true in the Unit Tests.
|
|
701
|
+
definition.footer = (currentPage/*, pageCount, pageSize*/) => {
|
|
702
|
+
let tableDefinition = bTableNode ? this.__getTableDefinition(tableNode, {"layout": "noBorders", "currentPage":currentPage}) : null;
|
|
703
|
+
return tableDefinition;
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
__addDocumentMetadata(definition, documentProperties){
|
|
709
|
+
definition.info = {};
|
|
710
|
+
definition.info.creator = "Consumer Goods Cloud";
|
|
711
|
+
definition.info.producer = "Consumer Goods Cloud";
|
|
712
|
+
_.forEach(documentProperties, (value, key) => {
|
|
713
|
+
definition.info[key] = value;
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
__configureAutomaticPageBreak(reportLayout) {
|
|
718
|
+
if(!_.isNil(reportLayout.attributes) && !_.isNil(reportLayout.attributes.automaticPageBreak)){
|
|
719
|
+
this.__automaticPageBreak = reportLayout.attributes.automaticPageBreak;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
__addPageDimensionsOrientationMarginsWatermark(definition, reportLayout){
|
|
724
|
+
if(!_.isNil(reportLayout.attributes) && !_.isNil(reportLayout.attributes.pageSize)){
|
|
725
|
+
definition.pageSize = reportLayout.attributes.pageSize;
|
|
726
|
+
}
|
|
727
|
+
if(!_.isNil(reportLayout.attributes) && !_.isNil(reportLayout.attributes.watermark)){
|
|
728
|
+
definition.watermark = {text: reportLayout.attributes.watermark, opacity:0.1, fontSize: 120};
|
|
729
|
+
}
|
|
730
|
+
if(!_.isNil(reportLayout.attributes) && !_.isNil(reportLayout.attributes.pageMargins)){
|
|
731
|
+
definition.pageMargins = JSON.parse(reportLayout.attributes.pageMargins);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
__isLastMainRowOnPage(followingNodesOnPage) {
|
|
736
|
+
let result = false;
|
|
737
|
+
|
|
738
|
+
if (!_.isNil(followingNodesOnPage) && _.isArray(followingNodesOnPage)) {
|
|
739
|
+
result = (followingNodesOnPage.length === 0) || !(_.some(followingNodesOnPage, y => {
|
|
740
|
+
let tcid = TableCellIdentifier.fromString(y.id);
|
|
741
|
+
return (tcid.isKnown() && tcid.isFirstMainRowCell());
|
|
742
|
+
}));
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
return result;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
__isFirstNodeOnNextPageFirstMainRowCell(nodesOnNextPage) {
|
|
749
|
+
let result = false;
|
|
750
|
+
|
|
751
|
+
if (!_.isNil(nodesOnNextPage) && _.isArray(nodesOnNextPage) && nodesOnNextPage.length > 0) {
|
|
752
|
+
let firstNodeOnNextPage = _.first(nodesOnNextPage);
|
|
753
|
+
let tcid = TableCellIdentifier.fromString(firstNodeOnNextPage.id);
|
|
754
|
+
result = (tcid.isKnown() && tcid.isFirstMainRowCell());
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
return result;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
__calculatePageBreakForParentChildRows(currentNode, followingNodesOnPage, nodesOnNextPage, previousNodesOnPage, tcidCurrentNode) {
|
|
761
|
+
let doPageBreak = false;
|
|
762
|
+
|
|
763
|
+
// dynamic pageBreak logic for parent-child rows
|
|
764
|
+
if (!_.isNil(previousNodesOnPage) && _.isArray(previousNodesOnPage) && previousNodesOnPage.length > 0) {
|
|
765
|
+
let previousNode = _.last(previousNodesOnPage);
|
|
766
|
+
let tcidPreviousNode = TableCellIdentifier.fromString(previousNode.id);
|
|
767
|
+
|
|
768
|
+
// => check if we are the first cell of a main row ...
|
|
769
|
+
if (tcidCurrentNode.isFirstMainRowCell()) {
|
|
770
|
+
|
|
771
|
+
if (!_.isNil(followingNodesOnPage) && _.isArray(followingNodesOnPage)) {
|
|
772
|
+
|
|
773
|
+
let isCurrentNodeLastHeadOnPageX = this.__isLastMainRowOnPage(followingNodesOnPage);
|
|
774
|
+
let isFirstNodeOnNextPageFirstMainRowCellX = this.__isFirstNodeOnNextPageFirstMainRowCell(nodesOnNextPage);
|
|
775
|
+
let isPageBreakRelevant = (tcidPreviousNode.isKnown() && (tcidPreviousNode.isFirstMainRowCell() || tcidPreviousNode.isSubsequentMainRowCell() || tcidPreviousNode.isFirstCorrelatedRowCell() || tcidPreviousNode.isSubsequentCorrelatedRowCell()));
|
|
776
|
+
|
|
777
|
+
doPageBreak = (isCurrentNodeLastHeadOnPageX && !isFirstNodeOnNextPageFirstMainRowCellX && isPageBreakRelevant);
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
} else if (tcidCurrentNode.isSubsequentMainRowCell()) {
|
|
781
|
+
|
|
782
|
+
doPageBreak = (!tcidPreviousNode.isFirstMainRowCell() && !tcidPreviousNode.isSubsequentMainRowCell() || !(tcidCurrentNode.sharesMainRow(tcidPreviousNode)));
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
return doPageBreak;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
|
|
790
|
+
__calculatePageBreakForBrokenRows(currentNode, followingNodesOnPage, nodesOnNextPage, previousNodesOnPage, tcidCurrentNode) {
|
|
791
|
+
let doPageBreak = false;
|
|
792
|
+
|
|
793
|
+
// => check if we are the first cell of a row ...
|
|
794
|
+
if (tcidCurrentNode.isFirstMainRowCell() || tcidCurrentNode.isFirstCorrelatedRowCell()) {
|
|
795
|
+
// check for 'broken' row ...
|
|
796
|
+
// => check if i am the last row
|
|
797
|
+
let isLastRowOnPageX = (_.every(followingNodesOnPage, node => {
|
|
798
|
+
let tcidNode = TableCellIdentifier.fromString(node.id);
|
|
799
|
+
return !tcidNode.isKnown() || (tcidNode.isKnown() && tcidCurrentNode.sharesCorrelatedRow(tcidNode));
|
|
800
|
+
}));
|
|
801
|
+
|
|
802
|
+
if (isLastRowOnPageX) {
|
|
803
|
+
// check if any cell of the current row extends over more than one page => pageBreak!
|
|
804
|
+
// => check current cell (first cell of row)
|
|
805
|
+
doPageBreak = (!_.isNil(currentNode.pageNumbers) && _.isArray(currentNode.pageNumbers) && currentNode.pageNumbers.length > 1);
|
|
806
|
+
if (!doPageBreak) {
|
|
807
|
+
// => check following cells on current page and cells on next page for page overlaps (other cells of row)
|
|
808
|
+
doPageBreak = (_.some(followingNodesOnPage, node => {
|
|
809
|
+
let tcidNode = TableCellIdentifier.fromString(node.id);
|
|
810
|
+
if (tcidNode.isKnown() && tcidCurrentNode.sharesCorrelatedRow(tcidNode)) {
|
|
811
|
+
return !_.isEqual(currentNode.pageNumbers, node.pageNumbers);
|
|
812
|
+
}
|
|
813
|
+
return false;
|
|
814
|
+
}) || (_.some(nodesOnNextPage, node => {
|
|
815
|
+
let tcidNode = TableCellIdentifier.fromString(node.id);
|
|
816
|
+
if (tcidNode.isKnown() && tcidCurrentNode.sharesCorrelatedRow(tcidNode)) {
|
|
817
|
+
return !_.isEqual(currentNode.pageNumbers, node.pageNumbers);
|
|
818
|
+
}
|
|
819
|
+
return false;
|
|
820
|
+
})));
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
} else if (tcidCurrentNode.isSubsequentMainRowCell() || tcidCurrentNode.isSubsequentCorrelatedRowCell()) {
|
|
824
|
+
// => check other row cells ...
|
|
825
|
+
if (!_.isNil(previousNodesOnPage) && _.isArray(previousNodesOnPage) && previousNodesOnPage.length > 0) {
|
|
826
|
+
// check if last previous node is NOT precursor cell of current one => pageBreak!
|
|
827
|
+
let previousNode = _.last(previousNodesOnPage);
|
|
828
|
+
let tcidPreviousNode = TableCellIdentifier.fromString(previousNode.id);
|
|
829
|
+
doPageBreak = !tcidCurrentNode.isPreviousCell(tcidPreviousNode);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
return doPageBreak;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
__calculatePageBreakBefore(currentNode, followingNodesOnPage, nodesOnNextPage, previousNodesOnPage) {
|
|
837
|
+
let doPageBreak = false;
|
|
838
|
+
|
|
839
|
+
// looking for potential pageBreaks only makes sense if there are elements to be placed there (=> might require adaption for subtotals)
|
|
840
|
+
if (!_.isNil(nodesOnNextPage) && _.isArray(nodesOnNextPage) && nodesOnNextPage.length > 0) {
|
|
841
|
+
|
|
842
|
+
// get table cell identifier
|
|
843
|
+
let tcidCurrentNode = TableCellIdentifier.fromString(currentNode.id);
|
|
844
|
+
if (!_.isNil(tcidCurrentNode) && tcidCurrentNode.isKnown()) {
|
|
845
|
+
|
|
846
|
+
// check for dynamic pageBreak of parent-child rows
|
|
847
|
+
doPageBreak = this.__calculatePageBreakForParentChildRows(currentNode, followingNodesOnPage, nodesOnNextPage, previousNodesOnPage, tcidCurrentNode);
|
|
848
|
+
if (!doPageBreak) {
|
|
849
|
+
// check for dynamic pageBreak of 'broken' row
|
|
850
|
+
doPageBreak = this.__calculatePageBreakForBrokenRows(currentNode, followingNodesOnPage, nodesOnNextPage, previousNodesOnPage, tcidCurrentNode);
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
if (doPageBreak && !_.isUndefined(this.__definition.dynamicPageBreak) && this.__definition.dynamicPageBreak) {
|
|
854
|
+
if (tcidCurrentNode.isFirstMainRowCell() || tcidCurrentNode.isFirstCorrelatedRowCell()) {
|
|
855
|
+
// cache dynamic pageBreak to turn them into manual ones during the second run ...
|
|
856
|
+
this.__definition.dynamicPageBreakData.push(tcidCurrentNode.toString());
|
|
857
|
+
} else {
|
|
858
|
+
doPageBreak = false;
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
return doPageBreak;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
__createPdfDocument(pdfDefinition, pdfCreationFunction) {
|
|
869
|
+
// clone pdf definition if applicable ...
|
|
870
|
+
let pdfDefinitionCopy = null;
|
|
871
|
+
if (!_.isNil(pdfDefinition) && !_.isUndefined(pdfDefinition.dynamicPageBreak) && pdfDefinition.dynamicPageBreak &&
|
|
872
|
+
!_.isNil(pdfCreationFunction) && _.isFunction(pdfCreationFunction)) {
|
|
873
|
+
// init empty dynamicPageBreakData ...
|
|
874
|
+
_.assign(pdfDefinition, {
|
|
875
|
+
dynamicPageBreakData: []
|
|
876
|
+
});
|
|
877
|
+
|
|
878
|
+
pdfDefinitionCopy = _.cloneDeep(pdfDefinition);
|
|
879
|
+
// skip header / footer for initial layouting and move them to final layouting
|
|
880
|
+
if (!_.isUndefined(pdfDefinition.header)) {
|
|
881
|
+
let headerFunction = pdfDefinition.header;
|
|
882
|
+
_.assign(pdfDefinitionCopy, {
|
|
883
|
+
'header': headerFunction
|
|
884
|
+
});
|
|
885
|
+
_.unset(pdfDefinition, 'header');
|
|
886
|
+
}
|
|
887
|
+
if (!_.isUndefined(pdfDefinition.footer)) {
|
|
888
|
+
let footerFunction = pdfDefinition.footer;
|
|
889
|
+
_.assign(pdfDefinitionCopy, {
|
|
890
|
+
'footer': footerFunction
|
|
891
|
+
});
|
|
892
|
+
_.unset(pdfDefinition, 'footer');
|
|
893
|
+
}
|
|
894
|
+
// remove dynamic pageBreak logic
|
|
895
|
+
_.unset(pdfDefinitionCopy, 'pageBreakBefore');
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
// set pdf definition to be layouted ...
|
|
899
|
+
this.__definition = pdfDefinition;
|
|
900
|
+
|
|
901
|
+
// exec pdfCreation function ...
|
|
902
|
+
pdfCreationFunction.apply(this, [pdfDefinition]);
|
|
903
|
+
|
|
904
|
+
return pdfDefinitionCopy;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
__createFinalPdfDocument(pdfDefinition, pdfDefinitionCopy, pdfCreationFunction) {
|
|
908
|
+
// perform pageBreak magic ...
|
|
909
|
+
if (!_.isNil(pdfDefinition) && !_.isUndefined(pdfDefinition.dynamicPageBreak) && pdfDefinition.dynamicPageBreak &&
|
|
910
|
+
!_.isUndefined(pdfDefinition.dynamicPageBreakData) && _.isArray(pdfDefinition.dynamicPageBreakData) &&
|
|
911
|
+
!_.isNil(pdfDefinitionCopy) && !_.isUndefined(pdfDefinitionCopy.dynamicPageBreak) && pdfDefinitionCopy.dynamicPageBreak &&
|
|
912
|
+
!_.isNil(pdfCreationFunction) && _.isFunction(pdfCreationFunction)) {
|
|
913
|
+
|
|
914
|
+
// transfer dynamicPageBreakData from pdf definition to its copy
|
|
915
|
+
pdfDefinitionCopy.dynamicPageBreakData = pdfDefinition.dynamicPageBreakData;
|
|
916
|
+
|
|
917
|
+
this.__applyPageBreakData(pdfDefinitionCopy);
|
|
918
|
+
|
|
919
|
+
// set pdf definition to be layouted ...
|
|
920
|
+
this.__definition = pdfDefinitionCopy;
|
|
921
|
+
|
|
922
|
+
// exec pdfCreation function ...
|
|
923
|
+
pdfCreationFunction.apply(this, [pdfDefinitionCopy]);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
toPdfDefinition(json/*, format*/) {
|
|
928
|
+
this.__initializePdfDefinition();
|
|
929
|
+
this.__addDocumentMetadata(this.__definition, json.documentProperties);
|
|
930
|
+
let reportLayout = json.reportLayout;
|
|
931
|
+
this.__configureAutomaticPageBreak(reportLayout);
|
|
932
|
+
this.__addPageDimensionsOrientationMarginsWatermark(this.__definition, reportLayout);
|
|
933
|
+
this.__addHeader(this.__definition, reportLayout);
|
|
934
|
+
this.__addBody(this.__definition, reportLayout);
|
|
935
|
+
this.__addFooter(this.__definition,reportLayout);
|
|
936
|
+
return this.__definition;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
writeToStream(pdfDefinition, stream) {
|
|
940
|
+
// setup pdf creator ...
|
|
941
|
+
let printer = new PdfPrinter(ServerFonts);
|
|
942
|
+
let pdfDoc = null;
|
|
943
|
+
let pdfCreatorFunction = (definition) => {
|
|
944
|
+
printer = new PdfPrinter(ServerFonts);
|
|
945
|
+
pdfDoc = printer.createPdfKitDocument(definition, {
|
|
946
|
+
tableLayouts: TableLayouts
|
|
947
|
+
});
|
|
948
|
+
};
|
|
949
|
+
|
|
950
|
+
// create pdf and prepare for recreation if applicable ...
|
|
951
|
+
let pdfDefinitionCopy = this.__createPdfDocument(pdfDefinition, pdfCreatorFunction);
|
|
952
|
+
|
|
953
|
+
// recreate pdf if applicable ...
|
|
954
|
+
this.__createFinalPdfDocument(pdfDefinition, pdfDefinitionCopy, pdfCreatorFunction);
|
|
955
|
+
|
|
956
|
+
pdfDoc.pipe(stream);
|
|
957
|
+
pdfDoc.end();
|
|
958
|
+
|
|
959
|
+
return (pdfDefinitionCopy || pdfDefinition);
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
async __createPdfDocumentAsync(pdfDefinition) {
|
|
963
|
+
return new Promise((resolve, reject) => {
|
|
964
|
+
try {
|
|
965
|
+
|
|
966
|
+
// clone pdf definition if applicable ...
|
|
967
|
+
let pdfDefinitionCopy = null;
|
|
968
|
+
if (!_.isNil(pdfDefinition) && !_.isUndefined(pdfDefinition.dynamicPageBreak) && pdfDefinition.dynamicPageBreak) {
|
|
969
|
+
// init empty dynamicPageBreakData ...
|
|
970
|
+
_.assign(pdfDefinition, {
|
|
971
|
+
dynamicPageBreakData: []
|
|
972
|
+
});
|
|
973
|
+
|
|
974
|
+
pdfDefinitionCopy = _.cloneDeep(pdfDefinition);
|
|
975
|
+
// skip header / footer for initial layouting and move them to final layouting
|
|
976
|
+
if (!_.isUndefined(pdfDefinition.header)) {
|
|
977
|
+
let headerFunction = pdfDefinition.header;
|
|
978
|
+
_.assign(pdfDefinitionCopy, {
|
|
979
|
+
'header': headerFunction
|
|
980
|
+
});
|
|
981
|
+
_.unset(pdfDefinition, 'header');
|
|
982
|
+
}
|
|
983
|
+
if (!_.isUndefined(pdfDefinition.footer)) {
|
|
984
|
+
let footerFunction = pdfDefinition.footer;
|
|
985
|
+
_.assign(pdfDefinitionCopy, {
|
|
986
|
+
'footer': footerFunction
|
|
987
|
+
});
|
|
988
|
+
_.unset(pdfDefinition, 'footer');
|
|
989
|
+
}
|
|
990
|
+
// remove dynamic pageBreak logic
|
|
991
|
+
_.unset(pdfDefinitionCopy, 'pageBreakBefore');
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
// set pdf definition to be layouted ...
|
|
995
|
+
this.__definition = pdfDefinition;
|
|
996
|
+
|
|
997
|
+
resolve(pdfDefinitionCopy);
|
|
998
|
+
} catch (error) {
|
|
999
|
+
reject(error);
|
|
1000
|
+
}
|
|
1001
|
+
});
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
async __createFinalPdfDocumentAsync(pdfDefinition, pdfDefinitionCopy) {
|
|
1005
|
+
return new Promise((resolve, reject) => {
|
|
1006
|
+
try {
|
|
1007
|
+
// perform pageBreak magic ...
|
|
1008
|
+
if (!_.isNil(pdfDefinition) && !_.isUndefined(pdfDefinition.dynamicPageBreak) && pdfDefinition.dynamicPageBreak &&
|
|
1009
|
+
!_.isUndefined(pdfDefinition.dynamicPageBreakData) && _.isArray(pdfDefinition.dynamicPageBreakData) &&
|
|
1010
|
+
!_.isNil(pdfDefinitionCopy) && !_.isUndefined(pdfDefinitionCopy.dynamicPageBreak) && pdfDefinitionCopy.dynamicPageBreak) {
|
|
1011
|
+
|
|
1012
|
+
// transfer dynamicPageBreakData from pdf definition to its copy
|
|
1013
|
+
pdfDefinitionCopy.dynamicPageBreakData = pdfDefinition.dynamicPageBreakData;
|
|
1014
|
+
|
|
1015
|
+
this.__applyPageBreakData(pdfDefinitionCopy);
|
|
1016
|
+
|
|
1017
|
+
// set pdf definition to be layouted ...
|
|
1018
|
+
this.__definition = pdfDefinitionCopy;
|
|
1019
|
+
}
|
|
1020
|
+
resolve();
|
|
1021
|
+
} catch (error) {
|
|
1022
|
+
reject(error);
|
|
1023
|
+
}
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
async __getPdfDataAsync(type, pdfDefinition, previousResult = null) {
|
|
1028
|
+
return new Promise((resolve, reject) => {
|
|
1029
|
+
try {
|
|
1030
|
+
if (_.isNil(pdfDefinition) && !_.isNil(previousResult)) {
|
|
1031
|
+
resolve(previousResult);
|
|
1032
|
+
} else {
|
|
1033
|
+
let pdfDocGenerator = this.__pdfMake.createPdf(pdfDefinition, TableLayouts, BrowserFonts, BrowserFontsVfs.pdfMake.vfs);
|
|
1034
|
+
|
|
1035
|
+
switch (type) {
|
|
1036
|
+
case EXPORT_TYPE.BASE_64:
|
|
1037
|
+
pdfDocGenerator.getBase64((data) => {
|
|
1038
|
+
resolve(data);
|
|
1039
|
+
});
|
|
1040
|
+
break;
|
|
1041
|
+
|
|
1042
|
+
case EXPORT_TYPE.BLOB:
|
|
1043
|
+
pdfDocGenerator.getBlob((blob) => {
|
|
1044
|
+
resolve(blob);
|
|
1045
|
+
});
|
|
1046
|
+
break;
|
|
1047
|
+
|
|
1048
|
+
case EXPORT_TYPE.DATA_URL:
|
|
1049
|
+
pdfDocGenerator.getDataUrl((dataUrl) => {
|
|
1050
|
+
resolve(dataUrl);
|
|
1051
|
+
});
|
|
1052
|
+
break;
|
|
1053
|
+
|
|
1054
|
+
default:
|
|
1055
|
+
throw new Error('Unknown export type: ' + type );
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
} catch (error) {
|
|
1060
|
+
reject(error);
|
|
1061
|
+
}
|
|
1062
|
+
});
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
async toBase64(pdfDefinition) {
|
|
1066
|
+
// hint: works only in browser avoid calling it in node.js
|
|
1067
|
+
let pdfDefinitionCopy = null;
|
|
1068
|
+
let firstResult = null;
|
|
1069
|
+
|
|
1070
|
+
return this.__createPdfDocumentAsync(pdfDefinition).then((pdfDef) => {
|
|
1071
|
+
pdfDefinitionCopy = pdfDef;
|
|
1072
|
+
return this.__getPdfDataAsync(EXPORT_TYPE.BASE_64, pdfDefinition);
|
|
1073
|
+
}).then((pdfData) => {
|
|
1074
|
+
firstResult = pdfData;
|
|
1075
|
+
return this.__createFinalPdfDocumentAsync(pdfDefinition, pdfDefinitionCopy);
|
|
1076
|
+
}).then(() => {
|
|
1077
|
+
return this.__getPdfDataAsync(EXPORT_TYPE.BASE_64, pdfDefinitionCopy, firstResult);
|
|
1078
|
+
});
|
|
1079
|
+
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
async toBlob(pdfDefinition) {
|
|
1083
|
+
// hint: works only in browser avoid calling it in node.js
|
|
1084
|
+
let pdfDefinitionCopy = null;
|
|
1085
|
+
let firstResult = null;
|
|
1086
|
+
|
|
1087
|
+
return this.__createPdfDocumentAsync(pdfDefinition).then((pdfDef) => {
|
|
1088
|
+
pdfDefinitionCopy = pdfDef;
|
|
1089
|
+
return this.__getPdfDataAsync(EXPORT_TYPE.BLOB, pdfDefinition);
|
|
1090
|
+
}).then((pdfData) => {
|
|
1091
|
+
firstResult = pdfData;
|
|
1092
|
+
return this.__createFinalPdfDocumentAsync(pdfDefinition, pdfDefinitionCopy);
|
|
1093
|
+
}).then(() => {
|
|
1094
|
+
return this.__getPdfDataAsync(EXPORT_TYPE.BLOB, pdfDefinitionCopy, firstResult);
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
async toDataUrl(pdfDefinition) {
|
|
1099
|
+
// hint: works only in browser avoid calling it in node.js
|
|
1100
|
+
let pdfDefinitionCopy = null;
|
|
1101
|
+
let firstResult = null;
|
|
1102
|
+
|
|
1103
|
+
return this.__createPdfDocumentAsync(pdfDefinition).then((pdfDef) => {
|
|
1104
|
+
pdfDefinitionCopy = pdfDef;
|
|
1105
|
+
return this.__getPdfDataAsync(EXPORT_TYPE.DATA_URL, pdfDefinition);
|
|
1106
|
+
}).then((pdfData) => {
|
|
1107
|
+
firstResult = pdfData;
|
|
1108
|
+
return this.__createFinalPdfDocumentAsync(pdfDefinition, pdfDefinitionCopy);
|
|
1109
|
+
}).then(() => {
|
|
1110
|
+
return this.__getPdfDataAsync(EXPORT_TYPE.DATA_URL, pdfDefinitionCopy, firstResult);
|
|
1111
|
+
});
|
|
1112
|
+
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
static isValidFormat(format) {
|
|
1116
|
+
let supportedFormats = ['A3', 'A4', 'A5', 'Legal', 'Letter', 'Tabloid'];
|
|
1117
|
+
return supportedFormats.includes(format);
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
|
|
1123
|
+
module.exports = PdfConverter;
|