8c921565a84e9824ee37ac7697b2aa651858845a
[Evergreen.git] / Open-ILS / web / opac / skin / default / js / result_common.js
1
2 var recordsHandled = 0;
3 var recordsCache = [];
4 var lowHitCount = 4;
5
6 var resultFetchAllRecords = false;
7
8 /* set up the event handlers */
9 if( findCurrentPage() == MRESULT || findCurrentPage() == RRESULT ) {
10         G.evt.result.hitCountReceived.push(resultSetHitInfo);
11         G.evt.result.recordReceived.push(resultDisplayRecord, resultAddCopyCounts);
12         G.evt.result.copyCountsReceived.push(resultDisplayCopyCounts);
13         G.evt.result.allRecordsReceived.push(resultBuildCaches, resultDrawSubjects, resultDrawAuthors, resultDrawSeries);
14         attachEvt('result','lowHits',resultLowHits);
15         attachEvt('result','zeroHits',resultZeroHits);
16         attachEvt( "common", "locationUpdated", resultSBSubmit );
17         /* do this after we have ID's so the rank for mr pages will be correct */
18         attachEvt("result", "preCollectRecords", resultPaginate);
19 }
20
21 function resultSBSubmit(){searchBarSubmit();}
22
23 /* returns the last 'index' postion ocurring in this page */
24 function resultFinalPageIndex() {
25         if(getHitCount() < (getOffset() + getDisplayCount())) 
26                 return getHitCount() - 1;
27         return getOffset() + getDisplayCount() - 1;
28 }
29
30
31
32
33 /* generic search method */
34 function resultCollectSearchIds( type, method, handler ) {
35
36         var sort                = (getSort() == SORT_TYPE_REL) ? null : getSort(); 
37         var sortdir = (sort) ? ((getSortDir()) ? getSortDir() : SORT_DIR_ASC) : null;
38
39         var item_type;
40         var item_form;
41         var args = {};
42
43         if( type ) {
44                 args.searches = {};
45                 args.searches[getStype()] = {};
46                 var term = getTerm();
47                 if( term ) {
48                         term = term.replace(/'/,'');
49                         args.searches[getStype()].term = term;
50                 }
51
52                 var form = parseForm(getForm());
53                 item_type = form.item_type;
54                 item_form = form.item_form;
55
56         } else {
57                 args.searches = JSON2js(getSearches());
58                 item_type = (getItemType()) ? getItemType().split(/,/) : null;
59                 item_form = (getItemForm()) ? getItemForm().split(/,/) : null;
60         }
61
62         var limit = (resultFetchAllRecords) ? 1000 : getDisplayCount();
63
64         if( getOffset() > 0 ) {
65                 if( getHitCount() > 0 && (getOffset() + getDisplayCount()) > getHitCount() ) 
66                         limit = getHitCount() - getOffset();
67         }
68
69         args.org_unit = getLocation();
70         args.depth    = getDepth();
71         args.limit    = limit;
72         args.offset   = getOffset();
73
74         if(sort) args.sort = sort;
75         if(sortdir) args.sort_dir = sortdir;
76         if(item_type) args.item_type    = item_type;
77         if(item_form) args.item_form    = item_form;
78
79
80         if(getAudience()) args.audience  = getAudience().split(/,/);
81         if(getLitForm()) args.lit_form  = getLitForm().split(/,/);
82         if(getLanguage()) args.language = getLanguage().split(/,/);
83
84         //alert(js2JSON(args));
85         _debug('SEARCH: \n' + js2JSON(args) + '\n\n');
86         var req = new Request(method, args, 1);
87         req.callback(handler);
88         req.send();
89 }
90
91
92
93
94
95 /* set the search result info, number of hits, which results we're 
96         displaying, links to the next/prev pages, etc. */
97 function resultSetHitInfo() { 
98
99
100         /* tell the user where the results are coming from */
101         var baseorg = findOrgUnit(getLocation());
102         var depth = getDepth();
103         var mydepth = findOrgDepth(baseorg);
104         if( findOrgDepth(baseorg) != depth ) {
105                 var tmporg = baseorg;
106                 while( mydepth > depth ) {
107                         mydepth--;
108                         tmporg = findOrgUnit(tmporg.parent_ou());
109                 }
110                 unHideMe($('including_results_for'));
111                 $('including_results_location').appendChild(text(tmporg.name()));
112         }
113
114
115         try{searchTimer.stop()}catch(e){}
116
117         if( findCurrentPage() == MRESULT ) {
118                 if(getHitCount() <= lowHitCount && getTerm())
119                         runEvt('result', 'lowHits');
120         }
121
122         if(getHitCount() == 0) {
123                 runEvt('result', 'zeroHits');
124                 return;
125         }
126
127
128         var pages = getHitCount() / getDisplayCount();
129         if(pages % 1) pages = parseInt(pages) + 1;
130
131         
132
133         var cpage = (getOffset()/getDisplayCount()) + 1;
134
135         G.ui.result.current_page.appendChild(text(cpage));
136         G.ui.result.num_pages.appendChild(text(pages + ")")); /* the ) is dumb */
137
138         /* set the offsets */
139         var offsetEnd = getDisplayCount() + getOffset();  
140         if( getDisplayCount() > (getHitCount() - getOffset()))  
141                 offsetEnd = getHitCount();
142
143         G.ui.result.offset_end.appendChild(text(offsetEnd));
144         G.ui.result.offset_start.appendChild(text(getOffset() + 1));
145
146         G.ui.result.result_count.appendChild(text(getHitCount()));
147         unHideMe(G.ui.result.info);
148 }
149
150 function resultLowHits() {
151         showCanvas();
152         unHideMe($('result_low_hits'));
153         if(getHitCount() > 0)
154                 unHideMe($('result_low_hits_msg'));
155
156         var sreq = new Request(CHECK_SPELL, getTerm());
157         sreq.callback(resultSuggestSpelling);
158         sreq.send();
159
160         var words = getTerm().split(' ');
161         var word;
162         while( word = words.shift() ) {
163                 var areq = new Request(FETCH_CROSSREF, getStype(), getTerm() );
164                 areq.callback(resultLowHitXRef);
165                 areq.send();
166         }
167
168         if( !(getForm() == null || getForm() == 'all' || getForm() == "") ) {
169                 var a = {};
170                 a[PARAM_FORM] = "all";
171                 $('low_hits_remove_format_link').setAttribute('href',buildOPACLink(a));
172                 unHideMe($('low_hits_remove_format'));
173         }
174
175         resultSuggestSearchClass();
176
177         if(getTerm()) resultExpandSearch(); /* advanced search */
178 }
179
180 var lowHitsXRefLink;
181 var lowHitsXRefLinkParent;
182 function resultLowHitXRef(r) {
183         if(!lowHitsXRefLink){
184                 lowHitsXRefLinkParent = $('low_hits_xref_link').parentNode;
185                 lowHitsXRefLink = lowHitsXRefLinkParent.removeChild($('low_hits_xref_link'));
186         }
187         var res = r.getResultObject();
188         var arr = res.from;
189         arr.concat(res.also);
190         if(arr && arr.length > 0) {
191                 unHideMe($('low_hits_cross_ref'));
192                 var word;
193                 var c = 0;
194                 while( word = arr.shift() ) {
195                         if(c++ > 20) break;
196                         var a = {};
197                         a[PARAM_TERM] = word;
198                         var template = lowHitsXRefLink.cloneNode(true);
199                         template.setAttribute('href',buildOPACLink(a));
200                         template.appendChild(text(word));
201                         lowHitsXRefLinkParent.appendChild(template);
202                         lowHitsXRefLinkParent.appendChild(text(' '));
203                 }
204         }
205 }
206
207 function resultZeroHits() {
208         showCanvas();
209         unHideMe($('result_low_hits'));
210         unHideMe($('result_zero_hits_msg'));
211         //if(getTerm()) resultExpandSearch(); /* advanced search */
212 }
213
214 function resultExpandSearch() {
215         var top = findOrgDepth(globalOrgTree);
216         if(getDepth() == top) return;
217         unHideMe($('low_hits_expand_range'));
218         var par = $('low_hits_expand_link').parentNode;
219         var template = par.removeChild($('low_hits_expand_link'));
220
221         var bottom = getDepth();
222         while( top < bottom ) {
223                 var a = {};
224                 a[PARAM_DEPTH] = top;
225                 var temp = template.cloneNode(true);
226                 temp.appendChild(text(findOrgTypeFromDepth(top).opac_label()))
227                 temp.setAttribute('href',buildOPACLink(a));
228                 par.appendChild(temp);
229                 top++;
230         }
231 }
232
233 function resultSuggestSearchClass() {
234         var stype = getStype();
235         if(stype == STYPE_KEYWORD) return;
236         var a = {}; var ref;
237         unHideMe($('low_hits_search_type'));
238         if(stype != STYPE_TITLE) {
239                 ref = $('low_hits_title_search');
240                 unHideMe(ref);
241                 a[PARAM_STYPE] = STYPE_TITLE;
242                 ref.setAttribute('href',buildOPACLink(a));
243         }
244         if(stype != STYPE_AUTHOR) {
245                 ref = $('low_hits_author_search');
246                 unHideMe(ref);
247                 a[PARAM_STYPE] = STYPE_AUTHOR;
248                 ref.setAttribute('href',buildOPACLink(a));
249         }
250         if(stype != STYPE_SUBJECT) {
251                 ref = $('low_hits_subject_search');
252                 unHideMe(ref);
253                 a[PARAM_STYPE] = STYPE_SUBJECT;
254                 ref.setAttribute('href',buildOPACLink(a));
255         }
256         if(stype != STYPE_KEYWORD) {
257                 ref = $('low_hits_keyword_search');
258                 unHideMe(ref);
259                 a[PARAM_STYPE] = STYPE_KEYWORD;
260                 ref.setAttribute('href',buildOPACLink(a));
261         }
262         if(stype != STYPE_SERIES) {
263                 ref = $('low_hits_series_search');
264                 unHideMe(ref);
265                 a[PARAM_STYPE] = STYPE_SERIES;
266                 ref.setAttribute('href',buildOPACLink(a));
267         }
268 }
269
270 function resultSuggestSpelling(r) {
271         var res = r.getResultObject();
272         var phrase = getTerm();
273         var words = phrase.split(/ /);
274
275         var newterm = "";
276
277         for( var w = 0; w < words.length; w++ ) {
278                 var word = words[w];
279                 var blob = grep(res, function(i){return (i.word == word);});
280                 if( blob ) blob = blob[0];
281                 else continue;
282                 if( blob.word == word ) {
283                         if( blob.suggestions && blob.suggestions[0] ) {
284                                 newterm += " " + blob.suggestions[0];
285                                 unHideMe($('did_you_mean'));
286                         } else {
287                                 newterm += " " + word;
288                         }
289                 }
290         }
291
292         var arg = {};
293         arg[PARAM_TERM] = newterm;
294         $('spell_check_link').setAttribute('href', buildOPACLink(arg));
295         $('spell_check_link').appendChild(text(newterm));
296 }
297
298
299 function resultPaginate() {
300         var o = getOffset();
301
302         if( !(  ((o) + getDisplayCount()) >= getHitCount()) ) {
303
304                 var args = {};
305                 args[PARAM_OFFSET]      = o + getDisplayCount();
306                 args[PARAM_SORT]                = SORT;
307                 args[PARAM_SORT_DIR] = SORT_DIR;
308                 args[PARAM_RLIST]               = new CGI().param(PARAM_RLIST);
309
310                 G.ui.result.next_link.setAttribute("href", buildOPACLink(args)); 
311                 addCSSClass(G.ui.result.next_link, config.css.result.nav_active);
312
313                 args[PARAM_OFFSET] = getHitCount() - (getHitCount() % getDisplayCount());
314
315                 /* when hit count is divisible by display count, we have to adjust */
316                 if( getHitCount() % getDisplayCount() == 0 ) 
317                         args[PARAM_OFFSET] -= getDisplayCount();
318
319                 G.ui.result.end_link.setAttribute("href", buildOPACLink(args)); 
320                 addCSSClass(G.ui.result.end_link, config.css.result.nav_active);
321         }
322
323         if( o > 0 ) {
324
325                 var args = {};
326                 args[PARAM_SORT]                = SORT;
327                 args[PARAM_SORT_DIR] = SORT_DIR;
328                 args[PARAM_RLIST]               = new CGI().param(PARAM_RLIST);
329
330                 args[PARAM_OFFSET] = o - getDisplayCount();
331                 G.ui.result.prev_link.setAttribute( "href", buildOPACLink(args)); 
332                 addCSSClass(G.ui.result.prev_link, config.css.result.nav_active);
333
334                 args[PARAM_OFFSET] = 0;
335                 G.ui.result.home_link.setAttribute( "href", buildOPACLink(args)); 
336                 addCSSClass(G.ui.result.home_link, config.css.result.nav_active);
337         }
338
339         if(getDisplayCount() < getHitCount())
340                 unHideMe($('start_end_links_span'));
341
342         showCanvas();
343         try{searchTimer.stop()}catch(e){}
344 }
345
346 function buildunAPISpan (span, type, id) {
347         var cgi = new CGI();
348         var d = new Date();
349
350         addCSSClass(span,'unapi-id');
351
352         span.setAttribute(
353                 'title',
354                 'tag:' + cgi.server_name + ',' +
355                         d.getFullYear() +
356                         ':' + type + '/' + id
357         );
358 }
359
360 /* display the record info in the record display table 'pos' is the 
361                 zero based position the record should have in the display table */
362 function resultDisplayRecord(rec, pos, is_mr) {
363
364         if(rec == null) rec = new mvr(); /* so the page won't die if there was an error */
365         recordsHandled++;
366         recordsCache.push(rec);
367
368         var r = table.rows[pos + 1];
369
370         
371         try {
372                 var rank = parseFloat(ranks[pos + getOffset()]);
373                 rank            = parseInt( rank * 100 );
374                 var relspan = $n(r, "relevancy_span");
375                 relspan.appendChild(text(rank));
376                 unHideMe(relspan.parentNode);
377         } catch(e){ }
378
379         var pic = $n(r, config.names.result.item_jacket);
380         pic.setAttribute("src", buildISBNSrc(cleanISBN(rec.isbn())));
381
382         var title_link = $n(r, config.names.result.item_title);
383         var author_link = $n(r, config.names.result.item_author);
384
385         if( is_mr )  {
386                 var onlyrec = onlyrecord[ getOffset() + pos ];
387                 if(onlyrec) {
388                         buildunAPISpan($n(r,'unapi'), 'biblio-record_entry', onlyrec);
389
390                         var args = {};
391                         args.page = RDETAIL;
392                         args[PARAM_OFFSET] = 0;
393                         args[PARAM_RID] = onlyrec;
394                         args[PARAM_MRID] = rec.doc_id();
395                         pic.parentNode.setAttribute("href", buildOPACLink(args));
396                         title_link.setAttribute("href", buildOPACLink(args));
397                         title_link.appendChild(text(normalize(truncate(rec.title(), 65))));
398                         
399                 } else {
400                         buildunAPISpan($n(r,'unapi'), 'metabib-metarecord', rec.doc_id());
401
402                         buildTitleLink(rec, title_link); 
403                         var args = {};
404                         args.page = RRESULT;
405                         args[PARAM_OFFSET] = 0;
406                         args[PARAM_MRID] = rec.doc_id();
407                         pic.parentNode.setAttribute("href", buildOPACLink(args));
408                 }
409
410         } else {
411                 buildunAPISpan($n(r,'unapi'), 'biblio-record_entry', rec.doc_id());
412
413                 buildTitleDetailLink(rec, title_link); 
414                 var args = {};
415                 args.page = RDETAIL;
416                 args[PARAM_OFFSET] = 0;
417                 args[PARAM_RID] = rec.doc_id();
418                 pic.parentNode.setAttribute("href", buildOPACLink(args));
419
420                 unHideMe($n(r,'place_hold_span'));
421                 $n(r,'place_hold_link').setAttribute(
422                         'href','javascript:holdsDrawEditor({record:"'+rec.doc_id()+'",type:"T"});');
423         }
424
425         buildSearchLink(STYPE_AUTHOR, rec.author(), author_link);
426
427         if(! is_mr ) {
428         
429                 if(!isNull(rec.edition()))      {
430                         unHideMe( $n(r, "result_table_extra_span"));
431                         $n(r, "result_table_edition_span").appendChild( text( rec.edition()) );
432                 }
433                 if(!isNull(rec.pubdate())) {
434                         unHideMe( $n(r, "result_table_extra_span"));
435                         unHideMe($n(r, "result_table_pub_span"));
436                         $n(r, "result_table_pub_span").appendChild( text( rec.pubdate() ));
437                 }
438                 if(!isNull(rec.publisher()) ) {
439                         unHideMe( $n(r, "result_table_extra_span"));
440                         unHideMe($n(r, "result_table_pub_span"));
441                         $n(r, "result_table_pub_span").appendChild( text( " " + rec.publisher() ));
442                 }
443
444                 if(!isNull(rec.physical_description()) ) {
445                         unHideMe( $n(r, "result_table_extra_span"));
446                         var t = " " + rec.physical_description();
447                         //$n(r, "result_table_phys_span").appendChild( text(t.replace(/:.*/g,'')));
448                         $n(r, "result_table_phys_span").appendChild( text(t));
449                 }
450
451         }
452
453         resultBuildFormatIcons( r, rec, is_mr );
454
455         unHideMe(r);
456         
457         runEvt("result", "recordDrawn", rec.doc_id(), title_link);
458
459         /*
460         if(resultPageIsDone())  {
461                 runEvt('result', 'allRecordsReceived', recordsCache);
462         }
463         */
464 }
465
466 function _resultFindRec(id) {
467         for( var i = 0; i != recordsCache.length; i++ ) {
468                 var rec = recordsCache[i];
469                 if( rec && rec.doc_id() == id )
470                         return rec;
471         }
472         return null;
473 }
474
475
476 function resultBuildFormatIcons( row, rec, is_mr ) {
477
478         var ress = rec.types_of_resource();
479
480         for( var i in ress ) {
481
482                 var res = ress[i];
483                 if(!res) continue;
484
485                 var link = $n(row, res + "_link");
486                 link.title = res;
487                 var img = link.getElementsByTagName("img")[0];
488                 removeCSSClass( img, config.css.dim );
489
490                 var f = getForm();
491                 if( f != "all" ) {
492                         if( f == modsFormatToMARC(res) ) 
493                                 addCSSClass( img, "dim2_border");
494                 }
495
496                 var args = {};
497                 args[PARAM_OFFSET] = 0;
498
499                 if(is_mr) {
500                         args.page = RRESULT;
501                         args[PARAM_TFORM] = modsFormatToMARC(res);
502                         args[PARAM_MRID] = rec.doc_id();
503
504                 } else {
505                         args.page = RDETAIL
506                         args[PARAM_RID] = rec.doc_id();
507                 }
508
509                 link.setAttribute("href", buildOPACLink(args));
510
511         }
512 }
513
514
515 function resultPageIsDone(pos) {
516         return (recordsHandled == getDisplayCount() 
517                 || recordsHandled + getOffset() == getHitCount());
518 }
519
520 var resultCCHeaderApplied = false;
521
522 /* -------------------------------------------------------------------- */
523 /* dynamically add the copy count rows based on the org type 'countsrow' 
524         is the row into which we will add TD's to hold the copy counts 
525         This code generates copy count cells with an id of
526         'copy_count_cell_<depth>_<pagePosition>'  */
527 function resultAddCopyCounts(rec, pagePosition) {
528
529         var r = table.rows[pagePosition + 1];
530         var countsrow = $n(r, config.names.result.counts_row );
531         var ccell = $n(countsrow, config.names.result.count_cell);
532
533         var nodes = orgNodeTrail(findOrgUnit(getLocation()));
534         var node = nodes[0];
535         var type = findOrgType(node.ou_type());
536         ccell.id = "copy_count_cell_" + type.depth() + "_" + pagePosition;
537         ccell.title = type.opac_label();
538         //addCSSClass(ccell, config.css.result.cc_cell_even);
539
540         var lastcell = ccell;
541         var lastheadcell = null;
542
543         var cchead = null;
544         var ccheadcell = null;
545         if(!resultCCHeaderApplied) {
546                 ccrow = $('result_thead_row');
547                 ccheadcell =  ccrow.removeChild($n(ccrow, "result_thead_ccell"));
548                 var t = ccheadcell.cloneNode(true);
549                 lastheadcell = t;
550                 t.appendChild(text(type.opac_label()));
551                 ccrow.appendChild(t);
552                 resultCCHeaderApplied = true;
553         }
554
555         if(nodes[1]) {
556
557                 var x = 1;
558                 var d = findOrgDepth(nodes[1]);
559                 var d2 = findOrgDepth(nodes[nodes.length -1]);
560
561                 for( var i = d; i <= d2 ; i++ ) {
562         
563                         ccell = ccell.cloneNode(true);
564
565                         //if((i % 2)) removeCSSClass(ccell, "copy_count_cell_even");
566                         //else addCSSClass(ccell, "copy_count_cell_even");
567
568                         var node = nodes[x++];
569                         var type = findOrgType(node.ou_type());
570         
571                         ccell.id = "copy_count_cell_" + type.depth() + "_" + pagePosition;
572                         ccell.title = type.opac_label();
573                         countsrow.insertBefore(ccell, lastcell);
574                         lastcell = ccell;
575
576                         if(ccheadcell) {
577                                 var t = ccheadcell.cloneNode(true);
578                                 t.appendChild(text(type.opac_label()));
579                                 ccrow.insertBefore(t, lastheadcell);
580                                 lastheadcell = t;
581                         }
582                 }
583         }
584
585         unHideMe($("search_info_table"));
586 }
587
588 /* collect copy counts for a record using method 'methodName' */
589 function resultCollectCopyCounts(rec, pagePosition, methodName) {
590         if(rec == null || rec.doc_id() == null) return;
591         var req = new Request(methodName, getLocation(), rec.doc_id(), getForm() );
592         req.request.userdata = [ rec, pagePosition ];
593         req.callback(resultHandleCopyCounts);
594         req.send();
595 }
596
597 function resultHandleCopyCounts(r) {
598         runEvt('result', 'copyCountsReceived', r.userdata[0], r.userdata[1], r.getResultObject()); 
599 }
600
601
602 /* display the collected copy counts */
603 function resultDisplayCopyCounts(rec, pagePosition, copy_counts) {
604         if(copy_counts == null || rec == null) return;
605         var i = 0;
606         while(copy_counts[i] != null) {
607                 var cell = $("copy_count_cell_" + i +"_" + pagePosition);
608                 var cts = copy_counts[i];
609                 cell.appendChild(text(cts.available + " / " + cts.count));
610
611                 if(isXUL()) {
612                         /* here we style opac-invisible records for xul */
613
614                         if( cts.depth == 0 ) {
615                                 if(!cts.transcendant && !cts.unshadow) {
616                                         _debug("found an opac-shadowed record: " + rec.doc_id());
617                                         var row = cell.parentNode.parentNode.parentNode.parentNode.parentNode; 
618                                         if( cts.count == 0 ) 
619                                                 addCSSClass( row, 'no_copies' );
620                                         else 
621                                                 addCSSClass( row, 'shadowed' );
622                                 }
623                         }
624                 }
625                 i++;
626         }
627 }
628
629