2 * egPrint : manage print templates, process templates, print content
5 angular.module('egCoreMod')
8 ['$q','$window','$timeout','$http','egHatch','egAuth','egIDL','egOrg','egEnv',
9 function($q , $window , $timeout , $http , egHatch , egAuth , egIDL , egOrg , egEnv) {
13 'circ.staff_client.receipt.alert_text',
14 'circ.staff_client.receipt.event_text',
15 'circ.staff_client.receipt.footer_text',
16 'circ.staff_client.receipt.header_text',
17 'circ.staff_client.receipt.notice_text',
23 service.template_base_path = 'share/print_templates/t_';
26 * context : 'default', 'receipt','label', etc.
27 * scope : data loaded into the template environment
28 * template : template name (e.g. 'checkout', 'transit_slip'
29 * content : content to print. If 'template' is set, content is
30 * derived from the template.
31 * content_type : 'text/html', 'text/plain', 'text/csv'
32 * show_dialog : boolean, if true, print dialog is shown. This setting
33 * only affects remote printers, since browser printers
34 * do not allow such control
36 service.print = function(args) {
37 if (!args) return $q.when();
40 // fetch the template, then proceed to printing
42 return service.getPrintTemplate(args.template)
43 .then(function(content) {
44 args.content = content;
45 if (!args.content_type) args.content_type = 'text/html';
46 service.getPrintTemplateContext(args.template)
47 .then(function(context) {
48 args.context = context;
49 return service.print_content(args);
55 return service.print_content(args);
58 // add commonly used attributes to the print scope
59 service.fleshPrintScope = function(scope) {
60 if (!scope) scope = {};
61 scope.today = new Date().toISOString();
64 scope.staff = egIDL.toHash(egAuth.user());
65 scope.current_location =
66 egIDL.toHash(egOrg.get(egAuth.user().ws_ou()));
69 return service.fetch_includes(scope);
72 // Retrieve org settings for receipt includes and add them
73 // to the print scope under scope.includes.<name>
74 service.fetch_includes = function(scope) {
75 // org settings for the workstation org are cached
76 // within egOrg. No need to cache them locally.
77 return egOrg.settings(service.include_settings).then(
81 angular.forEach(settings, function(val, key) {
82 // strip the settings prefix so you just have
83 // e.g. scope.includes.alert_text
84 scope.includes[key.split(/\./).pop()] = val;
90 service.last_print = {};
92 // Template has been fetched (or no template needed)
93 // Process the template and send the result off to the printer.
94 service.print_content = function(args) {
96 if (args.context === 'no-print') {
97 console.debug('Skipping print request with No-Print context');
101 return service.fleshPrintScope(args.scope)
102 .then(function() { return egHatch.usePrinting(); })
103 .then(function(useHatch) {
104 if (!useHatch) { return false; }
105 return egHatch.getPrintConfig(args.context || 'default')
106 .then(function(config) {
107 // Avoid using Hatch if the print context calls
108 // for native browser printing.
109 return config.printer != 'hatch_browser_printing';
112 .then(function(useHatch) {
113 var promise = useHatch ?
114 service.print_via_hatch(args) :
115 service.print_via_browser(args);
117 return promise['finally'](
118 function() { service.clear_print_content() });
122 service.print_via_hatch = function(args) {
125 if (args.content_type == 'text/html') {
126 promise = service.ingest_print_content(
127 args.content_type, args.content, args.scope
128 ).then(function(html) {
129 // For good measure, wrap the compiled HTML in container tags.
130 return "<html><body>" + html + "</body></html>";
133 // text content requires no compilation for remote printing.
134 promise = $q.when(args.content);
137 return promise.then(function(content) {
138 service.last_print.content = content;
139 service.last_print.context = args.context || 'default';
140 service.last_print.content_type = args.content_type;
141 service.last_print.show_dialog = args.show_dialog;
143 egHatch.setLocalItem('eg.print.last_printed', service.last_print);
145 return service._remotePrint();
149 service._remotePrint = function () {
150 return egHatch.remotePrint(
151 service.last_print.context,
152 service.last_print.content_type,
153 service.last_print.content,
154 service.last_print.show_dialog
158 service.print_via_browser = function(args) {
159 var type = args.content_type;
160 var content = args.content;
161 var printScope = args.scope;
163 if (type == 'text/csv' || type == 'text/plain') {
164 // preserve newlines, spaces, etc.
165 content = '<pre>' + content + '</pre>';
168 // Fetch the print CSS required for in-browser printing.
169 return $http.get(egEnv.basePath + 'css/print.css')
170 .then(function(response) {
172 // Add the bare CSS to the content
173 return '<style type="text/css" media="print">' +
178 }).then(function(content) {
180 // Ingest the content into the page DOM.
181 return service.ingest_print_content(type, content, printScope);
183 }).then(function(html) {
185 // Note browser ignores print context
186 service.last_print.content = html;
187 service.last_print.content_type = type;
188 egHatch.setLocalItem('eg.print.last_printed', service.last_print);
194 service.reprintLast = function () {
195 var last = egHatch.getLocalItem('eg.print.last_printed');
196 if (!last || !last.content) { return $q.reject(); }
198 service.last_print = last;
200 return egHatch.usePrinting().then(function(useHatch) {
203 return service._remotePrint();
205 return service.ingest_print_content(
206 null, null, null, service.last_print.content)
207 .then(function() { $window.print(); });
210 }).finally(function() { service.clear_print_content(); });
213 // loads an HTML print template by name from the server
214 // If no template is available in local/hatch storage,
215 // fetch the template as an HTML file from the server.
216 service.getPrintTemplate = function(name) {
217 var deferred = $q.defer();
219 egHatch.getItem('eg.print.template.' + name)
220 .then(function(html) {
223 // we have a locally stored template
224 deferred.resolve(html);
228 var path = service.template_base_path + name;
229 console.debug('fetching template ' + path);
231 $http.get(path).then(
232 function(data) { deferred.resolve(data.data) },
234 console.error('unable to locate print template: ' + name);
240 return deferred.promise;
243 service.storePrintTemplate = function(name, html) {
244 return egHatch.setItem('eg.print.template.' + name, html);
247 service.removePrintTemplate = function(name) {
248 return egHatch.removeItem('eg.print.template.' + name);
251 service.getPrintTemplateContext = function(name) {
252 var deferred = $q.defer();
254 egHatch.getItem('eg.print.template_context.' + name)
256 function(context) { deferred.resolve(context); },
257 function() { deferred.resolve('default'); }
260 return deferred.promise;
262 service.storePrintTemplateContext = function(name, context) {
263 return egHatch.setItem('eg.print.template_context.' + name, context);
265 service.removePrintTemplateContext = function(name) {
266 return egHatch.removeItem('eg.print.template_context.' + name);
274 * Container for inserting print data into the browser page.
275 * On insert, $window.print() is called to print the data.
276 * The div housing eg-print-container must apply the correct
277 * print media CSS to ensure this content (and not the rest
278 * of the page) is printed.
280 * NOTE: There should only ever be 1 egPrintContainer instance per page.
281 * egPrintContainer attaches functions to the egPrint service with
282 * closures around the egPrintContainer instance's $scope (including its
283 * DOM element). Having multiple egPrintContainers could result in chaos.
286 .directive('egPrintContainer', ['$compile', function($compile) {
289 scope : {}, // isolate our scope
290 link : function(scope, element, attrs) {
294 ['$scope','$q','$window','$timeout','egHatch','egPrint','egEnv',
295 function($scope , $q , $window , $timeout , egHatch , egPrint , egEnv) {
297 egPrint.clear_print_content = function() {
299 $compile($scope.elm.contents())($scope.$new(true));
302 // Insert the printable content into the DOM.
303 // For remote printing, this lets us exract the compiled HTML
305 // For local printing, this lets us print directly from the
306 // DOM with print CSS.
307 // Returns a promise reolved with the compiled HTML as a string.
309 // If a pre-compiled HTML string is provided, it's inserted
310 // as-is into the DOM for browser printing without any
311 // additional interpolation. This is useful for reprinting,
312 // previously compiled content.
313 egPrint.ingest_print_content =
314 function(type, content, printScope, compiledHtml) {
317 $scope.elm.html(compiledHtml);
318 return $q.when(compiledHtml);
321 $scope.elm.html(content);
323 var sub_scope = $scope.$new(true);
324 angular.forEach(printScope, function(val, key) {
325 sub_scope[key] = val;
328 var resp = $compile($scope.elm.contents())(sub_scope);
331 var deferred = $q.defer();
333 // give the $digest a chance to complete then resolve
334 // with the compiled HTML from our print container
335 deferred.resolve($scope.elm.html());
338 return deferred.promise;