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