1 angular.module('egCoreMod')
4 * Iframe container for (mostly legacy) embedded interfaces
6 .directive('egEmbedFrame', function() {
11 // URL to load in the embed iframe
14 // optional hash of functions which augment or override
15 // the stock xulG functions defined below.
19 // called after onload of each new iframe page
22 // called after egFrameEmbedLoader, during link phase
25 // for tweaking height
29 // to display button for displaying embedded page
34 templateUrl : './share/t_eframe',
36 link: function (scope, element, attrs) {
37 scope.autoresize = 'autoresize' in attrs;
38 scope.showIframe = true;
39 // well, I *might* embed XUL; in any event, this gives a way
40 // for things like Dojo widgets to detect whether they are
41 // running in an eframe before the frame load has finished.
42 window.IEMBEDXUL = true;
43 element.find('iframe').on(
46 scope.egEmbedFrameLoader(this);
47 if (scope.afterload) this.contentWindow[scope.afterload]();
53 ['$scope','$window','$location','$q','$timeout','egCore',
54 function($scope , $window , $location , $q , $timeout , egCore) {
56 $scope.save_space = $scope.saveSpace ? $scope.saveSpace : 300;
57 // Set the initial iframe height to just under the window height.
58 // leave room for the navbar, padding, margins, etc.
59 $scope.height = $window.outerHeight - $scope.save_space;
60 if ($scope.minHeight && $scope.height < $scope.minHeight) {
61 $scope.height = $scope.minHeight;
64 // browser client doesn't use cookies, so we don't load the
65 // (at the time of writing, quite limited) angular.cookies
66 // module. We could load something, but this seems to work
67 // well enough for setting the auth cookie (at least, until
70 // note: document.cookie is smart enough to leave unreferenced
71 // cookies alone, so contrary to how this might look, it's not
72 // deleting other cookies (anoncache, etc.)
74 // delete any existing ses cookie
75 $window.document.cookie = "ses=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT";
76 // push our authtoken in
77 $window.document.cookie = 'ses=' + egCore.auth.token() + '; path=/; secure'
79 // $location has functions for modifying paths and search,
80 // but they all assume you are staying within the angular
81 // app, which we are not. Build the URLs by hand.
82 function open_tab(path) {
83 var url = 'https://' + $window.location.hostname +
84 egCore.env.basePath + path;
85 console.debug('egEmbedFrame opening tab ' + url);
86 $window.open(url, '_blank').focus();
89 // define our own xulG functions to be inserted into the
90 // iframe. NOTE: window-level functions are bad. Though
91 // there is probably a way, I was unable to correctly wire
92 // up the iframe onload handler within the controller or link
93 // funcs. In any event, the code below is meant as a stop-gap
94 // for porting dojo, etc. apps to angular apps and should
95 // eventually go away.
96 // NOTE: catalog integration is not a stop-gap
98 $scope.egEmbedFrameLoader = function(iframe) {
100 $scope.frame = {dom:iframe};
101 $scope.iframe = iframe;
103 if ($scope.autoresize) {
104 iFrameResize({}, $scope.iframe);
106 // Reset the iframe height to the final content height.
107 if ($scope.height < $scope.iframe.contentWindow.document.body.scrollHeight)
108 $scope.height = $scope.iframe.contentWindow.document.body.scrollHeight;
111 var page = $scope.iframe.contentWindow.location.href;
112 console.debug('egEmbedFrameLoader(): ' + page);
114 if (page.match(/eg\/staff\/loading$/)) { // loading page
116 // If we have a startup-time URL, apply it now.
118 console.debug('Applying initial URL: ' + $scope.url);
119 iframe.contentWindow.location.href = $scope.url;
122 // Watch for future URL changes
123 $scope.$watch('url', function(newVal, oldVal) {
124 if (newVal && newVal != oldVal) {
125 iframe.contentWindow.location.href = newVal;
129 // Nothing more is needed until the iframe is
130 // loaded once more with a real URL.
134 // reload ifram page w/o reloading the entire UI
135 $scope.reload = function() {
136 $scope.iframe.contentWindow.location.replace(
137 $scope.iframe.contentWindow.location);
140 $scope.style = function() {
141 return 'height:' + $scope.height + 'px';
144 // tell the iframe'd window its inside the staff client
145 $scope.iframe.contentWindow.IAMXUL = true;
147 // also tell it it's inside the browser client, which
148 // may be needed in a few special cases.
149 $scope.iframe.contentWindow.IAMBROWSER /* hear me roar */ = true;
151 // XUL has a dump() function which is occasinally called
152 // from embedded browsers.
153 $scope.iframe.contentWindow.dump = function(msg) {
154 console.debug('egEmbedFrame:dump(): ' + msg);
157 // Adjust the height again if the iframe loads the openils.Util Dojo module
158 $timeout(function () {
159 if ($scope.autoresize) return; // let iframe-resizer handle it
160 if ($scope.iframe.contentWindow.openils && $scope.iframe.contentWindow.openils.Util) {
162 // HACK! for patron reg page
163 var e = $scope.iframe.contentWindow.document.getElementById('myForm');
166 // HACK! for vandelay
168 e = $scope.iframe.contentWindow.document.getElementById('vl-body-wrapper');
173 e = $scope.iframe.contentWindow.document.body;
177 if ($scope.height < e.scrollHeight + extra) {
178 $scope.iframe.contentWindow.openils.Util.addOnLoad( function() {
179 var old_height = $scope.height;
180 $scope.height = e.scrollHeight + extra;
187 // define a few commonly used stock xulG handlers.
189 $scope.iframe.contentWindow.xulG = {
191 spawn_search : function(search) {
192 open_tab('/circ/patron/search?search='
193 + encodeURIComponent(js2JSON(search)));
196 // edit an existing user
197 spawn_editor : function(info) {
199 open_tab('/circ/patron/register/edit/' + info.usr);
201 } else if (info.clone) {
202 // FIXME: The save-and-clone operation in the
203 // patron editor results in this action.
204 // For some reason, this specific function results
205 // in a new browser window opening instead of a
206 // browser tab. Possibly this is caused by the
207 // fact that the action occurs as a result of a
208 // button click instead of an href. *shrug*.
210 open_tab('/circ/patron/register/clone/' + info.clone);
214 // open a user account
215 new_patron_tab : function(tab_info, usr_info) {
216 open_tab('/circ/patron/' + usr_info.id + '/checkout');
219 get_barcode_and_settings_async : function(barcode, only_settings) {
220 if (!barcode) return $q.reject();
221 var deferred = $q.defer();
223 var barcode_promise = $q.when(barcode);
224 if (!only_settings) {
226 // first verify / locate the barcode
227 barcode_promise = egCore.net.request(
229 'open-ils.actor.get_barcodes',
231 egCore.auth.user().ws_ou(), 'actor', barcode
232 ).then(function(resp) {
234 if (!resp || egCore.evt.parse(resp) || !resp.length) {
235 console.error('user not found: ' + barcode);
241 return barcode = resp.barcode;
245 barcode_promise.then(function(barcode) {
246 if (!barcode) return;
248 return egCore.net.request(
250 'open-ils.actor.user.fleshed.retrieve_by_barcode',
251 egCore.auth.token(), barcode);
253 }).then(function(user) {
254 if (!user) return null;
256 if (e = egCore.evt.parse(user)) {
257 console.error('user fetch failed : ' + e.toString());
262 egCore.org.settings(['circ.staff_placed_holds_fallback_to_ws_ou'])
263 .then(function(auth_usr_aous){
265 // copied more or less directly from XUL menu.js
267 for(var i = 0; i < user.settings().length; i++) {
268 settings[user.settings()[i].name()] =
269 JSON2js(user.settings()[i].value());
272 // find applicable YAOUSes for staff-placed holds
273 var requestor = egCore.auth.user();
274 var pickup_lib = user.home_ou(); // default to home ou
275 if (requestor.id() !== user.id()){
276 // this is a staff-placed hold, optionally default to ws ou
277 if (auth_usr_aous['circ.staff_placed_holds_fallback_to_ws_ou']){
278 pickup_lib = requestor.ws_ou();
282 if(!settings['opac.default_phone'] && user.day_phone())
283 settings['opac.default_phone'] = user.day_phone();
284 if(!settings['opac.hold_notify'] && settings['opac.hold_notify'] !== '')
285 settings['opac.hold_notify'] = 'email:phone';
287 // Taken from patron/util.js format_name
290 ( user.prefix() ? user.prefix() + ' ' : '') +
291 user.family_name() + ', ' +
292 user.first_given_name() + ' ' +
293 ( user.second_given_name() ? user.second_given_name() + ' ' : '' ) +
294 ( user.suffix() ? user.suffix() : '');
298 "pickup_lib": pickup_lib,
299 "settings" : settings,
300 "user_email" : user.email(),
301 "patron_name" : patron_name
306 return deferred.promise;
310 if ($scope.handlers) {
311 $scope.handlers.reload = $scope.reload;
312 angular.forEach($scope.handlers, function(val, key) {
313 console.log('eframe applying xulG handlers: ' + key);
314 $scope.iframe.contentWindow.xulG[key] = val;
318 if ($scope.onchange) $scope.onchange(page);
321 // open a new tab with the embedded URL
322 $scope.escapeEmbed = function() {
323 $scope.showIframe = false;
324 $window.open($scope.iframe.contentWindow.location, '_blank').focus();
326 $scope.restoreEmbed = function() {
327 $scope.showIframe = true;