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