]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/web/js/ui/default/staff/services/eframe.js
7fdbd0af4b3084531ea1086f5641bf6d5931164b
[Evergreen.git] / Open-ILS / web / js / ui / default / staff / services / eframe.js
1 angular.module('egCoreMod')
2
3 /*
4  * Iframe container for (mostly legacy) embedded interfaces
5  */
6 .directive('egEmbedFrame', function() {
7     return {
8         restrict : 'AE',
9         replace : true,
10         scope : {
11             // URL to load in the embed iframe
12             url : '=',
13
14             // optional hash of functions which augment or override 
15             // the stock xulG functions defined below.
16             handlers : '=?',
17             frame : '=?',
18
19             // called after onload of each new iframe page
20             onchange : '=?',
21
22             // for tweaking height
23             saveSpace : '@',
24             minHeight : '=?',
25
26             // to display button for displaying embedded page
27             // in a new tab
28             allowEscape : '=?'
29         },
30
31         templateUrl : './share/t_eframe',
32
33         link: function (scope, element, attrs) {
34             scope.autoresize = 'autoresize' in attrs;
35             scope.showIframe = true;
36             element.find('iframe').on(
37                 'load',
38                 function() {scope.egEmbedFrameLoader(this)}
39             );
40         },
41
42         controller : 
43                    ['$scope','$window','$location','$q','$timeout','egCore',
44             function($scope , $window , $location , $q , $timeout , egCore) {
45
46             $scope.save_space = $scope.saveSpace ? $scope.saveSpace : 300;
47             // Set the initial iframe height to just under the window height.
48             // leave room for the navbar, padding, margins, etc.
49             $scope.height = $window.outerHeight - $scope.save_space;
50             if ($scope.minHeight && $scope.height < $scope.minHeight) {
51                 $scope.height = $scope.minHeight;
52             }
53
54             // browser client doesn't use cookies, so we don't load the
55             // (at the time of writing, quite limited) angular.cookies
56             // module.  We could load something, but this seems to work
57             // well enough for setting the auth cookie (at least, until 
58             // it doesn't).
59             //
60             // note: document.cookie is smart enough to leave unreferenced
61             // cookies alone, so contrary to how this might look, it's not 
62             // deleting other cookies (anoncache, etc.)
63             
64             // delete any existing ses cookie
65             $window.document.cookie = "ses=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT";
66             // push our authtoken in
67             $window.document.cookie = 'ses=' + egCore.auth.token() + '; path=/; secure'
68
69             // $location has functions for modifying paths and search,
70             // but they all assume you are staying within the angular
71             // app, which we are not.  Build the URLs by hand.
72             function open_tab(path) {
73                 var url = 'https://' + $window.location.hostname + 
74                     egCore.env.basePath + path;
75                 console.debug('egEmbedFrame opening tab ' + url);
76                 $window.open(url, '_blank').focus();
77             }
78
79             // define our own xulG functions to be inserted into the
80             // iframe.  NOTE: window-level functions are bad.  Though
81             // there is probably a way, I was unable to correctly wire
82             // up the iframe onload handler within the controller or link
83             // funcs.  In any event, the code below is meant as a stop-gap
84             // for porting dojo, etc. apps to angular apps and should
85             // eventually go away.
86             // NOTE: catalog integration is not a stop-gap
87
88             $scope.egEmbedFrameLoader = function(iframe) {
89
90                 $scope.frame = {dom:iframe};
91                 $scope.iframe = iframe;
92
93                 if ($scope.autoresize) {
94                     iFrameResize({}, $scope.iframe);
95                 } else {
96                     // Reset the iframe height to the final content height.
97                     if ($scope.height < $scope.iframe.contentWindow.document.body.scrollHeight)
98                         $scope.height = $scope.iframe.contentWindow.document.body.scrollHeight;
99                 }
100
101                 var page = $scope.iframe.contentWindow.location.href;
102                 console.debug('egEmbedFrameLoader(): ' + page);
103
104                 // reload ifram page w/o reloading the entire UI
105                 $scope.reload = function() {
106                     $scope.iframe.contentWindow.location.replace(
107                         $scope.iframe.contentWindow.location);
108                 }
109
110                 $scope.style = function() {
111                     return 'height:' + $scope.height + 'px';
112                 }
113
114                 // tell the iframe'd window its inside the staff client
115                 $scope.iframe.contentWindow.IAMXUL = true;
116
117                 // also tell it it's inside the browser client, which 
118                 // may be needed in a few special cases.
119                 $scope.iframe.contentWindow.IAMBROWSER /* hear me roar */ = true; 
120
121                 // XUL has a dump() function which is occasinally called 
122                 // from embedded browsers.
123                 $scope.iframe.contentWindow.dump = function(msg) {
124                     console.debug('egEmbedFrame:dump(): ' + msg);
125                 }
126
127                 // Adjust the height again if the iframe loads the openils.Util Dojo module
128                 $timeout(function () {
129                     if ($scope.autoresize) return; // let iframe-resizer handle it
130                     if ($scope.iframe.contentWindow.openils && $scope.iframe.contentWindow.openils.Util) {
131
132                         // HACK! for patron reg page
133                         var e = $scope.iframe.contentWindow.document.getElementById('myForm');
134                         var extra = 50;
135                         
136                         // HACK! for vandelay
137                         if (!e) {
138                             e = $scope.iframe.contentWindow.document.getElementById('vl-body-wrapper');
139                             extra = 10000;
140                         }
141
142                         if (!e) {
143                             e = $scope.iframe.contentWindow.document.body;
144                             extra = 0;
145                         }
146
147                         if ($scope.height < e.scrollHeight + extra) {
148                             $scope.iframe.contentWindow.openils.Util.addOnLoad( function() {
149                                 var old_height = $scope.height;
150                                 $scope.height = e.scrollHeight + extra;
151                                 $scope.$apply();
152                             });
153                         }
154                     }
155                 });
156
157                 // define a few commonly used stock xulG handlers. 
158                 
159                 $scope.iframe.contentWindow.xulG = {
160                     // patron search
161                     spawn_search : function(search) {
162                         open_tab('/circ/patron/search?search=' 
163                             + encodeURIComponent(js2JSON(search)));
164                     },
165
166                     // edit an existing user
167                     spawn_editor : function(info) {
168                         if (info.usr) {
169                             open_tab('/circ/patron/register/edit/' + info.usr);
170                         
171                         } else if (info.clone) {
172                             // FIXME: The save-and-clone operation in the
173                             // patron editor results in this action.  
174                             // For some reason, this specific function results
175                             // in a new browser window opening instead of a 
176                             // browser tab.  Possibly this is caused by the 
177                             // fact that the action occurs as a result of a
178                             // button click instead of an href.  *shrug*.
179                             // It's obnoxious.
180                             open_tab('/circ/patron/register/clone/' + info.clone);
181                         } 
182                     },
183
184                     // open a user account
185                     new_patron_tab : function(tab_info, usr_info) {
186                         open_tab('/circ/patron/' + usr_info.id + '/checkout');
187                     },
188
189                     get_barcode_and_settings_async : function(barcode, only_settings) {
190                         if (!barcode) return $q.reject();
191                         var deferred = $q.defer();
192
193                         var barcode_promise = $q.when(barcode);
194                         if (!only_settings) {
195
196                             // first verify / locate the barcode
197                             barcode_promise = egCore.net.request(
198                                 'open-ils.actor',
199                                 'open-ils.actor.get_barcodes',
200                                 egCore.auth.token(), 
201                                 egCore.auth.user().ws_ou(), 'actor', barcode
202                             ).then(function(resp) {
203
204                                 if (!resp || egCore.evt.parse(resp) || !resp.length) {
205                                     console.error('user not found: ' + barcode);
206                                     deferred.reject();
207                                     return null;
208                                 } 
209
210                                 resp = resp[0];
211                                 return barcode = resp.barcode;
212                             });
213                         }
214
215                         barcode_promise.then(function(barcode) {
216                             if (!barcode) return;
217
218                             return egCore.net.request(
219                                 'open-ils.actor',
220                                 'open-ils.actor.user.fleshed.retrieve_by_barcode',
221                                 egCore.auth.token(), barcode);
222
223                         }).then(function(user) {
224                             if (!user) return null;
225
226                             if (e = egCore.evt.parse(user)) {
227                                 console.error('user fetch failed : ' + e.toString());
228                                 deferred.reject();
229                                 return null;
230                             }
231
232                             // copied more or less directly from XUL menu.js
233                             var settings = {};
234                             for(var i = 0; i < user.settings().length; i++) {
235                                 settings[user.settings()[i].name()] = 
236                                     JSON2js(user.settings()[i].value());
237                             }
238
239                             if(!settings['opac.default_phone'] && user.day_phone()) 
240                                 settings['opac.default_phone'] = user.day_phone();
241                             if(!settings['opac.hold_notify'] && settings['opac.hold_notify'] !== '') 
242                                 settings['opac.hold_notify'] = 'email:phone';
243
244                             // Taken from patron/util.js format_name
245                             // FIXME: I18n
246                             var patron_name = 
247                                 ( user.prefix() ? user.prefix() + ' ' : '') +
248                                 user.family_name() + ', ' +
249                                 user.first_given_name() + ' ' +
250                                 ( user.second_given_name() ? user.second_given_name() + ' ' : '' ) +
251                                 ( user.suffix() ? user.suffix() : '');
252
253                             deferred.resolve({
254                                 "barcode": barcode, 
255                                 "settings" : settings, 
256                                 "user_email" : user.email(), 
257                                 "patron_name" : patron_name
258                             });
259                         });
260
261                         return deferred.promise;
262                     }
263                 }
264
265                 if ($scope.handlers) {
266                     $scope.handlers.reload = $scope.reload;
267                     angular.forEach($scope.handlers, function(val, key) {
268                         console.log('eframe applying xulG handlers: ' + key);
269                         $scope.iframe.contentWindow.xulG[key] = val;
270                     });
271                 }
272
273                 if ($scope.onchange) $scope.onchange(page);
274             }
275
276             // open a new tab with the embedded URL
277             $scope.escapeEmbed = function() {
278                 $scope.showIframe = false;
279                 $window.open($scope.iframe.contentWindow.location, '_blank').focus();
280             }
281             $scope.restoreEmbed = function() {
282                 $scope.showIframe = true;
283                 $scope.reload();
284             }
285         }]
286     }
287 })
288
289