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