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