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