@digicole/pdfmake-rtl 1.2.0 → 2.1.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 (100) hide show
  1. package/.vscode/tasks.json +17 -0
  2. package/CHANGELOG.md +83 -128
  3. package/LICENSE +22 -22
  4. package/README.md +188 -681
  5. package/build/fonts/Cairo/Cairo-Black.ttf +0 -0
  6. package/build/fonts/Cairo/Cairo-Bold.ttf +0 -0
  7. package/build/fonts/Cairo/Cairo-ExtraLight.ttf +0 -0
  8. package/build/fonts/Cairo/Cairo-Light.ttf +0 -0
  9. package/build/fonts/Cairo/Cairo-Regular.ttf +0 -0
  10. package/build/fonts/Cairo/Cairo-SemiBold.ttf +0 -0
  11. package/build/fonts/Cairo.js +27 -0
  12. package/build/fonts/Roboto/Roboto-Italic.ttf +0 -0
  13. package/build/fonts/Roboto/Roboto-Medium.ttf +0 -0
  14. package/build/fonts/Roboto/Roboto-MediumItalic.ttf +0 -0
  15. package/build/fonts/Roboto/Roboto-Regular.ttf +0 -0
  16. package/build/fonts/Roboto.js +27 -0
  17. package/build/pdfmake.js +63736 -71285
  18. package/build/pdfmake.js.map +1 -1
  19. package/build/pdfmake.min.js +2 -2
  20. package/build/pdfmake.min.js.map +1 -1
  21. package/build/standard-fonts/Courier.js +27 -0
  22. package/build/standard-fonts/Helvetica.js +27 -0
  23. package/build/standard-fonts/Symbol.js +21 -0
  24. package/build/standard-fonts/Times.js +27 -0
  25. package/build/standard-fonts/ZapfDingbats.js +21 -0
  26. package/build/vfs_fonts.js +11 -7
  27. package/build-vfs.js +44 -44
  28. package/fonts/Cairo/Cairo-Black.ttf +0 -0
  29. package/fonts/Cairo/Cairo-Bold.ttf +0 -0
  30. package/fonts/Cairo/Cairo-ExtraLight.ttf +0 -0
  31. package/fonts/Cairo/Cairo-Light.ttf +0 -0
  32. package/fonts/Cairo/Cairo-Regular.ttf +0 -0
  33. package/fonts/Cairo/Cairo-SemiBold.ttf +0 -0
  34. package/fonts/Cairo.js +8 -0
  35. package/fonts/Roboto/Roboto-Italic.ttf +0 -0
  36. package/fonts/Roboto/Roboto-Medium.ttf +0 -0
  37. package/fonts/Roboto/Roboto-MediumItalic.ttf +0 -0
  38. package/fonts/Roboto/Roboto-Regular.ttf +0 -0
  39. package/fonts/Roboto.js +8 -0
  40. package/index.js +26 -26
  41. package/package.json +42 -39
  42. package/src/3rd-party/svg-to-pdfkit/LICENSE +9 -9
  43. package/src/3rd-party/svg-to-pdfkit/source.js +229 -36
  44. package/src/3rd-party/svg-to-pdfkit.js +3 -3
  45. package/src/OutputDocument.js +64 -0
  46. package/src/OutputDocumentServer.js +32 -0
  47. package/src/PDFDocument.js +174 -0
  48. package/src/PageSize.js +53 -0
  49. package/src/Renderer.js +445 -0
  50. package/src/TextBreaker.js +168 -0
  51. package/src/TextInlines.js +263 -0
  52. package/src/URLResolver.js +43 -0
  53. package/src/base.js +70 -0
  54. package/src/browser-extensions/OutputDocumentBrowser.js +80 -0
  55. package/src/browser-extensions/fonts/Cairo.js +27 -0
  56. package/src/browser-extensions/fonts/Roboto.js +27 -0
  57. package/src/browser-extensions/index.js +61 -0
  58. package/src/browser-extensions/pdfMake.js +1 -355
  59. package/src/browser-extensions/standard-fonts/Courier.js +27 -0
  60. package/src/browser-extensions/standard-fonts/Helvetica.js +27 -0
  61. package/src/browser-extensions/standard-fonts/Symbol.js +21 -0
  62. package/src/browser-extensions/standard-fonts/Times.js +27 -0
  63. package/src/browser-extensions/standard-fonts/ZapfDingbats.js +21 -0
  64. package/src/browser-extensions/virtual-fs-cjs.js +1 -0
  65. package/src/columnCalculator.js +154 -157
  66. package/src/docMeasure.js +802 -810
  67. package/src/docPreprocessor.js +306 -273
  68. package/src/documentContext.js +345 -340
  69. package/src/elementWriter.js +736 -411
  70. package/src/helpers/node.js +136 -0
  71. package/src/helpers/tools.js +44 -0
  72. package/src/helpers/variableType.js +50 -0
  73. package/src/index.js +16 -0
  74. package/src/layoutBuilder.js +1393 -1197
  75. package/src/line.js +122 -104
  76. package/src/pageElementWriter.js +187 -174
  77. package/src/printer.js +370 -727
  78. package/src/qrEnc.js +796 -791
  79. package/src/rtlUtils.js +500 -485
  80. package/src/standardPageSizes.js +52 -54
  81. package/src/styleContextStack.js +208 -138
  82. package/src/svgMeasure.js +109 -70
  83. package/src/tableLayouts.js +100 -0
  84. package/src/tableProcessor.js +620 -606
  85. package/src/textDecorator.js +175 -157
  86. package/src/virtual-fs.js +66 -0
  87. package/standard-fonts/Courier.js +8 -0
  88. package/standard-fonts/Helvetica.js +8 -0
  89. package/standard-fonts/Symbol.js +5 -0
  90. package/standard-fonts/Times.js +8 -0
  91. package/standard-fonts/ZapfDingbats.js +5 -0
  92. package/index.html +0 -396
  93. package/src/browser-extensions/URLBrowserResolver.js +0 -96
  94. package/src/browser-extensions/virtual-fs.js +0 -55
  95. package/src/fontProvider.js +0 -68
  96. package/src/helpers.js +0 -138
  97. package/src/imageMeasure.js +0 -62
  98. package/src/pdfKitEngine.js +0 -21
  99. package/src/textTools.js +0 -391
  100. package/src/traversalTracker.js +0 -47
