printjs-rpk 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/js/init.js ADDED
@@ -0,0 +1,169 @@
1
+ 'use strict'
2
+
3
+ import Browser from './browser'
4
+ import Modal from './modal'
5
+ import Pdf from './pdf'
6
+ import Html from './html'
7
+ import RawHtml from './raw-html'
8
+ import Image from './image'
9
+ import Json from './json'
10
+
11
+ const printTypes = ['pdf', 'html', 'image', 'json', 'raw-html']
12
+
13
+ export default {
14
+ init () {
15
+ const params = {
16
+ printable: null,
17
+ fallbackPrintable: null,
18
+ type: 'pdf',
19
+ header: null,
20
+ headerStyle: 'font-weight: 300;',
21
+ maxWidth: 800,
22
+ properties: null,
23
+ gridHeaderStyle: 'font-weight: bold; padding: 5px; border: 1px solid #dddddd;',
24
+ gridStyle: 'border: 1px solid lightgray; margin-bottom: -1px;',
25
+ showModal: false,
26
+ onError: (error) => { throw error },
27
+ onLoadingStart: null,
28
+ onLoadingEnd: null,
29
+ onPrintDialogClose: () => {},
30
+ onIncompatibleBrowser: () => {},
31
+ modalMessage: 'Retrieving Document...',
32
+ frameId: 'printJS',
33
+ frameRemoveDelay: null,
34
+ printableElement: null,
35
+ documentTitle: 'Document',
36
+ targetStyle: ['clear', 'display', 'width', 'min-width', 'height', 'min-height', 'max-height'],
37
+ targetStyles: ['border', 'box', 'break', 'text-decoration'],
38
+ ignoreElements: [],
39
+ repeatTableHeader: true,
40
+ css: null,
41
+ style: null,
42
+ scanStyles: true,
43
+ base64: false,
44
+
45
+ // Deprecated
46
+ onPdfOpen: null,
47
+ font: 'TimesNewRoman',
48
+ font_size: '12pt',
49
+ honorMarginPadding: true,
50
+ honorColor: false,
51
+ imageStyle: 'max-width: 100%;'
52
+ }
53
+
54
+ // Check if a printable document or object was supplied
55
+ const args = arguments[0]
56
+ if (args === undefined) {
57
+ throw new Error('printJS expects at least 1 attribute.')
58
+ }
59
+
60
+ // Process parameters
61
+ switch (typeof args) {
62
+ case 'string':
63
+ params.printable = encodeURI(args)
64
+ params.fallbackPrintable = params.printable
65
+ params.type = arguments[1] || params.type
66
+ break
67
+ case 'object':
68
+ params.printable = args.printable
69
+ params.fallbackPrintable = typeof args.fallbackPrintable !== 'undefined' ? args.fallbackPrintable : params.printable
70
+ params.fallbackPrintable = params.base64 ? `data:application/pdf;base64,${params.fallbackPrintable}` : params.fallbackPrintable
71
+ for (var k in params) {
72
+ if (k === 'printable' || k === 'fallbackPrintable') continue
73
+
74
+ params[k] = typeof args[k] !== 'undefined' ? args[k] : params[k]
75
+ }
76
+ break
77
+ default:
78
+ throw new Error('Unexpected argument type! Expected "string" or "object", got ' + typeof args)
79
+ }
80
+
81
+ // Validate printable
82
+ if (!params.printable) throw new Error('Missing printable information.')
83
+
84
+ // Validate type
85
+ if (!params.type || typeof params.type !== 'string' || printTypes.indexOf(params.type.toLowerCase()) === -1) {
86
+ throw new Error('Invalid print type. Available types are: pdf, html, image and json.')
87
+ }
88
+
89
+ // Check if we are showing a feedback message to the user (useful for large files)
90
+ if (params.showModal) Modal.show(params)
91
+
92
+ // Check for a print start hook function
93
+ if (params.onLoadingStart) params.onLoadingStart()
94
+
95
+ // To prevent duplication and issues, remove any used printFrame from the DOM
96
+ const usedFrame = document.getElementById(params.frameId)
97
+
98
+ if (usedFrame) usedFrame.parentNode.removeChild(usedFrame)
99
+
100
+ // Create a new iframe for the print job
101
+ const printFrame = document.createElement('iframe')
102
+
103
+ if (Browser.isFirefox()) {
104
+ // Set the iframe to be is visible on the page (guaranteed by fixed position) but hidden using opacity 0, because
105
+ // this works in Firefox. The height needs to be sufficient for some part of the document other than the PDF
106
+ // viewer's toolbar to be visible in the page
107
+ printFrame.setAttribute('style', 'width: 1px; height: 100px; position: fixed; left: 0; top: 0; opacity: 0; border-width: 0; margin: 0; padding: 0')
108
+ } else {
109
+ // Hide the iframe in other browsers
110
+ printFrame.setAttribute('style', 'visibility: hidden; height: 0; width: 0; position: absolute; border: 0')
111
+ }
112
+
113
+ // Set iframe element id
114
+ printFrame.setAttribute('id', params.frameId)
115
+
116
+ // For non pdf printing, pass an html document string to srcdoc (force onload callback)
117
+ if (params.type !== 'pdf') {
118
+ printFrame.srcdoc = '<html><head><title>' + params.documentTitle + '</title>'
119
+
120
+ // Attach css files
121
+ if (params.css) {
122
+ // Add support for single file
123
+ if (!Array.isArray(params.css)) params.css = [params.css]
124
+
125
+ // Create link tags for each css file
126
+ params.css.forEach(file => {
127
+ printFrame.srcdoc += '<link rel="stylesheet" href="' + file + '">'
128
+ })
129
+ }
130
+
131
+ printFrame.srcdoc += '</head><body></body></html>'
132
+ }
133
+
134
+ // Check printable type
135
+ switch (params.type) {
136
+ case 'pdf':
137
+ // Check browser support for pdf and if not supported we will just open the pdf file instead
138
+ if (Browser.isIE()) {
139
+ try {
140
+ console.info('Print.js doesn\'t support PDF printing in Internet Explorer.')
141
+ const win = window.open(params.fallbackPrintable, '_blank')
142
+ win.focus()
143
+ params.onIncompatibleBrowser()
144
+ } catch (error) {
145
+ params.onError(error)
146
+ } finally {
147
+ // Make sure there is no loading modal opened
148
+ if (params.showModal) Modal.close()
149
+ if (params.onLoadingEnd) params.onLoadingEnd()
150
+ }
151
+ } else {
152
+ Pdf.print(params, printFrame)
153
+ }
154
+ break
155
+ case 'image':
156
+ Image.print(params, printFrame)
157
+ break
158
+ case 'html':
159
+ Html.print(params, printFrame)
160
+ break
161
+ case 'raw-html':
162
+ RawHtml.print(params, printFrame)
163
+ break
164
+ case 'json':
165
+ Json.print(params, printFrame)
166
+ break
167
+ }
168
+ }
169
+ }
package/src/js/json.js ADDED
@@ -0,0 +1,109 @@
1
+ import { capitalizePrint, addHeader } from './functions'
2
+ import Print from './print'
3
+
4
+ export default {
5
+ print: (params, printFrame) => {
6
+ // Check if we received proper data
7
+ if (typeof params.printable !== 'object') {
8
+ throw new Error('Invalid javascript data object (JSON).')
9
+ }
10
+
11
+ // Validate repeatTableHeader
12
+ if (typeof params.repeatTableHeader !== 'boolean') {
13
+ throw new Error('Invalid value for repeatTableHeader attribute (JSON).')
14
+ }
15
+
16
+ // Validate properties
17
+ if (!params.properties || !Array.isArray(params.properties)) {
18
+ throw new Error('Invalid properties array for your JSON data.')
19
+ }
20
+
21
+ // We will format the property objects to keep the JSON api compatible with older releases
22
+ params.properties = params.properties.map(property => {
23
+ return {
24
+ field: typeof property === 'object' ? property.field : property,
25
+ displayName: typeof property === 'object' ? property.displayName : property,
26
+ columnSize: typeof property === 'object' && property.columnSize ? property.columnSize + ';' : 100 / params.properties.length + '%;'
27
+ }
28
+ })
29
+
30
+ // Create a print container element
31
+ params.printableElement = document.createElement('div')
32
+
33
+ // Check if we are adding a print header
34
+ if (params.header) {
35
+ addHeader(params.printableElement, params)
36
+ }
37
+
38
+ // Build the printable html data
39
+ params.printableElement.innerHTML += jsonToHTML(params)
40
+
41
+ // Print the json data
42
+ Print.send(params, printFrame)
43
+ }
44
+ }
45
+
46
+ function jsonToHTML (params) {
47
+ // Get the row and column data
48
+ const data = params.printable
49
+ const properties = params.properties
50
+
51
+ // Create a html table
52
+ let htmlData = '<table style="border-collapse: collapse; width: 100%;">'
53
+
54
+ // Check if the header should be repeated
55
+ if (params.repeatTableHeader) {
56
+ htmlData += '<thead>'
57
+ }
58
+
59
+ // Add the table header row
60
+ htmlData += '<tr>'
61
+
62
+ // Add the table header columns
63
+ for (let a = 0; a < properties.length; a++) {
64
+ htmlData += '<th style="width:' + properties[a].columnSize + ';' + params.gridHeaderStyle + '">' + capitalizePrint(properties[a].displayName) + '</th>'
65
+ }
66
+
67
+ // Add the closing tag for the table header row
68
+ htmlData += '</tr>'
69
+
70
+ // If the table header is marked as repeated, add the closing tag
71
+ if (params.repeatTableHeader) {
72
+ htmlData += '</thead>'
73
+ }
74
+
75
+ // Create the table body
76
+ htmlData += '<tbody>'
77
+
78
+ // Add the table data rows
79
+ for (let i = 0; i < data.length; i++) {
80
+ // Add the row starting tag
81
+ htmlData += '<tr>'
82
+
83
+ // Print selected properties only
84
+ for (let n = 0; n < properties.length; n++) {
85
+ let stringData = data[i]
86
+
87
+ // Support nested objects
88
+ const property = properties[n].field.split('.')
89
+ if (property.length > 1) {
90
+ for (let p = 0; p < property.length; p++) {
91
+ stringData = stringData[property[p]]
92
+ }
93
+ } else {
94
+ stringData = stringData[properties[n].field]
95
+ }
96
+
97
+ // Add the row contents and styles
98
+ htmlData += '<td style="width:' + properties[n].columnSize + params.gridStyle + '">' + stringData + '</td>'
99
+ }
100
+
101
+ // Add the row closing tag
102
+ htmlData += '</tr>'
103
+ }
104
+
105
+ // Add the table and body closing tags
106
+ htmlData += '</tbody></table>'
107
+
108
+ return htmlData
109
+ }
@@ -0,0 +1,62 @@
1
+ const Modal = {
2
+ show (params) {
3
+ // Build modal
4
+ const modalStyle = 'font-family:sans-serif; ' +
5
+ 'display:table; ' +
6
+ 'text-align:center; ' +
7
+ 'font-weight:300; ' +
8
+ 'font-size:30px; ' +
9
+ 'left:0; top:0;' +
10
+ 'position:fixed; ' +
11
+ 'z-index: 9990;' +
12
+ 'color: #0460B5; ' +
13
+ 'width: 100%; ' +
14
+ 'height: 100%; ' +
15
+ 'background-color:rgba(255,255,255,.9);' +
16
+ 'transition: opacity .3s ease;'
17
+
18
+ // Create wrapper
19
+ const printModal = document.createElement('div')
20
+ printModal.setAttribute('style', modalStyle)
21
+ printModal.setAttribute('id', 'printJS-Modal')
22
+
23
+ // Create content div
24
+ const contentDiv = document.createElement('div')
25
+ contentDiv.setAttribute('style', 'display:table-cell; vertical-align:middle; padding-bottom:100px;')
26
+
27
+ // Add close button (requires print.css)
28
+ const closeButton = document.createElement('div')
29
+ closeButton.setAttribute('class', 'printClose')
30
+ closeButton.setAttribute('id', 'printClose')
31
+ contentDiv.appendChild(closeButton)
32
+
33
+ // Add spinner (requires print.css)
34
+ const spinner = document.createElement('span')
35
+ spinner.setAttribute('class', 'printSpinner')
36
+ contentDiv.appendChild(spinner)
37
+
38
+ // Add message
39
+ const messageNode = document.createTextNode(params.modalMessage)
40
+ contentDiv.appendChild(messageNode)
41
+
42
+ // Add contentDiv to printModal
43
+ printModal.appendChild(contentDiv)
44
+
45
+ // Append print modal element to document body
46
+ document.getElementsByTagName('body')[0].appendChild(printModal)
47
+
48
+ // Add event listener to close button
49
+ document.getElementById('printClose').addEventListener('click', function () {
50
+ Modal.close()
51
+ })
52
+ },
53
+ close () {
54
+ const printModal = document.getElementById('printJS-Modal')
55
+
56
+ if (printModal) {
57
+ printModal.parentNode.removeChild(printModal)
58
+ }
59
+ }
60
+ }
61
+
62
+ export default Modal
package/src/js/pdf.js ADDED
@@ -0,0 +1,57 @@
1
+ import Print from './print'
2
+ import { cleanUp } from './functions'
3
+
4
+ export default {
5
+ print: (params, printFrame) => {
6
+ // Check if we have base64 data
7
+ if (params.base64) {
8
+ const bytesArray = Uint8Array.from(atob(params.printable), c => c.charCodeAt(0))
9
+ createBlobAndPrint(params, printFrame, bytesArray)
10
+ return
11
+ }
12
+
13
+ // Format pdf url
14
+ params.printable = /^(blob|http|\/\/)/i.test(params.printable)
15
+ ? params.printable
16
+ : window.location.origin + (params.printable.charAt(0) !== '/' ? '/' + params.printable : params.printable)
17
+
18
+ // Get the file through a http request (Preload)
19
+ const req = new window.XMLHttpRequest()
20
+ req.responseType = 'arraybuffer'
21
+
22
+ req.addEventListener('error', () => {
23
+ cleanUp(params)
24
+ params.onError(req.statusText, req)
25
+
26
+ // Since we don't have a pdf document available, we will stop the print job
27
+ })
28
+
29
+ req.addEventListener('load', () => {
30
+ // Check for errors
31
+ if ([200, 201].indexOf(req.status) === -1) {
32
+ cleanUp(params)
33
+ params.onError(req.statusText, req)
34
+
35
+ // Since we don't have a pdf document available, we will stop the print job
36
+ return
37
+ }
38
+
39
+ // Print requested document
40
+ createBlobAndPrint(params, printFrame, req.response)
41
+ })
42
+
43
+ req.open('GET', params.printable, true)
44
+ req.send()
45
+ }
46
+ }
47
+
48
+ function createBlobAndPrint (params, printFrame, data) {
49
+ // Pass response or base64 data to a blob and create a local object url
50
+ let localPdf = new window.Blob([data], { type: 'application/pdf' })
51
+ localPdf = window.URL.createObjectURL(localPdf)
52
+
53
+ // Set iframe src with pdf document url
54
+ printFrame.setAttribute('src', localPdf)
55
+
56
+ Print.send(params, printFrame)
57
+ }
@@ -0,0 +1,102 @@
1
+ import Browser from './browser'
2
+ import { cleanUp } from './functions'
3
+
4
+ const Print = {
5
+ send: (params, printFrame) => {
6
+ // Append iframe element to document body
7
+ document.getElementsByTagName('body')[0].appendChild(printFrame)
8
+
9
+ // Get iframe element
10
+ const iframeElement = document.getElementById(params.frameId)
11
+
12
+ // Wait for iframe to load all content
13
+ iframeElement.onload = () => {
14
+ if (params.type === 'pdf') {
15
+ // Add a delay for Firefox. In my tests, 1000ms was sufficient but 100ms was not
16
+ if (Browser.isFirefox()) {
17
+ setTimeout(() => performPrint(iframeElement, params), 1000)
18
+ } else {
19
+ performPrint(iframeElement, params)
20
+ }
21
+ return
22
+ }
23
+
24
+ // Get iframe element document
25
+ let printDocument = (iframeElement.contentWindow || iframeElement.contentDocument)
26
+ if (printDocument.document) printDocument = printDocument.document
27
+
28
+ // Append printable element to the iframe body
29
+ printDocument.body.appendChild(params.printableElement)
30
+
31
+ // Add custom style
32
+ if (params.type !== 'pdf' && params.style) {
33
+ // Create style element
34
+ const style = document.createElement('style')
35
+ style.innerHTML = params.style
36
+
37
+ // Append style element to iframe's head
38
+ printDocument.head.appendChild(style)
39
+ }
40
+
41
+ // If printing images, wait for them to load inside the iframe
42
+ const images = printDocument.getElementsByTagName('img')
43
+
44
+ if (images.length > 0) {
45
+ loadIframeImages(Array.from(images)).then(() => performPrint(iframeElement, params))
46
+ } else {
47
+ performPrint(iframeElement, params)
48
+ }
49
+ }
50
+ }
51
+ }
52
+
53
+ function performPrint (iframeElement, params) {
54
+ try {
55
+ iframeElement.focus()
56
+
57
+ // If Edge or IE, try catch with execCommand
58
+ if (Browser.isEdge() || Browser.isIE()) {
59
+ try {
60
+ iframeElement.contentWindow.document.execCommand('print', false, null)
61
+ } catch (e) {
62
+ iframeElement.contentWindow.print()
63
+ }
64
+ } else {
65
+ // Other browsers
66
+ iframeElement.contentWindow.print()
67
+ }
68
+ } catch (error) {
69
+ params.onError(error)
70
+ } finally {
71
+ if (Browser.isFirefox()) {
72
+ // Move the iframe element off-screen and make it invisible
73
+ iframeElement.style.visibility = 'hidden'
74
+ iframeElement.style.left = '-1px'
75
+ }
76
+
77
+ cleanUp(params)
78
+ }
79
+ }
80
+
81
+ function loadIframeImages (images) {
82
+ const promises = images.map(image => {
83
+ if (image.src && image.src !== window.location.href) {
84
+ return loadIframeImage(image)
85
+ }
86
+ })
87
+
88
+ return Promise.all(promises)
89
+ }
90
+
91
+ function loadIframeImage (image) {
92
+ return new Promise(resolve => {
93
+ const pollImage = () => {
94
+ !image || typeof image.naturalWidth === 'undefined' || image.naturalWidth === 0 || !image.complete
95
+ ? setTimeout(pollImage, 500)
96
+ : resolve()
97
+ }
98
+ pollImage()
99
+ })
100
+ }
101
+
102
+ export default Print
@@ -0,0 +1,15 @@
1
+ import Print from './print'
2
+
3
+ export default {
4
+ print: (params, printFrame) => {
5
+ // Create printable element (container)
6
+ params.printableElement = document.createElement('div')
7
+ params.printableElement.setAttribute('style', 'width:100%')
8
+
9
+ // Set our raw html as the printable element inner html content
10
+ params.printableElement.innerHTML = params.printable
11
+
12
+ // Print html contents
13
+ Print.send(params, printFrame)
14
+ }
15
+ }
@@ -0,0 +1,14 @@
1
+ /*
2
+ |--------------------------------------------------------------------------
3
+ | Modules
4
+ |--------------------------------------------------------------------------
5
+ */
6
+ @import './modules/colors';
7
+
8
+ /*
9
+ |--------------------------------------------------------------------------
10
+ | Partials
11
+ |--------------------------------------------------------------------------
12
+ */
13
+ @import './partials/modal';
14
+ @import './partials/spinner';
@@ -0,0 +1,10 @@
1
+ $blue: hsl(209, 96%, 36%);
2
+ $white: hsl(0, 0%, 100%);
3
+
4
+ /*
5
+ |--------------------------------------------------------------------------
6
+ | Aliases
7
+ |--------------------------------------------------------------------------
8
+ */
9
+ $primary: $blue;
10
+ $bg-color: rgba($white, .9);
@@ -0,0 +1,41 @@
1
+ .printModal {
2
+ font-family:sans-serif;
3
+ display:flex;
4
+ text-align:center;
5
+ font-weight:300;
6
+ font-size:30px;
7
+ left:0;
8
+ top:0;
9
+ position:absolute;
10
+ color: $primary;
11
+ width: 100%;
12
+ height: 100%;
13
+ background-color: $bg-color;
14
+ }
15
+
16
+ /*
17
+ |--------------------------------------------------------------------------
18
+ | Close Button
19
+ |--------------------------------------------------------------------------
20
+ */
21
+ .printClose {
22
+ position:absolute;
23
+ right:10px;
24
+ top:10px;
25
+ }
26
+
27
+ .printClose:before {
28
+ content: "\00D7";
29
+ font-family: "Helvetica Neue", sans-serif;
30
+ font-weight: 100;
31
+ line-height: 1px;
32
+ padding-top: 0.5em;
33
+ display: block;
34
+ font-size: 2em;
35
+ text-indent: 1px;
36
+ overflow: hidden;
37
+ height: 1.25em;
38
+ width: 1.25em;
39
+ text-align: center;
40
+ cursor: pointer;
41
+ }
@@ -0,0 +1,46 @@
1
+ .printSpinner {
2
+ margin-top: 3px;
3
+ margin-left: -40px;
4
+ position: absolute;
5
+ display: inline-block;
6
+ width: 25px;
7
+ height: 25px;
8
+ border: 2px solid $primary;
9
+ border-radius: 50%;
10
+ animation: spin 0.75s infinite linear;
11
+ }
12
+
13
+ .printSpinner::before, .printSpinner::after {
14
+ left: -2px;
15
+ top: -2px;
16
+ display: none;
17
+ position: absolute;
18
+ content: '';
19
+ width: inherit;
20
+ height: inherit;
21
+ border: inherit;
22
+ border-radius: inherit;
23
+ }
24
+
25
+ .printSpinner, .printSpinner::before, .printSpinner::after {
26
+ display: inline-block;
27
+ border-color: transparent;
28
+ border-top-color: $primary;
29
+ animation-duration: 1.2s;
30
+ }
31
+ .printSpinner::before {
32
+ transform: rotate(120deg);
33
+ }
34
+ .printSpinner::after {
35
+ transform: rotate(240deg);
36
+ }
37
+
38
+ /* Keyframes for the animation */
39
+ @keyframes spin {
40
+ from {
41
+ transform: rotate(0deg);
42
+ }
43
+ to {
44
+ transform: rotate(360deg);
45
+ }
46
+ }