Showing
3 changed files
with
57 additions
and
27 deletions
@@ -37,8 +37,7 @@ for documentation. | @@ -37,8 +37,7 @@ for documentation. | ||
37 | 4. For MacOS add printing capability by opening macos directory in XCode | 37 | 4. For MacOS add printing capability by opening macos directory in XCode |
38 | 38 | ||
39 | 5. For the web, a javascript library and a small script has to be added to | 39 | 5. For the web, a javascript library and a small script has to be added to |
40 | - your `web/index.html` file, just before | ||
41 | - `<script src="main.dart.js" type="application/javascript"></script>`: | 40 | + your `web/index.html` file, just before `</head>`: |
42 | 41 | ||
43 | ```html | 42 | ```html |
44 | <script src="//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.8.335/pdf.min.js"></script> | 43 | <script src="//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.8.335/pdf.min.js"></script> |
@@ -43,6 +43,8 @@ class PrintingPlugin extends PrintingPlatform { | @@ -43,6 +43,8 @@ class PrintingPlugin extends PrintingPlatform { | ||
43 | PrintingPlatform.instance = PrintingPlugin(); | 43 | PrintingPlatform.instance = PrintingPlugin(); |
44 | } | 44 | } |
45 | 45 | ||
46 | + static const String _scriptId = '__net_nfet_printing_s__'; | ||
47 | + | ||
46 | static const String _frameId = '__net_nfet_printing__'; | 48 | static const String _frameId = '__net_nfet_printing__'; |
47 | 49 | ||
48 | @override | 50 | @override |
@@ -99,59 +101,76 @@ class PrintingPlugin extends PrintingPlatform { | @@ -99,59 +101,76 @@ class PrintingPlugin extends PrintingPlatform { | ||
99 | final isChrome = js.context['chrome'] != null; | 101 | final isChrome = js.context['chrome'] != null; |
100 | final isSafari = js.context['safari'] != null; | 102 | final isSafari = js.context['safari'] != null; |
101 | final isMobile = userAgent.contains('Mobile'); | 103 | final isMobile = userAgent.contains('Mobile'); |
102 | - // Maybe Firefox will support iframe printing | ||
103 | - // https://bugzilla.mozilla.org/show_bug.cgi?id=911444 | ||
104 | - // final isFirefox = userAgent.contains('Firefox'); | 104 | + final isFirefox = userAgent.contains('Firefox'); |
105 | 105 | ||
106 | - // Chrome and Safari on a desktop computer | ||
107 | - if ((isChrome || isSafari) && !isMobile) { | 106 | + // Chrome, Safari, and Firefox on a desktop computer |
107 | + if ((isChrome || isSafari || isFirefox) && !isMobile) { | ||
108 | final completer = Completer<bool>(); | 108 | final completer = Completer<bool>(); |
109 | final pdfFile = html.Blob( | 109 | final pdfFile = html.Blob( |
110 | - <Uint8List>[Uint8List.fromList(result)], | 110 | + <Uint8List>[result], |
111 | 'application/pdf', | 111 | 'application/pdf', |
112 | ); | 112 | ); |
113 | final pdfUrl = html.Url.createObjectUrl(pdfFile); | 113 | final pdfUrl = html.Url.createObjectUrl(pdfFile); |
114 | final html.HtmlDocument doc = js.context['document']; | 114 | final html.HtmlDocument doc = js.context['document']; |
115 | 115 | ||
116 | + final script = | ||
117 | + doc.getElementById(_scriptId) ?? doc.createElement('script'); | ||
118 | + script.setAttribute('id', _scriptId); | ||
119 | + script.setAttribute('type', 'text/javascript'); | ||
120 | + script.innerText = | ||
121 | + '''function ${_frameId}_print(){var f=document.getElementById('$_frameId');f.focus();f.contentWindow.print();}'''; | ||
122 | + doc.body!.append(script); | ||
123 | + | ||
116 | final frame = doc.getElementById(_frameId) ?? doc.createElement('iframe'); | 124 | final frame = doc.getElementById(_frameId) ?? doc.createElement('iframe'); |
125 | + if (isFirefox) { | ||
126 | + // Set the iframe to be is visible on the page (guaranteed by fixed position) but hidden using opacity 0, because | ||
127 | + // this works in Firefox. The height needs to be sufficient for some part of the document other than the PDF | ||
128 | + // viewer's toolbar to be visible in the page | ||
129 | + frame.setAttribute('style', | ||
130 | + 'width: 1px; height: 100px; position: fixed; left: 0; top: 0; opacity: 0; border-width: 0; margin: 0; padding: 0'); | ||
131 | + } else { | ||
132 | + // Hide the iframe in other browsers | ||
117 | frame.setAttribute( | 133 | frame.setAttribute( |
118 | 'style', | 134 | 'style', |
119 | 'visibility: hidden; height: 0; width: 0; position: absolute;', | 135 | 'visibility: hidden; height: 0; width: 0; position: absolute;', |
120 | // 'height: 400px; width: 600px; position: absolute; z-index: 1000', | 136 | // 'height: 400px; width: 600px; position: absolute; z-index: 1000', |
121 | ); | 137 | ); |
138 | + } | ||
122 | 139 | ||
123 | frame.setAttribute('id', _frameId); | 140 | frame.setAttribute('id', _frameId); |
124 | frame.setAttribute('src', pdfUrl); | 141 | frame.setAttribute('src', pdfUrl); |
142 | + final stopWatch = Stopwatch(); | ||
125 | 143 | ||
126 | html.EventListener? load; | 144 | html.EventListener? load; |
127 | load = (html.Event event) { | 145 | load = (html.Event event) { |
128 | frame.removeEventListener('load', load); | 146 | frame.removeEventListener('load', load); |
129 | - final js.JsObject win = | ||
130 | - js.JsObject.fromBrowserObject(frame)['contentWindow']; | ||
131 | - frame.focus(); | ||
132 | - win.callMethod('print'); | 147 | + Timer(Duration(milliseconds: isSafari ? 500 : 0), () { |
148 | + try { | ||
149 | + stopWatch.start(); | ||
150 | + js.context.callMethod('${_frameId}_print'); | ||
151 | + stopWatch.stop(); | ||
133 | completer.complete(true); | 152 | completer.complete(true); |
153 | + } catch (e) { | ||
154 | + print(e); | ||
155 | + completer.complete(_getPdf(result)); | ||
156 | + } | ||
157 | + }); | ||
134 | }; | 158 | }; |
135 | 159 | ||
136 | frame.addEventListener('load', load); | 160 | frame.addEventListener('load', load); |
137 | 161 | ||
138 | doc.body!.append(frame); | 162 | doc.body!.append(frame); |
139 | - return completer.future; | 163 | + |
164 | + final res = await completer.future; | ||
165 | + // If print() is synchronous | ||
166 | + if (stopWatch.elapsedMilliseconds > 1000) { | ||
167 | + frame.remove(); | ||
168 | + script.remove(); | ||
169 | + } | ||
170 | + return res; | ||
140 | } | 171 | } |
141 | 172 | ||
142 | - // All the others | ||
143 | - final pdfFile = html.Blob( | ||
144 | - <Uint8List>[Uint8List.fromList(result)], | ||
145 | - 'application/pdf', | ||
146 | - ); | ||
147 | - final pdfUrl = html.Url.createObjectUrl(pdfFile); | ||
148 | - final html.HtmlDocument doc = js.context['document']; | ||
149 | - final link = html.AnchorElement(href: pdfUrl); | ||
150 | - link.target = '_blank'; | ||
151 | - doc.body?.append(link); | ||
152 | - link.click(); | ||
153 | - link.remove(); | ||
154 | - return true; | 173 | + return _getPdf(result); |
155 | } | 174 | } |
156 | 175 | ||
157 | @override | 176 | @override |
@@ -163,14 +182,22 @@ class PrintingPlugin extends PrintingPlatform { | @@ -163,14 +182,22 @@ class PrintingPlugin extends PrintingPlatform { | ||
163 | String? body, | 182 | String? body, |
164 | List<String>? emails, | 183 | List<String>? emails, |
165 | ) async { | 184 | ) async { |
185 | + return _getPdf(bytes, filename: filename); | ||
186 | + } | ||
187 | + | ||
188 | + Future<bool> _getPdf(Uint8List bytes, {String? filename}) async { | ||
166 | final pdfFile = html.Blob( | 189 | final pdfFile = html.Blob( |
167 | - <Uint8List>[Uint8List.fromList(bytes)], | 190 | + <Uint8List>[bytes], |
168 | 'application/pdf', | 191 | 'application/pdf', |
169 | ); | 192 | ); |
170 | final pdfUrl = html.Url.createObjectUrl(pdfFile); | 193 | final pdfUrl = html.Url.createObjectUrl(pdfFile); |
171 | final html.HtmlDocument doc = js.context['document']; | 194 | final html.HtmlDocument doc = js.context['document']; |
172 | final link = html.AnchorElement(href: pdfUrl); | 195 | final link = html.AnchorElement(href: pdfUrl); |
196 | + if (filename != null) { | ||
173 | link.download = filename; | 197 | link.download = filename; |
198 | + } else { | ||
199 | + link.target = '_blank'; | ||
200 | + } | ||
174 | doc.body?.append(link); | 201 | doc.body?.append(link); |
175 | link.click(); | 202 | link.click(); |
176 | link.remove(); | 203 | link.remove(); |
-
Please register or login to post a comment