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