@flowaccount/pdfmake 0.2.20-staging.2

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,277 @@
1
+ 'use strict';
2
+
3
+ var isString = require('./helpers').isString;
4
+ var isNumber = require('./helpers').isNumber;
5
+ var isBoolean = require('./helpers').isBoolean;
6
+ var isArray = require('./helpers').isArray;
7
+ var isUndefined = require('./helpers').isUndefined;
8
+ var fontStringify = require('./helpers').fontStringify;
9
+
10
+ function DocPreprocessor() {
11
+
12
+ }
13
+
14
+ DocPreprocessor.prototype.preprocessDocument = function (docStructure) {
15
+ this.parentNode = null;
16
+ this.tocs = {};
17
+ this.nodeReferences = {};
18
+ return this.preprocessNode(docStructure);
19
+ };
20
+
21
+ DocPreprocessor.prototype.preprocessNode = function (node) {
22
+ // expand shortcuts and casting values
23
+ if (isArray(node)) {
24
+ node = { stack: node };
25
+ } else if (isString(node)) {
26
+ node = { text: node };
27
+ } else if (isNumber(node) || isBoolean(node)) {
28
+ node = { text: node.toString() };
29
+ } else if (node === undefined || node === null) {
30
+ node = { text: '' };
31
+ } else if (Object.keys(node).length === 0) { // empty object
32
+ node = { text: '' };
33
+ } else if ('text' in node && (node.text === undefined || node.text === null)) {
34
+ node.text = '';
35
+ }
36
+
37
+ if (node.columns) {
38
+ return this.preprocessColumns(node);
39
+ } else if (node.stack) {
40
+ return this.preprocessVerticalContainer(node);
41
+ } else if (node.layers) {
42
+ return this.preprocessLayers(node);
43
+ } else if (node.ul) {
44
+ return this.preprocessList(node);
45
+ } else if (node.ol) {
46
+ return this.preprocessList(node);
47
+ } else if (node.table) {
48
+ return this.preprocessTable(node);
49
+ } else if (node.text !== undefined) {
50
+ return this.preprocessText(node);
51
+ } else if (node.toc) {
52
+ return this.preprocessToc(node);
53
+ } else if (node.image) {
54
+ return this.preprocessImage(node);
55
+ } else if (node.svg) {
56
+ return this.preprocessSVG(node);
57
+ } else if (node.canvas) {
58
+ return this.preprocessCanvas(node);
59
+ } else if (node.qr) {
60
+ return this.preprocessQr(node);
61
+ } else if (node.pageReference || node.textReference) {
62
+ return this.preprocessText(node);
63
+ } else {
64
+ throw 'Unrecognized document structure: ' + JSON.stringify(node, fontStringify);
65
+ }
66
+ };
67
+
68
+ DocPreprocessor.prototype.preprocessColumns = function (node) {
69
+ var columns = node.columns;
70
+
71
+ for (var i = 0, l = columns.length; i < l; i++) {
72
+ columns[i] = this.preprocessNode(columns[i]);
73
+ }
74
+
75
+ return node;
76
+ };
77
+
78
+ DocPreprocessor.prototype.preprocessVerticalContainer = function (node) {
79
+ var items = node.stack;
80
+
81
+ for (var i = 0, l = items.length; i < l; i++) {
82
+ items[i] = this.preprocessNode(items[i]);
83
+ }
84
+
85
+ return node;
86
+ };
87
+
88
+ DocPreprocessor.prototype.preprocessLayers = function (node) {
89
+ var items = node.layers;
90
+
91
+ for (var i = 0, l = items.length; i < l; i++) {
92
+ items[i] = this.preprocessNode(items[i]);
93
+ }
94
+
95
+ return node;
96
+ };
97
+
98
+ DocPreprocessor.prototype.preprocessList = function (node) {
99
+ var items = node.ul || node.ol;
100
+
101
+ for (var i = 0, l = items.length; i < l; i++) {
102
+ items[i] = this.preprocessNode(items[i]);
103
+ }
104
+
105
+ return node;
106
+ };
107
+
108
+ DocPreprocessor.prototype.preprocessTable = function (node) {
109
+ var col, row, cols, rows;
110
+
111
+ if (!node.table.body || !node.table.body[0]) {
112
+ return node;
113
+ }
114
+
115
+ for (col = 0, cols = node.table.body[0].length; col < cols; col++) {
116
+ for (row = 0, rows = node.table.body.length; row < rows; row++) {
117
+ var rowData = node.table.body[row];
118
+ var data = rowData[col];
119
+ if (data !== undefined) {
120
+ if (data === null) { // transform to object
121
+ data = '';
122
+ }
123
+ if (!data._span) {
124
+ rowData[col] = this.preprocessNode(data);
125
+ }
126
+ }
127
+ }
128
+ }
129
+
130
+ return node;
131
+ };
132
+
133
+ DocPreprocessor.prototype.preprocessText = function (node) {
134
+ var i;
135
+ var l;
136
+
137
+ if (node.tocItem) {
138
+ if (!isArray(node.tocItem)) {
139
+ node.tocItem = [node.tocItem];
140
+ }
141
+
142
+ for (i = 0, l = node.tocItem.length; i < l; i++) {
143
+ if (!isString(node.tocItem[i])) {
144
+ node.tocItem[i] = '_default_';
145
+ }
146
+
147
+ var tocItemId = node.tocItem[i];
148
+
149
+ if (!this.tocs[tocItemId]) {
150
+ this.tocs[tocItemId] = { toc: { _items: [], _pseudo: true } };
151
+ }
152
+
153
+ if (!node.id) {
154
+ node.id = 'toc-' + tocItemId + '-' + this.tocs[tocItemId].toc._items.length;
155
+ }
156
+
157
+ var tocItemRef = {
158
+ _nodeRef: this._getNodeForNodeRef(node),
159
+ _textNodeRef: node
160
+ };
161
+ this.tocs[tocItemId].toc._items.push(tocItemRef);
162
+ }
163
+ }
164
+
165
+ if (node.id) {
166
+ if (this.nodeReferences[node.id]) {
167
+ if (!this.nodeReferences[node.id]._pseudo) {
168
+ throw "Node id '" + node.id + "' already exists";
169
+ }
170
+
171
+ this.nodeReferences[node.id]._nodeRef = this._getNodeForNodeRef(node);
172
+ this.nodeReferences[node.id]._textNodeRef = node;
173
+ this.nodeReferences[node.id]._pseudo = false;
174
+ } else {
175
+ this.nodeReferences[node.id] = {
176
+ _nodeRef: this._getNodeForNodeRef(node),
177
+ _textNodeRef: node
178
+ };
179
+ }
180
+ }
181
+
182
+ if (node.pageReference) {
183
+ if (!this.nodeReferences[node.pageReference]) {
184
+ this.nodeReferences[node.pageReference] = {
185
+ _nodeRef: {},
186
+ _textNodeRef: {},
187
+ _pseudo: true
188
+ };
189
+ }
190
+ node.text = '00000';
191
+ node.linkToDestination = node.pageReference;
192
+ node._pageRef = this.nodeReferences[node.pageReference];
193
+ }
194
+
195
+ if (node.textReference) {
196
+ if (!this.nodeReferences[node.textReference]) {
197
+ this.nodeReferences[node.textReference] = {
198
+ _nodeRef: {},
199
+ _pseudo: true
200
+ };
201
+ }
202
+
203
+ node.text = '';
204
+ node.linkToDestination = node.textReference;
205
+ node._textRef = this.nodeReferences[node.textReference];
206
+ }
207
+
208
+ if (node.text && node.text.text) {
209
+ node.text = [this.preprocessNode(node.text)];
210
+ } else if (isArray(node.text)) {
211
+ var isSetParentNode = false;
212
+ if (this.parentNode === null) {
213
+ this.parentNode = node;
214
+ isSetParentNode = true;
215
+ }
216
+
217
+ for (i = 0, l = node.text.length; i < l; i++) {
218
+ node.text[i] = this.preprocessNode(node.text[i]);
219
+ }
220
+
221
+ if (isSetParentNode) {
222
+ this.parentNode = null;
223
+ }
224
+ }
225
+
226
+ return node;
227
+ };
228
+
229
+ DocPreprocessor.prototype.preprocessToc = function (node) {
230
+ if (!node.toc.id) {
231
+ node.toc.id = '_default_';
232
+ }
233
+
234
+ node.toc.title = node.toc.title ? this.preprocessNode(node.toc.title) : null;
235
+ node.toc._items = [];
236
+
237
+ if (this.tocs[node.toc.id]) {
238
+ if (!this.tocs[node.toc.id].toc._pseudo) {
239
+ throw "TOC '" + node.toc.id + "' already exists";
240
+ }
241
+
242
+ node.toc._items = this.tocs[node.toc.id].toc._items;
243
+ }
244
+
245
+ this.tocs[node.toc.id] = node;
246
+
247
+ return node;
248
+ };
249
+
250
+ DocPreprocessor.prototype.preprocessImage = function (node) {
251
+ if (!isUndefined(node.image.type) && !isUndefined(node.image.data) && (node.image.type === 'Buffer') && isArray(node.image.data)) {
252
+ node.image = Buffer.from(node.image.data);
253
+ }
254
+ return node;
255
+ };
256
+
257
+ DocPreprocessor.prototype.preprocessSVG = function (node) {
258
+ return node;
259
+ };
260
+
261
+ DocPreprocessor.prototype.preprocessCanvas = function (node) {
262
+ return node;
263
+ };
264
+
265
+ DocPreprocessor.prototype.preprocessQr = function (node) {
266
+ return node;
267
+ };
268
+
269
+ DocPreprocessor.prototype._getNodeForNodeRef = function (node) {
270
+ if (this.parentNode) {
271
+ return this.parentNode;
272
+ }
273
+
274
+ return node;
275
+ };
276
+
277
+ module.exports = DocPreprocessor;
@@ -0,0 +1,383 @@
1
+ 'use strict';
2
+
3
+ var TraversalTracker = require('./traversalTracker');
4
+ var isString = require('./helpers').isString;
5
+
6
+ /**
7
+ * Creates an instance of DocumentContext - a store for current x, y positions and available width/height.
8
+ * It facilitates column divisions and vertical sync
9
+ */
10
+ function DocumentContext(pageSize, pageMargins, footerGapOption = {}) {
11
+ this.pages = [];
12
+
13
+ this.pageMargins = pageMargins;
14
+
15
+ this.x = pageMargins.left;
16
+ this.availableWidth = pageSize.width - pageMargins.left - pageMargins.right;
17
+ this.availableHeight = 0;
18
+ this.page = -1;
19
+
20
+ this._footerColumnGuides = null;
21
+ this._footerGapOption = footerGapOption;
22
+
23
+ this.snapshots = [];
24
+
25
+ this.tracker = new TraversalTracker();
26
+
27
+ this.backgroundLength = [];
28
+
29
+ this.addPage(pageSize);
30
+ }
31
+
32
+ DocumentContext.prototype.beginColumnGroup = function (marginXTopParent, bottomByPage = {}) {
33
+ this.snapshots.push({
34
+ x: this.x,
35
+ y: this.y,
36
+ availableHeight: this.availableHeight,
37
+ availableWidth: this.availableWidth,
38
+ page: this.page,
39
+ bottomByPage: bottomByPage ? bottomByPage : {},
40
+ bottomMost: {
41
+ x: this.x,
42
+ y: this.y,
43
+ availableHeight: this.availableHeight,
44
+ availableWidth: this.availableWidth,
45
+ page: this.page
46
+ },
47
+ lastColumnWidth: this.lastColumnWidth
48
+ });
49
+
50
+ this.lastColumnWidth = 0;
51
+ if (marginXTopParent) {
52
+ this.marginXTopParent = marginXTopParent;
53
+ }
54
+ };
55
+
56
+ DocumentContext.prototype.updateBottomByPage = function () {
57
+ const lastSnapshot = this.snapshots[this.snapshots.length - 1];
58
+ if (!lastSnapshot) {
59
+ return;
60
+ }
61
+
62
+ if (!lastSnapshot.bottomByPage) {
63
+ lastSnapshot.bottomByPage = {};
64
+ }
65
+
66
+ const lastPage = this.page;
67
+ let previousBottom = -Number.MIN_VALUE;
68
+ if (lastSnapshot.bottomByPage[lastPage] !== undefined) {
69
+ previousBottom = lastSnapshot.bottomByPage[lastPage];
70
+ }
71
+ lastSnapshot.bottomByPage[lastPage] = Math.max(previousBottom, this.y);
72
+ };
73
+
74
+ DocumentContext.prototype.resetMarginXTopParent = function () {
75
+ this.marginXTopParent = null;
76
+ };
77
+
78
+ DocumentContext.prototype.beginColumn = function (width, offset, endingCell) {
79
+ var saved = this.snapshots[this.snapshots.length - 1];
80
+
81
+ this.calculateBottomMost(saved, endingCell);
82
+
83
+ this.page = saved.page;
84
+ this.x = this.x + this.lastColumnWidth + (offset || 0);
85
+ this.y = saved.y;
86
+ this.availableWidth = width; //saved.availableWidth - offset;
87
+ this.availableHeight = saved.availableHeight;
88
+
89
+ this.lastColumnWidth = width;
90
+ };
91
+
92
+ DocumentContext.prototype.calculateBottomMost = function (destContext, endingCell) {
93
+ if (endingCell) {
94
+ this.saveContextInEndingCell(endingCell);
95
+ } else {
96
+ destContext.bottomMost = bottomMostContext(this, destContext.bottomMost);
97
+ }
98
+ };
99
+
100
+ DocumentContext.prototype.markEnding = function (endingCell, originalXOffset, discountY) {
101
+ this.page = endingCell._columnEndingContext.page;
102
+ this.x = endingCell._columnEndingContext.x + originalXOffset;
103
+ this.y = endingCell._columnEndingContext.y - discountY;
104
+ this.availableWidth = endingCell._columnEndingContext.availableWidth;
105
+ this.availableHeight = endingCell._columnEndingContext.availableHeight;
106
+ this.lastColumnWidth = endingCell._columnEndingContext.lastColumnWidth;
107
+ };
108
+
109
+ DocumentContext.prototype.saveContextInEndingCell = function (endingCell) {
110
+ endingCell._columnEndingContext = {
111
+ page: this.page,
112
+ x: this.x,
113
+ y: this.y,
114
+ availableHeight: this.availableHeight,
115
+ availableWidth: this.availableWidth,
116
+ lastColumnWidth: this.lastColumnWidth
117
+ };
118
+ };
119
+
120
+ DocumentContext.prototype.completeColumnGroup = function (height, endingCell) {
121
+ var saved = this.snapshots.pop();
122
+
123
+ this.calculateBottomMost(saved, endingCell);
124
+
125
+ this.x = saved.x;
126
+
127
+ var y = saved.bottomMost.y;
128
+ if (height) {
129
+ if (saved.page === saved.bottomMost.page) {
130
+ if ((saved.y + height) > y) {
131
+ y = saved.y + height;
132
+ }
133
+ } else {
134
+ y += height;
135
+ }
136
+ }
137
+
138
+ this.y = y;
139
+ this.page = saved.bottomMost.page;
140
+ this.height = saved.bottomMost.y - saved.y;
141
+ this.availableWidth = saved.availableWidth;
142
+ this.availableHeight = saved.bottomMost.availableHeight;
143
+ if (height) {
144
+ this.availableHeight -= (y - saved.bottomMost.y);
145
+ }
146
+ this.lastColumnWidth = saved.lastColumnWidth;
147
+ return saved.bottomByPage;
148
+ };
149
+
150
+ DocumentContext.prototype.addMargin = function (left, right) {
151
+ this.x += left;
152
+ this.availableWidth -= left + (right || 0);
153
+ };
154
+
155
+ DocumentContext.prototype.moveDown = function (offset) {
156
+ this.y += offset;
157
+ this.availableHeight -= offset;
158
+
159
+ return this.availableHeight > 0;
160
+ };
161
+
162
+ DocumentContext.prototype.initializePage = function () {
163
+ this.y = this.pageMargins.top;
164
+ this.availableHeight = this.getCurrentPage().pageSize.height - this.pageMargins.top - this.pageMargins.bottom;
165
+ this.fullHeight = this.availableHeight;
166
+ const { pageCtx, isSnapshot } = this.pageSnapshot();
167
+ pageCtx.availableWidth = this.getCurrentPage().pageSize.width - this.pageMargins.left - this.pageMargins.right;
168
+ if (isSnapshot && this.marginXTopParent) {
169
+ pageCtx.availableWidth -= this.marginXTopParent[0];
170
+ pageCtx.availableWidth -= this.marginXTopParent[1];
171
+ }
172
+ };
173
+
174
+ DocumentContext.prototype.pageSnapshot = function () {
175
+ if (this.snapshots[0]) {
176
+ return { pageCtx: this.snapshots[0], isSnapshot: true };
177
+ } else {
178
+ return { pageCtx: this, isSnapshot: false };
179
+ }
180
+ };
181
+
182
+ DocumentContext.prototype.moveTo = function (x, y) {
183
+ if (x !== undefined && x !== null) {
184
+ this.x = x;
185
+ this.availableWidth = this.getCurrentPage().pageSize.width - this.x - this.pageMargins.right;
186
+ }
187
+ if (y !== undefined && y !== null) {
188
+ this.y = y;
189
+ this.availableHeight = this.getCurrentPage().pageSize.height - this.y - this.pageMargins.bottom;
190
+ }
191
+ };
192
+
193
+ DocumentContext.prototype.moveToRelative = function (x, y) {
194
+ if (x !== undefined && x !== null) {
195
+ this.x = this.x + x;
196
+ }
197
+ if (y !== undefined && y !== null) {
198
+ this.y = this.y + y;
199
+ }
200
+ };
201
+
202
+ DocumentContext.prototype.beginDetachedBlock = function () {
203
+ this.snapshots.push({
204
+ x: this.x,
205
+ y: this.y,
206
+ availableHeight: this.availableHeight,
207
+ availableWidth: this.availableWidth,
208
+ page: this.page,
209
+ lastColumnWidth: this.lastColumnWidth
210
+ });
211
+ };
212
+
213
+ DocumentContext.prototype.endDetachedBlock = function () {
214
+ var saved = this.snapshots.pop();
215
+
216
+ this.x = saved.x;
217
+ this.y = saved.y;
218
+ this.availableWidth = saved.availableWidth;
219
+ this.availableHeight = saved.availableHeight;
220
+ this.page = saved.page;
221
+ this.lastColumnWidth = saved.lastColumnWidth;
222
+ };
223
+
224
+ function pageOrientation(pageOrientationString, currentPageOrientation) {
225
+ if (pageOrientationString === undefined) {
226
+ return currentPageOrientation;
227
+ } else if (isString(pageOrientationString) && (pageOrientationString.toLowerCase() === 'landscape')) {
228
+ return 'landscape';
229
+ } else {
230
+ return 'portrait';
231
+ }
232
+ }
233
+
234
+ var getPageSize = function (currentPage, newPageOrientation) {
235
+
236
+ newPageOrientation = pageOrientation(newPageOrientation, currentPage.pageSize.orientation);
237
+
238
+ if (newPageOrientation !== currentPage.pageSize.orientation) {
239
+ return {
240
+ orientation: newPageOrientation,
241
+ width: currentPage.pageSize.height,
242
+ height: currentPage.pageSize.width
243
+ };
244
+ } else {
245
+ return {
246
+ orientation: currentPage.pageSize.orientation,
247
+ width: currentPage.pageSize.width,
248
+ height: currentPage.pageSize.height
249
+ };
250
+ }
251
+
252
+ };
253
+
254
+
255
+ DocumentContext.prototype.moveToNextPage = function (pageOrientation) {
256
+ var nextPageIndex = this.page + 1;
257
+
258
+ var prevPage = this.page;
259
+ var prevY = this.y;
260
+
261
+ // If we are in a column group
262
+ if (this.snapshots.length > 0) {
263
+ var lastSnapshot = this.snapshots[this.snapshots.length - 1];
264
+ // We have to update prevY accordingly by also taking into consideration
265
+ // the 'y' of cells that don't break page
266
+ if (lastSnapshot.bottomMost && lastSnapshot.bottomMost.y) {
267
+ prevY = Math.max(this.y, lastSnapshot.bottomMost.y);
268
+ }
269
+ }
270
+
271
+ var createNewPage = nextPageIndex >= this.pages.length;
272
+ if (createNewPage) {
273
+ var currentAvailableWidth = this.availableWidth;
274
+ var currentPageOrientation = this.getCurrentPage().pageSize.orientation;
275
+
276
+ var pageSize = getPageSize(this.getCurrentPage(), pageOrientation);
277
+ this.addPage(pageSize);
278
+
279
+ if (currentPageOrientation === pageSize.orientation) {
280
+ this.availableWidth = currentAvailableWidth;
281
+ }
282
+ } else {
283
+ this.page = nextPageIndex;
284
+ this.initializePage();
285
+ }
286
+
287
+ return {
288
+ newPageCreated: createNewPage,
289
+ prevPage: prevPage,
290
+ prevY: prevY,
291
+ y: this.y
292
+ };
293
+ };
294
+
295
+
296
+ DocumentContext.prototype.addPage = function (pageSize) {
297
+ var page = { items: [], pageSize: pageSize };
298
+ this.pages.push(page);
299
+ this.backgroundLength.push(0);
300
+ this.page = this.pages.length - 1;
301
+ this.initializePage();
302
+
303
+ this.tracker.emit('pageAdded');
304
+
305
+ return page;
306
+ };
307
+
308
+ DocumentContext.prototype.getCurrentPage = function () {
309
+ if (this.page < 0 || this.page >= this.pages.length) {
310
+ return null;
311
+ }
312
+
313
+ return this.pages[this.page];
314
+ };
315
+
316
+ DocumentContext.prototype.getCurrentPosition = function () {
317
+ var pageSize = this.getCurrentPage().pageSize;
318
+ var innerHeight = pageSize.height - this.pageMargins.top - this.pageMargins.bottom;
319
+ var innerWidth = pageSize.width - this.pageMargins.left - this.pageMargins.right;
320
+
321
+ return {
322
+ pageNumber: this.page + 1,
323
+ pageOrientation: pageSize.orientation,
324
+ pageInnerHeight: innerHeight,
325
+ pageInnerWidth: innerWidth,
326
+ left: this.x,
327
+ top: this.y,
328
+ verticalRatio: ((this.y - this.pageMargins.top) / innerHeight),
329
+ horizontalRatio: ((this.x - this.pageMargins.left) / innerWidth)
330
+ };
331
+ };
332
+
333
+ function bottomMostContext(c1, c2) {
334
+ if (!c1 && !c2) {
335
+ return {
336
+ page: 0,
337
+ x: 0,
338
+ y: 0,
339
+ availableHeight: 0,
340
+ availableWidth: 0
341
+ };
342
+ }
343
+
344
+ if (!c1) {
345
+ return {
346
+ page: c2.page,
347
+ x: c2.x,
348
+ y: c2.y,
349
+ availableHeight: c2.availableHeight,
350
+ availableWidth: c2.availableWidth
351
+ };
352
+ }
353
+
354
+ if (!c2) {
355
+ return {
356
+ page: c1.page,
357
+ x: c1.x,
358
+ y: c1.y,
359
+ availableHeight: c1.availableHeight,
360
+ availableWidth: c1.availableWidth
361
+ };
362
+ }
363
+
364
+ var r;
365
+
366
+ if (c1.page > c2.page) {
367
+ r = c1;
368
+ } else if (c2.page > c1.page) {
369
+ r = c2;
370
+ } else {
371
+ r = (c1.y > c2.y) ? c1 : c2;
372
+ }
373
+
374
+ return {
375
+ page: r.page,
376
+ x: r.x,
377
+ y: r.y,
378
+ availableHeight: r.availableHeight,
379
+ availableWidth: r.availableWidth
380
+ };
381
+ }
382
+
383
+ module.exports = DocumentContext;