not launching timer on timeout==0
[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         if(at) new AuthTimer(at).run(); 
322         return G.user;
323 }
324
325
326 /* sets the 'prefs' field of the user object to their preferences 
327         and returns the preferences */
328 function grabUserPrefs(user, force) {
329         if(user == null) user = G.user;
330         if(!force && user.prefs) return user.prefs;     
331         var req = new Request(FETCH_USER_PREFS, user.session, user.id());
332         req.send(true);
333         user.prefs = req.result();
334         return user.prefs;
335 }
336
337 function grabFleshedUser() {
338
339         if(!G.user || !G.user.session) {
340                 grabUser();     
341                 if(!G.user || !G.user.session) return null;
342         }
343
344         if(G.user.fleshed) return G.user;
345
346    var req = new Request(FETCH_FLESHED_USER, G.user.session);
347         req.send(true);
348
349         G.user = req.result();
350
351         if(!G.user || G.user.length == 0) { 
352                 G.user = null; return false; 
353                 cookieManager.remove(COOKIE_SES);
354         }
355
356         G.user.session = ses;
357         G.user.fleshed = true;
358
359         cookieManager.write(COOKIE_SES, ses, '+1y'); /*  update the cookie */
360         return G.user;
361 }
362
363 function checkUserSkin(new_skin) {
364
365         return; /* XXX do some debugging with this... */
366
367         var user_skin = getSkin();
368         var cur_skin = grabSkinFromURL();
369
370         if(new_skin) user_skin = new_skin;
371
372         if(!user_skin) {
373
374                 if(grabUser()) {
375                         if(grabUserPrefs()) {
376                                 user_skin = G.user.prefs["opac.skin"];
377                                 cookieManager.write( COOKIE_SKIN, user_skin, '+1y' );
378                         }
379                 }
380         }
381
382         if(!user_skin) return;
383
384         if( cur_skin != user_skin ) {
385                 var url = buildOPACLink();
386                 goTo(url.replace(cur_skin, user_skin));
387         }
388 }
389
390 function updateUserSetting(setting, value, user) {
391         if(user == null) user = G.user;
392         var a = {};
393         a[setting] = value;
394         var req = new Request( UPDATE_USER_PREFS, user.session, a );
395         req.send(true);
396         return req.result();
397 }
398
399 function commitUserPrefs() {
400         var req = new Request( 
401                 UPDATE_USER_PREFS, G.user.session, null, G.user.prefs );
402         req.send(true);
403         return req.result();
404 }
405
406 function grabSkinFromURL() {
407         var path = findBasePath();
408         path = path.replace("/xml/", "");
409         var skin = "";
410         for( var i = path.length - 1; i >= 0; i-- ) {
411                 var ch = path.charAt(i);
412                 if(ch == "/") break;
413                 skin += ch;
414         }
415
416         var skin2 = "";
417         for( i = skin.length - 1; i >= 0; i--)
418                 skin2 += skin.charAt(i);
419
420         return skin2;
421 }
422
423
424 /* returns a fleshed G.user on success, false on failure */
425 function doLogin() {
426
427         cleanRemoteRequests(); /* cancel whatever is out there */
428
429         var uname = G.ui.login.username.value;
430         var passwd = G.ui.login.password.value; 
431
432         var init_request = new Request( LOGIN_INIT, uname );
433    init_request.send(true);
434    var seed = init_request.result();
435
436    if( ! seed || seed == '0') {
437       alert( "Error Communicating with Authentication Server" );
438       return null;
439    }
440
441    var auth_request = new Request( LOGIN_COMPLETE, 
442                 uname, hex_md5(seed + hex_md5(passwd)), "opac", getOrigLocation());
443
444
445    auth_request.send(true);
446    var auth_result = auth_request.result();
447
448         var code = checkILSEvent(auth_result);
449         if(code) { alertILSEvent(code); return null; }
450
451         AUTHTIME = parseInt(auth_result.payload.authtime);
452         var u = grabUser(auth_result.payload.authtoken, true);
453         if(u) runEvt( "common", "locationChanged", u.home_ou(), findOrgDepth(u.home_ou()) );
454
455         checkUserSkin();
456
457         return u;
458 }
459
460 function doLogout(noredirect) {
461
462         /* cancel everything else */
463         cleanRemoteRequests();
464
465         /* be nice and delete the session from the server */
466         if(G.user && G.user.session) { 
467                 var req = new Request(LOGIN_DELETE, G.user.session);
468       req.send(true);
469                 try { req.result(); } catch(E){}
470     }
471
472         G.user = null;
473         cookieManager.remove(COOKIE_SES);
474         cookieManager.remove(COOKIE_SKIN);
475         checkUserSkin("default");
476         COUNT = 10;
477
478         var args = {};
479         args[PARAM_TERM] = "";
480         args[PARAM_LOCATION] = globalOrgTree.id();
481         args[PARAM_DEPTH] = findOrgDepth(globalOrgTree);
482         args.page = "home";
483
484         var nored = false;
485         try{ if(isFrontPage) nored = true; } catch(e){nored = false;}
486         if(!nored) goTo(buildOPACLink(args));
487 }
488
489
490 function hideMe(obj) { addCSSClass(obj, config.css.hide_me); } 
491 function unHideMe(obj) { removeCSSClass(obj, config.css.hide_me); }
492
493
494 /* ----------------------------------------------------------------------- */
495 /* build the org tree */
496 /* ----------------------------------------------------------------------- */
497 function drawOrgTree() {
498         //setTimeout( 'buildOrgSelector(G.ui.common.org_tree, orgTreeSelector);', 10 );
499         setTimeout( 'buildOrgSelector(G.ui.common.org_tree, orgTreeSelector);', 1 );
500 }
501         
502 var orgTreeSelector;
503 function buildOrgSelector(node) {
504         var tree = new SlimTree(node,'orgTreeSelector');
505         orgTreeSelector = tree;
506         for( var i in orgArraySearcher ) { 
507                 var node = orgArraySearcher[i];
508                 if( node == null ) continue;
509                 if(node.parent_ou() == null)
510                         tree.addNode(node.id(), -1, node.name(), 
511                                 "javascript:orgSelect(" + node.id() + ");", node.name());
512                 else {
513                         tree.addNode(node.id(), findOrgUnit(node.parent_ou()).id(), node.name(), 
514                                 "javascript:orgSelect(" + node.id() + ");", node.name());
515                 }
516         }
517         hideMe($('org_loading_div'));
518         unHideMe($('org_selector_tip'));
519         return tree;
520 }
521
522 function orgSelect(id) {
523         showCanvas();
524         runEvt("common", "locationChanged", id, findOrgDepth(id) );
525
526         removeChildren(G.ui.common.now_searching);
527         G.ui.common.now_searching.appendChild(text(findOrgUnit(id).name()));
528 }
529
530 var fontCookie = new HTTP.Cookies();
531 function setFontSize(size) {
532         scaleFonts(size);
533         fontCookie.write(COOKIE_FONT, size, '+1y');
534 }
535
536
537 var resourceFormats = [
538    "text",
539    "moving image",
540    "sound recording", "software, multimedia",
541    "still images",
542    "cartographic",
543    "mixed material",
544    "notated music",
545    "three dimensional object" ];
546
547
548 function modsFormatToMARC(format) {
549    switch(format) {
550       case "text":
551          return "at";
552       case "moving image":
553          return "g";
554       case "sound recording":
555          return "ij";
556       case "sound recording-nonmusical":
557          return "i";
558       case "sound recording-musical":
559          return "j";
560       case "software, multimedia":
561          return "m";
562       case "still images":
563          return "k";
564       case "cartographic":
565          return "ef";
566       case "mixed material":
567          return "op";
568       case "notated music":
569          return "cd";
570       case "three dimensional object":
571          return "r";
572    }
573    return "at";
574 }
575
576
577 function MARCFormatToMods(format) {
578    switch(format) {
579       case "a":
580       case "t":
581          return "text";
582       case "g":
583          return "moving image";
584       case "i":
585          return "sound recording-nonmusical";
586       case "j":
587          return "sound recording-musical";
588       case "m":
589          return "software, multimedia";
590       case "k":
591          return "still images";
592       case "e":
593       case "f":
594          return "cartographic";
595       case "o":
596       case "p":
597          return "mixed material";
598       case "c":
599       case "d":
600          return "notated music";
601       case "r":
602          return "three dimensional object";
603    }
604    return "text";
605 }
606
607 function setResourcePic( img, resource ) {
608         img.setAttribute( "src", "../../../../images/tor/" + resource + ".jpg");
609         img.title = resource;
610 }
611
612
613
614 function msg( text ) {
615         try { alert( text ); } catch(e) {}
616 }
617
618 function findRecord(id,type) {
619         try {
620                 for( var i = 0; i != recordsCache.length; i++ ) {
621                         var rec = recordsCache[i];
622                         if( rec && rec.doc_id() == id ) return rec;
623                 }
624         } catch(E){}
625         var meth = FETCH_RMODS
626         if(type == 'M') meth = FETCH_MRMODS;
627         var req = new Request(meth, id);
628         req.send(true);
629         return req.result();
630 }
631
632 function Timer(name, node){
633         this.name = name;
634         this.count = 1;
635         this.node = node;
636 }
637 Timer.prototype.start = 
638         function(){_timerRun(this.name);}
639 Timer.prototype.stop = 
640         function(){this.done = true;}
641 function _timerRun(tname) {
642         var _t;
643         eval('_t='+tname);
644         if(_t.done) return;
645         if(_t.count > 100) return;
646         var str = ' . ';
647         if( (_t.count % 5) == 0 ) 
648                 str = _t.count / 5;
649         _t.node.appendChild(text(str));
650         setTimeout("_timerRun('"+tname+"');", 200);
651         _t.count++;
652 }
653
654 function checkILSEvent(obj) {
655         if( obj.ilsevent != null && obj.ilsevent != 0 )
656                 return parseInt(obj.ilsevent);
657         return null;
658 }
659 function alertILSEvent(code, msg) {
660    if(!msg) msg = "";
661         alert( msg + '\n' + $('ilsevent.' + code).innerHTML );
662 }
663
664
665 var __authTimer;
666 function AuthTimer(time) { 
667         this.time = (time - LOGOUT_WARNING_TIME) * 1000; 
668         __authTimer = this;
669 }
670
671 AuthTimer.prototype.run = function() {
672         setTimeout('_authTimerAlert()', this.time);
673 }
674
675 function _authTimerAlert() {
676         alert( $('auth_session_expiring').innerHTML );
677         if(!grabUser(null, true)) doLogout();
678 }
679
680
681 function grabUserByBarcode( authtoken, barcode ) {
682         var req = new Request( FETCH_USER_BYBARCODE, authtoken, barcode );
683         req.send(true);
684         return req.result();
685 }
686
687
688 function goHome() {
689         goTo(buildOPACLink({page:HOME}));
690 }
691
692
693