]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/web/opac/common/js/opac_utils.js
User activity tracking: ingress, auth.verify, and login agent
[Evergreen.git] / Open-ILS / web / opac / common / js / opac_utils.js
1 /* - Request ------------------------------------------------------------- */
2
3
4 /* define it again here for pages that don't load RemoteRequest */
5 function isXUL() { try { if(IAMXUL) return true;}catch(e){return false;}; }
6
7
8 var __ilsEvent; /* the last event the occurred */
9
10 var DEBUGSLIM;
11 function Request(type) {
12
13         var s = type.split(":");
14         if(s[2] == "1" && isXUL()) s[1] += ".staff";
15         this.request = new RemoteRequest(s[0], s[1]);
16         var p = [];
17
18         if(isXUL()) {
19                 if(!location.href.match(/^https:/))
20                         this.request.setSecure(false);
21
22         } else {
23
24                 if( G.user && G.user.session ) {
25                         /* if the user is logged in, all activity resets the timeout 
26                                 This is not entirely accurate in the sense that not all 
27                                 requests will reset the server timeout - this should
28                                 get close enough, however.
29                         */
30                         var at = getAuthtime();
31                         if(at) new AuthTimer(at).run(); 
32                 }
33         }
34
35         for( var x = 1; x!= arguments.length; x++ ) {
36                 p.push(arguments[x]);
37                 this.request.addParam(arguments[x]);
38         }
39
40         if( getDebug() ) {
41                 var str = "";
42                 for( var i = 0; i != p.length; i++ ) {
43                         if( i > 0 ) str += ", "
44                         str += js2JSON(p[i]);
45                 }
46                 _debug('request ' + s[0] + ' ' + s[1] + ' ' + str );
47
48         } else if( DEBUGSLIM ) {
49                 _debug('request ' + s[1]);
50         }
51 }
52
53 Request.prototype.callback = function(cal) {this.request.setCompleteCallback(cal);}
54 Request.prototype.send          = function(block){this.request.send(block);}
55 Request.prototype.result        = function(){return this.request.getResultObject();}
56
57 function showCanvas() {
58         for( var x in G.ui.altcanvas ) {
59                 hideMe(G.ui.altcanvas[x]);
60         }
61         hideMe(G.ui.common.loading);
62         unHideMe(G.ui.common.canvas_main);
63         try{G.ui.searchbar.text.focus();}catch(e){}
64 }
65
66 function swapCanvas(newNode) {
67         for( var x in G.ui.altcanvas ) 
68                 hideMe(G.ui.altcanvas[x]);
69
70         hideMe(G.ui.common.loading);
71         hideMe(G.ui.common.canvas_main);
72         unHideMe(newNode);
73 }
74
75 /* finds the name of the current page */
76 var currentPage = null;
77 function findCurrentPage() {
78         if(currentPage) return currentPage;
79
80         var pages = [];
81         for( var p in config.page ) pages.push(config.page[p]);
82         pages = pages.sort( function(a,b){ return - (a.length - b.length); } );
83
84         var path = location.pathname;
85         if(!path.match(/.*\.xml$/))
86                 path += "index.xml"; /* in case they go to  / */
87
88         var page = null;
89         for( var p = 0; p < pages.length; p++ ) {
90                 if( path.indexOf(pages[p]) != -1)
91                         page = pages[p];
92         }
93
94         for( var p in config.page ) {
95                 if(config.page[p] == page) {
96                         currentPage = p;
97                         return p;
98                 }
99         }
100         return null;
101 }
102
103
104 /* sets all of the params values  ----------------------------- */
105 function initParams() {
106         var cgi = new CGI();    
107
108         /* handle the location var */
109         var org;
110         var loc = cgi.param(PARAM_LOCATION);
111         var lasso = cgi.param(PARAM_LASSO);
112
113     if ( lasso ) {
114                 lasso = findOrgLasso( lasso );
115                 LASSO = lasso ? lasso.id() : null;
116         }
117
118     if (loc) {
119                 org = findOrgUnit(loc);
120                 LOCATION = org ? org.id() : null;
121
122                 if ( !LOCATION ){
123                         org = findOrgUnit(loc);
124                         LOCATION = org ? org.id() : null;
125                 }
126     }
127
128         org = null;
129         loc = cgi.param(PARAM_ORIGLOC);
130         if( loc ) {
131                 org = findOrgUnit(loc);
132                 if(!org) org = findOrgUnitSN(loc);
133         }
134         ORIGLOC = (org) ? org.id() : null;
135
136
137         DEPTH = parseInt(cgi.param(PARAM_DEPTH));
138         if(isNaN(DEPTH)) DEPTH = null;
139
140
141         FACET           = cgi.param(PARAM_FACET);
142         TERM            = cgi.param(PARAM_TERM);
143         STYPE           = cgi.param(PARAM_STYPE);
144         FORM            = cgi.param(PARAM_FORM);
145         //DEPTH         = parseInt(cgi.param(PARAM_DEPTH));
146         OFFSET  = parseInt(cgi.param(PARAM_OFFSET));
147         COUNT           = parseInt(cgi.param(PARAM_COUNT));
148         HITCOUNT        = parseInt(cgi.param(PARAM_HITCOUNT));
149         MRID            = parseInt(cgi.param(PARAM_MRID));
150         RID             = parseInt(cgi.param(PARAM_RID));
151         AUTHTIME        = parseInt(cgi.param(PARAM_AUTHTIME));
152         ADVTERM = cgi.param(PARAM_ADVTERM);
153         ADVTYPE = cgi.param(PARAM_ADVTYPE);
154         RTYPE           = cgi.param(PARAM_RTYPE);
155         SORT            = cgi.param(PARAM_SORT);
156         SORT_DIR        = cgi.param(PARAM_SORT_DIR);
157         DEBUG           = cgi.param(PARAM_DEBUG);
158         CALLNUM = cgi.param(PARAM_CN);
159         LITFORM = cgi.param(PARAM_LITFORM);
160         ITEMFORM        = cgi.param(PARAM_ITEMFORM);
161         ITEMTYPE        = cgi.param(PARAM_ITEMTYPE);
162         BIBLEVEL        = cgi.param(PARAM_BIBLEVEL);
163         AUDIENCE        = cgi.param(PARAM_AUDIENCE);
164         SEARCHES = cgi.param(PARAM_SEARCHES);
165         LANGUAGE        = cgi.param(PARAM_LANGUAGE);
166         TFORM           = cgi.param(PARAM_TFORM);
167         RDEPTH  = cgi.param(PARAM_RDEPTH);
168     AVAIL   = cgi.param(PARAM_AVAIL);
169     COPYLOCS   = cgi.param(PARAM_COPYLOCS);
170     PUBD_BEFORE = cgi.param(PARAM_PUBD_BEFORE);
171     PUBD_AFTER = cgi.param(PARAM_PUBD_AFTER);
172     PUBD_BETWEEN = cgi.param(PARAM_PUBD_BETWEEN);
173     PUBD_DURING = cgi.param(PARAM_PUBD_DURING);
174
175     
176         /* set up some sane defaults */
177         //if(isNaN(DEPTH))      DEPTH           = 0;
178         if(isNaN(RDEPTH))       RDEPTH  = 0;
179         if(isNaN(OFFSET))       OFFSET  = 0;
180         if(isNaN(COUNT))        COUNT           = 10;
181         if(isNaN(HITCOUNT))     HITCOUNT        = 0;
182         if(isNaN(MRID))         MRID            = 0;
183         if(isNaN(RID))          RID             = 0;
184         if(isNaN(ORIGLOC))      ORIGLOC = 0; /* so we know it hasn't been set */
185         if(isNaN(AUTHTIME))     AUTHTIME        = 0;
186         if(ADVTERM==null)       ADVTERM = "";
187     if(isNaN(AVAIL))    AVAIL = 0;
188 }
189
190 function clearSearchParams() {
191         TERM        = null;
192         STYPE       = null;
193         FORM        = null;
194         OFFSET      = 0;
195         HITCOUNT    = 0;  
196         ADVTERM     = null;
197         ADVTYPE     = null;
198         MRID        = null;
199         RID         = null;
200         RTYPE       = null;
201         SORT        = null;
202         SORT_DIR    = null;
203         RLIST       = null;
204         CALLNUM     = null;
205         LITFORM     = null;
206         ITEMFORM    = null;
207         ITEMTYPE    = null;
208         BIBLEVEL    = null;
209         AUDIENCE    = null;
210         SEARCHES    = null;
211         LANGUAGE    = null;
212         RDEPTH      = null;
213     AVAIL       = null;
214     COPYLOCS    = null;
215     PUBD_BEFORE = null;
216     PUBD_AFTER  = null;
217     PUBD_BETWEEN = null;
218     PUBD_DURING = null;
219 }
220
221
222 function initCookies() {
223     dojo.require('dojo.cookie');
224         FONTSIZE = "regular";
225         var font = dojo.cookie(COOKIE_FONT);
226         scaleFonts(font);
227         if(font) FONTSIZE = font;
228         SKIN = dojo.cookie(COOKIE_SKIN);
229     if(findCurrentPage() == HOME)
230         dojo.cookie(COOKIE_SEARCH,null,{'expires':-1});
231 }
232
233 /* URL param accessors */
234 function getTerm(){return TERM;}
235 function getFacet(){return FACET;}
236 function getStype(){return STYPE;}
237 function getLocation(){return LOCATION;}
238 function getLasso(){return LASSO;}
239 function getDepth(){return DEPTH;}
240 function getForm(){return FORM;}
241 function getTform(){return TFORM;}
242 function getOffset(){return OFFSET;}
243 function getDisplayCount(){return COUNT;}
244 function getHitCount(){return HITCOUNT;}
245 function getMrid(){return MRID;};
246 function getRid(){return RID;};
247 function getOrigLocation(){return ORIGLOC;}
248 function getAuthtime() { return AUTHTIME; }
249 function getSearchBarExtras(){return SBEXTRAS;}
250 function getFontSize(){return FONTSIZE;};
251 function getSkin(){return SKIN;};
252 function getAdvTerm(){return ADVTERM;}
253 function getAdvType(){return ADVTYPE;}
254 function getRtype(){return RTYPE;}
255 function getSort(){return SORT;}
256 function getSortDir(){return SORT_DIR;}
257 function getDebug(){return DEBUG;}
258 function getCallnumber() { return CALLNUM; }
259 function getLitForm() { return LITFORM; }
260 function getItemForm() { return ITEMFORM; }
261 function getItemType() { return ITEMTYPE; }
262 function getBibLevel() { return BIBLEVEL; }
263 function getAudience() { return AUDIENCE; }
264 function getSearches() { return SEARCHES; }
265 function getLanguage() { return LANGUAGE; }
266 function getRdepth() { return RDEPTH; }
267 function getAvail() { return AVAIL; }
268 function getCopyLocs() { return COPYLOCS; }
269 function getPubdBefore() { return PUBD_BEFORE; }
270 function getPubdAfter() { return PUBD_AFTER; }
271 function getPubdBetween() { return PUBD_BETWEEN; }
272 function getPubdDuring() { return PUBD_DURING; }
273
274
275 function findBasePath() {
276         var path = location.pathname;
277         if(!path.match(/.*\.xml$/)) path += "index.xml"; 
278         var idx = path.indexOf(config.page[findCurrentPage()]);
279         return path.substring(0, idx);
280 }
281
282 function findBaseURL(ssl) {
283         var path = findBasePath();
284         var proto = (ssl) ? "https:" : "http:";
285
286         /* strip port numbers.  This is necessary for browsers that
287         send an explicit  <host>:80, 443 - explicit ports
288         break links that need to change ports (e.g. http -> https) */
289         var h = location.host.replace(/:.*/,''); 
290
291         return proto + "//" + h + path;
292 }
293
294 /*
295 function buildISBNSrc(isbn) {
296         return "http://" + location.host + "/jackets/" + isbn;
297 }
298 */
299
300 function buildImageLink(name, ssl) {
301         return findBaseURL(ssl) + "../../../../images/" + name;
302 }
303
304 function buildExtrasLink(name, ssl) {
305         return findBaseURL(ssl) + "../../../../extras/" + name;
306 }
307
308 var consoleService;
309 function _debug(str) { 
310         try { dump('dbg: ' + str + '\n'); } catch(e) {} 
311
312         /* potentially useful, but usually just annoying */
313         /*
314         if(!IE) {
315                 if(!consoleService) {
316                         try {
317                                 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
318                                 this.consoleService = Components.classes['@mozilla.org/consoleservice;1']
319                                         .getService(Components.interfaces.nsIConsoleService);
320                         } catch(e) {}
321                 }
322         
323                 try {
324                         if(consoleService) {
325                                 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
326                                 consoleService.logStringMessage(str + '\n');
327                         }
328                 } catch(e){}
329         }
330         */
331 }
332
333 var forceLoginSSL; // set via Apache env variable
334 function  buildOPACLink(args, slim, ssl) {
335
336         if(!args) args = {};
337         var string = "";
338
339     if( ssl == undefined && (
340             location.protocol == 'https:' ||
341             (forceLoginSSL && G.user && G.user.session))) {
342         ssl = true;
343     }
344
345         if(!slim) {
346                 string = findBaseURL(ssl);
347                 if(args.page) string += config.page[args.page];
348                 else string += config.page[findCurrentPage()];
349         }
350
351         /* this may seem unnecessary.. safety precaution for now */
352         /*
353         if( args[PARAM_DEPTH] == null )
354                 args[PARAM_DEPTH] = getDepth();
355                 */
356
357         string += "?";
358
359         for( var x in args ) {
360                 var v = args[x];
361                 if(x == "page" || v == null || v == undefined || v+'' == 'NaN' ) continue;
362                 if(x == PARAM_OFFSET && v == 0) continue;
363                 if(x == PARAM_COUNT && v == 10) continue;
364                 if(x == PARAM_FORM && v == 'all' ) continue;
365                 if( instanceOf(v, Array) && v.length ) {
366                         for( var i = 0; i < v.length; i++ ) {
367                                 string += "&" + x + "=" + encodeURIComponent(v[i]);
368                         }
369                 } else {
370                         string += "&" + x + "=" + encodeURIComponent(v);
371                 }
372         }
373
374         if(getDebug())
375                 string += _appendParam(DEBUG,           PARAM_DEBUG, args, getDebug, string);
376         if(getOrigLocation() != 1) 
377                 string += _appendParam(ORIGLOC, PARAM_ORIGLOC, args, getOrigLocation, string);
378         if(getTerm()) 
379                 string += _appendParam(TERM,            PARAM_TERM, args, getTerm, string);
380         if(getFacet()) 
381                 string += _appendParam(FACET,           PARAM_FACET, args, getFacet, string);
382         if(getStype()) 
383                 string += _appendParam(STYPE,           PARAM_STYPE, args, getStype, string);
384         if(getLocation() != 1) 
385                 string += _appendParam(LOCATION, PARAM_LOCATION, args, getLocation, string);
386         if(getLasso() != null) 
387                 string += _appendParam(LASSO, PARAM_LASSO, args, getLasso, string);
388         if(getDepth() != null) 
389                 string += _appendParam(DEPTH,           PARAM_DEPTH, args, getDepth, string);
390         if(getForm() && (getForm() != 'all') ) 
391                 string += _appendParam(FORM,            PARAM_FORM, args, getForm, string);
392         if(getTform() && (getTform() != 'all') ) 
393                 string += _appendParam(TFORM,           PARAM_TFORM, args, getTform, string);
394         if(getOffset() != 0) 
395                 string += _appendParam(OFFSET,  PARAM_OFFSET, args, getOffset, string);
396         if(getDisplayCount() != 10) 
397                 string += _appendParam(COUNT,           PARAM_COUNT, args, getDisplayCount, string);
398         if(getHitCount()) 
399                 string += _appendParam(HITCOUNT, PARAM_HITCOUNT, args, getHitCount, string);
400         if(getMrid())
401                 string += _appendParam(MRID,            PARAM_MRID, args, getMrid, string);
402         if(getRid())
403                 string += _appendParam(RID,             PARAM_RID, args, getRid, string);
404         if(getAuthtime())
405                 string += _appendParam(AUTHTIME,        PARAM_AUTHTIME, args, getAuthtime, string);
406         if(getAdvTerm())
407                 string += _appendParam(ADVTERM, PARAM_ADVTERM, args, getAdvTerm, string);
408         if(getAdvType())
409                 string += _appendParam(ADVTYPE, PARAM_ADVTYPE, args, getAdvType, string);
410         if(getRtype())
411                 string += _appendParam(RTYPE,           PARAM_RTYPE, args, getRtype, string);
412         if(getItemForm())
413                 string += _appendParam(ITEMFORM,        PARAM_ITEMFORM, args, getItemForm, string);
414         if(getItemType())
415                 string += _appendParam(ITEMTYPE,        PARAM_ITEMTYPE, args, getItemType, string);
416         if(getBibLevel())
417                 string += _appendParam(BIBLEVEL,        PARAM_BIBLEVEL, args, getBibLevel, string);
418         if(getLitForm())
419                 string += _appendParam(LITFORM, PARAM_LITFORM, args, getLitForm, string);
420         if(getAudience())
421                 string += _appendParam(AUDIENCE,        PARAM_AUDIENCE, args, getAudience, string);
422         if(getSearches())
423                 string += _appendParam(SEARCHES,        PARAM_SEARCHES, args, getSearches, string);
424         if(getLanguage())
425                 string += _appendParam(LANGUAGE,        PARAM_LANGUAGE, args, getLanguage, string);
426         if(getRdepth() != null)
427                 string += _appendParam(RDEPTH,  PARAM_RDEPTH, args, getRdepth, string);
428         if(getSort() != null)
429                 string += _appendParam(SORT,    PARAM_SORT, args, getSort, string);
430         if(getSortDir() != null)
431                 string += _appendParam(SORT_DIR,        PARAM_SORT_DIR, args, getSortDir, string);
432         if(getAvail())
433                 string += _appendParam(AVAIL, PARAM_AVAIL, args, getAvail, string);
434         if(getCopyLocs())
435                 string += _appendParam(COPYLOCS, PARAM_COPYLOCS, args, getCopyLocs, string);
436     if(getPubdBefore())
437                 string += _appendParam(PUBD_BEFORE, PARAM_PUBD_BEFORE, args, getPubdBefore, string);
438     if(getPubdAfter())
439                 string += _appendParam(PUBD_AFTER, PARAM_PUBD_AFTER, args, getPubdAfter, string);
440     if(getPubdBetween())
441                 string += _appendParam(PUBD_BETWEEN, PARAM_PUBD_BETWEEN, args, getPubdBetween, string);
442     if(getPubdDuring())
443                 string += _appendParam(PUBD_DURING, PARAM_PUBD_DURING, args, getPubdDuring, string);
444
445
446         return string.replace(/\&$/,'').replace(/\?\&/,"?");    
447 }
448
449 var xx = 1;
450 function _appendParam( fieldVar, fieldName, overrideArgs, getFunc, string ) {
451
452         var ret = "";
453
454         if(     fieldVar != null && 
455                         (fieldVar +'' != 'NaN') && 
456                         overrideArgs[fieldName] == null &&
457                         getFunc() != null &&
458                         getFunc()+'' != '' ) {
459
460                 ret = "&" + fieldName + "=" + encodeURIComponent(getFunc());
461         }
462
463         return ret;
464 }
465
466 /* ----------------------------------------------------------------------- */
467 function cleanISBN(isbn) {
468    if(isbn) {
469       isbn = isbn.toString().replace(/^\s+/,"");
470       var idx = isbn.indexOf(" ");
471       if(idx > -1) { isbn = isbn.substring(0, idx); }
472    } else isbn = "";
473    return isbn;
474 }       
475
476
477 /* builds a link that goes to the title listings for a metarecord */
478 function buildTitleLink(rec, link) {
479         if(!rec) return;
480         link.appendChild(text(normalize(truncate(rec.title(), 65))));
481         var args = {};
482         args.page = RRESULT;
483         args[PARAM_OFFSET] = 0;
484         args[PARAM_MRID] = rec.doc_id();
485         args[PARAM_RTYPE] = RTYPE_MRID;
486     var linkText = link.innerHTML; // IE
487         link.setAttribute("href", buildOPACLink(args));
488     link.innerHTML = linkText; // IE
489 }
490
491 function buildTitleDetailLink(rec, link) {
492         if(!rec) return;
493         link.appendChild(text(normalize(truncate(rec.title(), 65))));
494         var args = {};
495         args.page = RDETAIL;
496         args[PARAM_RID] = rec.doc_id();
497     // in IE, if the link text contains a '@', it replaces the innerHTML text 
498     // with the value of the href attribute.  Wait, what?  Yes.  Capture the
499     // innerHTML and put it back into place after the href is set
500     var linkText = link.innerHTML; // IE
501         link.setAttribute("href", buildOPACLink(args));
502     link.innerHTML = linkText; // IE
503 }
504
505 /* 'type' is one of STYPE_AUTHOR, STYPE_SUBJECT, ... found in config.js 
506         'trunc' is the number of characters to show in the string, defaults to 65 */
507 function buildSearchLink(type, string, linknode, trunc) {
508         if(!trunc) trunc = 65;
509         var args = {};
510         if( SHOW_MR_DEFAULT || findCurrentPage() == MRESULT ) {
511                 args.page = MRESULT;
512         } else {
513                 args.page = RRESULT;
514                 args[PARAM_RTYPE] = type;
515         }
516         args[PARAM_OFFSET] = 0;
517         args[PARAM_TERM] = string;
518         args[PARAM_STYPE] = type;
519         linknode.appendChild(text(normalize(truncate(string, trunc))));
520         linknode.setAttribute("href", buildOPACLink(args));
521 }
522
523 function setSessionCookie(ses) {
524         dojo.cookie(COOKIE_SES, ses);
525 }
526
527
528
529 /* ----------------------------------------------------------------------- */
530 /* user session handling */
531 /* ----------------------------------------------------------------------- */
532 /* session is the login session.  If no session is provided, we attempt
533         to find one in the cookies.  If 'force' is true we retrieve the 
534         user from the server even if there is already a global user present.
535         if ses != G.user.session, we also force a grab */
536 function grabUser(ses, force) {
537
538     _debug("grabUser auth token = " + ses);
539         if(!ses && isXUL()) {
540                 stash = fetchXULStash();
541                 ses = stash.session.key
542                 _debug("stash auth token = " + ses);
543         }
544
545         if(!ses) {
546                 ses = dojo.cookie(COOKIE_SES);
547                 /* https cookies don't show up in http servers.. */
548                 _debug("cookie auth token = " + ses);
549         }
550
551         if(!ses) return false;
552
553         if(!force) 
554                 if(G.user && G.user.session == ses)
555                         return G.user;
556
557         /* first make sure the session is valid */
558         var request = new Request(FETCH_SESSION, ses);
559         request.request.alertEvent = false;
560         request.send(true);
561         var user = request.result();
562
563         if(!user || user.textcode == 'NO_SESSION') {
564
565         if(isXUL()) {
566             dojo.require('openils.XUL');
567             dump('getNewSession in opac_utils.js\n');
568             openils.XUL.getNewSession( 
569                 function(success, authtoken) { 
570                     if(success) {
571                         ses = authtoken;
572                         var request = new Request(FETCH_SESSION, ses);
573                         request.request.alertEvent = false;
574                         request.send(true);
575                         user = request.result();
576                     }
577                 }
578             );
579         }
580
581             if(!user || user.textcode == 'NO_SESSION') {
582                     doLogout();
583                     return false; /* unable to grab the session */
584         }
585         }
586
587         if( !(typeof user == 'object' && user._isfieldmapper) ) {
588                 doLogout();
589                 return false;
590         }
591
592         G.user = user;
593         G.user.fleshed = false;
594         G.user.session = ses;
595         setSessionCookie(ses);
596
597         grabUserPrefs();
598         if(G.user.prefs['opac.hits_per_page'])
599                 COUNT = parseInt(G.user.prefs['opac.hits_per_page']);
600
601         if(G.user.prefs[PREF_DEF_FONT]) 
602                 setFontSize(G.user.prefs[PREF_DEF_FONT]);
603
604         var at = getAuthtime();
605         //if(isXUL()) at = xulG['authtime'];
606
607         if(at && !isXUL()) new AuthTimer(at).run(); 
608         return G.user;
609 }
610
611
612 /* sets the 'prefs' field of the user object to their preferences 
613         and returns the preferences */
614 function grabUserPrefs(user, force) {
615         if(user == null) user = G.user;
616         if(!force && user.prefs) return user.prefs;     
617         var req = new Request(FETCH_USER_PREFS, G.user.session, user.id());
618         req.send(true);
619         user.prefs = req.result();
620         return user.prefs;
621 }
622
623 function grabFleshedUser() {
624
625         if(!G.user || !G.user.session) {
626                 grabUser();     
627                 if(!G.user || !G.user.session) return null;
628         }
629
630         if(G.user.fleshed) return G.user;
631
632    var req = new Request(FETCH_FLESHED_USER, G.user.session);
633         req.send(true);
634
635         G.user = req.result();
636
637         if(!G.user || G.user.length == 0) { 
638                 dojo.cookie(COOKIE_SES,null,{'expires':-1});
639                 G.user = null; return false; 
640         }
641
642         G.user.session = ses;
643         G.user.fleshed = true;
644
645         setSessionCookie(ses);
646         return G.user;
647 }
648
649 function checkUserSkin(new_skin) {
650
651         return; /* XXX do some debugging with this... */
652
653         var user_skin = getSkin();
654         var cur_skin = grabSkinFromURL();
655
656         if(new_skin) user_skin = new_skin;
657
658         if(!user_skin) {
659
660                 if(grabUser()) {
661                         if(grabUserPrefs()) {
662                                 user_skin = G.user.prefs["opac.skin"];
663                                 dojo.cookie( COOKIE_SKIN, user_skin, { 'expires' : 365 } );
664                         }
665                 }
666         }
667
668         if(!user_skin) return;
669
670         if( cur_skin != user_skin ) {
671                 var url = buildOPACLink();
672                 goTo(url.replace(cur_skin, user_skin));
673         }
674 }
675
676 function updateUserSetting(setting, value, user) {
677         if(user == null) user = G.user;
678         var a = {};
679         a[setting] = value;
680         var req = new Request( UPDATE_USER_PREFS, user.session, a );
681         req.send(true);
682         return req.result();
683 }
684
685 function commitUserPrefs() {
686         var req = new Request( 
687                 UPDATE_USER_PREFS, G.user.session, null, G.user.prefs );
688         req.send(true);
689         return req.result();
690 }
691
692 function grabSkinFromURL() {
693         var path = findBasePath();
694         path = path.replace("/xml/", "");
695         var skin = "";
696         for( var i = path.length - 1; i >= 0; i-- ) {
697                 var ch = path.charAt(i);
698                 if(ch == "/") break;
699                 skin += ch;
700         }
701
702         var skin2 = "";
703         for( i = skin.length - 1; i >= 0; i--)
704                 skin2 += skin.charAt(i);
705
706         return skin2;
707 }
708
709
710 /* returns a fleshed G.user on success, false on failure */
711 function doLogin(suppressEvents) {
712
713         abortAllRequests();
714
715         var uname = G.ui.login.username.value;
716         var passwd = G.ui.login.password.value; 
717
718         var init_request = new Request( LOGIN_INIT, uname );
719    init_request.send(true);
720    var seed = init_request.result();
721
722    if( ! seed || seed == '0') {
723       alert( "Error Communicating with Authentication Server" );
724       return null;
725    }
726
727         var args = {
728                 password : hex_md5(seed + hex_md5(passwd)), 
729                 type            : "opac", 
730                 org             : getOrigLocation(),
731                 agent : 'opac'
732         };
733
734     r = fetchOrgSettingDefault(globalOrgTree.id(), 'opac.barcode_regex');
735     if(r) REGEX_BARCODE = new RegExp(r);
736     
737     if( uname.match(REGEX_BARCODE) ) args.barcode = uname;
738         else args.username = uname;
739
740    var auth_request = new Request( LOGIN_COMPLETE, args );
741
742         auth_request.request.alertEvent = false;
743    auth_request.send(true);
744    var auth_result = auth_request.result();
745
746         if(!auth_result) {
747                 alertId('patron_login_failed');
748                 return null;
749         }
750
751         if( checkILSEvent(auth_result) ) {
752
753                 if( auth_result.textcode == 'PATRON_INACTIVE' ) {
754                         alertId('patron_inactive_alert');
755                         return;
756                 }
757
758                 if( auth_result.textcode == 'PATRON_CARD_INACTIVE' ) {
759                         alertId('patron_card_inactive_alert');
760                         return;
761                 }
762
763                 if( auth_result.textcode == 'LOGIN_FAILED' || 
764                                 auth_result.textcode == 'PERM_FAILURE' ) {
765                         alertId('patron_login_failed');
766                         return;
767                 }
768         }
769
770
771         AUTHTIME = parseInt(auth_result.payload.authtime);
772         var u = grabUser(auth_result.payload.authtoken, true);
773         if(u && ! suppressEvents) 
774                 runEvt( "common", "locationChanged", u.ws_ou(), findOrgDepth(u.ws_ou()) );
775
776         checkUserSkin();
777
778         return u;
779 }
780
781 function doLogout() {
782
783         /* cancel everything else */
784         abortAllRequests();
785
786         /* be nice and delete the session from the server */
787         if(G.user && G.user.session) { 
788                 var req = new Request(LOGIN_DELETE, G.user.session);
789       req.send(true);
790                 try { req.result(); } catch(E){}
791     }
792
793         G.user = null;
794
795         /* remove any cached data */
796     dojo.require('dojo.cookie');
797     dojo.cookie(COOKIE_SES, null, {expires:-1});
798     dojo.cookie(COOKIE_RIDS, null, {expires:-1});
799     dojo.cookie(COOKIE_SKIN, null, {expires:-1});
800     dojo.cookie(COOKIE_SEARCH, null, {expires:-1});
801
802
803         checkUserSkin("default");
804         COUNT = 10;
805
806
807         var args = {};
808         args[PARAM_TERM] = "";
809         args[PARAM_LOCATION] = getOrigLocation();
810     args[PARAM_DEPTH] = findOrgDepth(getOrigLocation() || globalOrgTree);
811         args.page = "home";
812
813         
814         var nored = false;
815         try{ if(isFrontPage) nored = true; } catch(e){nored = false;}
816         if(!nored) goTo(buildOPACLink(args, false, false));
817 }
818
819
820 function hideMe(obj) { addCSSClass(obj, config.css.hide_me); } 
821 function unHideMe(obj) { removeCSSClass(obj, config.css.hide_me); }
822
823
824 /* ----------------------------------------------------------------------- */
825 /* build the org tree */
826 /* ----------------------------------------------------------------------- */
827 function drawOrgTree() {
828         //setTimeout( 'buildOrgSelector(G.ui.common.org_tree, orgTreeSelector);', 10 );
829         setTimeout( 'buildOrgSelector(G.ui.common.org_tree, orgTreeSelector);', 1 );
830 }
831
832 var checkOrgHiding_cached = false;
833 var checkOrgHiding_cached_context_org;
834 var checkOrgHiding_cached_depth;
835 function checkOrgHiding() {
836     if (isXUL()) {
837         return false; // disable org hiding for staff client
838     }
839     var context_org = getOrigLocation() || globalOrgTree.id();
840     var depth;
841     if (checkOrgHiding_cached) {
842         if (checkOrgHiding_cached_context_org != context_org) {
843             checkOrgHiding_cached_context_org = context_org;
844             checkOrgHiding_cached_depth = undefined;
845             checkOrgHiding_cached = false;
846         } else {
847             depth = checkOrgHiding_cached_depth;
848         }
849     } else {
850         depth = fetchOrgSettingDefault( context_org, 'opac.org_unit_hiding.depth');
851         checkOrgHiding_cached_depth = depth;
852         checkOrgHiding_cached_context_org = context_org;
853         checkOrgHiding_cached = true;
854     }
855     if ( findOrgDepth( context_org ) < depth ) {
856         return false; // disable org hiding if Original Location doesn't make sense with setting depth (avoids disjointed org selectors)
857     }
858     if (depth) {
859         return { 'org' : findOrgUnit(context_org), 'depth' : depth };
860     } else {
861         return false;
862     }
863 }
864
865 var orgTreeSelector;
866 function buildOrgSelector(node) {
867         var tree = new SlimTree(node,'orgTreeSelector');
868         orgTreeSelector = tree;
869         var orgHiding = checkOrgHiding();
870         for( var i in orgArraySearcher ) { 
871                 var node = orgArraySearcher[i];
872                 if( node == null ) continue;
873                 if(!isXUL() && !isTrue(node.opac_visible())) continue; 
874                 if (orgHiding) {
875                         if ( ! orgIsMine( orgHiding.org, node, orgHiding.depth ) ) {
876                                 continue;
877                         }
878                 }
879                 if(node.parent_ou() == null) {
880                         tree.addNode(node.id(), -1, node.name(), 
881                                 "javascript:orgSelect(" + node.id() + ");", node.name());
882                 } else {
883                         if (orgHiding && orgHiding.depth == findOrgDepth(node)) {
884                                 tree.addNode(node.id(), -1, node.name(), 
885                                         "javascript:orgSelect(" + node.id() + ");", node.name());
886                         } else {
887                                 tree.addNode(node.id(), node.parent_ou(), node.name(), 
888                                         "javascript:orgSelect(" + node.id() + ");", node.name());
889                         }
890                 }
891         }
892         hideMe($('org_loading_div'));
893         unHideMe($('org_selector_tip'));
894         return tree;
895 }
896
897 function orgSelect(id) {
898         showCanvas();
899         runEvt("common", "locationChanged", id, findOrgDepth(id) );
900
901
902         var loc = findOrgLasso(getLasso());
903         if (!loc) loc = findOrgUnit(id);
904
905         removeChildren(G.ui.common.now_searching);
906         G.ui.common.now_searching.appendChild(text(loc.name()));
907 }
908
909 function setFontSize(size) {
910         scaleFonts(size);
911         dojo.cookie(COOKIE_FONT, size, { 'expires' : 365});
912 }
913
914 var resourceFormats = [
915    "text",
916    "moving image",
917    "sound recording", "software, multimedia",
918    "still image",
919    "cartographic",
920    "mixed material",
921    "notated music",
922    "three dimensional object" ];
923
924
925 function modsFormatToMARC(format) {
926    switch(format) {
927       case "text":
928          return "at";
929       case "moving image":
930          return "g";
931       case "sound recording":
932          return "ij";
933       case "sound recording-nonmusical":
934          return "i";
935       case "sound recording-musical":
936          return "j";
937       case "software, multimedia":
938          return "m";
939       case "still image":
940          return "k";
941       case "cartographic":
942          return "ef";
943       case "mixed material":
944          return "op";
945       case "notated music":
946          return "cd";
947       case "three dimensional object":
948          return "r";
949    }
950    return "at";
951 }
952
953
954 function MARCFormatToMods(format) {
955    switch(format) {
956       case "a":
957       case "t":
958          return "text";
959       case "g":
960          return "moving image";
961       case "i":
962          return "sound recording-nonmusical";
963       case "j":
964          return "sound recording-musical";
965       case "m":
966          return "software, multimedia";
967       case "k":
968          return "still image";
969       case "e":
970       case "f":
971          return "cartographic";
972       case "o":
973       case "p":
974          return "mixed material";
975       case "c":
976       case "d":
977          return "notated music";
978       case "r":
979          return "three dimensional object";
980    }
981    return "text";
982 }
983
984 function MARCTypeToFriendly(format) {
985         var words = $('format_words');
986         switch(format) {
987                 case 'a' :
988                 case 't' : return $n(words, 'at').innerHTML;
989                 default:
990                         var node = $n(words,format);
991                         if( node ) return node.innerHTML;
992         }
993         return "";
994 }
995
996 function setResourcePic( img, resource ) {
997         img.setAttribute( "src", "../../../../images/tor/" + resource + ".jpg");
998         img.title = resource;
999 }
1000
1001
1002
1003 function msg( text ) {
1004         try { alert( text ); } catch(e) {}
1005 }
1006
1007 function findRecord(id,type) {
1008         try {
1009                 for( var i = 0; i != recordsCache.length; i++ ) {
1010                         var rec = recordsCache[i];
1011                         if( rec && rec.doc_id() == id ) return rec;
1012                 }
1013         } catch(E){}
1014         var meth = FETCH_RMODS
1015         if(type == 'M') meth = FETCH_MRMODS;
1016         var req = new Request(meth, id);
1017         req.request.alertEvent = false;
1018         req.send(true);
1019         var res = req.result();
1020         if( checkILSEvent(res) ) return null; 
1021         return res;
1022 }
1023
1024 function Timer(name, node){
1025         this.name = name;
1026         this.count = 1;
1027         this.node = node;
1028 }
1029 Timer.prototype.start = 
1030         function(){_timerRun(this.name);}
1031 Timer.prototype.stop = 
1032         function(){this.done = true;}
1033 function _timerRun(tname) {
1034         var _t;
1035         eval('_t='+tname);
1036         if(_t.done) return;
1037         if(_t.count > 100) return;
1038         var str = ' . ';
1039         if( (_t.count % 5) == 0 ) 
1040                 str = _t.count / 5;
1041         _t.node.appendChild(text(str));
1042         setTimeout("_timerRun('"+tname+"');", 200);
1043         _t.count++;
1044 }
1045
1046 function checkILSEvent(obj) {
1047         if (obj && typeof obj == 'object' && typeof obj.ilsevent != 'undefined') {
1048         if (obj.ilsevent === '') {
1049             return true;
1050         } else if ( obj.ilsevent != null && obj.ilsevent != 0 ) {
1051             return parseInt(obj.ilsevent);
1052         }
1053     }
1054         return null;
1055 }
1056
1057
1058 function alertILSEvent(evt, msg) {
1059    if(!msg) msg = "";
1060         if(msg)
1061                 alert(msg +'\n' + evt.textcode + '\n' + evt.desc );
1062         else 
1063                 alert(evt.textcode + '\n' + evt.desc );
1064 }
1065
1066
1067 var __authTimer;
1068 function AuthTimer(time) { 
1069         this.time = (time - LOGOUT_WARNING_TIME) * 1000; 
1070         if(__authTimer) 
1071                 try {clearTimeout(__authTimer.id)} catch(e){}
1072         __authTimer = this;
1073 }
1074
1075 AuthTimer.prototype.run = function() {
1076         this.id = setTimeout('_authTimerAlert()', this.time);
1077 }
1078
1079 function _authTimerAlert() {
1080         alert( $('auth_session_expiring').innerHTML );
1081         if(!grabUser(null, true)) doLogout();
1082 }
1083
1084
1085 function grabUserByBarcode( authtoken, barcode ) {
1086         var req = new Request( FETCH_USER_BYBARCODE, authtoken, barcode );
1087         req.send(true);
1088         return req.result();
1089 }
1090
1091
1092 function goHome() {
1093         goTo(buildOPACLink({page:HOME}));
1094 }
1095
1096
1097 function buildOrgSel(selector, org, offset, namecol) {
1098     if(!namecol) namecol = 'name';
1099     if(!isXUL() && !isTrue(org.opac_visible())) return;
1100         insertSelectorVal( selector, -1, 
1101                 org[namecol](), org.id(), null, findOrgDepth(org) - offset );
1102     var kids = org.children();
1103     if (kids) {
1104             for( var c = 0; c < kids.length; c++ )
1105                     buildOrgSel( selector, kids[c], offset, namecol);
1106     }
1107 }
1108
1109 function buildMergedOrgSel(selector, org_list, offset, namecol) {
1110     if(!namecol) namecol = 'name';
1111     for(var i = 0; i < org_list.length; i++) {
1112         var org = findOrgUnit(org_list[i]);
1113         insertSelectorVal( selector, -1, 
1114                     org[namecol](), org.id(), null, findOrgDepth(org) - offset );
1115         var kids = org.children();
1116         if (kids) {
1117                 for( var c = 0; c < kids.length; c++ )
1118                         buildOrgSel( selector, kids[c], offset, namecol);
1119         }
1120     }
1121 }
1122
1123
1124 function parseForm(form) {
1125         if(!form) return {};
1126
1127         var it = form.replace(/-\w+$/,"");
1128         var itf = null;
1129         var item_form;
1130         var item_type;
1131
1132         if(form.match(/-/)) itf = form.replace(/^\w+-/,"");
1133
1134         if(it) {
1135                 item_type = [];
1136                 for( var i = 0; i < it.length; i++ ) 
1137                         item_type.push( it.charAt(i) );
1138         }
1139
1140         if(itf) {
1141                 item_form = [];
1142                 for( var i = 0; i < itf.length; i++ ) 
1143                         item_form.push( itf.charAt(i) );
1144         }
1145
1146         return {item_type: item_type, item_form:item_form};
1147 }
1148
1149
1150 function isTrue(x) { return ( x && x != "0" && !(x+'').match(/^f$/i) ); }
1151
1152 function fetchPermOrgs() {
1153         var a = []; /* Q: why does arguments come accross as an object and not an array? A: because arguments is a special object, a collection */
1154
1155         for( var i = 0; i < arguments.length; i++ ) 
1156                 a.push(arguments[i])
1157
1158         var preq = new Request(FETCH_HIGHEST_PERM_ORG, 
1159                 G.user.session, G.user.id(), a );
1160         preq.send(true);
1161         return preq.result();
1162 }
1163
1164
1165 function print_tabs(t) {
1166         var r = '';
1167         for (var j = 0; j < t; j++ ) { r = r + "  "; }
1168         return r;
1169 }
1170 function formatJSON(s) {
1171         var r = ''; var t = 0;
1172         for (var i in s) {
1173                 if (s[i] == '{' || s[i] == '[' ) {
1174                         r = r + s[i] + "\n" + print_tabs(++t);
1175                 } else if (s[i] == '}' || s[i] == ']') {
1176                         t--; r = r + "\n" + print_tabs(t) + s[i];
1177                 } else if (s[i] == ',') {
1178                         r = r + s[i] + "\n" + print_tabs(t);
1179                 } else {
1180                         r = r + s[i];
1181                 }
1182         }
1183         return r;
1184 }