]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/opac/skin/default/js/result_common.js
d5052d34c65f4b8c52ea6bbaa4cb3e468ae7a338
[working/Evergreen.git] / Open-ILS / web / opac / skin / default / js / result_common.js
1 dojo.require('openils.BibTemplate');
2 dojo.requireLocalization("openils.opac", "opac");
3 var opac_strings = dojo.i18n.getLocalization("openils.opac", "opac");
4
5 var recordsHandled = 0;
6 var recordsCache = [];
7 var lowHitCount = 4;
8 var isbnList = new Array();
9 var googleBooksLink = true;
10 var OpenLibraryLinks = true;
11
12 var resultFetchAllRecords = false;
13 var resultCompiledSearch = null;
14
15 /* set up the event handlers */
16 if( findCurrentPage() == MRESULT || findCurrentPage() == RRESULT ) {
17         G.evt.result.hitCountReceived.push(resultSetHitInfo);
18         G.evt.result.recordReceived.push(resultDisplayRecord, resultAddCopyCounts);
19         G.evt.result.copyCountsReceived.push(resultDisplayCopyCounts);
20         G.evt.result.allRecordsReceived.push( function(){unHideMe($('result_info_2'))}, fetchOpenLibraryLinks, fetchGoogleBooksLink, fetchChiliFreshReviews);
21
22         attachEvt('result','lowHits',resultLowHits);
23         attachEvt('result','zeroHits',resultZeroHits);
24         attachEvt( "common", "locationUpdated", resultSBSubmit );
25         /* do this after we have ID's so the rank for mr pages will be correct */
26         attachEvt("result", "preCollectRecords", resultPaginate);
27 }
28
29 function resultSBSubmit(){searchBarSubmit();}
30
31 /* returns the last 'index' postion ocurring in this page */
32 function resultFinalPageIndex() {
33         if(getHitCount() < (getOffset() + getDisplayCount())) 
34                 return getHitCount() - 1;
35         return getOffset() + getDisplayCount() - 1;
36 }
37
38
39
40
41 /* generic search method */
42 function resultCollectSearchIds( type, method, handler ) {
43
44         var sort                = (getSort() == SORT_TYPE_REL) ? null : getSort(); 
45         var sortdir = (sort) ? ((getSortDir()) ? getSortDir() : SORT_DIR_ASC) : null;
46
47         var item_type;
48         var item_form;
49         var args = {};
50
51         if( type ) {
52                 var form = parseForm(getForm());
53                 item_type = form.item_type;
54                 item_form = form.item_form;
55
56         } else {
57                 item_type = (getItemType()) ? getItemType().split(/,/) : null;
58                 item_form = (getItemForm()) ? getItemForm().split(/,/) : null;
59         }
60
61         var limit = (resultFetchAllRecords) ? 1000 : getDisplayCount();
62
63         if( getOffset() > 0 ) {
64                 if( getHitCount() > 0 && (getOffset() + getDisplayCount()) > getHitCount() ) 
65                         limit = getHitCount() - getOffset();
66         }
67
68         var lasso = getLasso();
69
70         if (lasso) args.org_unit = -lasso;
71         else args.org_unit = getLocation();
72
73         args.depth    = getDepth();
74         args.limit    = limit;
75         args.offset   = getOffset();
76         args.visibility_limit = 3000;
77     args.default_class = getStype();
78
79         if(sort) args.sort = sort;
80         if(sortdir) args.sort_dir = sortdir;
81         if(item_type) args.item_type    = item_type;
82         if(item_form) args.item_form    = item_form;
83     if(getAvail()) args.available = 1;
84
85
86         if(getFacet()) args.facets  = getFacet();
87
88         if(getAudience()) args.audience  = getAudience().split(/,/);
89         if(getLitForm()) args.lit_form  = getLitForm().split(/,/);
90         if(getLanguage()) args.language = getLanguage().split(/,/);
91         if(getBibLevel()) args.bib_level        = getBibLevel().split(/,/);
92         if(getCopyLocs()) args.locations        = getCopyLocs().split(/,/);
93     if(getPubdBefore()) args.before = getPubdBefore();
94     else if(getPubdAfter()) args.after = getPubdAfter();
95     else if(getPubdBetween()) args.between = getPubdBetween().split(/,/);
96
97         _debug('Search args: ' + js2JSON(args));
98         _debug('Raw query: ' + getTerm());
99
100         var my_ou = findOrgUnit(args.org_unit);
101         if (my_ou && my_ou.shortname()) {
102                 var atomfeed = "/opac/extras/opensearch/1.1/" + my_ou.shortname() + "/atom-full/" + getStype() + '?searchTerms=' + getTerm();
103                 if (args.facets) { atomfeed += ' ' + args.facets; }
104                 if (sort) { atomfeed += '&searchSort=' + sort; }
105                 if (sortdir) { atomfeed += '&searchSortDir=' + sortdir; }
106                 dojo.create('link', {"rel":"alternate", "href":atomfeed, "type":"application/atom+xml"}, dojo.query('head')[0]);
107         }
108
109         var req = new Request(method, args, getTerm(), 1);
110         req.callback(handler);
111         req.send();
112 }
113
114
115
116
117
118 /* set the search result info, number of hits, which results we're 
119         displaying, links to the next/prev pages, etc. */
120 function resultSetHitInfo() { 
121
122         var lasso = getLasso();
123         if (!lasso) {
124                 /* tell the user where the results are coming from */
125                 var baseorg = findOrgUnit(getLocation());
126                 var depth = getDepth();
127                 var mydepth = findOrgDepth(baseorg);
128                 if( findOrgDepth(baseorg) != depth ) {
129                         var tmporg = baseorg;
130                         while( mydepth > depth ) {
131                                 mydepth--;
132                                 tmporg = findOrgUnit(tmporg.parent_ou());
133                         }
134                         unHideMe($('including_results_for'));
135                         $('including_results_location').appendChild(text(tmporg.name()));
136                 }
137         }
138
139
140         try{searchTimer.stop()}catch(e){}
141
142         //if( findCurrentPage() == MRESULT ) {
143         if( findCurrentPage() == MRESULT || 
144
145                 (findCurrentPage() == RRESULT &&
146                         (
147                                 getRtype() == RTYPE_TITLE ||
148                                 getRtype() == RTYPE_AUTHOR ||
149                                 getRtype() == RTYPE_SUBJECT ||
150                                 getRtype() == RTYPE_SERIES ||
151                                 getRtype() == RTYPE_KEYWORD 
152                         )
153
154                 ) ) {
155
156                 if(getHitCount() <= lowHitCount && getTerm())
157                         runEvt('result', 'lowHits');
158         }
159
160         if(getHitCount() == 0) {
161                 runEvt('result', 'zeroHits');
162                 return;
163         }
164
165
166         var pages = getHitCount() / getDisplayCount();
167         if(pages % 1) pages = parseInt(pages) + 1;
168
169         
170
171         var cpage = (getOffset()/getDisplayCount()) + 1;
172
173         G.ui.result.current_page.appendChild(text(cpage));
174         G.ui.result.num_pages.appendChild(text(pages + ")")); /* the ) is dumb */
175
176         $('current_page2').appendChild(text(cpage));
177         $('num_pages2').appendChild(text(pages + ")")); /* the ) is dumb */
178
179         /* set the offsets */
180         var offsetEnd = getDisplayCount() + getOffset();  
181         if( getDisplayCount() > (getHitCount() - getOffset()))  
182                 offsetEnd = getHitCount();
183
184         G.ui.result.offset_end.appendChild(text(offsetEnd));
185         G.ui.result.offset_start.appendChild(text(getOffset() + 1));
186
187         $('offset_end2').appendChild(text(offsetEnd));
188         $('offset_start2').appendChild(text(getOffset() + 1));
189
190         G.ui.result.result_count.appendChild(text(getHitCount()));
191         unHideMe(G.ui.result.info);
192
193         $('result_count2').appendChild(text(getHitCount()));
194         unHideMe($('result_info_div2'));
195 }
196
197 function resultLowHits() {
198         showCanvas();
199         unHideMe($('result_low_hits'));
200         if(getHitCount() > 0)
201                 unHideMe($('result_low_hits_msg'));
202
203     var words = [];
204     for(var key in resultCompiledSearch.searches) 
205         words.push(resultCompiledSearch.searches[key].term);
206
207         var sreq = new Request(CHECK_SPELL, words.join(' '));
208         sreq.callback(resultSuggestSpelling);
209         sreq.send();
210
211     for(var key in resultCompiledSearch.searches) {
212                 var areq = new Request(FETCH_CROSSREF, key, resultCompiledSearch.searches[key].term);
213                 areq.callback(resultLowHitXRef);
214                 areq.send();
215         }
216
217         if( !(getForm() == null || getForm() == 'all' || getForm() == "") ) {
218                 var a = {};
219                 a[PARAM_FORM] = "all";
220                 $('low_hits_remove_format_link').setAttribute('href',buildOPACLink(a));
221                 unHideMe($('low_hits_remove_format'));
222         }
223
224         resultSuggestSearchClass();
225
226         if(getTerm()) resultExpandSearch(); /* advanced search */
227 }
228
229 var lowHitsXRefSet = {};
230 var lowHitsXRefLink;
231 var lowHitsXRefLinkParent;
232 function resultLowHitXRef(r) {
233         if(!lowHitsXRefLink){
234                 lowHitsXRefLinkParent = $('low_hits_xref_link').parentNode;
235                 lowHitsXRefLink = lowHitsXRefLinkParent.removeChild($('low_hits_xref_link'));
236         }
237         var res = r.getResultObject();
238         var arr = res.from;
239         arr.concat(res.also);
240         if(arr && arr.length > 0) {
241                 unHideMe($('low_hits_cross_ref'));
242                 var word;
243                 var c = 0;
244                 while( word = arr.shift() ) {
245
246             if (lowHitsXRefSet[word] == 1) continue;
247             lowHitsXRefSet[word] = 1;
248
249                         if(c++ > 20) break;
250                         var a = {};
251                         a[PARAM_TERM] = word;
252                         var template = lowHitsXRefLink.cloneNode(true);
253                         template.setAttribute('href',buildOPACLink(a));
254                         template.appendChild(text(word));
255                         lowHitsXRefLinkParent.appendChild(template);
256                         lowHitsXRefLinkParent.appendChild(text(' '));
257                 }
258         }
259 }
260
261 function resultZeroHits() {
262         showCanvas();
263         unHideMe($('result_low_hits'));
264         unHideMe($('result_zero_hits_msg'));
265         //if(getTerm()) resultExpandSearch(); /* advanced search */
266 }
267
268 function resultExpandSearch() {
269         var top = findOrgDepth(globalOrgTree);
270         if(getDepth() == top) return;
271         unHideMe($('low_hits_expand_range'));
272         var par = $('low_hits_expand_link').parentNode;
273         var template = par.removeChild($('low_hits_expand_link'));
274
275         var bottom = getDepth();
276         while( top < bottom ) {
277                 var a = {};
278                 a[PARAM_DEPTH] = top;
279                 var temp = template.cloneNode(true);
280                 temp.appendChild(text(findOrgTypeFromDepth(top).opac_label()))
281                 temp.setAttribute('href',buildOPACLink(a));
282                 par.appendChild(temp);
283                 top++;
284         }
285 }
286
287 function resultSuggestSearchClass() {
288         var stype = getStype();
289         if(stype == STYPE_KEYWORD) return;
290         var a = {}; var ref;
291         unHideMe($('low_hits_search_type'));
292         if(stype != STYPE_TITLE) {
293                 ref = $('low_hits_title_search');
294                 unHideMe(ref);
295                 a[PARAM_STYPE] = STYPE_TITLE;
296                 ref.setAttribute('href',buildOPACLink(a));
297         }
298         if(stype != STYPE_AUTHOR) {
299                 ref = $('low_hits_author_search');
300                 unHideMe(ref);
301                 a[PARAM_STYPE] = STYPE_AUTHOR;
302                 ref.setAttribute('href',buildOPACLink(a));
303         }
304         if(stype != STYPE_SUBJECT) {
305                 ref = $('low_hits_subject_search');
306                 unHideMe(ref);
307                 a[PARAM_STYPE] = STYPE_SUBJECT;
308                 ref.setAttribute('href',buildOPACLink(a));
309         }
310         if(stype != STYPE_KEYWORD) {
311                 ref = $('low_hits_keyword_search');
312                 unHideMe(ref);
313                 a[PARAM_STYPE] = STYPE_KEYWORD;
314                 ref.setAttribute('href',buildOPACLink(a));
315         }
316         if(stype != STYPE_SERIES) {
317                 ref = $('low_hits_series_search');
318                 unHideMe(ref);
319                 a[PARAM_STYPE] = STYPE_SERIES;
320                 ref.setAttribute('href',buildOPACLink(a));
321         }
322 }
323
324 function resultSuggestSpelling(r) {
325         var res = r.getResultObject();
326         var phrase = getTerm();
327         var words = phrase.split(/ /);
328
329         var newterm = "";
330
331         for( var w = 0; w < words.length; w++ ) {
332                 var word = words[w];
333                 var blob = grep(res, function(i){return (i.word == word);});
334                 if( blob ) blob = blob[0];
335                 else continue;
336                 if( blob.word == word ) {
337                         if( !blob.found && blob.suggestions && blob.suggestions[0] ) {
338                                 newterm += " " + blob.suggestions[0];
339                                 unHideMe($('did_you_mean'));
340                         } else {
341                                 newterm += " " + word;
342                         }
343                 }
344         }
345
346         var arg = {};
347         arg[PARAM_TERM] = newterm;
348         $('spell_check_link').setAttribute('href', buildOPACLink(arg));
349         $('spell_check_link').appendChild(text(newterm));
350 }
351
352
353 function resultPaginate() {
354         var o = getOffset();
355
356         if( !(  ((o) + getDisplayCount()) >= getHitCount()) ) {
357
358                 var args = {};
359                 args[PARAM_OFFSET]      = o + getDisplayCount();
360                 args[PARAM_SORT]                = SORT;
361                 args[PARAM_SORT_DIR] = SORT_DIR;
362                 args[PARAM_RLIST]               = new CGI().param(PARAM_RLIST);
363
364                 G.ui.result.next_link.setAttribute("href", buildOPACLink(args)); 
365                 addCSSClass(G.ui.result.next_link, config.css.result.nav_active);
366
367                 $('next_link2').setAttribute("href", buildOPACLink(args)); 
368                 addCSSClass($('next_link2'), config.css.result.nav_active);
369
370                 args[PARAM_OFFSET] = getHitCount() - (getHitCount() % getDisplayCount());
371
372                 /* when hit count is divisible by display count, we have to adjust */
373                 if( getHitCount() % getDisplayCount() == 0 ) 
374                         args[PARAM_OFFSET] -= getDisplayCount();
375
376         /*
377                 G.ui.result.end_link.setAttribute("href", buildOPACLink(args)); 
378                 addCSSClass(G.ui.result.end_link, config.css.result.nav_active);
379
380                 $('end_link2').setAttribute("href", buildOPACLink(args)); 
381                 addCSSClass($('end_link2'), config.css.result.nav_active);
382         */
383         }
384
385         if( o > 0 ) {
386
387                 var args = {};
388                 args[PARAM_SORT]                = SORT;
389                 args[PARAM_SORT_DIR] = SORT_DIR;
390                 args[PARAM_RLIST]               = new CGI().param(PARAM_RLIST);
391
392                 args[PARAM_OFFSET] = o - getDisplayCount();
393                 G.ui.result.prev_link.setAttribute( "href", buildOPACLink(args)); 
394                 addCSSClass(G.ui.result.prev_link, config.css.result.nav_active);
395
396                 $('prev_link2').setAttribute( "href", buildOPACLink(args)); 
397                 addCSSClass($('prev_link2'), config.css.result.nav_active);
398
399                 args[PARAM_OFFSET] = 0;
400                 G.ui.result.home_link.setAttribute( "href", buildOPACLink(args)); 
401                 addCSSClass(G.ui.result.home_link, config.css.result.nav_active);
402
403                 $('search_home_link2').setAttribute( "href", buildOPACLink(args)); 
404                 addCSSClass($('search_home_link2'), config.css.result.nav_active);
405         }
406
407         if(getDisplayCount() < getHitCount()) {
408                 unHideMe($('start_end_links_span'));
409                 unHideMe($('start_end_links_span2'));
410    }
411
412         showCanvas();
413         try{searchTimer.stop()}catch(e){}
414 }
415
416 function buildunAPISpan (span, type, id) {
417         var cgi = new CGI();
418         var d = new Date();
419
420         addCSSClass(span,'unapi-id');
421
422         span.setAttribute(
423                 'title',
424                 'tag:' + cgi.server_name + ',' +
425                         d.getFullYear() +
426                         ':' + type + '/' + id
427         );
428 }
429
430 function unhideGoogleBooksLink (data) {
431     for (var i = 0; i < data.items.length; i++) {
432         var item = data.items[i];
433
434         var gbspan;
435         for (var j = 0; j < item.volumeInfo.industryIdentifiers.length; j++) {
436             // XXX: As of 11-17-2011, some items do not return their own ISBN
437             // as an identifier, so this code fails.  For example:
438             // https://www.googleapis.com/books/v1/volumes?q=isbn:0743243560&callback=unhideGoogleBooksLink
439             // It seems the only way around this would be doing a separate
440             // search for each result rather than one search for the whole
441             // page.  Informal testing seems to indicate that these books
442             // are generally Google-unfriendly (no previews, not embeddable),
443             // so we will live without them for now.
444             var ident = item.volumeInfo.industryIdentifiers[j].identifier;
445             gbspan = $n(document.documentElement, 'googleBooksLink-' + ident);
446             if (gbspan) break;
447         }
448         if (!gbspan) continue;
449
450         var gba = $n(gbspan, "googleBooks-link");
451
452         gba.setAttribute(
453             'href',
454             item.volumeInfo.infoLink
455             // XXX: we might consider constructing the above link ourselves,
456             // as the link provided populates the search box with our original
457             // multi-item search.  Something like:
458             // 'http://books.google.com/books?id=' + item.id
459             // Postive: cleaner display
460             // Negative: more fragile (link format subject to change; likely
461             // enough to matter?)
462         );
463         removeCSSClass( gbspan, 'hide_me' );
464     }
465 }
466
467 /* display the record info in the record display table 'pos' is the 
468                 zero based position the record should have in the display table */
469 function resultDisplayRecord(rec, pos, is_mr) {
470
471     fieldmapper.IDL.load(['mvr']);
472         if(rec == null) rec = new mvr(); /* so the page won't die if there was an error */
473         recordsHandled++;
474         recordsCache.push(rec);
475
476         var r = table.rows[pos + 1];
477     var currentISBN = cleanISBN(rec.isbn());
478
479     if (currentISBN) {
480         isbnList.push(currentISBN);
481         if (OpenLibraryLinks) {
482             var olspan = $n(r, 'openLibraryLink');
483             olspan.setAttribute('name', olspan.getAttribute('name') + 
484                 '-' + currentISBN
485             );
486         }
487
488         if (googleBooksLink) {
489             var gbspan = $n(r, "googleBooksLink");
490             // Google never has dashes in the ISBN, records sometimes do;
491             // remove them to match results list
492             // XXX: consider making part of cleanISBN(), or we can work around
493             // this if we move to one request per record
494             gbspan.setAttribute(
495                 'name',
496                 gbspan.getAttribute('name') + '-' + currentISBN.toString().replace(/-/g,"")
497             );
498
499         }
500     }
501
502     if (currentISBN && chilifresh && chilifresh != '(none)') {
503         var cfrow = $n(r, "chilifreshReview");
504         if (cfrow) {
505             removeCSSClass( cfrow, 'hide_me' );
506         }
507         var cflink = $n(r, "chilifreshReviewLink");
508         if (cflink) {
509             cflink.setAttribute(
510                 'id',
511                 'isbn_' + currentISBN
512             );
513         }
514         var cfdiv = $n(r, "chilifreshReviewResult");
515         if (cfdiv) {
516             cfdiv.setAttribute(
517                 'id',
518                 'chili_review_' + currentISBN
519             )
520         }
521     }
522
523 /*
524         try {
525                 var rank = parseFloat(ranks[pos + getOffset()]);
526                 rank            = parseInt( rank * 100 );
527                 var relspan = $n(r, "relevancy_span");
528                 relspan.appendChild(text(rank));
529                 unHideMe(relspan.parentNode);
530         } catch(e){ }
531 */
532
533     var pic = $n(r, config.names.result.item_jacket);
534     if (currentISBN) {
535         pic.setAttribute("src", buildISBNSrc(currentISBN));
536     } else {
537         pic.setAttribute("src", "/opac/images/blank.png");
538     }
539
540         var title_link = $n(r, config.names.result.item_title);
541         var author_link = $n(r, config.names.result.item_author);
542
543         var onlyrec;
544         if( is_mr )  {
545                 onlyrec = onlyrecord[ getOffset() + pos ];
546                 if(onlyrec) {
547                         buildunAPISpan($n(r,'unapi'), 'biblio-record_entry', onlyrec);
548
549                         var args = {};
550                         args.page = RDETAIL;
551                         args[PARAM_OFFSET] = 0;
552                         args[PARAM_RID] = onlyrec;
553                         args[PARAM_MRID] = rec.doc_id();
554                         pic.parentNode.setAttribute("href", buildOPACLink(args));
555                         title_link.setAttribute("href", buildOPACLink(args));
556                         title_link.appendChild(text(normalize(truncate(rec.title(), 65))));
557
558                 } else {
559                         buildunAPISpan($n(r,'unapi'), 'metabib-metarecord', rec.doc_id());
560
561                         buildTitleLink(rec, title_link); 
562                         var args = {};
563                         args.page = RRESULT;
564                         args[PARAM_OFFSET] = 0;
565                         args[PARAM_MRID] = rec.doc_id();
566                         pic.parentNode.setAttribute("href", buildOPACLink(args));
567                 }
568
569                 unHideMe($n(r,'place_hold_span'));
570                 $n(r,'place_hold_link').onclick = function() { resultDrawHoldsWindow(rec.doc_id(), 'M'); }
571             
572
573         } else {
574                 onlyrec = rec.doc_id();
575                 buildunAPISpan($n(r,'unapi'), 'biblio-record_entry', rec.doc_id());
576
577                 buildTitleDetailLink(rec, title_link); 
578                 var args = {};
579                 args.page = RDETAIL;
580                 args[PARAM_OFFSET] = 0;
581                 args[PARAM_RID] = rec.doc_id();
582                 pic.parentNode.setAttribute("href", buildOPACLink(args));
583
584                 unHideMe($n(r,'place_hold_span'));
585                 $n(r,'place_hold_link').onclick = function() { resultDrawHoldsWindow(rec.doc_id(), 'T'); }
586         }
587
588         buildSearchLink(STYPE_AUTHOR, rec.author(), author_link);
589
590         if(! is_mr ) {
591         
592                 if(!isNull(rec.edition()))      {
593                         unHideMe( $n(r, "result_table_extra_span"));
594                         $n(r, "result_table_edition_span").appendChild( text( rec.edition()) );
595                 }
596                 if(!isNull(rec.pubdate())) {
597                         unHideMe( $n(r, "result_table_extra_span"));
598                         unHideMe($n(r, "result_table_pub_span"));
599                         $n(r, "result_table_pub_span").appendChild( text( rec.pubdate() ));
600                 }
601                 if(!isNull(rec.publisher()) ) {
602                         unHideMe( $n(r, "result_table_extra_span"));
603                         unHideMe($n(r, "result_table_pub_span"));
604                         $n(r, "result_table_pub_span").appendChild( text( " " + rec.publisher() ));
605                 }
606
607                 if(!isNull(rec.physical_description()) ) {
608                         unHideMe( $n(r, "result_table_extra_span"));
609                         var t = " " + rec.physical_description();
610                         //$n(r, "result_table_phys_span").appendChild( text(t.replace(/:.*/g,'')));
611                         $n(r, "result_table_phys_span").appendChild( text(t));
612                 }
613
614         }
615
616         resultBuildFormatIcons( r, rec, is_mr );
617
618         var bt_params = {
619                 sync                    : false,
620                 root                    : r,
621                 subObjectLimit  : 10,
622                 org_unit                : findOrgUnit(getLocation()).shortname(),
623                 depth                   : getDepth()
624         };
625
626         if (!is_mr) {
627                 bt_params = dojo.mixin( bt_params, { record : onlyrec } );
628         } else {
629                 bt_params = dojo.mixin( bt_params, { metarecord : onlyrec } );
630         }
631
632         if (findOrgType(findOrgUnit(getLocation()).ou_type()).can_have_vols())
633                 unHideMe($n(r,'local_callnumber_list'));
634
635         new openils.BibTemplate( bt_params ).render();
636
637         unHideMe(r);
638         
639         runEvt("result", "recordDrawn", rec.doc_id(), title_link);
640
641         /*
642         if(resultPageIsDone())  {
643                 runEvt('result', 'allRecordsReceived', recordsCache);
644         }
645         */
646 }
647
648 function resultDrawHoldsWindow(hold_target, hold_type) {
649     var src = location.href;
650
651     if(forceLoginSSL && src.match(/^http:/)) {
652
653         src = src.replace(/^http:/, 'https:');
654
655         if(src.match(/&hold_target=/)) {
656             src.replace(/&hold_target=(\d+)/, hold_target);
657
658         } else {
659             src += '&hold_target=' + hold_target;
660         }
661
662         location.href = src;
663
664     } else {
665         holdsDrawEditor({record:hold_target, type:hold_type});
666     }
667 }
668
669
670
671 function _resultFindRec(id) {
672         for( var i = 0; i != recordsCache.length; i++ ) {
673                 var rec = recordsCache[i];
674                 if( rec && rec.doc_id() == id )
675                         return rec;
676         }
677         return null;
678 }
679
680
681 function resultBuildFormatIcons( row, rec, is_mr ) {
682
683         var ress = rec.types_of_resource();
684
685         for( var i in ress ) {
686
687                 var res = ress[i];
688                 if(!res) continue;
689
690                 var link = $n(row, res + "_link");
691                 link.title = res;
692                 var img = link.getElementsByTagName("img")[0];
693                 removeCSSClass( img, config.css.dim );
694
695                 var f = getForm();
696                 if( f != "all" ) {
697                         if( f == modsFormatToMARC(res) ) 
698                                 addCSSClass( img, "dim2_border");
699                 }
700
701                 var args = {};
702                 args[PARAM_OFFSET] = 0;
703
704                 if(is_mr) {
705                         args.page = RRESULT;
706                         args[PARAM_TFORM] = modsFormatToMARC(res);
707                         args[PARAM_MRID] = rec.doc_id();
708
709                 } else {
710                         args.page = RDETAIL
711                         args[PARAM_RID] = rec.doc_id();
712                 }
713
714                 link.setAttribute("href", buildOPACLink(args));
715
716         }
717 }
718
719 function fetchOpenLibraryLinks() {
720     if (isbnList.length > 0 && OpenLibraryLinks) {
721         /* OpenLibrary supports a number of different identifiers:
722          * ISBN: isbn:<isbn>
723          * LCCN: lccn:<lccn>
724          * OpenLibrary ID: olid:<openlibrary-ID>
725          *
726          * We'll just fire off ISBNs for now.
727          */
728
729         var isbns = '';
730         dojo.forEach(isbnList, function(isbn) {
731             isbns += 'isbn:' + isbn + '|';
732         });
733         isbns = isbns.replace(/.$/, '');
734     }
735
736     dojo.xhrGet({
737         "url": "/opac/extras/ac/proxy/json/" + isbns,
738         "handleAs": "json",
739         "load": function (data) { renderOpenLibraryLinks(data); }
740     });
741
742 }
743
744 function renderOpenLibraryLinks(response) {
745     var ol_ebooks = {};
746
747     /* Iterate over each identifier we requested */
748     for (var item_id in response) {
749
750         var isbn = item_id.replace(/^isbn:/, '');
751         /* Iterate over each matching item; OpenLibrary supplies access info:
752          *  * match: "exact" or "similar"
753          *  * status: "full access" or "lendable"
754          */
755         dojo.forEach(response[item_id].items, function(item) {
756             ol_ebooks[isbn] = {};
757             if (item.match == 'exact') {
758                 if (item.status == 'full access') {
759                     ol_ebooks[isbn]['exact_full'] = item.itemURL;
760                 } else {
761                     ol_ebooks[isbn]['exact_lendable'] = item.itemURL;
762                 }
763             } else {
764                 if (item.status == 'full access') {
765                     ol_ebooks[isbn]['similar_full'] = item.itemURL;
766                 } else {
767                     ol_ebooks[isbn]['similar_lendable'] = item.itemURL;
768                 }
769             }
770         });
771
772         /* If there are no books to read or borrow, move on */
773         if (!ol_ebooks[isbn]) {
774             continue;
775         }
776
777         /* Now populate the results page with our ebook goodness*/
778         /* Go for the jugular - exact match with full access */
779         if (ol_ebooks[isbn]['exact_full']) {
780             createOpenLibraryLink(
781                 isbn, ol_ebooks[isbn]['exact_full'], 'Read online'
782             );
783             continue;
784         }
785
786         /* Fall back to slightly less palatable options */
787         else if (ol_ebooks[isbn]['exact_lendable']) {
788             createOpenLibraryLink(
789                 isbn, ol_ebooks[isbn]['exact_lendable'], 'Borrow online'
790             );
791         }
792
793         if (ol_ebooks[isbn]['similar_full']) {
794             createOpenLibraryLink(
795                 isbn, ol_ebooks[isbn]['similar_full'], 'Read similar online'
796             );
797         } else if (ol_ebooks[isbn]['similar_lendable']) {
798             createOpenLibraryLink(
799                 isbn, ol_ebooks[isbn]['similar_lendable'], 'Borrow similar online'
800             );
801         }
802     }
803 }
804
805 function createOpenLibraryLink(isbn, url, text) {
806     var ol_span = $n(document.documentElement, 'openLibraryLink-' + isbn);
807
808     var ol_a_span = dojo.create('a', {
809             "href": url,
810             "class": "classic_link"
811         }, ol_span
812     );
813     dojo.create('img', {
814             "src": "/opac/images/openlibrary.gif"
815         }, ol_a_span
816     );
817     dojo.create('br', null, ol_a_span);
818     ol_a_span.appendChild(dojo.doc.createTextNode(text));
819     dojo.removeClass(ol_span, 'hide_me');
820 }
821
822 function fetchGoogleBooksLink () {
823     if (isbnList.length > 0 && googleBooksLink) {
824         var scriptElement = document.createElement("script");
825         scriptElement.setAttribute("id", "jsonScript");
826         scriptElement.setAttribute("src",
827             "https://www.googleapis.com/books/v1/volumes?q=" +
828             escape('isbn:' + isbnList.join(' | isbn:')) + "&callback=unhideGoogleBooksLink");
829         scriptElement.setAttribute("type", "text/javascript");
830         // make the request to Google Book Search
831         document.documentElement.firstChild.appendChild(scriptElement);
832     }
833 }
834
835 function fetchChiliFreshReviews() {
836     if (chilifresh && chilifresh != '(none)') {
837         try { chili_init(); } catch(E) { console.log(E + '\n'); }
838     }
839 }
840
841 function resultPageIsDone(pos) {
842
843         return (recordsHandled == getDisplayCount() 
844                 || recordsHandled + getOffset() == getHitCount());
845 }
846
847 var resultCCHeaderApplied = false;
848
849 /* -------------------------------------------------------------------- */
850 /* dynamically add the copy count rows based on the org type 'countsrow' 
851         is the row into which we will add TD's to hold the copy counts 
852         This code generates copy count cells with an id of
853         'copy_count_cell_<depth>_<pagePosition>'  */
854 function resultAddCopyCounts(rec, pagePosition) {
855
856         var r = table.rows[pagePosition + 1];
857         var countsrow = $n(r, config.names.result.counts_row );
858         var ccell = $n(countsrow, config.names.result.count_cell);
859
860         var nodes = orgNodeTrail(findOrgUnit(getLocation()));
861         var start_here = 0;
862         var orgHiding = checkOrgHiding();
863         if (orgHiding) {
864                 for (var i = 0; i < nodes.length; i++) {
865                         if (orgHiding.depth == findOrgDepth(nodes[i])) {
866                                 start_here = i;
867                         }
868                 }
869         }
870
871         var node = nodes[start_here];
872         var type = findOrgType(node.ou_type());
873         ccell.id = "copy_count_cell_" + type.depth() + "_" + pagePosition;
874         ccell.title = type.opac_label();
875         //addCSSClass(ccell, config.css.result.cc_cell_even);
876
877         var lastcell = ccell;
878         var lastheadcell = null;
879
880         var cchead = null;
881         var ccheadcell = null;
882         if(!resultCCHeaderApplied && !getLasso()) {
883                 ccrow = $('result_thead_row');
884                 ccheadcell =  ccrow.removeChild($n(ccrow, "result_thead_ccell"));
885                 var t = ccheadcell.cloneNode(true);
886                 lastheadcell = t;
887                 t.appendChild(text(type.opac_label()));
888                 ccrow.appendChild(t);
889                 resultCCHeaderApplied = true;
890         }
891
892         if(nodes[start_here+1]) {
893
894                 var x = start_here+1;
895                 var d = findOrgDepth(nodes[start_here+1]);
896                 var d2 = findOrgDepth(nodes[nodes.length -1]);
897
898                 for( var i = d; i <= d2 ; i++ ) {
899         
900                         ccell = ccell.cloneNode(true);
901
902                         //if((i % 2)) removeCSSClass(ccell, "copy_count_cell_even");
903                         //else addCSSClass(ccell, "copy_count_cell_even");
904
905                         var node = nodes[x++];
906                         var type = findOrgType(node.ou_type());
907         
908                         ccell.id = "copy_count_cell_" + type.depth() + "_" + pagePosition;
909                         ccell.title = type.opac_label();
910                         countsrow.insertBefore(ccell, lastcell);
911                         lastcell = ccell;
912
913                         if(ccheadcell) {
914                                 var t = ccheadcell.cloneNode(true);
915                                 t.appendChild(text(type.opac_label()));
916                                 ccrow.insertBefore(t, lastheadcell);
917                                 lastheadcell = t;
918                         }
919                 }
920         }
921
922         unHideMe($("search_info_table"));
923 }
924
925 /* collect copy counts for a record using method 'methodName' */
926 function resultCollectCopyCounts(rec, pagePosition, methodName) {
927         if(rec == null || rec.doc_id() == null) return;
928
929         var loc = getLasso();
930         if (loc) loc = -loc;
931         else loc= getLocation();
932
933         var req = new Request(methodName, loc, rec.doc_id(), getForm() );
934         req.request.userdata = [ rec, pagePosition ];
935         req.callback(resultHandleCopyCounts);
936         req.send();
937 }
938
939 function resultHandleCopyCounts(r) {
940         runEvt('result', 'copyCountsReceived', r.userdata[0], r.userdata[1], r.getResultObject()); 
941 }
942
943
944 /* XXX Needs to understand Lasso copy counts... */
945 /* display the collected copy counts */
946 function resultDisplayCopyCounts(rec, pagePosition, copy_counts) {
947         if(copy_counts == null || rec == null) return;
948
949         if (getLasso()) {
950                 var copy_counts_lasso = {
951                         transcendant : null,
952                         count : 0,
953                         unshadow : 0,
954                         available : 0,
955                         depth : -1,
956                         org_unit : getLasso()
957                 };
958
959                 for (var i in copy_counts) {
960                         copy_counts_lasso.transcendant = copy_counts[i].transcendant;
961                         copy_counts_lasso.count += parseInt(copy_counts[i].count);
962                         copy_counts_lasso.unshadow += parseInt(copy_counts[i].unshadow);
963                         copy_counts_lasso.available += parseInt(copy_counts[i].available);
964                 }
965
966                 copy_counts = [ copy_counts_lasso ];
967         }
968
969         var i = 0;
970         while(copy_counts[i] != null) {
971                 var cell = $("copy_count_cell_" + i +"_" + pagePosition);
972                 if (cell) {
973                         var cts = copy_counts[i];
974                         cell.appendChild(text(cts.available + " / " + cts.count));
975
976                         if(isXUL()) {
977                                 /* here we style opac-invisible records for xul */
978
979                                 if( cts.depth == 0 ) {
980                                         if(cts.transcendant == null && cts.unshadow == 0) {
981                                                 _debug("found an opac-shadowed record: " + rec.doc_id());
982                                                 var row = cell.parentNode.parentNode.parentNode.parentNode.parentNode; 
983                                                 if( cts.count == 0 ) 
984                                                         addCSSClass( row, 'no_copies' );
985                                                 else 
986                                                         addCSSClass( row, 'shadowed' );
987                                         }
988                                 }
989                         }
990                 }
991                 i++;
992         }
993 }
994
995