@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.
@@ -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;