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