@ind-rcg/plugins-printengine 250.1004.0 → 254.1005.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.
@@ -52,18 +52,29 @@ function __validateCommonParameters(contract, params, format){
52
52
  }
53
53
  }
54
54
 
55
- function __innerPrintLogic(printType, contract, params, _stream, format) {
55
+ function __innerPrintLogic(printType, contract, params, _stream, format, config) {
56
56
  let json = contractParser.toJson(contract, params);
57
57
  let pdfDefinition = pdfConverter.toPdfDefinition(json, format, testReportName);
58
-
59
58
  switch (printType) {
60
59
  case PRINT_TYPE.STREAM:
61
60
  pdfConverter.writeToStream(pdfDefinition, _stream);
62
61
  break;
63
62
 
64
63
  case PRINT_TYPE.BLOB:
65
- return pdfConverter.toBlob(pdfDefinition);
66
-
64
+ return new Promise((resolve, reject) => {
65
+ pdfConverter.toBlob(pdfDefinition).then((blobData)=>{
66
+ if(config && config.metaData === true){
67
+ resolve({
68
+ data: blobData,
69
+ pdfJson: json
70
+ });
71
+ } else {
72
+ resolve(blobData);
73
+ }
74
+ }, (err)=>{
75
+ reject(err);
76
+ });
77
+ });
67
78
  case PRINT_TYPE.DATA_URL:
68
79
  return pdfConverter.toDataUrl(pdfDefinition);
69
80
 
@@ -73,25 +84,25 @@ function __innerPrintLogic(printType, contract, params, _stream, format) {
73
84
  }
74
85
  }
75
86
 
76
- function printToStream(contract, params, _stream, format = "A4") {
87
+ function printToStream(contract, params, _stream, format = "A4", config = {}) {
77
88
  // Validate parameters
78
89
  if(!(_stream instanceof stream.Stream)) {
79
90
  throw new TypeError("Not a valid stream.");
80
91
  }
81
92
  __validateCommonParameters(contract, params, format);
82
- __innerPrintLogic(PRINT_TYPE.STREAM, contract, params, _stream, format);
93
+ __innerPrintLogic(PRINT_TYPE.STREAM, contract, params, _stream, format, config);
83
94
  }
84
95
 
85
- function printToDataUrl(contract, params, format = "A4") {
96
+ function printToDataUrl(contract, params, format = "A4", config = {}) {
86
97
  // Validate parameters
87
98
  __validateCommonParameters(contract, params, format);
88
- return __innerPrintLogic(PRINT_TYPE.DATA_URL, contract, params, null, format);
99
+ return __innerPrintLogic(PRINT_TYPE.DATA_URL, contract, params, null, format, config);
89
100
  }
90
101
 
91
- function printToBlob(contract, params, format = "A4") {
102
+ function printToBlob(contract, params, format = "A4", config = {}) {
92
103
  // Validate parameters
93
104
  __validateCommonParameters(contract, params, format);
94
- return __innerPrintLogic(PRINT_TYPE.BLOB, contract, params, null, format);
105
+ return __innerPrintLogic(PRINT_TYPE.BLOB, contract, params, null, format, config);
95
106
  }
96
107
 
97
108
 
@@ -10,6 +10,7 @@ const TableCellIdentifier = require('./tableCellIdentifier');
10
10
 
11
11
  // required for webpack include (browser impl), used in conjunction with BrowserFonts definition
12
12
  const BrowserFontsVfs = require('pdfmake/build/vfs_fonts.js');
13
+ const classLog = require("./logClass");
13
14
 
14
15
  // => use 'Roboto' font (pdfMake default) due to licensing (Apache 2.0)
15
16
  // https://fonts.google.com/specimen/Roboto || https://en.wikipedia.org/wiki/Roboto
@@ -82,6 +83,9 @@ const TableLayouts = {
82
83
  }
83
84
  };
84
85
 
86
+ const ThermalPrintLayoutPageMargins = [5,5,5,5];
87
+ let __log = new classLog();
88
+
85
89
  const STYLE_HEADING1 = "heading1";
86
90
  const STYLE_HEADING2 = "heading2";
87
91
  const STYLE_PARAGRAPH = "paragraph";
@@ -102,6 +106,11 @@ class PdfConverter {
102
106
  }
103
107
 
104
108
  this.__format = new Format();
109
+ this.__pdfHeight = null;
110
+ }
111
+
112
+ __isThermalPrintLayout() {
113
+ return this.__pdfHeight === 'auto';
105
114
  }
106
115
 
107
116
  __applyPageBreakData(pdfDefinition) {
@@ -212,7 +221,11 @@ class PdfConverter {
212
221
  }
213
222
 
214
223
  __getParagraphDefinition(paragraphNode, paragraphStyle) {
215
- return this.__createHeadingOrParagraphText(paragraphNode, paragraphNode.elements[0].text, paragraphStyle);
224
+ let text = '';
225
+ if (paragraphNode.elements) {
226
+ text = paragraphNode.elements[0].text;
227
+ }
228
+ return this.__createHeadingOrParagraphText(paragraphNode, text, paragraphStyle);
216
229
  }
217
230
 
218
231
  __getImageDefinition(imageNode, useAlignment) {
@@ -359,6 +372,10 @@ class PdfConverter {
359
372
  let i = 0;
360
373
 
361
374
  if (bAllowedStrings && _.isString(attribute)){
375
+ //the width can be given as a percentage only if the layout is 3-inch endless printer i.e, the height is auto
376
+ if(this.__pdfHeight === 'auto' && (/^\d+(\.\d+)?%$/).test(attribute)){
377
+ return attribute;
378
+ }
362
379
  for (i=0; i<allowedStrings.length; i++) {
363
380
  if (attribute === allowedStrings[i]) {
364
381
  return attribute;
@@ -488,9 +505,9 @@ class PdfConverter {
488
505
  return result;
489
506
  }
490
507
 
491
- __createTableColumn(content, style, colSpan, rowSpan, alignment, bold, italics, cellId) {
492
- let bTextOnly = _.isNil(content.image) && _.isNil(style) && _.isNil(colSpan) && _.isNil(rowSpan)
493
- && _.isNil(alignment) && _.isNil(bold) && _.isNil(italics) && _.isNil(cellId);
508
+ __createTableColumn(content, style, attributesJson) {
509
+ let bTextOnly = _.isNil(content.image) && _.isNil(style) && _.isNil(attributesJson.colSpan) && _.isNil(attributesJson.rowSpan)
510
+ && _.isNil(attributesJson.alignment) && _.isNil(attributesJson.bold) && _.isNil(attributesJson.italics) && _.isNil(attributesJson.cellId);
494
511
 
495
512
  if (bTextOnly) {
496
513
  return content.text;
@@ -508,23 +525,23 @@ class PdfConverter {
508
525
  if (!_.isNil(style)) {
509
526
  column.style = style;
510
527
  }
511
- if (!_.isNil(colSpan)) {
512
- column.colSpan = colSpan;
528
+ if (!_.isNil(attributesJson.colSpan)) {
529
+ column.colSpan = attributesJson.colSpan;
513
530
  }
514
- if (!_.isNil(rowSpan)) {
515
- column.rowSpan = rowSpan;
531
+ if (!_.isNil(attributesJson.rowSpan)) {
532
+ column.rowSpan = attributesJson.rowSpan;
516
533
  }
517
- if (!_.isNil(alignment)) {
518
- column.alignment = alignment;
534
+ if (!_.isNil(attributesJson.alignment)) {
535
+ column.alignment = attributesJson.alignment;
519
536
  }
520
- if (!_.isNil(bold)) {
521
- column.bold = bold;
537
+ if (!_.isNil(attributesJson.bold)) {
538
+ column.bold = attributesJson.bold;
522
539
  }
523
- if (!_.isNil(italics)) {
524
- column.italics = italics;
540
+ if (!_.isNil(attributesJson.italics)) {
541
+ column.italics = attributesJson.italics;
525
542
  }
526
- if (!_.isNil(cellId)) {
527
- column.id = cellId;
543
+ if (!_.isNil(attributesJson.cellId)) {
544
+ column.id = attributesJson.cellId;
528
545
  }
529
546
 
530
547
  return column;
@@ -538,7 +555,14 @@ class PdfConverter {
538
555
  let alignmentAttribute = this.__checkEnumAttribute(thOrTdNode, 'alignment', ["left", "center", "right"], null);
539
556
  let cellId = this.__checkStringAttribute(thOrTdNode, 'id', null);
540
557
 
541
- return [colSpanAttributeValue, rowSpanAttributeValue, alignmentAttribute, boldAttribute, italicsAttribute, cellId];
558
+ return {
559
+ colSpan: colSpanAttributeValue,
560
+ rowSpan: rowSpanAttributeValue,
561
+ alignment: alignmentAttribute,
562
+ bold: boldAttribute,
563
+ italics: italicsAttribute,
564
+ cellId: cellId
565
+ };
542
566
  }
543
567
 
544
568
  __evaluateTableDefinitionRowBreak(tableNode, dynamicPageBreak) {
@@ -596,24 +620,10 @@ class PdfConverter {
596
620
  let bNoWidths = false;
597
621
  let theadNode = _.find(tableNode.elements, {name: 'thead'});
598
622
  let tbodyNode = _.find(tableNode.elements, {name: 'tbody'});
623
+ let theadAlignmentValues = [];
599
624
 
600
625
  if(!_.isNil(theadNode)) {
601
- _.forEach(theadNode.elements, headerTrNode=> {
602
- let row = [];
603
- _.forEach(headerTrNode.elements, value => {
604
- let attributeValues = this.__getTableCellAttributes(value);
605
-
606
- if (pdfTableDefinition.table.headerRows === 0) {
607
- let widthAttributeValue = this.__checkIntegerAttribute(value, 'width', ['*', 'auto'], true, 'auto');
608
- pdfTableDefinition.table.widths.push(widthAttributeValue);
609
- }
610
- let content = this.__getThOrTdContent(value, settings);
611
- row.push(this.__createTableColumn(content, 'tableHeader', ...attributeValues));
612
- });
613
-
614
- pdfTableDefinition.table.body.push(row);
615
- pdfTableDefinition.table.headerRows += 1;
616
- });
626
+ this.__getTheadNodeDefinition(theadNode, pdfTableDefinition, settings, theadAlignmentValues);
617
627
  } else if(!_.isNil(tbodyNode)) {
618
628
  bNoWidths = true;
619
629
  } else {
@@ -624,24 +634,7 @@ class PdfConverter {
624
634
  }
625
635
 
626
636
  if(!_.isNil(tbodyNode)) {
627
- _.forEach(tbodyNode.elements, tbodyTrNode=> {
628
- let row = [];
629
- _.forEach(tbodyTrNode.elements, value => {
630
- let attributeValues = this.__getTableCellAttributes(value);
631
-
632
- if ((bNoWidths === true)) {
633
- let widthAttributeValue = this.__checkIntegerAttribute(value, 'width', ['*', 'auto'], true, 'auto');
634
- pdfTableDefinition.table.widths.push(widthAttributeValue);
635
- }
636
- let content = this.__getThOrTdContent(value, settings);
637
- content.text = this.__applyNumberFormatAttribute(value, content.text);
638
-
639
- row.push(this.__createTableColumn(content, null, ...attributeValues));
640
- });
641
-
642
- bNoWidths = false;
643
- pdfTableDefinition.table.body.push(row);
644
- });
637
+ this.__getTbodyNodeDefinition(tbodyNode, pdfTableDefinition, bNoWidths, settings, theadAlignmentValues);
645
638
  }
646
639
 
647
640
  this.__checkSpansAndColumns(pdfTableDefinition);
@@ -649,8 +642,89 @@ class PdfConverter {
649
642
  return pdfTableDefinition;
650
643
  }
651
644
 
645
+ __getTheadNodeDefinition(theadNode, pdfTableDefinition, settings, theadAlignmentValues) {
646
+ _.forEach(theadNode.elements, headerTrNode=> {
647
+ let row = [];
648
+ _.forEach(headerTrNode.elements, value => {
649
+ let attributesJson = this.__getTableCellAttributes(value);
650
+
651
+ if (pdfTableDefinition.table.headerRows === 0) {
652
+ let widthAttributeValue = this.__checkIntegerAttribute(value, 'width', ['*', 'auto'], true, 'auto');
653
+ pdfTableDefinition.table.widths.push(widthAttributeValue);
654
+ }
655
+ let content = this.__getThOrTdContent(value, settings);
656
+ row.push(this.__createTableColumn(content, 'tableHeader', attributesJson));
657
+
658
+ //store the alignment values from th to be set to corresponding td for thermal print layout
659
+ if(this.__isThermalPrintLayout()) {
660
+ theadAlignmentValues.push(attributesJson.alignment || 'left');
661
+ }
662
+ });
663
+
664
+ pdfTableDefinition.table.body.push(row);
665
+ pdfTableDefinition.table.headerRows += 1;
666
+ });
667
+ }
668
+
669
+ __getTbodyNodeDefinition(tbodyNode, pdfTableDefinition, bNoWidths, settings, theadAlignmentValues) {
670
+ _.forEach(tbodyNode.elements, tbodyTrNode=> {
671
+ let row = [];
672
+ _.forEach(tbodyTrNode.elements, (value, index) => {
673
+ //for thermal printer layout the alignment value for each td should be same as that column's th OR by default left
674
+ //if alignment for th is not defined
675
+ if (this.__isThermalPrintLayout()) {
676
+ value.attributes = value.attributes || {}; // Ensure attributes exist for the tdNode
677
+ value.attributes.alignment = theadAlignmentValues[index] || 'left'; // Set alignment to the corresponding th
678
+ }
679
+ let attributesJson = this.__getTableCellAttributes(value);
680
+ if ((bNoWidths === true)) {
681
+ let widthAttributeValue = this.__checkIntegerAttribute(value, 'width', ['*', 'auto'], true, 'auto');
682
+ pdfTableDefinition.table.widths.push(widthAttributeValue);
683
+ }
684
+ let content = this.__getThOrTdContent(value, settings);
685
+ content.text = this.__applyNumberFormatAttribute(value, content.text);
686
+
687
+ row.push(this.__createTableColumn(content, null, attributesJson));
688
+ });
689
+
690
+ bNoWidths = false;
691
+ pdfTableDefinition.table.body.push(row);
692
+ });
693
+ }
694
+
695
+ __getLineFeedDefinition() {
696
+ return { "text": "\n" };
697
+ }
698
+
699
+ __getRuleDefinition(definition) {
700
+ //for thermal PL pageMargins will always be ThermalPrintLayoutPageMargins
701
+ const horizontalMarginSum = ThermalPrintLayoutPageMargins[0] + ThermalPrintLayoutPageMargins[2];
702
+ const x2 = definition.pageSize.width - horizontalMarginSum;
703
+ let result = {
704
+ canvas: [
705
+ {
706
+ type: 'line',
707
+ x1: 0, y1: 0,
708
+ x2: x2, y2: 0,
709
+ lineWidth: 1,
710
+ dash: {
711
+ length: 4,
712
+ space: 2
713
+ }
714
+ },
715
+ ]
716
+ };
717
+ return result;
718
+ }
719
+
652
720
  __addBody(definition, json) {
653
721
 
722
+ //requirement: for thermal PL the watermark should be added at the top and bottom of the preview
723
+ //add watermark at the top of the body
724
+ if(this.__isThermalPrintLayout()) {
725
+ this.__getWatermarkDefinitionForThermalPrintLayout(definition, json);
726
+ }
727
+
654
728
  _.forEach(json.elements, contractElement => {
655
729
  if(contractElement.name === 'table') {
656
730
  let tableDefintion = this.__getTableDefinition(contractElement);
@@ -667,9 +741,50 @@ class PdfConverter {
667
741
  } else if (contractElement.name === 'img' || contractElement.name === 'signature') {
668
742
  let imageDefintion = this.__getImageDefinition(contractElement, true);
669
743
  definition.content.push(imageDefintion);
744
+ } else if (contractElement.name === 'lineFeed') {
745
+ if(this.__isThermalPrintLayout()) {
746
+ let lineFeedDefintion = this.__getLineFeedDefinition();
747
+ definition.content.push(lineFeedDefintion);
748
+ } else {
749
+ //linefeed is only supported for thermal PL so log a warning and ignore
750
+ __log.warn(contractElement.name + ' is supported only with thermal print layouts.');
751
+ }
752
+ } else if (contractElement.name === 'rule') {
753
+ if(this.__isThermalPrintLayout()) {
754
+ let ruleDefintion = this.__getRuleDefinition(definition);
755
+ definition.content.push(ruleDefintion);
756
+ } else {
757
+ //rule is only supported for thermal PL so log a warning and ignore
758
+ __log.warn(contractElement.name + ' is supported only with thermal print layouts.');
759
+ }
670
760
  }
671
761
  });
672
762
 
763
+ //add watermark at the bottom of the body
764
+ if(this.__isThermalPrintLayout()) {
765
+ this.__getWatermarkDefinitionForThermalPrintLayout(definition, json);
766
+ }
767
+
768
+ }
769
+
770
+ __getWatermarkDefinitionForThermalPrintLayout(definition, reportLayout) {
771
+ if(!_.isNil(reportLayout.attributes) && !_.isNil(reportLayout.attributes.watermark)) {
772
+ let watermarkDefinition = { "text": reportLayout.attributes.watermark };
773
+
774
+ //for thermal PL the watermark font size should be same as the H2 font size
775
+ let styleJson = this.__definition.styles[STYLE_HEADING2];
776
+
777
+ if (!_.isNil(styleJson.fontSize)) {
778
+ watermarkDefinition.fontSize = styleJson.fontSize;
779
+ }
780
+
781
+ //the watermark style should bold and center aligned
782
+ watermarkDefinition.bold = true;
783
+ watermarkDefinition.alignment = "center";
784
+ watermarkDefinition.margin = [0, 5, 0, 5];
785
+
786
+ definition.content.push(watermarkDefinition);
787
+ }
673
788
  }
674
789
 
675
790
  __addHeader(definition, json) {
@@ -739,16 +854,57 @@ class PdfConverter {
739
854
 
740
855
  __addPageDimensionsOrientationMarginsWatermark(definition, reportLayout){
741
856
  if(!_.isNil(reportLayout.attributes) && !_.isNil(reportLayout.attributes.pageSize)){
742
- definition.pageSize = reportLayout.attributes.pageSize;
857
+ if (/^\s*\[\s*\d+\s*,\s*(\d+|auto)\s*\]\s*$/.test(reportLayout.attributes.pageSize)) {
858
+ // pageSize is given as [width, height]
859
+ const [width, height] = reportLayout.attributes.pageSize
860
+ .replace(/\s/g, '') // remove whitespace
861
+ .replace('[', '').replace(']', '') //remove brackets
862
+ .split(',');
863
+ definition.pageSize = {
864
+ width : Number(width),
865
+ height: height === 'auto' ? height : Number(height)
866
+ };
867
+ this.__pdfHeight = height;
868
+ } else {
869
+ // assuming no other possibility for invalid pageSize format as it will be caught by during build
870
+ definition.pageSize = reportLayout.attributes.pageSize;
871
+ }
743
872
  }
744
873
  if(!_.isNil(reportLayout.attributes) && !_.isNil(reportLayout.attributes.watermark)){
745
- definition.watermark = {text: reportLayout.attributes.watermark, opacity:0.1, fontSize: 120};
874
+ //for thermal PL the watermark shouldn't be shown in the background so added a check
875
+ if(!this.__isThermalPrintLayout()) {
876
+ definition.watermark = {text: reportLayout.attributes.watermark, opacity:0.1, fontSize: 120};
877
+ }
746
878
  }
747
- if(!_.isNil(reportLayout.attributes) && !_.isNil(reportLayout.attributes.pageMargins)){
879
+ //for bluetooth thermal PL the pageMargins is not supported from the contracts and should be provided implicitly
880
+ if(this.__isThermalPrintLayout()) {
881
+ definition.pageMargins = ThermalPrintLayoutPageMargins;
882
+ } else if(!_.isNil(reportLayout.attributes) && !_.isNil(reportLayout.attributes.pageMargins)){
748
883
  definition.pageMargins = JSON.parse(reportLayout.attributes.pageMargins);
749
884
  }
750
885
  }
751
886
 
887
+ __addStyles(definition, json) {
888
+ let stylesNode = _.find(json.elements, {name:"styles"});
889
+ if(_.isNil(stylesNode)) return;
890
+ for (const styleElement of stylesNode.elements) {
891
+ for (let [property, value] of Object.entries(styleElement.attributes)) {
892
+ // invalid formats will be caught during build
893
+ if (property === 'fontSize') {
894
+ value = Number(value);
895
+ } else if (property === 'bold' || property === 'italics') {
896
+ value = value === 'true' || value === '1';
897
+ } else if (property === 'margin') {
898
+ value = JSON.parse(value);
899
+ }
900
+
901
+ if (property !== 'name') {
902
+ definition.styles[styleElement.attributes.name][property] = value;
903
+ }
904
+ }
905
+ }
906
+ }
907
+
752
908
  __isLastMainRowOnPage(followingNodesOnPage) {
753
909
  let result = false;
754
910
 
@@ -948,6 +1104,7 @@ class PdfConverter {
948
1104
  let reportLayout = json.reportLayout;
949
1105
  this.__configureAutomaticPageBreak(reportLayout);
950
1106
  this.__addPageDimensionsOrientationMarginsWatermark(this.__definition, reportLayout);
1107
+ this.__addStyles(this.__definition, reportLayout);
951
1108
  this.__addHeader(this.__definition, reportLayout);
952
1109
  this.__addBody(this.__definition, reportLayout);
953
1110
  this.__addFooter(this.__definition,reportLayout);