pdfmake 0.2.4 → 0.3.0-beta.1

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.
Files changed (128) hide show
  1. package/CHANGELOG.md +8 -30
  2. package/README.md +8 -6
  3. package/build/pdfmake.js +28921 -26825
  4. package/build/pdfmake.js.map +1 -1
  5. package/build/pdfmake.min.js +2 -2
  6. package/build/pdfmake.min.js.map +1 -1
  7. package/build/standard-fonts/Courier.js +27 -0
  8. package/build/standard-fonts/Helvetica.js +27 -0
  9. package/build/standard-fonts/Symbol.js +21 -0
  10. package/build/standard-fonts/Times.js +27 -0
  11. package/build/standard-fonts/ZapfDingbats.js +21 -0
  12. package/build/vfs_fonts.js +2 -2
  13. package/build-vfs.js +2 -2
  14. package/fonts/Roboto/Roboto-Italic.ttf +0 -0
  15. package/fonts/Roboto/Roboto-Medium.ttf +0 -0
  16. package/fonts/Roboto/Roboto-MediumItalic.ttf +0 -0
  17. package/fonts/Roboto/Roboto-Regular.ttf +0 -0
  18. package/fonts/Roboto.js +8 -0
  19. package/js/3rd-party/svg-to-pdfkit/source.js +4301 -0
  20. package/js/3rd-party/svg-to-pdfkit.js +11 -0
  21. package/js/DocMeasure.js +750 -0
  22. package/js/DocPreprocessor.js +285 -0
  23. package/js/DocumentContext.js +306 -0
  24. package/js/ElementWriter.js +377 -0
  25. package/js/LayoutBuilder.js +833 -0
  26. package/js/Line.js +125 -0
  27. package/js/OutputDocument.js +86 -0
  28. package/js/OutputDocumentServer.js +34 -0
  29. package/js/PDFDocument.js +163 -0
  30. package/js/PageElementWriter.js +161 -0
  31. package/js/PageSize.js +88 -0
  32. package/js/Printer.js +238 -0
  33. package/js/Renderer.js +433 -0
  34. package/js/SVGMeasure.js +89 -0
  35. package/js/StyleContextStack.js +206 -0
  36. package/js/TableProcessor.js +590 -0
  37. package/js/TextBreaker.js +182 -0
  38. package/js/TextDecorator.js +181 -0
  39. package/js/TextInlines.js +248 -0
  40. package/js/URLResolver.js +79 -0
  41. package/js/base.js +69 -0
  42. package/js/browser-extensions/OutputDocumentBrowser.js +131 -0
  43. package/js/browser-extensions/URLBrowserResolver.js +89 -0
  44. package/js/browser-extensions/fonts/Roboto.js +42 -0
  45. package/js/browser-extensions/index.js +70 -0
  46. package/js/browser-extensions/pdfMake.js +17 -0
  47. package/js/browser-extensions/standard-fonts/Courier.js +42 -0
  48. package/js/browser-extensions/standard-fonts/Helvetica.js +42 -0
  49. package/js/browser-extensions/standard-fonts/Symbol.js +27 -0
  50. package/js/browser-extensions/standard-fonts/Times.js +42 -0
  51. package/js/browser-extensions/standard-fonts/ZapfDingbats.js +27 -0
  52. package/js/browser-extensions/virtual-fs-cjs.js +3 -0
  53. package/js/columnCalculator.js +142 -0
  54. package/js/helpers/node.js +122 -0
  55. package/js/helpers/tools.js +48 -0
  56. package/js/helpers/variableType.js +52 -0
  57. package/js/index.js +21 -0
  58. package/js/qrEnc.js +810 -0
  59. package/js/standardPageSizes.js +57 -0
  60. package/js/tableLayouts.js +127 -0
  61. package/js/virtual-fs.js +77 -0
  62. package/package.json +26 -22
  63. package/src/3rd-party/svg-to-pdfkit.js +2 -2
  64. package/src/DocMeasure.js +694 -0
  65. package/src/DocPreprocessor.js +258 -0
  66. package/src/DocumentContext.js +309 -0
  67. package/src/ElementWriter.js +368 -0
  68. package/src/LayoutBuilder.js +814 -0
  69. package/src/Line.js +114 -0
  70. package/src/OutputDocument.js +78 -0
  71. package/src/OutputDocumentServer.js +26 -0
  72. package/src/PDFDocument.js +148 -0
  73. package/src/PageElementWriter.js +156 -0
  74. package/src/PageSize.js +53 -0
  75. package/src/Printer.js +220 -0
  76. package/src/Renderer.js +370 -0
  77. package/src/SVGMeasure.js +79 -0
  78. package/src/StyleContextStack.js +216 -0
  79. package/src/TableProcessor.js +558 -0
  80. package/src/TextBreaker.js +149 -0
  81. package/src/TextDecorator.js +161 -0
  82. package/src/TextInlines.js +223 -0
  83. package/src/URLResolver.js +69 -0
  84. package/src/base.js +61 -0
  85. package/src/browser-extensions/OutputDocumentBrowser.js +117 -0
  86. package/src/browser-extensions/URLBrowserResolver.js +46 -53
  87. package/src/browser-extensions/fonts/Roboto.js +27 -0
  88. package/src/browser-extensions/index.js +55 -0
  89. package/src/browser-extensions/pdfMake.js +10 -282
  90. package/src/browser-extensions/standard-fonts/Courier.js +27 -0
  91. package/src/browser-extensions/standard-fonts/Helvetica.js +27 -0
  92. package/src/browser-extensions/standard-fonts/Symbol.js +21 -0
  93. package/src/browser-extensions/standard-fonts/Times.js +27 -0
  94. package/src/browser-extensions/standard-fonts/ZapfDingbats.js +21 -0
  95. package/src/browser-extensions/virtual-fs-cjs.js +1 -0
  96. package/src/columnCalculator.js +29 -32
  97. package/src/helpers/node.js +110 -0
  98. package/src/helpers/tools.js +39 -0
  99. package/src/helpers/variableType.js +39 -0
  100. package/src/index.js +16 -0
  101. package/src/qrEnc.js +15 -10
  102. package/src/standardPageSizes.js +1 -3
  103. package/src/tableLayouts.js +100 -0
  104. package/src/virtual-fs.js +66 -0
  105. package/standard-fonts/Courier.js +8 -0
  106. package/standard-fonts/Helvetica.js +9 -0
  107. package/standard-fonts/Symbol.js +5 -0
  108. package/standard-fonts/Times.js +8 -0
  109. package/standard-fonts/ZapfDingbats.js +5 -0
  110. package/src/browser-extensions/virtual-fs.js +0 -55
  111. package/src/docMeasure.js +0 -807
  112. package/src/docPreprocessor.js +0 -255
  113. package/src/documentContext.js +0 -314
  114. package/src/elementWriter.js +0 -322
  115. package/src/fontProvider.js +0 -68
  116. package/src/helpers.js +0 -126
  117. package/src/imageMeasure.js +0 -51
  118. package/src/layoutBuilder.js +0 -807
  119. package/src/line.js +0 -91
  120. package/src/pageElementWriter.js +0 -174
  121. package/src/pdfKitEngine.js +0 -21
  122. package/src/printer.js +0 -705
  123. package/src/styleContextStack.js +0 -179
  124. package/src/svgMeasure.js +0 -70
  125. package/src/tableProcessor.js +0 -561
  126. package/src/textDecorator.js +0 -157
  127. package/src/textTools.js +0 -373
  128. package/src/traversalTracker.js +0 -47
