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