pdfmake 0.2.1 → 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 (130) hide show
  1. package/CHANGELOG.md +8 -14
  2. package/README.md +8 -6
  3. package/build/pdfmake.js +31416 -28217
  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 +3 -3
  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 +31 -25
  63. package/src/3rd-party/svg-to-pdfkit/LICENSE +9 -0
  64. package/src/3rd-party/svg-to-pdfkit/source.js +2552 -0
  65. package/src/3rd-party/svg-to-pdfkit.js +3 -0
  66. package/src/DocMeasure.js +694 -0
  67. package/src/DocPreprocessor.js +258 -0
  68. package/src/DocumentContext.js +309 -0
  69. package/src/ElementWriter.js +368 -0
  70. package/src/LayoutBuilder.js +814 -0
  71. package/src/Line.js +114 -0
  72. package/src/OutputDocument.js +78 -0
  73. package/src/OutputDocumentServer.js +26 -0
  74. package/src/PDFDocument.js +148 -0
  75. package/src/PageElementWriter.js +156 -0
  76. package/src/PageSize.js +53 -0
  77. package/src/Printer.js +220 -0
  78. package/src/Renderer.js +370 -0
  79. package/src/SVGMeasure.js +79 -0
  80. package/src/StyleContextStack.js +216 -0
  81. package/src/TableProcessor.js +558 -0
  82. package/src/TextBreaker.js +149 -0
  83. package/src/TextDecorator.js +161 -0
  84. package/src/TextInlines.js +223 -0
  85. package/src/URLResolver.js +69 -0
  86. package/src/base.js +61 -0
  87. package/src/browser-extensions/OutputDocumentBrowser.js +117 -0
  88. package/src/browser-extensions/URLBrowserResolver.js +46 -53
  89. package/src/browser-extensions/fonts/Roboto.js +27 -0
  90. package/src/browser-extensions/index.js +55 -0
  91. package/src/browser-extensions/pdfMake.js +10 -287
  92. package/src/browser-extensions/standard-fonts/Courier.js +27 -0
  93. package/src/browser-extensions/standard-fonts/Helvetica.js +27 -0
  94. package/src/browser-extensions/standard-fonts/Symbol.js +21 -0
  95. package/src/browser-extensions/standard-fonts/Times.js +27 -0
  96. package/src/browser-extensions/standard-fonts/ZapfDingbats.js +21 -0
  97. package/src/browser-extensions/virtual-fs-cjs.js +1 -0
  98. package/src/columnCalculator.js +29 -32
  99. package/src/helpers/node.js +110 -0
  100. package/src/helpers/tools.js +39 -0
  101. package/src/helpers/variableType.js +39 -0
  102. package/src/index.js +16 -0
  103. package/src/qrEnc.js +15 -10
  104. package/src/standardPageSizes.js +1 -3
  105. package/src/tableLayouts.js +100 -0
  106. package/src/virtual-fs.js +66 -0
  107. package/standard-fonts/Courier.js +8 -0
  108. package/standard-fonts/Helvetica.js +9 -0
  109. package/standard-fonts/Symbol.js +5 -0
  110. package/standard-fonts/Times.js +8 -0
  111. package/standard-fonts/ZapfDingbats.js +5 -0
  112. package/src/browser-extensions/virtual-fs.js +0 -55
  113. package/src/docMeasure.js +0 -807
  114. package/src/docPreprocessor.js +0 -255
  115. package/src/documentContext.js +0 -314
  116. package/src/elementWriter.js +0 -322
  117. package/src/fontProvider.js +0 -68
  118. package/src/helpers.js +0 -113
  119. package/src/imageMeasure.js +0 -51
  120. package/src/layoutBuilder.js +0 -807
  121. package/src/line.js +0 -91
  122. package/src/pageElementWriter.js +0 -174
  123. package/src/pdfKitEngine.js +0 -21
  124. package/src/printer.js +0 -685
  125. package/src/styleContextStack.js +0 -179
  126. package/src/svgMeasure.js +0 -70
  127. package/src/tableProcessor.js +0 -542
  128. package/src/textDecorator.js +0 -151
  129. package/src/textTools.js +0 -373
  130. 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;