]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/ui/default/staff/services/print.js
webstaff: add support for per-template printer contexts
[working/Evergreen.git] / Open-ILS / web / js / ui / default / staff / services / print.js
1 /**
2  * egPrint : manage print templates, process templates, print content
3  *
4  */
5 angular.module('egCoreMod')
6
7 .factory('egPrint',
8        ['$q','$window','$timeout','$http','egHatch','egAuth','egIDL','egOrg','egEnv',
9 function($q , $window , $timeout , $http , egHatch , egAuth , egIDL , egOrg , egEnv) {
10
11     var service = {};
12
13     service.template_base_path = 'share/print_templates/t_';
14
15     /*
16      * context  : 'default', 'receipt','label', etc. 
17      * scope    : data loaded into the template environment
18      * template : template name (e.g. 'checkout', 'transit_slip'
19      * content  : content to print.  If 'template' is set, content is
20      *            derived from the template.
21      * content_type : 'text/html', 'text/plain', 'text/csv'
22      * show_dialog  : boolean, if true, print dialog is shown.  This setting
23      *                only affects remote printers, since browser printers
24      *                do not allow such control
25      */
26     service.print = function(args) {
27         if (!args) return $q.when();
28
29         if (args.template) {
30             // fetch the template, then proceed to printing
31
32             return service.getPrintTemplate(args.template)
33             .then(function(content) {
34                 args.content = content;
35                 if (!args.content_type) args.content_type = 'html';
36                 service.getPrintTemplateContext(args.template)
37                 .then(function(context) {
38                     args.context = context;
39                     return service.print_content(args);
40                 });
41             });
42
43         } 
44
45         return service.print_content(args);
46     }
47
48     // add commonly used attributes to the print scope
49     service.fleshPrintScope = function(scope) {
50         if (!scope) scope = {};
51         scope.today = new Date().toISOString();
52         scope.staff = egIDL.toHash(egAuth.user());
53         scope.current_location = 
54             egIDL.toHash(egOrg.get(egAuth.user().ws_ou()));
55     }
56
57     // Template has been fetched (or no template needed) 
58     // Process the template and send the result off to the printer.
59     service.print_content = function(args) {
60         service.fleshPrintScope(args.scope);
61
62         var promise;
63         if (args.content_type == 'text/html') {
64
65             // all HTML content is assumed to require compilation, 
66             // regardless of the print destination
67             promise = service.ingest_print_content(
68                 args.content_type, args.content, args.scope);
69
70         } else {
71             // text content does not require compilation for remote printing
72             promise = $q.when(args.content);
73         }
74
75         var context = args.context || 'default';
76
77         return promise.then(function(html) {
78
79             return egHatch.remotePrint(context,
80                 args.content_type, html, args.show_dialog)['catch'](
81
82                 function(msg) {
83                     // remote print not available; 
84
85                     if (egHatch.hatchRequired()) {
86                         console.error("Unable to print data; "
87                          + "hatchRequired=true, but hatch is not connected");
88                          return $q.reject();
89                     }
90
91                     if (args.content_type != 'text/html') {
92                         // text content does require compilation 
93                         // (absorption) for browser printing
94                         return service.ingest_print_content(
95                             args.content_type, args.content, args.scope
96                         ).then(function() { $window.print(); service.clear_print_content(); });
97                     } else {
98                         // HTML content is already ingested and accessible
99                         // within the page to the printer.  
100                         $window.print();
101                         service.clear_print_content();
102                     }
103                 }
104             );
105         });
106     }
107
108     // loads an HTML print template by name from the server
109     // If no template is available in local/hatch storage, 
110     // fetch the template as an HTML file from the server.
111     service.getPrintTemplate = function(name) {
112         var deferred = $q.defer();
113
114         egHatch.getItem('eg.print.template.' + name)
115         .then(function(html) {
116
117             if (html) {
118                 // we have a locally stored template
119                 deferred.resolve(html);
120                 return;
121             }
122
123             var path = service.template_base_path + name;
124             console.debug('fetching template ' + path);
125
126             $http.get(path)
127             .success(function(data) { deferred.resolve(data) })
128             .error(function() {
129                 console.error('unable to locate print template: ' + name);
130                 deferred.reject();
131             });
132         });
133
134         return deferred.promise;
135     }
136
137     service.storePrintTemplate = function(name, html) {
138         return egHatch.setItem('eg.print.template.' + name, html);
139     }
140
141     service.getPrintTemplateContext = function(name) {
142         var deferred = $q.defer();
143
144         egHatch.getItem('eg.print.template_context.' + name)
145         .then(
146             function(context) { deferred.resolve(context); },
147             function()        { deferred.resolve('default'); }
148         );
149
150         return deferred.promise;
151     }
152     service.storePrintTemplateContext = function(name, context) {
153         return egHatch.setItem('eg.print.template_context.' + name, context);
154     }
155
156     return service;
157 }])
158
159
160 /**
161  * Container for inserting print data into the browser page.
162  * On insert, $window.print() is called to print the data.
163  * The div housing eg-print-container must apply the correct
164  * print media CSS to ensure this content (and not the rest
165  * of the page) is printed.
166  */
167
168 // FIXME: only apply print CSS when print commands are issued via the 
169 // print container, otherwise using the browser's native print page 
170 // option will always result in empty pages.  Move the print CSS
171 // out of the standalone CSS file and put it into a template file
172 // for this directive.
173 .directive('egPrintContainer', ['$compile', '$http', function($compile, $http) {
174     return {
175         restrict : 'AE',
176         scope : {}, // isolate our scope
177         link : function(scope, element, attrs) {
178             scope.elm = element;
179         },
180         controller : 
181                    ['$scope','$q','$window','$timeout','egHatch','egPrint','egEnv',
182             function($scope , $q , $window , $timeout , egHatch , egPrint , egEnv) {
183
184                 egPrint.clear_print_content = function() {
185                     $scope.elm.html('');
186                     $compile($scope.elm.contents())($scope.$new(true));
187                 }
188
189                 egPrint.ingest_print_content = function(type, content, printScope) {
190
191                     if (type == 'text/csv' || type == 'text/plain') {
192                         // preserve newlines, spaces, etc.
193                         content = '<pre>' + content + '</pre>';
194                     }
195
196                     return $http.get(egEnv.basePath + 'css/print.css').then(
197                         function(response) {
198                             content = '<style type="text/css" media="print">' +
199                                       response.data +
200                                       '</style>' +
201                                       content;
202                             return finish_ingest_print_content(type, content, printScope);
203                         },
204                         function() {
205                             return finish_ingest_print_content(type, content, printScope);
206                         }
207                     );
208
209                 }
210
211                 function finish_ingest_print_content(type, content, printScope) {
212                     $scope.elm.html(content);
213
214                     var sub_scope = $scope.$new(true);
215                     angular.forEach(printScope, function(val, key) {
216                         sub_scope[key] = val;
217                     })
218
219                     var resp = $compile($scope.elm.contents())(sub_scope);
220
221                     var deferred = $q.defer();
222                     $timeout(function(){
223                         // give the $digest a chance to complete then
224                         // resolve with the compiled HTML from our
225                         // print container
226
227                         deferred.resolve(
228                             resp.contents()[0].parentNode.innerHTML
229                         );
230                     });
231
232                     return deferred.promise;
233                 }
234             }
235         ]
236     }
237 }])
238