basic record level holds working on record result and record detail pages
[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         return G.user;
253
254 }
255
256 /* sets the 'prefs' field of the user object to their preferences 
257         and returns the preferences */
258 function grabUserPrefs(user, force) {
259         if(user == null) user = G.user;
260         if(!force && user.prefs) return user.prefs;     
261         var req = new Request(FETCH_USER_PREFS, user.session, user.id());
262         req.send(true);
263         user.prefs = req.result();
264         return user.prefs;
265 }
266
267 function grabFleshedUser() {
268
269         if(!G.user || !G.user.session) {
270                 grabUser();     
271                 if(!G.user || !G.user.session) return null;
272         }
273
274         if(G.user.fleshed) return G.user;
275
276    var req = new Request(FETCH_FLESHED_USER, G.user.session);
277         req.send(true);
278
279         G.user = req.result();
280
281         if(!G.user || G.user.length == 0) { 
282                 G.user = null; return false; 
283                 cookie.remove(COOKIE_SES);
284         }
285
286         G.user.session = ses;
287         G.user.fleshed = true;
288
289         cookie.put(COOKIE_SES, ses); /*  update the cookie */
290         cookie.write();
291
292         return G.user;
293 }
294
295 var skinCookie = new cookieObject("skin", 1, "/", COOKIE_SKIN);
296 function checkUserSkin(new_skin) {
297
298         return; /* XXX do some debugging with this... */
299
300         var user_skin = getSkin();
301         var cur_skin = grabSkinFromURL();
302
303         if(new_skin) user_skin = new_skin;
304
305         if(!user_skin) {
306
307                 if(grabUser()) {
308                         if(grabUserPrefs()) {
309                                 user_skin = G.user.prefs["opac.skin"];
310                                 skinCookie.put( COOKIE_SKIN, user_skin );
311                                 skinCookie.write();
312                         }
313                 }
314         }
315
316         if(!user_skin) return;
317
318         if( cur_skin != user_skin ) {
319                 var url = buildOPACLink();
320                 goTo(url.replace(cur_skin, user_skin));
321         }
322 }
323
324 function updateUserSetting(setting, value, user) {
325         if(user == null) user = G.user;
326         var a = {};
327         a[setting] = value;
328         var req = new Request( UPDATE_USER_PREFS, user.session, a );
329         req.send(true);
330         return req.result();
331 }
332
333 function grabSkinFromURL() {
334         var path = findBasePath();
335         path = path.replace("/xml/", "");
336         var skin = "";
337         for( var i = path.length - 1; i >= 0; i-- ) {
338                 var ch = path.charAt(i);
339                 if(ch == "/") break;
340                 skin += ch;
341         }
342
343         var skin2 = "";
344         for( i = skin.length - 1; i >= 0; i--)
345                 skin2 += skin.charAt(i);
346
347         return skin2;
348 }
349
350
351 /* returns a fleshed G.user on success, false on failure */
352 function doLogin() {
353
354         var uname = G.ui.login.username.value;
355         var passwd = G.ui.login.password.value; 
356
357         var init_request = new Request( LOGIN_INIT, uname );
358    init_request.send(true);
359    var seed = init_request.result();
360
361    if( ! seed || seed == '0') {
362       alert( "Error Communicating with Authentication Server" );
363       return null;
364    }
365
366    var auth_request = new Request( LOGIN_COMPLETE, 
367                 uname, hex_md5(seed + hex_md5(passwd)), "opac");
368
369
370    auth_request.send(true);
371    var auth_result = auth_request.result();
372
373    if(auth_result == '0' || auth_result == null || auth_result.length == 0) { 
374                 alert("Login failed");
375                 return false; 
376         }
377
378         var u = grabUser(auth_result, true);
379         if(u) runEvt( "common", "locationChanged", u.home_ou(), findOrgDepth(u.home_ou()) );
380
381         checkUserSkin();
382
383         return u;
384 }
385
386 function doLogout() {
387
388         /* be nice and delete the session from the server */
389         if(G.user && G.user.session) { 
390                 var req = new Request(LOGIN_DELETE, G.user.session);
391       req.send(true);
392                 try { req.result(); } catch(E){}
393     }
394
395         G.user = null;
396         cookie.remove(COOKIE_SES);
397         skinCookie.remove(COOKIE_SKIN);
398         checkUserSkin("default");
399
400         var args = {};
401         args[PARAM_TERM] = "";
402         args[PARAM_LOCATION] = globalOrgTree.id();
403         args[PARAM_DEPTH] = findOrgDepth(globalOrgTree);
404         args.page = "home";
405
406         goTo(buildOPACLink(args));
407 }
408
409
410 function hideMe(obj) { addCSSClass(obj, config.css.hide_me); } 
411 function unHideMe(obj) { removeCSSClass(obj, config.css.hide_me); }
412
413
414 /* ----------------------------------------------------------------------- */
415 /* build the org tree */
416 /* ----------------------------------------------------------------------- */
417 function drawOrgTree() {
418         //G.ui.common.org_tree.innerHTML = buildOrgSelector().toString();
419         //buildOrgSelector(G.ui.common.org_tree, orgTreeSelector);
420         setTimeout( 'buildOrgSelector(G.ui.common.org_tree, orgTreeSelector);', 10 );
421 }
422         
423 var orgTreeSelector;
424 function buildOrgSelector(node) {
425         //var tree = new dTree("orgTreeSelector"); 
426         var tree = new SlimTree(node,'orgTreeSelector');
427         orgTreeSelector = tree;
428         for( var i in orgArraySearcher ) { 
429                 var node = orgArraySearcher[i];
430                 if( node == null ) continue;
431                 if(node.parent_ou() == null)
432                         tree.addNode(node.id(), -1, node.name(), 
433                                 "javascript:orgSelect(" + node.id() + ");", node.name());
434                 else {
435                         tree.addNode(node.id(), findOrgUnit(node.parent_ou()).id(), node.name(), 
436                                 "javascript:orgSelect(" + node.id() + ");", node.name());
437                 }
438         }
439         hideMe($('org_loading_div'));
440         unHideMe($('org_selector_tip'));
441         return tree;
442 }
443
444 function orgSelect(id) {
445         showCanvas();
446         runEvt("common", "locationChanged", id, findOrgDepth(id) );
447
448         removeChildren(G.ui.common.now_searching);
449         G.ui.common.now_searching.appendChild(text(findOrgUnit(id).name()));
450 }
451
452 var fontCookie = new cookieObject("fonts", 1, "/", COOKIE_FONT);
453 function setFontSize(size) {
454         scaleFonts(size);
455         fontCookie.put(COOKIE_FONT, size);
456         fontCookie.write();
457 }
458
459
460 var resourceFormats = [
461    "text",
462    "moving image",
463    "sound recording", "software, multimedia",
464    "still images",
465    "cartographic",
466    "mixed material",
467    "notated music",
468    "three dimensional object" ];
469
470
471 function modsFormatToMARC(format) {
472    switch(format) {
473       case "text":
474          return "at";
475       case "moving image":
476          return "g";
477       case "sound recording":
478          return "ij";
479       case "sound recording-nonmusical":
480          return "i";
481       case "sound recording-musical":
482          return "j";
483       case "software, multimedia":
484          return "m";
485       case "still images":
486          return "k";
487       case "cartographic":
488          return "ef";
489       case "mixed material":
490          return "op";
491       case "notated music":
492          return "cd";
493       case "three dimensional object":
494          return "r";
495    }
496    return "at";
497 }
498
499
500 function MARCFormatToMods(format) {
501    switch(format) {
502       case "a":
503       case "t":
504          return "text";
505       case "g":
506          return "moving image";
507       case "i":
508          return "sound recording-nonmusical";
509       case "j":
510          return "sound recording-musical";
511       case "m":
512          return "software, multimedia";
513       case "k":
514          return "still images";
515       case "e":
516       case "f":
517          return "cartographic";
518       case "o":
519       case "p":
520          return "mixed material";
521       case "c":
522       case "d":
523          return "notated music";
524       case "r":
525          return "three dimensional object";
526    }
527    return "text";
528 }
529
530 function setResourcePic( img, resource ) {
531         img.setAttribute( "src", "../../../images/tor/" + resource + ".jpg");
532         img.title = resource;
533 }
534
535
536
537 function msg( text ) {
538         try {
539                 alert( text );
540         } catch(e) {}
541 }
542
543 function findRecord(id,type) {
544         try {
545                 for( var i = 0; i != recordsCache.length; i++ ) {
546                         var rec = recordsCache[i];
547                         if( rec && rec.doc_id() == id ) return rec;
548                 }
549         } catch(E){}
550         var meth = FETCH_RMODS
551         if(type == 'M') meth = FETCH_MRMODS;
552         var req = new Request(meth, id);
553         req.send(true);
554         return req.result();
555 }
556
557
558
559