debugging the sort order stuff, changed some terminology, only
[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 ) 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 && 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         var uname = G.ui.login.username.value;
429         var passwd = G.ui.login.password.value; 
430
431         var init_request = new Request( LOGIN_INIT, uname );
432    init_request.send(true);
433    var seed = init_request.result();
434
435    if( ! seed || seed == '0') {
436       alert( "Error Communicating with Authentication Server" );
437       return null;
438    }
439
440    var auth_request = new Request( LOGIN_COMPLETE, 
441                 uname, hex_md5(seed + hex_md5(passwd)), "opac", getOrigLocation());
442
443
444    auth_request.send(true);
445    var auth_result = auth_request.result();
446
447         var code = checkILSEvent(auth_result);
448         if(code) { alertILSEvent(code); return null; }
449
450         AUTHTIME = parseInt(auth_result.payload.authtime);
451         var u = grabUser(auth_result.payload.authtoken, true);
452         if(u) runEvt( "common", "locationChanged", u.home_ou(), findOrgDepth(u.home_ou()) );
453
454         checkUserSkin();
455
456         return u;
457 }
458
459 function doLogout(noredirect) {
460
461         /* be nice and delete the session from the server */
462         if(G.user && G.user.session) { 
463                 var req = new Request(LOGIN_DELETE, G.user.session);
464       req.send(true);
465                 try { req.result(); } catch(E){}
466     }
467
468         G.user = null;
469         cookieManager.remove(COOKIE_SES);
470         cookieManager.remove(COOKIE_SKIN);
471         checkUserSkin("default");
472         COUNT = 10;
473
474         var args = {};
475         args[PARAM_TERM] = "";
476         args[PARAM_LOCATION] = globalOrgTree.id();
477         args[PARAM_DEPTH] = findOrgDepth(globalOrgTree);
478         args.page = "home";
479
480         var nored = false;
481         try{ if(isFrontPage) nored = true; } catch(e){nored = false;}
482         if(!nored) goTo(buildOPACLink(args));
483 }
484
485
486 function hideMe(obj) { addCSSClass(obj, config.css.hide_me); } 
487 function unHideMe(obj) { removeCSSClass(obj, config.css.hide_me); }
488
489
490 /* ----------------------------------------------------------------------- */
491 /* build the org tree */
492 /* ----------------------------------------------------------------------- */
493 function drawOrgTree() {
494         //setTimeout( 'buildOrgSelector(G.ui.common.org_tree, orgTreeSelector);', 10 );
495         setTimeout( 'buildOrgSelector(G.ui.common.org_tree, orgTreeSelector);', 1 );
496 }
497         
498 var orgTreeSelector;
499 function buildOrgSelector(node) {
500         var tree = new SlimTree(node,'orgTreeSelector');
501         orgTreeSelector = tree;
502         for( var i in orgArraySearcher ) { 
503                 var node = orgArraySearcher[i];
504                 if( node == null ) continue;
505                 if(node.parent_ou() == null)
506                         tree.addNode(node.id(), -1, node.name(), 
507                                 "javascript:orgSelect(" + node.id() + ");", node.name());
508                 else {
509                         tree.addNode(node.id(), findOrgUnit(node.parent_ou()).id(), node.name(), 
510                                 "javascript:orgSelect(" + node.id() + ");", node.name());
511                 }
512         }
513         hideMe($('org_loading_div'));
514         unHideMe($('org_selector_tip'));
515         return tree;
516 }
517
518 function orgSelect(id) {
519         showCanvas();
520         runEvt("common", "locationChanged", id, findOrgDepth(id) );
521
522         removeChildren(G.ui.common.now_searching);
523         G.ui.common.now_searching.appendChild(text(findOrgUnit(id).name()));
524 }
525
526 var fontCookie = new HTTP.Cookies();
527 function setFontSize(size) {
528         scaleFonts(size);
529         fontCookie.write(COOKIE_FONT, size, '+1y');
530 }
531
532
533 var resourceFormats = [
534    "text",
535    "moving image",
536    "sound recording", "software, multimedia",
537    "still images",
538    "cartographic",
539    "mixed material",
540    "notated music",
541    "three dimensional object" ];
542
543
544 function modsFormatToMARC(format) {
545    switch(format) {
546       case "text":
547          return "at";
548       case "moving image":
549          return "g";
550       case "sound recording":
551          return "ij";
552       case "sound recording-nonmusical":
553          return "i";
554       case "sound recording-musical":
555          return "j";
556       case "software, multimedia":
557          return "m";
558       case "still images":
559          return "k";
560       case "cartographic":
561          return "ef";
562       case "mixed material":
563          return "op";
564       case "notated music":
565          return "cd";
566       case "three dimensional object":
567          return "r";
568    }
569    return "at";
570 }
571
572
573 function MARCFormatToMods(format) {
574    switch(format) {
575       case "a":
576       case "t":
577          return "text";
578       case "g":
579          return "moving image";
580       case "i":
581          return "sound recording-nonmusical";
582       case "j":
583          return "sound recording-musical";
584       case "m":
585          return "software, multimedia";
586       case "k":
587          return "still images";
588       case "e":
589       case "f":
590          return "cartographic";
591       case "o":
592       case "p":
593          return "mixed material";
594       case "c":
595       case "d":
596          return "notated music";
597       case "r":
598          return "three dimensional object";
599    }
600    return "text";
601 }
602
603 function setResourcePic( img, resource ) {
604         img.setAttribute( "src", "../../../../images/tor/" + resource + ".jpg");
605         img.title = resource;
606 }
607
608
609
610 function msg( text ) {
611         try { alert( text ); } catch(e) {}
612 }
613
614 function findRecord(id,type) {
615         try {
616                 for( var i = 0; i != recordsCache.length; i++ ) {
617                         var rec = recordsCache[i];
618                         if( rec && rec.doc_id() == id ) return rec;
619                 }
620         } catch(E){}
621         var meth = FETCH_RMODS
622         if(type == 'M') meth = FETCH_MRMODS;
623         var req = new Request(meth, id);
624         req.send(true);
625         return req.result();
626 }
627
628 function Timer(name, node){
629         this.name = name;
630         this.count = 1;
631         this.node = node;
632 }
633 Timer.prototype.start = 
634         function(){_timerRun(this.name);}
635 Timer.prototype.stop = 
636         function(){this.done = true;}
637 function _timerRun(tname) {
638         var _t;
639         eval('_t='+tname);
640         if(_t.done) return;
641         if(_t.count > 100) return;
642         var str = ' . ';
643         if( (_t.count % 5) == 0 ) 
644                 str = _t.count / 5;
645         _t.node.appendChild(text(str));
646         setTimeout("_timerRun('"+tname+"');", 200);
647         _t.count++;
648 }
649
650 function checkILSEvent(obj) {
651         if( obj.ilsevent != null && obj.ilsevent != 0 )
652                 return parseInt(obj.ilsevent);
653         return null;
654 }
655 function alertILSEvent(code, msg) {
656    if(!msg) msg = "";
657         alert( msg + '\n' + $('ilsevent.' + code).innerHTML );
658 }
659
660
661 var __authTimer;
662 function AuthTimer(time) { 
663         this.time = (time - LOGOUT_WARNING_TIME) * 1000; 
664         __authTimer = this;
665 }
666
667 AuthTimer.prototype.run = function() {
668         setTimeout('_authTimerAlert()', this.time);
669 }
670
671 function _authTimerAlert() {
672         alert( $('auth_session_expiring').innerHTML );
673         if(!grabUser(null, true)) doLogout();
674 }
675
676
677 function grabUserByBarcode( authtoken, barcode ) {
678         var req = new Request( FETCH_USER_BYBARCODE, authtoken, barcode );
679         req.send(true);
680         return req.result();
681 }
682
683
684 function goHome() {
685         goTo(buildOPACLink({page:HOME}));
686 }
687
688
689