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