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