]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/web/js/ui/default/staff/services/print.js
d2ffbc95d1c31354332a4151f3ca9169134275f9
[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 = egHatch.hatchAvailable ?
63             service.print_via_hatch(args) :
64             service.print_via_browser(args);
65
66         return promise['finally'](
67             function() { service.clear_print_content() });
68     }
69
70     service.print_via_hatch = function(args) {
71         var promise;
72
73         if (args.content_type == 'text/html') {
74             promise = service.ingest_print_content(
75                 args.content_type, args.content, args.scope);
76         } else {
77             // text content requires no compilation for remote printing.
78             promise = $q.when(args.content);
79         }
80
81         return promise.then(function(html) {
82             return egHatch.remotePrint(
83                 args.context || 'default',
84                 args.content_type, 
85                 html, 
86                 args.show_dialog
87             );
88         });
89     }
90
91     service.print_via_browser = function(args) {
92         var type = args.content_type;
93         var content = args.content;
94         var printScope = args.scope;
95
96         if (type == 'text/csv' || type == 'text/plain') {
97             // preserve newlines, spaces, etc.
98             content = '<pre>' + content + '</pre>';
99         }
100
101         // Fetch the print CSS required for in-browser printing.
102         return $http.get(egEnv.basePath + 'css/print.css')
103         .then(function(response) {
104
105             // Add the bare CSS to the content
106             return '<style type="text/css" media="print">' +
107                   response.data +
108                   '</style>' +
109                   content;
110
111         }).then(function(content) {
112             // Ingest the content into the page DOM.
113             return service.ingest_print_content(type, content, printScope);
114
115         }).then(function() { 
116             $window.print();
117         });
118     }
119
120     // loads an HTML print template by name from the server
121     // If no template is available in local/hatch storage, 
122     // fetch the template as an HTML file from the server.
123     service.getPrintTemplate = function(name) {
124         var deferred = $q.defer();
125
126         egHatch.getItem('eg.print.template.' + name)
127         .then(function(html) {
128
129             if (html) {
130                 // we have a locally stored template
131                 deferred.resolve(html);
132                 return;
133             }
134
135             var path = service.template_base_path + name;
136             console.debug('fetching template ' + path);
137
138             $http.get(path)
139             .success(function(data) { deferred.resolve(data) })
140             .error(function() {
141                 console.error('unable to locate print template: ' + name);
142                 deferred.reject();
143             });
144         });
145
146         return deferred.promise;
147     }
148
149     service.storePrintTemplate = function(name, html) {
150         return egHatch.setItem('eg.print.template.' + name, html);
151     }
152
153     service.getPrintTemplateContext = function(name) {
154         var deferred = $q.defer();
155
156         egHatch.getItem('eg.print.template_context.' + name)
157         .then(
158             function(context) { deferred.resolve(context); },
159             function()        { deferred.resolve('default'); }
160         );
161
162         return deferred.promise;
163     }
164     service.storePrintTemplateContext = function(name, context) {
165         return egHatch.setItem('eg.print.template_context.' + name, context);
166     }
167
168     return service;
169 }])
170
171
172 /**
173  * Container for inserting print data into the browser page.
174  * On insert, $window.print() is called to print the data.
175  * The div housing eg-print-container must apply the correct
176  * print media CSS to ensure this content (and not the rest
177  * of the page) is printed.
178  *
179  * NOTE: There should only ever be 1 egPrintContainer instance per page.
180  * egPrintContainer attaches functions to the egPrint service with
181  * closures around the egPrintContainer instance's $scope (including its
182  * DOM element). Having multiple egPrintContainers could result in chaos.
183  */
184
185 .directive('egPrintContainer', ['$compile', function($compile) {
186     return {
187         restrict : 'AE',
188         scope : {}, // isolate our scope
189         link : function(scope, element, attrs) {
190             scope.elm = element;
191         },
192         controller : 
193                    ['$scope','$q','$window','$timeout','egHatch','egPrint','egEnv',
194             function($scope , $q , $window , $timeout , egHatch , egPrint , egEnv) {
195
196                 egPrint.clear_print_content = function() {
197                     $scope.elm.html('');
198                     $compile($scope.elm.contents())($scope.$new(true));
199                 }
200
201                 // Insert the printable content into the DOM.
202                 // For remote printing, this lets us exract the compiled HTML
203                 // from the DOM.
204                 // For local printing, this lets us print directly from the
205                 // DOM with print CSS.
206                 // Returns a promise reolved with the compiled HTML as a string.
207                 egPrint.ingest_print_content = function(type, content, printScope) {
208                     $scope.elm.html(content);
209
210                     var sub_scope = $scope.$new(true);
211                     angular.forEach(printScope, function(val, key) {
212                         sub_scope[key] = val;
213                     })
214
215                     var resp = $compile($scope.elm.contents())(sub_scope);
216
217                     var deferred = $q.defer();
218                     $timeout(function(){
219                         // give the $digest a chance to complete then
220                         // resolve with the compiled HTML from our
221                         // print container
222
223                         deferred.resolve(
224                             resp.contents()[0].parentNode.innerHTML
225                         );
226                     });
227
228                     return deferred.promise;
229                 }
230             }
231         ]
232     }
233 }])
234