@@ -0,0 +1,168 @@
1
+ import LineBreaker from 'linebreak';
2
+ import { isObject } from './helpers/variableType';
3
+ import StyleContextStack from './StyleContextStack';
4
+
5
+ /**
6
+ * @param {string} text
7
+ * @param {boolean} noWrap
8
+ * @param {boolean} breakAll
9
+ * @returns {Array}
10
+ */
11
+ const splitWords = (text, noWrap, breakAll = false) => {
12
+ let words = [];
13
+ if (text === undefined || text === null) {
14
+ text = '';
15
+ } else {
16
+ text = String(text);
17
+ }
18
+
19
+ if (noWrap) {
20
+ words.push({ text: text });
21
+ return words;
22
+ }
23
+ if (breakAll) {
24
+ return text.split('').map(c => {
25
+ if(c.match(/^\n$|^\r$/)) { // new line
26
+ return { text: '', lineEnd: true };
27
+ }
28
+ return { text: c };
29
+ });
30
+ }
31
+
32
+ if (text.length === 0) {
33
+ words.push({ text: '' });
34
+ return words;
35
+ }
36
+
37
+ let breaker = new LineBreaker(text);
38
+ let last = 0;
39
+ let bk;
40
+
41
+ while ((bk = breaker.nextBreak())) {
42
+ let word = text.slice(last, bk.position);
43
+
44
+ if (bk.required || word.match(/\r?\n$|\r$/)) { // new line
45
+ word = word.replace(/\r?\n$|\r$/, '');
46
+ words.push({ text: word, lineEnd: true });
47
+ } else {
48
+ words.push({ text: word });
49
+ }
50
+
51
+ last = bk.position;
52
+ }
53
+
54
+ return words;
55
+ };
56
+
57
+ /**
58
+ * @param {Array} words
59
+ * @param {boolean} noWrap
60
+ * @returns {?string}
61
+ */
62
+ const getFirstWord = (words, noWrap) => {
63
+ let word = words[0];
64
+ if (word === undefined) {
65
+ return null;
66
+ }
67
+
68
+ if (noWrap) { // text was not wrapped, we need only first word
69
+ let tmpWords = splitWords(word.text, false);
70
+ if (tmpWords[0] === undefined) {
71
+ return null;
72
+ }
73
+ word = tmpWords[0];
74
+ }
75
+
76
+ return word.text;
77
+ };
78
+
79
+ /**
80
+ * @param {Array} words
81
+ * @param {boolean} noWrap
82
+ * @returns {?string}
83
+ */
84
+ const getLastWord = (words, noWrap) => {
85
+ let word = words[words.length - 1];
86
+ if (word === undefined) {
87
+ return null;
88
+ }
89
+
90
+ if (word.lineEnd) {
91
+ return null;
92
+ }
93
+
94
+ if (noWrap) { // text was not wrapped, we need only last word
95
+ let tmpWords = splitWords(word.text, false);
96
+ if (tmpWords[tmpWords.length - 1] === undefined) {
97
+ return null;
98
+ }
99
+ word = tmpWords[tmpWords.length - 1];
100
+ }
101
+
102
+ return word.text;
103
+ };
104
+
105
+ class TextBreaker {
106
+ /**
107
+ * @param {string|Array} texts
108
+ * @param {StyleContextStack} styleContextStack
109
+ * @returns {Array}
110
+ */
111
+ getBreaks(texts, styleContextStack) {
112
+ let results = [];
113
+
114
+ if (!Array.isArray(texts)) {
115
+ texts = [texts];
116
+ }
117
+
118
+ let lastWord = null;
119
+ for (let i = 0, l = texts.length; i < l; i++) {
120
+ let item = texts[i];
121
+ let style = null;
122
+ let words;
123
+ let breakAll = StyleContextStack.getStyleProperty(item || {}, styleContextStack, 'wordBreak', 'normal') === 'break-all';
124
+ let noWrap = StyleContextStack.getStyleProperty(item || {}, styleContextStack, 'noWrap', false);
125
+ if (isObject(item)) {
126
+ if (item._textRef && item._textRef._textNodeRef.text) {
127
+ item.text = item._textRef._textNodeRef.text;
128
+ }
129
+ words = splitWords(item.text, noWrap, breakAll);
130
+ style = StyleContextStack.copyStyle(item);
131
+ } else {
132
+ words = splitWords(item, noWrap, breakAll);
133
+ }
134
+
135
+ if (lastWord && words.length) {
136
+ let firstWord = getFirstWord(words, noWrap);
137
+
138
+ let wrapWords = splitWords(lastWord + firstWord, false);
139
+ if (wrapWords.length === 1) {
140
+ results[results.length - 1].noNewLine = true;
141
+ }
142
+ }
143
+
144
+ for (let i2 = 0, l2 = words.length; i2 < l2; i2++) {
145
+ let result = {
146
+ text: words[i2].text
147
+ };
148
+
149
+ if (words[i2].lineEnd) {
150
+ result.lineEnd = true;
151
+ }
152
+
153
+ StyleContextStack.copyStyle(style, result);
154
+
155
+ results.push(result);
156
+ }
157
+
158
+ lastWord = null;
159
+ if (i + 1 < l) {
160
+ lastWord = getLastWord(words, noWrap);
161
+ }
162
+ }
163
+
164
+ return results;
165
+ }
166
+ }
167
+
168
+ export default TextBreaker;
@@ -0,0 +1,263 @@
1
+ import TextBreaker from './TextBreaker';
2
+ import StyleContextStack from './StyleContextStack';
3
+ import { containsRTL, getTextDirection } from './rtlUtils';
4
+
5
+ const LEADING = /^(\s)+/g;
6
+ const TRAILING = /(\s)+$/g;
7
+
8
+ /**
9
+ * @param {Array} array
10
+ * @returns {Array}
11
+ */
12
+ const flattenTextArray = array => {
13
+ function flatten(array) {
14
+ return array.reduce((prev, cur) => {
15
+ let current = Array.isArray(cur.text) ? flatten(cur.text) : cur;
16
+ let more = [].concat(current).some(Array.isArray);
17
+ return prev.concat(more ? flatten(current) : current);
18
+ }, []);
19
+ }
20
+
21
+ if (!Array.isArray(array)) {
22
+ array = [array];
23
+ }
24
+
25
+ // TODO: Styling in nested text (issue: https://github.com/bpampuch/pdfmake/issues/1174)
26
+
27
+ array = flatten(array);
28
+
29
+ return array;
30
+ };
31
+
32
+
33
+ /**
34
+ * Text measurement utility
35
+ */
36
+ class TextInlines {
37
+
38
+ /**
39
+ * @param {object} pdfDocument object is instance of PDFDocument
40
+ */
41
+ constructor(pdfDocument) {
42
+ this.pdfDocument = pdfDocument;
43
+ }
44
+
45
+ /**
46
+ * Converts an array of strings (or inline-definition-objects) into a collection
47
+ * of inlines and calculated minWidth/maxWidth and their min/max widths
48
+ *
49
+ * @param {Array|object} textArray an array of inline-definition-objects (or strings)
50
+ * @param {StyleContextStack} styleContextStack current style stack
51
+ * @returns {object} collection of inlines, minWidth, maxWidth
52
+ */
53
+ buildInlines(textArray, styleContextStack) {
54
+ const getTrimmedWidth = item => {
55
+ return Math.max(0, item.width - item.leadingCut - item.trailingCut);
56
+ };
57
+
58
+ let minWidth = 0;
59
+ let maxWidth = 0;
60
+ let currentLineWidth;
61
+
62
+ let flattenedTextArray = flattenTextArray(textArray);
63
+
64
+ const textBreaker = new TextBreaker();
65
+ let brokenText = textBreaker.getBreaks(flattenedTextArray, styleContextStack);
66
+
67
+ let measuredText = this.measure(brokenText, styleContextStack);
68
+
69
+ measuredText.forEach(inline => {
70
+ minWidth = Math.max(minWidth, getTrimmedWidth(inline));
71
+
72
+ if (!currentLineWidth) {
73
+ currentLineWidth = { width: 0, leadingCut: inline.leadingCut, trailingCut: 0 };
74
+ }
75
+
76
+ currentLineWidth.width += inline.width;
77
+ currentLineWidth.trailingCut = inline.trailingCut;
78
+
79
+ maxWidth = Math.max(maxWidth, getTrimmedWidth(currentLineWidth));
80
+
81
+ if (inline.lineEnd) {
82
+ currentLineWidth = null;
83
+ }
84
+ });
85
+
86
+ if (StyleContextStack.getStyleProperty({}, styleContextStack, 'noWrap', false)) {
87
+ minWidth = maxWidth;
88
+ }
89
+
90
+ return {
91
+ items: measuredText,
92
+ minWidth: minWidth,
93
+ maxWidth: maxWidth
94
+ };
95
+ }
96
+
97
+ measure(array, styleContextStack) {
98
+ if (array.length) {
99
+ let leadingIndent = StyleContextStack.getStyleProperty(array[0], styleContextStack, 'leadingIndent', 0);
100
+ if (leadingIndent) {
101
+ array[0].leadingCut = -leadingIndent;
102
+ array[0].leadingIndent = leadingIndent;
103
+ }
104
+ }
105
+
106
+ array.forEach(item => {
107
+ // Font resolution priority:
108
+ // 1. Item-level font (set directly on the text node)
109
+ // 2. Style/named-style font (from style stack)
110
+ // 3. defaultStyle font (from document definition)
111
+ // 4. Auto-detect: Cairo for RTL/Arabic text, Roboto for LTR/Latin text
112
+ let font = StyleContextStack.getStyleProperty(item, styleContextStack, 'font', null);
113
+ let bold = StyleContextStack.getStyleProperty(item, styleContextStack, 'bold', false);
114
+ let italics = StyleContextStack.getStyleProperty(item, styleContextStack, 'italics', false);
115
+
116
+ if (!font) {
117
+ // No font set by item, style, or defaultStyle — auto-detect from text content
118
+ if (item.text && containsRTL(item.text)) {
119
+ font = 'Cairo';
120
+ } else {
121
+ font = 'Roboto';
122
+ }
123
+ }
124
+
125
+ item.font = this.pdfDocument.provideFont(font, bold, italics);
126
+
127
+ item.alignment = StyleContextStack.getStyleProperty(item, styleContextStack, 'alignment', 'left');
128
+
129
+ // RTL Support: detect direction and set isRTL on each inline
130
+ let direction = StyleContextStack.getStyleProperty(item, styleContextStack, 'direction', null);
131
+ if (direction === 'rtl') {
132
+ item.isRTL = true;
133
+ item.direction = 'rtl';
134
+ } else if (direction === 'ltr') {
135
+ item.isRTL = false;
136
+ item.direction = 'ltr';
137
+ } else {
138
+ // Auto-detect from text content
139
+ let textDir = getTextDirection(item.text);
140
+ item.isRTL = textDir === 'rtl';
141
+ item.direction = textDir === 'rtl' ? 'rtl' : 'ltr';
142
+ }
143
+
144
+ // For RTL text, auto-default alignment to 'right' if not explicitly set
145
+ if (item.isRTL && item.alignment === 'left') {
146
+ let explicitAlignment = StyleContextStack.getStyleProperty(item, styleContextStack, 'alignment', null);
147
+ if (!explicitAlignment) {
148
+ item.alignment = 'right';
149
+ }
150
+ }
151
+
152
+ item.fontSize = StyleContextStack.getStyleProperty(item, styleContextStack, 'fontSize', 12);
153
+ item.fontFeatures = StyleContextStack.getStyleProperty(item, styleContextStack, 'fontFeatures', null);
154
+ item.characterSpacing = StyleContextStack.getStyleProperty(item, styleContextStack, 'characterSpacing', 0);
155
+ item.color = StyleContextStack.getStyleProperty(item, styleContextStack, 'color', 'black');
156
+ item.decoration = StyleContextStack.getStyleProperty(item, styleContextStack, 'decoration', null);
157
+ item.decorationColor = StyleContextStack.getStyleProperty(item, styleContextStack, 'decorationColor', null);
158
+ item.decorationStyle = StyleContextStack.getStyleProperty(item, styleContextStack, 'decorationStyle', null);
159
+ item.decorationThickness = StyleContextStack.getStyleProperty(item, styleContextStack, 'decorationThickness', null);
160
+ item.background = StyleContextStack.getStyleProperty(item, styleContextStack, 'background', null);
161
+ item.link = StyleContextStack.getStyleProperty(item, styleContextStack, 'link', null);
162
+ item.linkToPage = StyleContextStack.getStyleProperty(item, styleContextStack, 'linkToPage', null);
163
+ item.linkToDestination = StyleContextStack.getStyleProperty(item, styleContextStack, 'linkToDestination', null);
164
+ item.noWrap = StyleContextStack.getStyleProperty(item, styleContextStack, 'noWrap', null);
165
+ item.opacity = StyleContextStack.getStyleProperty(item, styleContextStack, 'opacity', 1);
166
+ item.sup = StyleContextStack.getStyleProperty(item, styleContextStack, 'sup', false);
167
+ item.sub = StyleContextStack.getStyleProperty(item, styleContextStack, 'sub', false);
168
+
169
+ if (item.sup || item.sub) {
170
+ // font size reduction taken from here: https://en.wikipedia.org/wiki/Subscript_and_superscript#Desktop_publishing
171
+ item.fontSize *= 0.58;
172
+ }
173
+
174
+ let lineHeight = StyleContextStack.getStyleProperty(item, styleContextStack, 'lineHeight', 1);
175
+
176
+ item.width = this.widthOfText(item.text, item);
177
+ item.height = item.font.lineHeight(item.fontSize) * lineHeight;
178
+
179
+ if (!item.leadingCut) {
180
+ item.leadingCut = 0;
181
+ }
182
+
183
+ let preserveLeadingSpaces = StyleContextStack.getStyleProperty(item, styleContextStack, 'preserveLeadingSpaces', false);
184
+ if (!preserveLeadingSpaces) {
185
+ let leadingSpaces = item.text.match(LEADING);
186
+ if (leadingSpaces) {
187
+ item.leadingCut += this.widthOfText(leadingSpaces[0], item);
188
+ }
189
+ }
190
+
191
+ item.trailingCut = 0;
192
+
193
+ let preserveTrailingSpaces = StyleContextStack.getStyleProperty(item, styleContextStack, 'preserveTrailingSpaces', false);
194
+ if (!preserveTrailingSpaces) {
195
+ let trailingSpaces = item.text.match(TRAILING);
196
+ if (trailingSpaces) {
197
+ item.trailingCut = this.widthOfText(trailingSpaces[0], item);
198
+ }
199
+ }
200
+ }, this);
201
+
202
+ return array;
203
+ }
204
+
205
+ /**
206
+ * Width of text
207
+ *
208
+ * @param {string} text
209
+ * @param {object} inline
210
+ * @returns {number}
211
+ */
212
+ widthOfText(text, inline) {
213
+ return inline.font.widthOfString(text, inline.fontSize, inline.fontFeatures) + ((inline.characterSpacing || 0) * (text.length - 1));
214
+ }
215
+
216
+ /**
217
+ * Returns size of the specified string (without breaking it) using the current style
218
+ *
219
+ * @param {string} text text to be measured
220
+ * @param {object} styleContextStack current style stack
221
+ * @returns {object} size of the specified string
222
+ */
223
+ sizeOfText(text, styleContextStack) {
224
+ //TODO: refactor - extract from measure
225
+ let fontName = StyleContextStack.getStyleProperty({}, styleContextStack, 'font', 'Roboto');
226
+ let fontSize = StyleContextStack.getStyleProperty({}, styleContextStack, 'fontSize', 12);
227
+ let fontFeatures = StyleContextStack.getStyleProperty({}, styleContextStack, 'fontFeatures', null);
228
+ let bold = StyleContextStack.getStyleProperty({}, styleContextStack, 'bold', false);
229
+ let italics = StyleContextStack.getStyleProperty({}, styleContextStack, 'italics', false);
230
+ let lineHeight = StyleContextStack.getStyleProperty({}, styleContextStack, 'lineHeight', 1);
231
+ let characterSpacing = StyleContextStack.getStyleProperty({}, styleContextStack, 'characterSpacing', 0);
232
+
233
+ let font = this.pdfDocument.provideFont(fontName, bold, italics);
234
+
235
+ return {
236
+ width: this.widthOfText(text, { font: font, fontSize: fontSize, characterSpacing: characterSpacing, fontFeatures: fontFeatures }),
237
+ height: font.lineHeight(fontSize) * lineHeight,
238
+ fontSize: fontSize,
239
+ lineHeight: lineHeight,
240
+ ascender: font.ascender / 1000 * fontSize,
241
+ descender: font.descender / 1000 * fontSize
242
+ };
243
+ }
244
+
245
+ /**
246
+ * Returns size of the specified rotated string (without breaking it) using the current style
247
+ *
248
+ * @param {string} text text to be measured
249
+ * @param {number} angle
250
+ * @param {object} styleContextStack current style stack
251
+ * @returns {object} size of the specified string
252
+ */
253
+ sizeOfRotatedText(text, angle, styleContextStack) {
254
+ let angleRad = angle * Math.PI / -180;
255
+ let size = this.sizeOfText(text, styleContextStack);
256
+ return {
257
+ width: Math.abs(size.height * Math.sin(angleRad)) + Math.abs(size.width * Math.cos(angleRad)),
258
+ height: Math.abs(size.width * Math.sin(angleRad)) + Math.abs(size.height * Math.cos(angleRad))
259
+ };
260
+ }
261
+ }
262
+
263
+ export default TextInlines;
@@ -0,0 +1,43 @@
1
+ async function fetchUrl(url, headers = {}) {
2
+ try {
3
+ const response = await fetch(url, { headers });
4
+ if (!response.ok) {
5
+ throw new Error(`Failed to fetch (status code: ${response.status}, url: "${url}")`);
6
+ }
7
+ return await response.arrayBuffer();
8
+ } catch (error) {
9
+ throw new Error(`Network request failed (url: "${url}", error: ${error.message})`);
10
+ }
11
+ }
12
+
13
+ class URLResolver {
14
+ constructor(fs) {
15
+ this.fs = fs;
16
+ this.resolving = {};
17
+ }
18
+
19
+ resolve(url, headers = {}) {
20
+ const resolveUrlInternal = async () => {
21
+ if (url.toLowerCase().startsWith('https://') || url.toLowerCase().startsWith('http://')) {
22
+ if (this.fs.existsSync(url)) {
23
+ return; // url was downloaded earlier
24
+ }
25
+ const buffer = await fetchUrl(url, headers);
26
+ this.fs.writeFileSync(url, buffer);
27
+ }
28
+ // else cannot be resolved
29
+ };
30
+
31
+ if (!this.resolving[url]) {
32
+ this.resolving[url] = resolveUrlInternal();
33
+ }
34
+ return this.resolving[url];
35
+ }
36
+
37
+ resolved() {
38
+ return Promise.all(Object.values(this.resolving));
39
+ }
40
+
41
+ }
42
+
43
+ export default URLResolver;
package/src/base.js ADDED
@@ -0,0 +1,70 @@
1
+ import Printer from './Printer';
2
+ import virtualfs from './virtual-fs';
3
+ import { pack } from './helpers/tools';
4
+ import { isObject } from './helpers/variableType';
5
+
6
+ class pdfmake {
7
+
8
+ constructor() {
9
+ this.virtualfs = virtualfs;
10
+ this.urlResolver = null;
11
+ }
12
+
13
+ /**
14
+ * @param {object} docDefinition
15
+ * @param {?object} options
16
+ * @returns {object}
17
+ */
18
+ createPdf(docDefinition, options = {}) {
19
+ if (!isObject(docDefinition)) {
20
+ throw new Error("Parameter 'docDefinition' has an invalid type. Object expected.");
21
+ }
22
+
23
+ if (!isObject(options)) {
24
+ throw new Error("Parameter 'options' has an invalid type. Object expected.");
25
+ }
26
+
27
+ options.progressCallback = this.progressCallback;
28
+ options.tableLayouts = this.tableLayouts;
29
+
30
+ let printer = new Printer(this.fonts, this.virtualfs, this.urlResolver());
31
+ const pdfDocumentPromise = printer.createPdfKitDocument(docDefinition, options);
32
+
33
+ return this._transformToDocument(pdfDocumentPromise);
34
+ }
35
+
36
+ setProgressCallback(callback) {
37
+ this.progressCallback = callback;
38
+ }
39
+
40
+ addTableLayouts(tableLayouts) {
41
+ this.tableLayouts = pack(this.tableLayouts, tableLayouts);
42
+ }
43
+
44
+ setTableLayouts(tableLayouts) {
45
+ this.tableLayouts = tableLayouts;
46
+ }
47
+
48
+ clearTableLayouts() {
49
+ this.tableLayouts = {};
50
+ }
51
+
52
+ addFonts(fonts) {
53
+ this.fonts = pack(this.fonts, fonts);
54
+ }
55
+
56
+ setFonts(fonts) {
57
+ this.fonts = fonts;
58
+ }
59
+
60
+ clearFonts() {
61
+ this.fonts = {};
62
+ }
63
+
64
+ _transformToDocument(doc) {
65
+ return doc;
66
+ }
67
+
68
+ }
69
+
70
+ export default pdfmake;
@@ -0,0 +1,80 @@
1
+ import OutputDocument from '../OutputDocument';
2
+ import { saveAs } from 'file-saver';
3
+
4
+ /**
5
+ * @returns {Window}
6
+ */
7
+ const openWindow = () => {
8
+ // we have to open the window immediately and store the reference
9
+ // otherwise popup blockers will stop us
10
+ let win = window.open('', '_blank');
11
+ if (win === null) {
12
+ throw new Error('Open PDF in new window blocked by browser');
13
+ }
14
+
15
+ return win;
16
+ };
17
+
18
+ class OutputDocumentBrowser extends OutputDocument {
19
+
20
+ /**
21
+ * @returns {Promise<Blob>}
22
+ */
23
+ async getBlob() {
24
+ const buffer = await this.getBuffer();
25
+ return new Blob([buffer], { type: 'application/pdf' });
26
+ }
27
+
28
+ /**
29
+ * @param {string} filename
30
+ * @returns {Promise}
31
+ */
32
+ async download(filename = 'file.pdf') {
33
+ const blob = await this.getBlob();
34
+ saveAs(blob, filename);
35
+ }
36
+
37
+ /**
38
+ * @param {Window} win
39
+ * @returns {Promise}
40
+ */
41
+ async open(win = null) {
42
+ if (!win) {
43
+ win = openWindow();
44
+ }
45
+ const blob = await this.getBlob();
46
+ try {
47
+ let urlCreator = window.URL || window.webkitURL;
48
+ let pdfUrl = urlCreator.createObjectURL(blob);
49
+ win.location.href = pdfUrl;
50
+
51
+ /* temporarily disabled
52
+ if (win === window) {
53
+ return;
54
+ } else {
55
+ setTimeout(() => {
56
+ if (win.window === null) { // is closed by AdBlock
57
+ window.location.href = pdfUrl; // open in actual window
58
+ }
59
+ return;
60
+ }, 500);
61
+ }
62
+ */
63
+ } catch (e) {
64
+ win.close();
65
+ throw e;
66
+ }
67
+ }
68
+
69
+ /**
70
+ * @param {Window} win
71
+ * @returns {Promise}
72
+ */
73
+ async print(win = null) {
74
+ const stream = await this.getStream();
75
+ stream.setOpenActionAsPrint();
76
+ await this.open(win);
77
+ }
78
+ }
79
+
80
+ export default OutputDocumentBrowser;
@@ -0,0 +1,27 @@
1
+ var fs = require('fs');
2
+
3
+ var fontContainer = {
4
+ vfs: {
5
+ 'Cairo-Regular.ttf': { data: fs.readFileSync(__dirname + '/../../../fonts/Cairo/Cairo-Regular.ttf', 'base64'), encoding: 'base64' },
6
+ 'Cairo-Bold.ttf': { data: fs.readFileSync(__dirname + '/../../../fonts/Cairo/Cairo-Bold.ttf', 'base64'), encoding: 'base64' },
7
+ 'Cairo-Light.ttf': { data: fs.readFileSync(__dirname + '/../../../fonts/Cairo/Cairo-Light.ttf', 'base64'), encoding: 'base64' },
8
+ 'Cairo-SemiBold.ttf': { data: fs.readFileSync(__dirname + '/../../../fonts/Cairo/Cairo-SemiBold.ttf', 'base64'), encoding: 'base64' }
9
+ },
10
+ fonts: {
11
+ Cairo: {
12
+ normal: 'Cairo-Regular.ttf',
13
+ bold: 'Cairo-Bold.ttf',
14
+ italics: 'Cairo-Light.ttf',
15
+ bolditalics: 'Cairo-SemiBold.ttf'
16
+ }
17
+ }
18
+ };
19
+
20
+ var _global = typeof window === 'object' ? window : typeof global === 'object' ? global : typeof self === 'object' ? self : this;
21
+ if (typeof _global.pdfMake !== 'undefined' && typeof _global.pdfMake.addFontContainer !== 'undefined') {
22
+ _global.pdfMake.addFontContainer(fontContainer);
23
+ }
24
+
25
+ if (typeof module !== 'undefined') {
26
+ module.exports = fontContainer;
27
+ }
@@ -0,0 +1,27 @@
1
+ var fs = require('fs');
2
+
3
+ var fontContainer = {
4
+ vfs: {
5
+ 'Roboto-Regular.ttf': { data: fs.readFileSync(__dirname + '/../../../fonts/Roboto/Roboto-Regular.ttf', 'base64'), encoding: 'base64' },
6
+ 'Roboto-Medium.ttf': { data: fs.readFileSync(__dirname + '/../../../fonts/Roboto/Roboto-Medium.ttf', 'base64'), encoding: 'base64' },
7
+ 'Roboto-Italic.ttf': { data: fs.readFileSync(__dirname + '/../../../fonts/Roboto/Roboto-Italic.ttf', 'base64'), encoding: 'base64' },
8
+ 'Roboto-MediumItalic.ttf': { data: fs.readFileSync(__dirname + '/../../../fonts/Roboto/Roboto-MediumItalic.ttf', 'base64'), encoding: 'base64' }
9
+ },
10
+ fonts: {
11
+ Roboto: {
12
+ normal: 'Roboto-Regular.ttf',
13
+ bold: 'Roboto-Medium.ttf',
14
+ italics: 'Roboto-Italic.ttf',
15
+ bolditalics: 'Roboto-MediumItalic.ttf'
16
+ }
17
+ }
18
+ };
19
+
20
+ var _global = typeof window === 'object' ? window : typeof global === 'object' ? global : typeof self === 'object' ? self : this;
21
+ if (typeof _global.pdfMake !== 'undefined' && typeof _global.pdfMake.addFontContainer !== 'undefined') {
22
+ _global.pdfMake.addFontContainer(fontContainer);
23
+ }
24
+
25
+ if (typeof module !== 'undefined') {
26
+ module.exports = fontContainer;
27
+ }