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