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