b0dcec71caff8ad853fa3f2491dc63194773346e
[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         //setTimeout( 'buildOrgSelector(G.ui.common.org_tree, orgTreeSelector);', 10 );
473         setTimeout( 'buildOrgSelector(G.ui.common.org_tree, orgTreeSelector);', 1 );
474 }
475         
476 var orgTreeSelector;
477 function buildOrgSelector(node) {
478         var tree = new SlimTree(node,'orgTreeSelector');
479         orgTreeSelector = tree;
480         for( var i in orgArraySearcher ) { 
481                 var node = orgArraySearcher[i];
482                 if( node == null ) continue;
483                 if(node.parent_ou() == null)
484                         tree.addNode(node.id(), -1, node.name(), 
485                                 "javascript:orgSelect(" + node.id() + ");", node.name());
486                 else {
487                         tree.addNode(node.id(), findOrgUnit(node.parent_ou()).id(), node.name(), 
488                                 "javascript:orgSelect(" + node.id() + ");", node.name());
489                 }
490         }
491         hideMe($('org_loading_div'));
492         unHideMe($('org_selector_tip'));
493         return tree;
494 }
495
496 function orgSelect(id) {
497         showCanvas();
498         runEvt("common", "locationChanged", id, findOrgDepth(id) );
499
500         removeChildren(G.ui.common.now_searching);
501         G.ui.common.now_searching.appendChild(text(findOrgUnit(id).name()));
502 }
503
504 var fontCookie = new cookieObject("fonts", 1, "/", COOKIE_FONT);
505 function setFontSize(size) {
506         scaleFonts(size);
507         fontCookie.put(COOKIE_FONT, size);
508         fontCookie.write();
509 }
510
511
512 var resourceFormats = [
513    "text",
514    "moving image",
515    "sound recording", "software, multimedia",
516    "still images",
517    "cartographic",
518    "mixed material",
519    "notated music",
520    "three dimensional object" ];
521
522
523 function modsFormatToMARC(format) {
524    switch(format) {
525       case "text":
526          return "at";
527       case "moving image":
528          return "g";
529       case "sound recording":
530          return "ij";
531       case "sound recording-nonmusical":
532          return "i";
533       case "sound recording-musical":
534          return "j";
535       case "software, multimedia":
536          return "m";
537       case "still images":
538          return "k";
539       case "cartographic":
540          return "ef";
541       case "mixed material":
542          return "op";
543       case "notated music":
544          return "cd";
545       case "three dimensional object":
546          return "r";
547    }
548    return "at";
549 }
550
551
552 function MARCFormatToMods(format) {
553    switch(format) {
554       case "a":
555       case "t":
556          return "text";
557       case "g":
558          return "moving image";
559       case "i":
560          return "sound recording-nonmusical";
561       case "j":
562          return "sound recording-musical";
563       case "m":
564          return "software, multimedia";
565       case "k":
566          return "still images";
567       case "e":
568       case "f":
569          return "cartographic";
570       case "o":
571       case "p":
572          return "mixed material";
573       case "c":
574       case "d":
575          return "notated music";
576       case "r":
577          return "three dimensional object";
578    }
579    return "text";
580 }
581
582 function setResourcePic( img, resource ) {
583         img.setAttribute( "src", "../../../../images/tor/" + resource + ".jpg");
584         img.title = resource;
585 }
586
587
588
589 function msg( text ) {
590         try { alert( text ); } catch(e) {}
591 }
592
593 function findRecord(id,type) {
594         try {
595                 for( var i = 0; i != recordsCache.length; i++ ) {
596                         var rec = recordsCache[i];
597                         if( rec && rec.doc_id() == id ) return rec;
598                 }
599         } catch(E){}
600         var meth = FETCH_RMODS
601         if(type == 'M') meth = FETCH_MRMODS;
602         var req = new Request(meth, id);
603         req.send(true);
604         return req.result();
605 }
606
607 function Timer(name, node){
608         this.name = name;
609         this.count = 1;
610         this.node = node;
611 }
612 Timer.prototype.start = 
613         function(){_timerRun(this.name);}
614 Timer.prototype.stop = 
615         function(){this.done = true;}
616 function _timerRun(tname) {
617         var _t;
618         eval('_t='+tname);
619         if(_t.done) return;
620         if(_t.count > 100) return;
621         var str = ' . ';
622         if( (_t.count % 5) == 0 ) 
623                 str = _t.count / 5;
624         _t.node.appendChild(text(str));
625         setTimeout("_timerRun('"+tname+"');", 200);
626         _t.count++;
627 }
628
629 function checkILSEvent(obj) {
630         if( obj.ilsevent != null && obj.ilsevent != 0 )
631                 return parseInt(obj.ilsevent);
632         return null;
633 }
634 function alertILSEvent(code, msg) {
635    if(!msg) msg = "";
636         alert( msg + '\n' + $('ilsevent.' + code).innerHTML );
637 }
638
639
640 var __authTimer;
641 function AuthTimer(time) { 
642         this.time = (time - LOGOUT_WARNING_TIME) * 1000; 
643         __authTimer = this;
644 }
645
646 AuthTimer.prototype.run = function() {
647         setTimeout('_authTimerAlert()', this.time);
648 }
649
650 function _authTimerAlert() {
651         alert( $('auth_session_expiring').innerHTML );
652         if(!grabUser(null, true)) doLogout();
653 }
654
655
656 function grabUserByBarcode( authtoken, barcode ) {
657         var req = new Request( FETCH_USER_BYBARCODE, authtoken, barcode );
658         req.send(true);
659         return req.result();
660 }
661
662
663 function goHome() {
664         goTo(buildOPACLink({page:HOME}));
665 }
666
667
668