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