b2293923a19e0fbb7b598e992fd136ca6869b8a5
[Evergreen.git] / Open-ILS / web / opac / common / js / opac_utils.js
1 /* - Request ------------------------------------------------------------- */
2
3 /* define it again here for pages that don't load RemoteRequest */
4 function isXUL() { try { if(IAMXUL) return true;}catch(e){return false;}; }
5
6 var __ilsEvent; /* the last event the occurred */
7
8 function Request(type) {
9         var s = type.split(":");
10         if(s[2] == "1" && isXUL()) s[1] += ".staff";
11         this.request = new RemoteRequest(s[0], s[1]);
12         for( var x = 1; x!= arguments.length; x++ ) 
13                 this.request.addParam(arguments[x]);
14 }
15
16 Request.prototype.callback = function(cal) { this.request.setCompleteCallback(cal); }
17 Request.prototype.send          = function(block){this.request.send(block);}
18 Request.prototype.result        = function(){return this.request.getResultObject();}
19
20 function showCanvas() {
21         for( var x in G.ui.altcanvas ) {
22                 hideMe(G.ui.altcanvas[x]);
23         }
24         hideMe(G.ui.common.loading);
25         unHideMe(G.ui.common.canvas_main);
26         try{G.ui.searchbar.text.focus();}catch(e){}
27 }
28
29 function swapCanvas(newNode) {
30         for( var x in G.ui.altcanvas ) 
31                 hideMe(G.ui.altcanvas[x]);
32
33         hideMe(G.ui.common.loading);
34         hideMe(G.ui.common.canvas_main);
35         unHideMe(newNode);
36 }
37
38 /* finds the name of the current page */
39 var currentPage = null;
40 function findCurrentPage() {
41         if(currentPage) return currentPage;
42
43         var pages = [];
44         for( var p in config.page ) pages.push(config.page[p]);
45         pages = pages.sort( function(a,b){ return - (a.length - b.length); } );
46
47         var path = location.pathname;
48         if(!path.match(/.*\.xml$/))
49                 path += "index.xml"; /* in case they go to  / */
50
51         var page = null;
52         for( var p in pages ) {
53                 if( path.indexOf(pages[p]) != -1)
54                         page = pages[p];
55         }
56
57         for( var p in config.page ) {
58                 if(config.page[p] == page) {
59                         currentPage = p;
60                         return p;
61                 }
62         }
63         return null;
64 }
65
66
67 /* sets all of the params values  ----------------------------- */
68 function initParams() {
69         var cgi = new CGI();    
70
71         TERM    = cgi.param(PARAM_TERM);
72         STYPE   = cgi.param(PARAM_STYPE);
73         FORM    = cgi.param(PARAM_FORM);
74
75         LOCATION        = parseInt(cgi.param(PARAM_LOCATION));
76         ORIGLOC = parseInt(cgi.param(PARAM_ORIGLOC));
77         DEPTH           = parseInt(cgi.param(PARAM_DEPTH));
78         OFFSET  = parseInt(cgi.param(PARAM_OFFSET));
79         COUNT           = parseInt(cgi.param(PARAM_COUNT));
80         HITCOUNT        = parseInt(cgi.param(PARAM_HITCOUNT));
81         MRID            = parseInt(cgi.param(PARAM_MRID));
82         RID             = parseInt(cgi.param(PARAM_RID));
83         TOPRANK  = parseFloat(cgi.param(PARAM_TOPRANK));
84         AUTHTIME        = parseInt(cgi.param(PARAM_AUTHTIME));
85         ADVTERM = cgi.param(PARAM_ADVTERM);
86         ADVTYPE = cgi.param(PARAM_ADVTYPE);
87
88         /* set up some sane defaults */
89         if(isNaN(LOCATION))     LOCATION        = 1;
90         if(isNaN(DEPTH))                DEPTH           = 0;
91         if(isNaN(OFFSET))               OFFSET  = 0;
92         if(isNaN(COUNT))                COUNT           = 10;
93         if(isNaN(HITCOUNT))     HITCOUNT        = 0;
94         if(isNaN(MRID))         MRID            = 0;
95         if(isNaN(RID))                  RID             = 0;
96         if(isNaN(ORIGLOC))      ORIGLOC = 0;
97         if(isNaN(TOPRANK))      TOPRANK = 1;
98         if(isNaN(AUTHTIME))     AUTHTIME        = 1;
99         if(ADVTERM==null)               ADVTERM = "";
100 }
101
102 function initCookies() {
103         FONTSIZE = "medium";
104         var font = fontCookie.get(COOKIE_FONT);
105         if(font) FONTSIZE = font;
106         SKIN = skinCookie.get(COOKIE_SKIN);
107 }
108
109 /* URL param accessors */
110 function getTerm(){return TERM;}
111 function getStype(){return STYPE;}
112 function getLocation(){return LOCATION;}
113 function getDepth(){return DEPTH;}
114 function getForm(){return FORM;}
115 function getOffset(){return OFFSET;}
116 function getDisplayCount(){return COUNT;}
117 function getHitCount(){return HITCOUNT;}
118 function getMrid(){return MRID;};
119 function getRid(){return RID;};
120 function getOrigLocation(){return ORIGLOC;}
121 function getTopRank(){return TOPRANK;}
122 function getAuthtime() { return AUTHTIME; }
123 function getSearchBarExtras(){return SBEXTRAS;}
124 function getFontSize(){return FONTSIZE;};
125 function getSkin(){return SKIN;};
126 function getAdvTerm(){return ADVTERM;}
127 function getAdvType(){return ADVTYPE;}
128
129
130 function findBasePath() {
131         var path = location.pathname;
132         if(!path.match(/.*\.xml$/)) path += "index.xml"; 
133         var idx = path.indexOf(config.page[findCurrentPage()]);
134         return path.substring(0, idx);
135 }
136
137 function findBaseURL(ssl) {
138         var path = findBasePath();
139         var proto = (ssl) ? "https:" : "http:";
140         return proto + "//" + location.host + path;
141         dump( 'ssl: ' + ssl + 'proto ' + proto );
142 }
143
144 /*
145 function buildISBNSrc(isbn) {
146         return "http://" + location.host + "/jackets/" + isbn;
147 }
148 */
149
150 function buildImageLink(name, ssl) {
151         return findBaseURL(ssl) + "../../../../images/" + name;
152 }
153
154 function buildExtrasLink(name, ssl) {
155         return findBaseURL(ssl) + "../../../../extras/" + name;
156 }
157
158 function  buildOPACLink(args, slim, ssl) {
159
160         if(!args) args = {};
161         var string = "";
162
163         if(!slim) {
164                 string = findBaseURL(ssl);
165                 if(args.page) string += config.page[args.page];
166                 else string += config.page[findCurrentPage()];
167         }
168
169         string += "?";
170
171         for( var x in args ) {
172                 if(x == "page" || args[x] == null) continue;
173                 string += "&" + x + "=" + encodeURIComponent(args[x]);
174         }
175
176         string += _appendParam(ORIGLOC, PARAM_ORIGLOC, args, getOrigLocation, string);
177         string += _appendParam(TERM,            PARAM_TERM, args, getTerm, string);
178         string += _appendParam(STYPE,           PARAM_STYPE, args, getStype, string);
179         string += _appendParam(LOCATION, PARAM_LOCATION, args, getLocation, string);
180         string += _appendParam(DEPTH,           PARAM_DEPTH, args, getDepth, string);
181         string += _appendParam(FORM,            PARAM_FORM, args, getForm, string);
182         string += _appendParam(OFFSET,  PARAM_OFFSET, args, getOffset, string);
183         string += _appendParam(COUNT,           PARAM_COUNT, args, getDisplayCount, string);
184         string += _appendParam(HITCOUNT, PARAM_HITCOUNT, args, getHitCount, string);
185         string += _appendParam(MRID,            PARAM_MRID, args, getMrid, string);
186         string += _appendParam(RID,             PARAM_RID, args, getRid, string);
187         string += _appendParam(TOPRANK, PARAM_TOPRANK, args, getTopRank, string);
188         string += _appendParam(AUTHTIME,        PARAM_AUTHTIME, args, getAuthtime, string);
189         string += _appendParam(ADVTERM, PARAM_ADVTERM, args, getAdvTerm, string);
190         string += _appendParam(ADVTYPE, PARAM_ADVTYPE, args, getAdvType, string);
191
192         return string.replace(/\&$/,'').replace(/\?\&/,"?");    
193 }
194
195 function _appendParam( fieldVar, fieldName, overrideArgs, getFunc, string ) {
196         var ret = "";
197         if( fieldVar != null && overrideArgs[fieldName] == null ) 
198                 ret = "&" + fieldName + "=" + encodeURIComponent(getFunc());
199         return ret;
200 }
201
202 /* ----------------------------------------------------------------------- */
203 function cleanISBN(isbn) {
204    if(isbn) {
205       isbn = isbn.toString().replace(/^\s+/,"");
206       var idx = isbn.indexOf(" ");
207       if(idx > -1) { isbn = isbn.substring(0, idx); }
208    } else isbn = "";
209    return isbn;
210 }       
211
212
213 /* builds a link that goes to the title listings for a metarecord */
214 function buildTitleLink(rec, link) {
215         if(!rec) return;
216         link.appendChild(text(normalize(truncate(rec.title(), 65))));
217         var args = {};
218         args.page = RRESULT;
219         args[PARAM_OFFSET] = 0;
220         args[PARAM_MRID] = rec.doc_id();
221         link.setAttribute("href", buildOPACLink(args));
222 }
223
224 function buildTitleDetailLink(rec, link) {
225         if(!rec) return;
226         link.appendChild(text(normalize(truncate(rec.title(), 65))));
227         var args = {};
228         args.page = RDETAIL;
229         args[PARAM_OFFSET] = 0;
230         args[PARAM_RID] = rec.doc_id();
231         link.setAttribute("href", buildOPACLink(args));
232 }
233
234 /* 'type' is one of STYPE_AUTHOR, STYPE_SUBJECT, ... found in config.js 
235         'trunc' is the number of characters to show in the string, defaults to 65 */
236 function buildSearchLink(type, string, linknode, trunc) {
237         if(!trunc) trunc = 65;
238         var args = {};
239         args.page = MRESULT;
240         args[PARAM_OFFSET] = 0;
241         args[PARAM_TERM] = string;
242         args[PARAM_STYPE] = type;
243         linknode.appendChild(text(normalize(truncate(string, trunc))));
244         linknode.setAttribute("href", buildOPACLink(args));
245 }
246
247
248 /* ----------------------------------------------------------------------- */
249 /* user session handling */
250 /* ----------------------------------------------------------------------- */
251 /* session is the login session.  If no session is provided, we attempt
252         to find one in the cookies.  If 'force' is true we retrieve the 
253         user from the server even if there is already a global user present.
254         if ses != G.user.session, we also force a grab */
255 var cookie = new cookieObject("ses", 1, "/", COOKIE_SES);
256 function grabUser(ses, force) {
257
258         if(!ses && isXUL()) ses = xulG['authtoken'];
259         if(!ses) ses = cookie.get(COOKIE_SES);
260         if(!ses) return false;
261
262         if(!force) 
263                 if(G.user && G.user.session == ses)
264                         return G.user;
265
266         /* first make sure the session is valid */
267         var request = new Request(FETCH_SESSION, ses, 1 );
268         request.send(true);
269         var user = request.result();
270
271         if(checkILSEvent(user)) {
272                 __ilsEvent = user;
273                 doLogout();
274                 return false; /* unable to grab the session */
275         }
276
277         if( !(typeof user == 'object' && user._isfieldmapper) ) {
278                 doLogout();
279                 return false;
280         }
281
282         G.user = user;
283         G.user.fleshed = false;
284         G.user.session = ses;
285         cookie.put(COOKIE_SES, ses);
286         cookie.write();
287
288         grabUserPrefs();
289         if(G.user.prefs['opac.hits_per_page'])
290                 COUNT = parseInt(G.user.prefs['opac.hits_per_page']);
291
292         var at = getAuthtime();
293         if(isXUL()) at = xulG['authtime'];
294
295         //new AuthTimer(at).run(); /* needs debugging... */
296
297         return G.user;
298 }
299
300
301 /* sets the 'prefs' field of the user object to their preferences 
302         and returns the preferences */
303 function grabUserPrefs(user, force) {
304         if(user == null) user = G.user;
305         if(!force && user.prefs) return user.prefs;     
306         var req = new Request(FETCH_USER_PREFS, user.session, user.id());
307         req.send(true);
308         user.prefs = req.result();
309         return user.prefs;
310 }
311
312 function grabFleshedUser() {
313
314         if(!G.user || !G.user.session) {
315                 grabUser();     
316                 if(!G.user || !G.user.session) return null;
317         }
318
319         if(G.user.fleshed) return G.user;
320
321    var req = new Request(FETCH_FLESHED_USER, G.user.session);
322         req.send(true);
323
324         G.user = req.result();
325
326         if(!G.user || G.user.length == 0) { 
327                 G.user = null; return false; 
328                 cookie.remove(COOKIE_SES);
329         }
330
331         G.user.session = ses;
332         G.user.fleshed = true;
333
334         cookie.put(COOKIE_SES, ses); /*  update the cookie */
335         cookie.write();
336
337         return G.user;
338 }
339
340 var skinCookie = new cookieObject("skin", 1, "/", COOKIE_SKIN);
341 function checkUserSkin(new_skin) {
342
343         return; /* XXX do some debugging with this... */
344
345         var user_skin = getSkin();
346         var cur_skin = grabSkinFromURL();
347
348         if(new_skin) user_skin = new_skin;
349
350         if(!user_skin) {
351
352                 if(grabUser()) {
353                         if(grabUserPrefs()) {
354                                 user_skin = G.user.prefs["opac.skin"];
355                                 skinCookie.put( COOKIE_SKIN, user_skin );
356                                 skinCookie.write();
357                         }
358                 }
359         }
360
361         if(!user_skin) return;
362
363         if( cur_skin != user_skin ) {
364                 var url = buildOPACLink();
365                 goTo(url.replace(cur_skin, user_skin));
366         }
367 }
368
369 function updateUserSetting(setting, value, user) {
370         if(user == null) user = G.user;
371         var a = {};
372         a[setting] = value;
373         var req = new Request( UPDATE_USER_PREFS, user.session, a );
374         req.send(true);
375         return req.result();
376 }
377
378 function commitUserPrefs() {
379         var req = new Request( 
380                 UPDATE_USER_PREFS, G.user.session, null, G.user.prefs );
381         req.send(true);
382         return req.result();
383 }
384
385 function grabSkinFromURL() {
386         var path = findBasePath();
387         path = path.replace("/xml/", "");
388         var skin = "";
389         for( var i = path.length - 1; i >= 0; i-- ) {
390                 var ch = path.charAt(i);
391                 if(ch == "/") break;
392                 skin += ch;
393         }
394
395         var skin2 = "";
396         for( i = skin.length - 1; i >= 0; i--)
397                 skin2 += skin.charAt(i);
398
399         return skin2;
400 }
401
402
403 /* returns a fleshed G.user on success, false on failure */
404 function doLogin() {
405
406         var uname = G.ui.login.username.value;
407         var passwd = G.ui.login.password.value; 
408
409         var init_request = new Request( LOGIN_INIT, uname );
410    init_request.send(true);
411    var seed = init_request.result();
412
413    if( ! seed || seed == '0') {
414       alert( "Error Communicating with Authentication Server" );
415       return null;
416    }
417
418    var auth_request = new Request( LOGIN_COMPLETE, 
419                 uname, hex_md5(seed + hex_md5(passwd)), "opac", getOrigLocation());
420
421
422    auth_request.send(true);
423    var auth_result = auth_request.result();
424
425         var code = checkILSEvent(auth_result);
426         if(code) { alertILSEvent(code); return null; }
427
428         AUTHTIME = parseInt(auth_result.payload.authtime);
429         var u = grabUser(auth_result.payload.authtoken, true);
430         if(u) runEvt( "common", "locationChanged", u.home_ou(), findOrgDepth(u.home_ou()) );
431
432         checkUserSkin();
433
434         return u;
435 }
436
437 function doLogout(noredirect) {
438
439         /* be nice and delete the session from the server */
440         if(G.user && G.user.session) { 
441                 var req = new Request(LOGIN_DELETE, G.user.session);
442       req.send(true);
443                 try { req.result(); } catch(E){}
444     }
445
446         G.user = null;
447         cookie.remove(COOKIE_SES);
448         skinCookie.remove(COOKIE_SKIN);
449         checkUserSkin("default");
450         COUNT = 10;
451
452         var args = {};
453         args[PARAM_TERM] = "";
454         args[PARAM_LOCATION] = globalOrgTree.id();
455         args[PARAM_DEPTH] = findOrgDepth(globalOrgTree);
456         args.page = "home";
457
458         var nored = false;
459         try{ if(isFrontPage) nored = true; } catch(e){nored = false;}
460         if(!nored) goTo(buildOPACLink(args));
461 }
462
463
464 function hideMe(obj) { addCSSClass(obj, config.css.hide_me); } 
465 function unHideMe(obj) { removeCSSClass(obj, config.css.hide_me); }
466
467
468 /* ----------------------------------------------------------------------- */
469 /* build the org tree */
470 /* ----------------------------------------------------------------------- */
471 function drawOrgTree() {
472         //G.ui.common.org_tree.innerHTML = buildOrgSelector().toString();
473         //buildOrgSelector(G.ui.common.org_tree, orgTreeSelector);
474         setTimeout( 'buildOrgSelector(G.ui.common.org_tree, orgTreeSelector);', 10 );
475 }
476         
477 var orgTreeSelector;
478 function buildOrgSelector(node) {
479         //var tree = new dTree("orgTreeSelector"); 
480         var tree = new SlimTree(node,'orgTreeSelector');
481         orgTreeSelector = tree;
482         for( var i in orgArraySearcher ) { 
483                 var node = orgArraySearcher[i];
484                 if( node == null ) continue;
485                 if(node.parent_ou() == null)
486                         tree.addNode(node.id(), -1, node.name(), 
487                                 "javascript:orgSelect(" + node.id() + ");", node.name());
488                 else {
489                         tree.addNode(node.id(), findOrgUnit(node.parent_ou()).id(), node.name(), 
490                                 "javascript:orgSelect(" + node.id() + ");", node.name());
491                 }
492         }
493         hideMe($('org_loading_div'));
494         unHideMe($('org_selector_tip'));
495         return tree;
496 }
497
498 function orgSelect(id) {
499         showCanvas();
500         runEvt("common", "locationChanged", id, findOrgDepth(id) );
501
502         removeChildren(G.ui.common.now_searching);
503         G.ui.common.now_searching.appendChild(text(findOrgUnit(id).name()));
504 }
505
506 var fontCookie = new cookieObject("fonts", 1, "/", COOKIE_FONT);
507 function setFontSize(size) {
508         scaleFonts(size);
509         fontCookie.put(COOKIE_FONT, size);
510         fontCookie.write();
511 }
512
513
514 var resourceFormats = [
515    "text",
516    "moving image",
517    "sound recording", "software, multimedia",
518    "still images",
519    "cartographic",
520    "mixed material",
521    "notated music",
522    "three dimensional object" ];
523
524
525 function modsFormatToMARC(format) {
526    switch(format) {
527       case "text":
528          return "at";
529       case "moving image":
530          return "g";
531       case "sound recording":
532          return "ij";
533       case "sound recording-nonmusical":
534          return "i";
535       case "sound recording-musical":
536          return "j";
537       case "software, multimedia":
538          return "m";
539       case "still images":
540          return "k";
541       case "cartographic":
542          return "ef";
543       case "mixed material":
544          return "op";
545       case "notated music":
546          return "cd";
547       case "three dimensional object":
548          return "r";
549    }
550    return "at";
551 }
552
553
554 function MARCFormatToMods(format) {
555    switch(format) {
556       case "a":
557       case "t":
558          return "text";
559       case "g":
560          return "moving image";
561       case "i":
562          return "sound recording-nonmusical";
563       case "j":
564          return "sound recording-musical";
565       case "m":
566          return "software, multimedia";
567       case "k":
568          return "still images";
569       case "e":
570       case "f":
571          return "cartographic";
572       case "o":
573       case "p":
574          return "mixed material";
575       case "c":
576       case "d":
577          return "notated music";
578       case "r":
579          return "three dimensional object";
580    }
581    return "text";
582 }
583
584 function setResourcePic( img, resource ) {
585         img.setAttribute( "src", "../../../../images/tor/" + resource + ".jpg");
586         img.title = resource;
587 }
588
589
590
591 function msg( text ) {
592         try { alert( text ); } catch(e) {}
593 }
594
595 function findRecord(id,type) {
596         try {
597                 for( var i = 0; i != recordsCache.length; i++ ) {
598                         var rec = recordsCache[i];
599                         if( rec && rec.doc_id() == id ) return rec;
600                 }
601         } catch(E){}
602         var meth = FETCH_RMODS
603         if(type == 'M') meth = FETCH_MRMODS;
604         var req = new Request(meth, id);
605         req.send(true);
606         return req.result();
607 }
608
609 function Timer(name, node){
610         this.name = name;
611         this.count = 1;
612         this.node = node;
613 }
614 Timer.prototype.start = 
615         function(){_timerRun(this.name);}
616 Timer.prototype.stop = 
617         function(){this.done = true;}
618 function _timerRun(tname) {
619         var _t;
620         eval('_t='+tname);
621         if(_t.done) return;
622         if(_t.count > 100) return;
623         var str = ' . ';
624         if( (_t.count % 5) == 0 ) 
625                 str = _t.count / 5;
626         _t.node.appendChild(text(str));
627         setTimeout("_timerRun('"+tname+"');", 200);
628         _t.count++;
629 }
630
631 function checkILSEvent(obj) {
632         if( obj.ilsevent != null && obj.ilsevent != 0 )
633                 return parseInt(obj.ilsevent);
634         return null;
635 }
636 function alertILSEvent(code, msg) {
637    if(!msg) msg = "";
638         alert( msg + '\n' + $('ilsevent.' + code).innerHTML );
639 }
640
641
642 var __authTimer;
643 function AuthTimer(time) { 
644         this.time = (time - LOGOUT_WARNING_TIME) * 1000; 
645         __authTimer = this;
646 }
647
648 AuthTimer.prototype.run = function() {
649         setTimeout('_authTimerAlert()', this.time);
650 }
651
652 function _authTimerAlert() {
653         if( confirm( $('auth_session_expiring').innerHTML ) ) 
654                 doLogout();
655         else {
656                 if(!grabUser(null, true)) {
657                         alert($('auth_session_expired').innerHTML);
658                 }
659         }
660 }
661
662
663 function grabUserByBarcode( authtoken, barcode ) {
664         var req = new Request( FETCH_USER_BYBARCODE, authtoken, barcode );
665         req.send(true);
666         return req.result();
667 }
668
669
670 function goHome() {
671         goTo(buildOPACLink({page:HOME}));
672 }
673
674
675