@@ -0,0 +1,558 @@
1
+ import ColumnCalculator from './columnCalculator';
2
+ import { isNumber } from './helpers/variableType';
3
+
4
+ class TableProcessor {
5
+ constructor(tableNode) {
6
+ this.tableNode = tableNode;
7
+ }
8
+
9
+ beginTable(writer) {
10
+ const getTableInnerContentWidth = () => {
11
+ let width = 0;
12
+
13
+ tableNode.table.widths.forEach(w => {
14
+ width += w._calcWidth;
15
+ });
16
+
17
+ return width;
18
+ };
19
+
20
+ const prepareRowSpanData = () => {
21
+ let rsd = [];
22
+ let x = 0;
23
+ let lastWidth = 0;
24
+
25
+ rsd.push({ left: 0, rowSpan: 0 });
26
+
27
+ for (let i = 0, l = this.tableNode.table.body[0].length; i < l; i++) {
28
+ let paddings = this.layout.paddingLeft(i, this.tableNode) + this.layout.paddingRight(i, this.tableNode);
29
+ let lBorder = this.layout.vLineWidth(i, this.tableNode);
30
+ lastWidth = paddings + lBorder + this.tableNode.table.widths[i]._calcWidth;
31
+ rsd[rsd.length - 1].width = lastWidth;
32
+ x += lastWidth;
33
+ rsd.push({ left: x, rowSpan: 0, width: 0 });
34
+ }
35
+
36
+ return rsd;
37
+ };
38
+
39
+ // Iterate through all cells. If the current cell is the start of a
40
+ // rowSpan/colSpan, update the border property of the cells on its
41
+ // bottom/right accordingly. This is needed since each iteration of the
42
+ // line-drawing loops draws lines for a single cell, not for an entire
43
+ // rowSpan/colSpan.
44
+ const prepareCellBorders = body => {
45
+ for (let rowIndex = 0; rowIndex < body.length; rowIndex++) {
46
+ let row = body[rowIndex];
47
+
48
+ for (let colIndex = 0; colIndex < row.length; colIndex++) {
49
+ let cell = row[colIndex];
50
+
51
+ if (cell.border) {
52
+ let rowSpan = cell.rowSpan || 1;
53
+ let colSpan = cell.colSpan || 1;
54
+
55
+ for (let rowOffset = 0; rowOffset < rowSpan; rowOffset++) {
56
+ // set left border
57
+ if (cell.border[0] !== undefined && rowOffset > 0) {
58
+ setBorder(rowIndex + rowOffset, colIndex, 0, cell.border[0]);
59
+ }
60
+
61
+ // set right border
62
+ if (cell.border[2] !== undefined) {
63
+ setBorder(rowIndex + rowOffset, colIndex + colSpan - 1, 2, cell.border[2]);
64
+ }
65
+ }
66
+
67
+ for (let colOffset = 0; colOffset < colSpan; colOffset++) {
68
+ // set top border
69
+ if (cell.border[1] !== undefined && colOffset > 0) {
70
+ setBorder(rowIndex, colIndex + colOffset, 1, cell.border[1]);
71
+ }
72
+
73
+ // set bottom border
74
+ if (cell.border[3] !== undefined) {
75
+ setBorder(rowIndex + rowSpan - 1, colIndex + colOffset, 3, cell.border[3]);
76
+ }
77
+ }
78
+ }
79
+ }
80
+ }
81
+
82
+ // helper function to set the border for a given cell
83
+ function setBorder(rowIndex, colIndex, borderIndex, borderValue) {
84
+ let cell = body[rowIndex][colIndex];
85
+ cell.border = cell.border || {};
86
+ cell.border[borderIndex] = borderValue;
87
+ }
88
+ };
89
+
90
+ let tableNode;
91
+ let availableWidth;
92
+
93
+ tableNode = this.tableNode;
94
+ this.offsets = tableNode._offsets;
95
+ this.layout = tableNode._layout;
96
+
97
+ availableWidth = writer.context().availableWidth - this.offsets.total;
98
+ ColumnCalculator.buildColumnWidths(tableNode.table.widths, availableWidth);
99
+
100
+ this.tableWidth = tableNode._offsets.total + getTableInnerContentWidth();
101
+ this.rowSpanData = prepareRowSpanData();
102
+ this.cleanUpRepeatables = false;
103
+
104
+ this.headerRows = tableNode.table.headerRows || 0;
105
+ this.rowsWithoutPageBreak = this.headerRows + (tableNode.table.keepWithHeaderRows || 0);
106
+ this.dontBreakRows = tableNode.table.dontBreakRows || false;
107
+
108
+ if (this.rowsWithoutPageBreak) {
109
+ writer.beginUnbreakableBlock();
110
+ }
111
+
112
+ // update the border properties of all cells before drawing any lines
113
+ prepareCellBorders(this.tableNode.table.body);
114
+
115
+ this.drawHorizontalLine(0, writer);
116
+ }
117
+
118
+ onRowBreak(rowIndex, writer) {
119
+ return () => {
120
+ let offset = this.rowPaddingTop + (!this.headerRows ? this.topLineWidth : 0);
121
+ writer.context().availableHeight -= this.reservedAtBottom;
122
+ writer.context().moveDown(offset);
123
+ };
124
+ }
125
+
126
+ beginRow(rowIndex, writer) {
127
+ this.topLineWidth = this.layout.hLineWidth(rowIndex, this.tableNode);
128
+ this.rowPaddingTop = this.layout.paddingTop(rowIndex, this.tableNode);
129
+ this.bottomLineWidth = this.layout.hLineWidth(rowIndex + 1, this.tableNode);
130
+ this.rowPaddingBottom = this.layout.paddingBottom(rowIndex, this.tableNode);
131
+
132
+ this.rowCallback = this.onRowBreak(rowIndex, writer);
133
+ writer.addListener('pageChanged', this.rowCallback);
134
+ if (this.dontBreakRows) {
135
+ writer.beginUnbreakableBlock();
136
+ }
137
+ this.rowTopY = writer.context().y;
138
+ this.reservedAtBottom = this.bottomLineWidth + this.rowPaddingBottom;
139
+
140
+ writer.context().availableHeight -= this.reservedAtBottom;
141
+
142
+ writer.context().moveDown(this.rowPaddingTop);
143
+ }
144
+
145
+ drawHorizontalLine(lineIndex, writer, overrideY) {
146
+ let lineWidth = this.layout.hLineWidth(lineIndex, this.tableNode);
147
+ if (lineWidth) {
148
+ let style = this.layout.hLineStyle(lineIndex, this.tableNode);
149
+ let dash;
150
+ if (style && style.dash) {
151
+ dash = style.dash;
152
+ }
153
+
154
+ let offset = lineWidth / 2;
155
+ let currentLine = null;
156
+ let body = this.tableNode.table.body;
157
+ let cellAbove;
158
+ let currentCell;
159
+ let rowCellAbove;
160
+
161
+ for (let i = 0, l = this.rowSpanData.length; i < l; i++) {
162
+ let data = this.rowSpanData[i];
163
+ let shouldDrawLine = !data.rowSpan;
164
+ let borderColor = null;
165
+
166
+ // draw only if the current cell requires a top border or the cell in the
167
+ // row above requires a bottom border
168
+ if (shouldDrawLine && i < l - 1) {
169
+ var topBorder = false, bottomBorder = false, rowBottomBorder = false;
170
+
171
+ // the cell in the row above
172
+ if (lineIndex > 0) {
173
+ cellAbove = body[lineIndex - 1][i];
174
+ bottomBorder = cellAbove.border ? cellAbove.border[3] : this.layout.defaultBorder;
175
+ if (bottomBorder && cellAbove.borderColor) {
176
+ borderColor = cellAbove.borderColor[3];
177
+ }
178
+ }
179
+
180
+ // the current cell
181
+ if (lineIndex < body.length) {
182
+ currentCell = body[lineIndex][i];
183
+ topBorder = currentCell.border ? currentCell.border[1] : this.layout.defaultBorder;
184
+ if (topBorder && borderColor == null && currentCell.borderColor) {
185
+ borderColor = currentCell.borderColor[1];
186
+ }
187
+ }
188
+
189
+ shouldDrawLine = topBorder || bottomBorder;
190
+ }
191
+
192
+ if (cellAbove && cellAbove._rowSpanCurrentOffset) {
193
+ rowCellAbove = body[lineIndex - 1 - cellAbove._rowSpanCurrentOffset][i];
194
+ rowBottomBorder = rowCellAbove && rowCellAbove.border ? rowCellAbove.border[3] : this.layout.defaultBorder;
195
+ if (rowBottomBorder && rowCellAbove && rowCellAbove.borderColor) {
196
+ borderColor = rowCellAbove.borderColor[3];
197
+ }
198
+ }
199
+
200
+ if (borderColor == null) {
201
+ borderColor = typeof this.layout.hLineColor === 'function' ? this.layout.hLineColor(lineIndex, this.tableNode, i) : this.layout.hLineColor;
202
+ }
203
+
204
+ if (!currentLine && shouldDrawLine) {
205
+ currentLine = { left: data.left, width: 0 };
206
+ }
207
+
208
+ if (shouldDrawLine) {
209
+ let colSpanIndex = 0;
210
+ if (rowCellAbove && rowCellAbove.colSpan && rowBottomBorder) {
211
+ while (rowCellAbove.colSpan > colSpanIndex) {
212
+ currentLine.width += (this.rowSpanData[i + colSpanIndex++].width || 0);
213
+ }
214
+ i += colSpanIndex - 1;
215
+ } else if (cellAbove && cellAbove.colSpan && bottomBorder) {
216
+ while (cellAbove.colSpan > colSpanIndex) {
217
+ currentLine.width += (this.rowSpanData[i + colSpanIndex++].width || 0);
218
+ }
219
+ i += colSpanIndex - 1;
220
+ } else if (currentCell && currentCell.colSpan && topBorder) {
221
+ while (currentCell.colSpan > colSpanIndex) {
222
+ currentLine.width += (this.rowSpanData[i + colSpanIndex++].width || 0);
223
+ }
224
+ i += colSpanIndex - 1;
225
+ } else {
226
+ currentLine.width += (this.rowSpanData[i].width || 0);
227
+ }
228
+ }
229
+
230
+ let y = (overrideY || 0) + offset;
231
+
232
+ if (shouldDrawLine) {
233
+ if (currentLine && currentLine.width) {
234
+ writer.addVector({
235
+ type: 'line',
236
+ x1: currentLine.left,
237
+ x2: currentLine.left + currentLine.width,
238
+ y1: y,
239
+ y2: y,
240
+ lineWidth: lineWidth,
241
+ dash: dash,
242
+ lineColor: borderColor
243
+ }, false, overrideY);
244
+ currentLine = null;
245
+ borderColor = null;
246
+ cellAbove = null;
247
+ currentCell = null;
248
+ rowCellAbove = null;
249
+ }
250
+ }
251
+ }
252
+
253
+ writer.context().moveDown(lineWidth);
254
+ }
255
+ }
256
+
257
+ drawVerticalLine(x, y0, y1, vLineColIndex, writer, vLineRowIndex, beforeVLineColIndex) {
258
+ let width = this.layout.vLineWidth(vLineColIndex, this.tableNode);
259
+ if (width === 0) {
260
+ return;
261
+ }
262
+ let style = this.layout.vLineStyle(vLineColIndex, this.tableNode);
263
+ let dash;
264
+ if (style && style.dash) {
265
+ dash = style.dash;
266
+ }
267
+
268
+ let body = this.tableNode.table.body;
269
+ let cellBefore;
270
+ let currentCell;
271
+ let borderColor;
272
+
273
+ // the cell in the col before
274
+ if (vLineColIndex > 0) {
275
+ cellBefore = body[vLineRowIndex][beforeVLineColIndex];
276
+ if (cellBefore && cellBefore.borderColor) {
277
+ if (cellBefore.border ? cellBefore.border[2] : this.layout.defaultBorder) {
278
+ borderColor = cellBefore.borderColor[2];
279
+ }
280
+ }
281
+ }
282
+
283
+ // the current cell
284
+ if (borderColor == null && vLineColIndex < body.length) {
285
+ currentCell = body[vLineRowIndex][vLineColIndex];
286
+ if (currentCell && currentCell.borderColor) {
287
+ if (currentCell.border ? currentCell.border[0] : this.layout.defaultBorder) {
288
+ borderColor = currentCell.borderColor[0];
289
+ }
290
+ }
291
+ }
292
+
293
+ if (borderColor == null && cellBefore && cellBefore._rowSpanCurrentOffset) {
294
+ let rowCellBeforeAbove = body[vLineRowIndex - cellBefore._rowSpanCurrentOffset][beforeVLineColIndex];
295
+ if (rowCellBeforeAbove.borderColor) {
296
+ if (rowCellBeforeAbove.border ? rowCellBeforeAbove.border[2] : this.layout.defaultBorder) {
297
+ borderColor = rowCellBeforeAbove.borderColor[2];
298
+ }
299
+ }
300
+ }
301
+
302
+ if (borderColor == null && currentCell && currentCell._rowSpanCurrentOffset) {
303
+ let rowCurrentCellAbove = body[vLineRowIndex - currentCell._rowSpanCurrentOffset][vLineColIndex];
304
+ if (rowCurrentCellAbove.borderColor) {
305
+ if (rowCurrentCellAbove.border ? rowCurrentCellAbove.border[2] : this.layout.defaultBorder) {
306
+ borderColor = rowCurrentCellAbove.borderColor[2];
307
+ }
308
+ }
309
+ }
310
+
311
+ if (borderColor == null) {
312
+ borderColor = typeof this.layout.vLineColor === 'function' ? this.layout.vLineColor(vLineColIndex, this.tableNode, vLineRowIndex) : this.layout.vLineColor;
313
+ }
314
+
315
+ writer.addVector({
316
+ type: 'line',
317
+ x1: x + width / 2,
318
+ x2: x + width / 2,
319
+ y1: y0,
320
+ y2: y1,
321
+ lineWidth: width,
322
+ dash: dash,
323
+ lineColor: borderColor
324
+ }, false, true);
325
+ cellBefore = null;
326
+ currentCell = null;
327
+ borderColor = null;
328
+ }
329
+
330
+ endTable(writer) {
331
+ if (this.cleanUpRepeatables) {
332
+ writer.popFromRepeatables();
333
+ }
334
+ }
335
+
336
+ endRow(rowIndex, writer, pageBreaks) {
337
+ const getLineXs = () => {
338
+ let result = [];
339
+ let cols = 0;
340
+
341
+ for (let i = 0, l = this.tableNode.table.body[rowIndex].length; i < l; i++) {
342
+ if (!cols) {
343
+ result.push({ x: this.rowSpanData[i].left, index: i });
344
+
345
+ let item = this.tableNode.table.body[rowIndex][i];
346
+ cols = (item._colSpan || item.colSpan || 0);
347
+ }
348
+ if (cols > 0) {
349
+ cols--;
350
+ }
351
+ }
352
+
353
+ result.push({ x: this.rowSpanData[this.rowSpanData.length - 1].left, index: this.rowSpanData.length - 1 });
354
+
355
+ return result;
356
+ };
357
+
358
+ writer.removeListener('pageChanged', this.rowCallback);
359
+ writer.context().moveDown(this.layout.paddingBottom(rowIndex, this.tableNode));
360
+ writer.context().availableHeight += this.reservedAtBottom;
361
+
362
+ let endingPage = writer.context().page;
363
+ let endingY = writer.context().y;
364
+
365
+ let xs = getLineXs();
366
+
367
+ let ys = [];
368
+
369
+ let hasBreaks = pageBreaks && pageBreaks.length > 0;
370
+ let body = this.tableNode.table.body;
371
+
372
+ ys.push({
373
+ y0: this.rowTopY,
374
+ page: hasBreaks ? pageBreaks[0].prevPage : endingPage
375
+ });
376
+
377
+ if (hasBreaks) {
378
+ for (let i = 0, l = pageBreaks.length; i < l; i++) {
379
+ let pageBreak = pageBreaks[i];
380
+ ys[ys.length - 1].y1 = pageBreak.prevY;
381
+
382
+ ys.push({ y0: pageBreak.y, page: pageBreak.prevPage + 1 });
383
+ }
384
+ }
385
+
386
+ ys[ys.length - 1].y1 = endingY;
387
+
388
+ let skipOrphanePadding = (ys[0].y1 - ys[0].y0 === this.rowPaddingTop);
389
+ for (let yi = (skipOrphanePadding ? 1 : 0), yl = ys.length; yi < yl; yi++) {
390
+ let willBreak = yi < ys.length - 1;
391
+ let rowBreakWithoutHeader = (yi > 0 && !this.headerRows);
392
+ let hzLineOffset = rowBreakWithoutHeader ? 0 : this.topLineWidth;
393
+ let y1 = ys[yi].y0;
394
+ let y2 = ys[yi].y1;
395
+
396
+ if (willBreak) {
397
+ y2 = y2 + this.rowPaddingBottom;
398
+ }
399
+
400
+ if (writer.context().page != ys[yi].page) {
401
+ writer.context().page = ys[yi].page;
402
+
403
+ //TODO: buggy, availableHeight should be updated on every pageChanged event
404
+ // TableProcessor should be pageChanged listener, instead of processRow
405
+ this.reservedAtBottom = 0;
406
+ }
407
+
408
+ for (let i = 0, l = xs.length; i < l; i++) {
409
+ let leftCellBorder = false;
410
+ let rightCellBorder = false;
411
+ let colIndex = xs[i].index;
412
+
413
+ // current cell
414
+ if (colIndex < body[rowIndex].length) {
415
+ let cell = body[rowIndex][colIndex];
416
+ leftCellBorder = cell.border ? cell.border[0] : this.layout.defaultBorder;
417
+ rightCellBorder = cell.border ? cell.border[2] : this.layout.defaultBorder;
418
+ }
419
+
420
+ // before cell
421
+ if (colIndex > 0 && !leftCellBorder) {
422
+ let cell = body[rowIndex][colIndex - 1];
423
+ leftCellBorder = cell.border ? cell.border[2] : this.layout.defaultBorder;
424
+ }
425
+
426
+ // after cell
427
+ if (colIndex + 1 < body[rowIndex].length && !rightCellBorder) {
428
+ let cell = body[rowIndex][colIndex + 1];
429
+ rightCellBorder = cell.border ? cell.border[0] : this.layout.defaultBorder;
430
+ }
431
+
432
+ if (leftCellBorder) {
433
+ this.drawVerticalLine(xs[i].x, y1 - hzLineOffset, y2 + this.bottomLineWidth, xs[i].index, writer, rowIndex, xs[i - 1] ? xs[i - 1].index : null);
434
+ }
435
+
436
+ if (i < l - 1) {
437
+ let fillColor = body[rowIndex][colIndex].fillColor;
438
+ let fillOpacity = body[rowIndex][colIndex].fillOpacity;
439
+ if (!fillColor) {
440
+ fillColor = typeof this.layout.fillColor === 'function' ? this.layout.fillColor(rowIndex, this.tableNode, colIndex) : this.layout.fillColor;
441
+ }
442
+ if (!isNumber(fillOpacity)) {
443
+ fillOpacity = typeof this.layout.fillOpacity === 'function' ? this.layout.fillOpacity(rowIndex, this.tableNode, colIndex) : this.layout.fillOpacity;
444
+ }
445
+ var overlayPattern = body[rowIndex][colIndex].overlayPattern;
446
+ var overlayOpacity = body[rowIndex][colIndex].overlayOpacity;
447
+ if (fillColor || overlayPattern) {
448
+ let widthLeftBorder = leftCellBorder ? this.layout.vLineWidth(colIndex, this.tableNode) : 0;
449
+ let widthRightBorder;
450
+ if ((colIndex === 0 || colIndex + 1 == body[rowIndex].length) && !rightCellBorder) {
451
+ widthRightBorder = this.layout.vLineWidth(colIndex + 1, this.tableNode);
452
+ } else if (rightCellBorder) {
453
+ widthRightBorder = this.layout.vLineWidth(colIndex + 1, this.tableNode) / 2;
454
+ } else {
455
+ widthRightBorder = 0;
456
+ }
457
+
458
+ let x1f = this.dontBreakRows ? xs[i].x + widthLeftBorder : xs[i].x + (widthLeftBorder / 2);
459
+ let y1f = this.dontBreakRows ? y1 : y1 - (hzLineOffset / 2);
460
+ let x2f = xs[i + 1].x + widthRightBorder;
461
+ let y2f = this.dontBreakRows ? y2 + this.bottomLineWidth : y2 + (this.bottomLineWidth / 2);
462
+ var bgWidth = x2f - x1f;
463
+ var bgHeight = y2f - y1f;
464
+ if (fillColor) {
465
+ writer.addVector({
466
+ type: 'rect',
467
+ x: x1f,
468
+ y: y1f,
469
+ w: bgWidth,
470
+ h: bgHeight,
471
+ lineWidth: 0,
472
+ color: fillColor,
473
+ fillOpacity: fillOpacity
474
+ }, false, true, writer.context().backgroundLength[writer.context().page]);
475
+ }
476
+
477
+ if (overlayPattern) {
478
+ writer.addVector({
479
+ type: 'rect',
480
+ x: x1f,
481
+ y: y1f,
482
+ w: bgWidth,
483
+ h: bgHeight,
484
+ lineWidth: 0,
485
+ color: overlayPattern,
486
+ fillOpacity: overlayOpacity
487
+ }, false, true);
488
+ }
489
+ }
490
+ }
491
+ }
492
+
493
+ if (willBreak && this.layout.hLineWhenBroken !== false) {
494
+ this.drawHorizontalLine(rowIndex + 1, writer, y2);
495
+ }
496
+ if (rowBreakWithoutHeader && this.layout.hLineWhenBroken !== false) {
497
+ this.drawHorizontalLine(rowIndex, writer, y1);
498
+ }
499
+ }
500
+
501
+ writer.context().page = endingPage;
502
+ writer.context().y = endingY;
503
+
504
+ let row = this.tableNode.table.body[rowIndex];
505
+ for (let i = 0, l = row.length; i < l; i++) {
506
+ if (row[i].rowSpan) {
507
+ this.rowSpanData[i].rowSpan = row[i].rowSpan;
508
+
509
+ // fix colSpans
510
+ if (row[i].colSpan && row[i].colSpan > 1) {
511
+ for (let j = 1; j < row[i].rowSpan; j++) {
512
+ this.tableNode.table.body[rowIndex + j][i]._colSpan = row[i].colSpan;
513
+ }
514
+ }
515
+
516
+ // fix rowSpans
517
+ if (row[i].rowSpan && row[i].rowSpan > 1) {
518
+ for (let j = 1; j < row[i].rowSpan; j++) {
519
+ this.tableNode.table.body[rowIndex + j][i]._rowSpanCurrentOffset = j;
520
+ }
521
+ }
522
+ }
523
+
524
+ if (this.rowSpanData[i].rowSpan > 0) {
525
+ this.rowSpanData[i].rowSpan--;
526
+ }
527
+ }
528
+
529
+ this.drawHorizontalLine(rowIndex + 1, writer);
530
+
531
+ if (this.headerRows && rowIndex === this.headerRows - 1) {
532
+ this.headerRepeatable = writer.currentBlockToRepeatable();
533
+ }
534
+
535
+ if (this.dontBreakRows) {
536
+ const pageChangedCallback = () => {
537
+ if (!this.headerRows && this.layout.hLineWhenBroken !== false) {
538
+ this.drawHorizontalLine(rowIndex, writer);
539
+ }
540
+ };
541
+
542
+ writer.addListener('pageChanged', pageChangedCallback);
543
+
544
+ writer.commitUnbreakableBlock();
545
+
546
+ writer.removeListener('pageChanged', pageChangedCallback);
547
+ }
548
+
549
+ if (this.headerRepeatable && (rowIndex === (this.rowsWithoutPageBreak - 1) || rowIndex === this.tableNode.table.body.length - 1)) {
550
+ writer.commitUnbreakableBlock();
551
+ writer.pushToRepeatables(this.headerRepeatable);
552
+ this.cleanUpRepeatables = true;
553
+ this.headerRepeatable = null;
554
+ }
555
+ }
556
+ }
557
+
558
+ export default TableProcessor;
@@ -0,0 +1,149 @@
1
+ import LineBreaker from '@foliojs-fork/linebreak';
2
+ import { isObject } from './helpers/variableType';
3
+ import StyleContextStack from './StyleContextStack';
4
+
5
+ /**
6
+ * @param {string} text
7
+ * @param {boolean} noWrap
8
+ * @returns {Array}
9
+ */
10
+ const splitWords = (text, noWrap) => {
11
+ let words = [];
12
+
13
+ if (noWrap) {
14
+ words.push({ text: text });
15
+ return words;
16
+ }
17
+
18
+ let breaker = new LineBreaker(text);
19
+ let last = 0;
20
+ let bk;
21
+
22
+ while ((bk = breaker.nextBreak())) {
23
+ let word = text.slice(last, bk.position);
24
+
25
+ if (bk.required || word.match(/\r?\n$|\r$/)) { // new line
26
+ word = word.replace(/\r?\n$|\r$/, '');
27
+ words.push({ text: word, lineEnd: true });
28
+ } else {
29
+ words.push({ text: word });
30
+ }
31
+
32
+ last = bk.position;
33
+ }
34
+
35
+ return words;
36
+ };
37
+
38
+ /**
39
+ * @param {Array} words
40
+ * @param {boolean} noWrap
41
+ * @returns {?string}
42
+ */
43
+ const getFirstWord = (words, noWrap) => {
44
+ let word = words[0];
45
+ if (word === undefined) {
46
+ return null;
47
+ }
48
+
49
+ if (noWrap) { // text was not wrapped, we need only first word
50
+ let tmpWords = splitWords(word.text, false);
51
+ if (tmpWords[0] === undefined) {
52
+ return null;
53
+ }
54
+ word = tmpWords[0];
55
+ }
56
+
57
+ return word.text;
58
+ };
59
+
60
+ /**
61
+ * @param {Array} words
62
+ * @param {boolean} noWrap
63
+ * @returns {?string}
64
+ */
65
+ const getLastWord = (words, noWrap) => {
66
+ let word = words[words.length - 1];
67
+ if (word === undefined) {
68
+ return null;
69
+ }
70
+
71
+ if (word.lineEnd) {
72
+ return null;
73
+ }
74
+
75
+ if (noWrap) { // text was not wrapped, we need only last word
76
+ let tmpWords = splitWords(word.text, false);
77
+ if (tmpWords[tmpWords.length - 1] === undefined) {
78
+ return null;
79
+ }
80
+ word = tmpWords[tmpWords.length - 1];
81
+ }
82
+
83
+ return word.text;
84
+ };
85
+
86
+ class TextBreaker {
87
+ /**
88
+ * @param {string|Array} texts
89
+ * @param {StyleContextStack} styleContextStack
90
+ * @returns {Array}
91
+ */
92
+ getBreaks(texts, styleContextStack) {
93
+ let results = [];
94
+
95
+ if (!Array.isArray(texts)) {
96
+ texts = [texts];
97
+ }
98
+
99
+ let lastWord = null;
100
+ for (let i = 0, l = texts.length; i < l; i++) {
101
+ let item = texts[i];
102
+ let style = null;
103
+ let words;
104
+
105
+ let noWrap = StyleContextStack.getStyleProperty(item || {}, styleContextStack, 'noWrap', false);
106
+ if (isObject(item)) {
107
+ if (item._textRef && item._textRef._textNodeRef.text) {
108
+ item.text = item._textRef._textNodeRef.text;
109
+ }
110
+ words = splitWords(item.text, noWrap);
111
+ style = StyleContextStack.copyStyle(item);
112
+ } else {
113
+ words = splitWords(item, noWrap);
114
+ }
115
+
116
+ if (lastWord && words.length) {
117
+ let firstWord = getFirstWord(words, noWrap);
118
+
119
+ let wrapWords = splitWords(lastWord + firstWord, false);
120
+ if (wrapWords.length === 1) {
121
+ results[results.length - 1].noNewLine = true;
122
+ }
123
+ }
124
+
125
+ for (let i2 = 0, l2 = words.length; i2 < l2; i2++) {
126
+ let result = {
127
+ text: words[i2].text
128
+ };
129
+
130
+ if (words[i2].lineEnd) {
131
+ result.lineEnd = true;
132
+ }
133
+
134
+ StyleContextStack.copyStyle(style, result);
135
+
136
+ results.push(result);
137
+ }
138
+
139
+ lastWord = null;
140
+ if (i + 1 < l) {
141
+ lastWord = getLastWord(words, noWrap);
142
+ }
143
+ }
144
+
145
+ return results;
146
+ }
147
+ }
148
+
149
+ export default TextBreaker;