]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/web/opac/skin/default/js/result_common.js
Teach result_common.js to OpenLibrary requests
[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 (currentISBN) {
455         isbnList.push(currentISBN);
456         if (OpenLibraryLinks) {
457             var olspan = $n(r, 'openLibraryLink');
458             olspan.setAttribute('name', olspan.getAttribute('name') + 
459                 '-' + currentISBN
460             );
461         }
462
463         if (googleBooksLink) {
464             var gbspan = $n(r, "googleBooksLink");
465             gbspan.setAttribute(
466                 'name',
467                 gbspan.getAttribute('name') + '-' + currentISBN
468             );
469
470         }
471     }
472
473     if (currentISBN && chilifresh && chilifresh != '(none)') {
474         var cfrow = $n(r, "chilifreshReview");
475         if (cfrow) {
476             removeCSSClass( cfrow, 'hide_me' );
477         }
478         var cflink = $n(r, "chilifreshReviewLink");
479         if (cflink) {
480             cflink.setAttribute(
481                 'id',
482                 'isbn_' + currentISBN
483             );
484         }
485         var cfdiv = $n(r, "chilifreshReviewResult");
486         if (cfdiv) {
487             cfdiv.setAttribute(
488                 'id',
489                 'chili_review_' + currentISBN
490             )
491         }
492     }
493
494 /*
495         try {
496                 var rank = parseFloat(ranks[pos + getOffset()]);
497                 rank            = parseInt( rank * 100 );
498                 var relspan = $n(r, "relevancy_span");
499                 relspan.appendChild(text(rank));
500                 unHideMe(relspan.parentNode);
501         } catch(e){ }
502 */
503
504         var pic = $n(r, config.names.result.item_jacket);
505         pic.setAttribute("src", buildISBNSrc(currentISBN));
506
507         var title_link = $n(r, config.names.result.item_title);
508         var author_link = $n(r, config.names.result.item_author);
509
510         var onlyrec;
511         if( is_mr )  {
512                 onlyrec = onlyrecord[ getOffset() + pos ];
513                 if(onlyrec) {
514                         buildunAPISpan($n(r,'unapi'), 'biblio-record_entry', onlyrec);
515
516                         var args = {};
517                         args.page = RDETAIL;
518                         args[PARAM_OFFSET] = 0;
519                         args[PARAM_RID] = onlyrec;
520                         args[PARAM_MRID] = rec.doc_id();
521                         pic.parentNode.setAttribute("href", buildOPACLink(args));
522                         title_link.setAttribute("href", buildOPACLink(args));
523                         title_link.appendChild(text(normalize(truncate(rec.title(), 65))));
524
525                 } else {
526                         buildunAPISpan($n(r,'unapi'), 'metabib-metarecord', rec.doc_id());
527
528                         buildTitleLink(rec, title_link); 
529                         var args = {};
530                         args.page = RRESULT;
531                         args[PARAM_OFFSET] = 0;
532                         args[PARAM_MRID] = rec.doc_id();
533                         pic.parentNode.setAttribute("href", buildOPACLink(args));
534                 }
535
536                 unHideMe($n(r,'place_hold_span'));
537                 $n(r,'place_hold_link').onclick = function() { resultDrawHoldsWindow(rec.doc_id(), 'M'); }
538             
539
540         } else {
541                 onlyrec = rec.doc_id();
542                 buildunAPISpan($n(r,'unapi'), 'biblio-record_entry', rec.doc_id());
543
544                 buildTitleDetailLink(rec, title_link); 
545                 var args = {};
546                 args.page = RDETAIL;
547                 args[PARAM_OFFSET] = 0;
548                 args[PARAM_RID] = rec.doc_id();
549                 pic.parentNode.setAttribute("href", buildOPACLink(args));
550
551                 unHideMe($n(r,'place_hold_span'));
552                 $n(r,'place_hold_link').onclick = function() { resultDrawHoldsWindow(rec.doc_id(), 'T'); }
553         }
554
555         buildSearchLink(STYPE_AUTHOR, rec.author(), author_link);
556
557         if(! is_mr ) {
558         
559                 if(!isNull(rec.edition()))      {
560                         unHideMe( $n(r, "result_table_extra_span"));
561                         $n(r, "result_table_edition_span").appendChild( text( rec.edition()) );
562                 }
563                 if(!isNull(rec.pubdate())) {
564                         unHideMe( $n(r, "result_table_extra_span"));
565                         unHideMe($n(r, "result_table_pub_span"));
566                         $n(r, "result_table_pub_span").appendChild( text( rec.pubdate() ));
567                 }
568                 if(!isNull(rec.publisher()) ) {
569                         unHideMe( $n(r, "result_table_extra_span"));
570                         unHideMe($n(r, "result_table_pub_span"));
571                         $n(r, "result_table_pub_span").appendChild( text( " " + rec.publisher() ));
572                 }
573
574                 if(!isNull(rec.physical_description()) ) {
575                         unHideMe( $n(r, "result_table_extra_span"));
576                         var t = " " + rec.physical_description();
577                         //$n(r, "result_table_phys_span").appendChild( text(t.replace(/:.*/g,'')));
578                         $n(r, "result_table_phys_span").appendChild( text(t));
579                 }
580
581         }
582
583         resultBuildFormatIcons( r, rec, is_mr );
584
585         var bt_params = {
586                 sync                    : false,
587                 root                    : r,
588                 subObjectLimit  : 10,
589                 org_unit                : findOrgUnit(getLocation()).shortname(),
590                 depth                   : getDepth()
591         };
592
593         if (!is_mr) {
594                 bt_params = dojo.mixin( bt_params, { record : onlyrec } );
595         } else {
596                 bt_params = dojo.mixin( bt_params, { metarecord : onlyrec } );
597         }
598
599         if (findOrgType(findOrgUnit(getLocation()).ou_type()).can_have_vols())
600                 unHideMe($n(r,'local_callnumber_list'));
601
602         new openils.BibTemplate( bt_params ).render();
603
604         unHideMe(r);
605         
606         runEvt("result", "recordDrawn", rec.doc_id(), title_link);
607
608         /*
609         if(resultPageIsDone())  {
610                 runEvt('result', 'allRecordsReceived', recordsCache);
611         }
612         */
613 }
614
615 function resultDrawHoldsWindow(hold_target, hold_type) {
616     var src = location.href;
617
618     if(forceLoginSSL && src.match(/^http:/)) {
619
620         src = src.replace(/^http:/, 'https:');
621
622         if(src.match(/&hold_target=/)) {
623             src.replace(/&hold_target=(\d+)/, hold_target);
624
625         } else {
626             src += '&hold_target=' + hold_target;
627         }
628
629         location.href = src;
630
631     } else {
632         holdsDrawEditor({record:hold_target, type:hold_type});
633     }
634 }
635
636
637
638 function _resultFindRec(id) {
639         for( var i = 0; i != recordsCache.length; i++ ) {
640                 var rec = recordsCache[i];
641                 if( rec && rec.doc_id() == id )
642                         return rec;
643         }
644         return null;
645 }
646
647
648 function resultBuildFormatIcons( row, rec, is_mr ) {
649
650         var ress = rec.types_of_resource();
651
652         for( var i in ress ) {
653
654                 var res = ress[i];
655                 if(!res) continue;
656
657                 var link = $n(row, res + "_link");
658                 link.title = res;
659                 var img = link.getElementsByTagName("img")[0];
660                 removeCSSClass( img, config.css.dim );
661
662                 var f = getForm();
663                 if( f != "all" ) {
664                         if( f == modsFormatToMARC(res) ) 
665                                 addCSSClass( img, "dim2_border");
666                 }
667
668                 var args = {};
669                 args[PARAM_OFFSET] = 0;
670
671                 if(is_mr) {
672                         args.page = RRESULT;
673                         args[PARAM_TFORM] = modsFormatToMARC(res);
674                         args[PARAM_MRID] = rec.doc_id();
675
676                 } else {
677                         args.page = RDETAIL
678                         args[PARAM_RID] = rec.doc_id();
679                 }
680
681                 link.setAttribute("href", buildOPACLink(args));
682
683         }
684 }
685
686 function fetchOpenLibraryLinks() {
687     if (isbnList.length > 0 && OpenLibraryLinks) {
688         /* OpenLibrary supports a number of different identifiers:
689          * ISBN: isbn:<isbn>
690          * LCCN: lccn:<lccn>
691          * OpenLibrary ID: olid:<openlibrary-ID>
692          *
693          * We'll just fire off ISBNs for now.
694          */
695
696         var isbns = '';
697         dojo.forEach(isbnList, function(isbn) {
698             isbns += 'isbn:' + isbn + '|';
699         });
700         isbns = isbns.replace(/.$/, '');
701     }
702
703     dojo.xhrGet({
704         "url": "/opac/extras/ac/proxy/json/" + isbns,
705         "handleAs": "json",
706         "load": function (data) { renderOpenLibraryLinks(data); }
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         /* If there are no books to read or borrow, move on */
740         if (!ol_ebooks[isbn]) {
741             continue;
742         }
743
744         /* Now populate the results page with our ebook goodness*/
745         /* Go for the jugular - exact match with full access */
746         if (ol_ebooks[isbn]['exact_full']) {
747             createOpenLibraryLink(
748                 isbn, ol_ebooks[isbn]['exact_full'], 'Read online'
749             );
750             continue;
751         }
752
753         /* Fall back to slightly less palatable options */
754         else if (ol_ebooks[isbn]['exact_lendable']) {
755             createOpenLibraryLink(
756                 isbn, ol_ebooks[isbn]['exact_lendable'], 'Borrow online'
757             );
758         }
759
760         if (ol_ebooks[isbn]['similar_full']) {
761             createOpenLibraryLink(
762                 isbn, ol_ebooks[isbn]['similar_full'], 'Read similar online'
763             );
764         } else if (ol_ebooks[isbn]['similar_lendable']) {
765             createOpenLibraryLink(
766                 isbn, ol_ebooks[isbn]['similar_full'], 'Borrow similar online'
767             );
768         }
769     }
770 }
771
772 function createOpenLibraryLink(isbn, url, text) {
773     var ol_span = $n(document.documentElement, 'openLibraryLink-' + isbn);
774
775     var ol_a_span = dojo.create('a', {
776             "href": url,
777             "class": "classic_link"
778         }, ol_span
779     );
780     dojo.create('img', {
781             "src": "/opac/images/openlibrary.gif"
782         }, ol_a_span
783     );
784     dojo.create('br', null, ol_a_span);
785     ol_a_span.appendChild(dojo.doc.createTextNode(text));
786     dojo.removeClass(ol_span, 'hide_me');
787 }
788
789 function fetchGoogleBooksLink () {
790     if (isbnList.length > 0 && googleBooksLink) {
791         var scriptElement = document.createElement("script");
792         scriptElement.setAttribute("id", "jsonScript");
793         scriptElement.setAttribute("src",
794             "http://books.google.com/books?bibkeys=" + 
795             escape(isbnList.join(', ')) + "&jscmd=viewapi&callback=unhideGoogleBooksLink");
796         scriptElement.setAttribute("type", "text/javascript");
797         // make the request to Google Book Search
798         document.documentElement.firstChild.appendChild(scriptElement);
799     }
800 }
801
802 function fetchChiliFreshReviews() {
803     if (chilifresh && chilifresh != '(none)') {
804         try { chili_init(); } catch(E) { console.log(E + '\n'); }
805     }
806 }
807
808 function resultPageIsDone(pos) {
809
810         return (recordsHandled == getDisplayCount() 
811                 || recordsHandled + getOffset() == getHitCount());
812 }
813
814 var resultCCHeaderApplied = false;
815
816 /* -------------------------------------------------------------------- */
817 /* dynamically add the copy count rows based on the org type 'countsrow' 
818         is the row into which we will add TD's to hold the copy counts 
819         This code generates copy count cells with an id of
820         'copy_count_cell_<depth>_<pagePosition>'  */
821 function resultAddCopyCounts(rec, pagePosition) {
822
823         var r = table.rows[pagePosition + 1];
824         var countsrow = $n(r, config.names.result.counts_row );
825         var ccell = $n(countsrow, config.names.result.count_cell);
826
827         var nodes = orgNodeTrail(findOrgUnit(getLocation()));
828         var start_here = 0;
829         var orgHiding = checkOrgHiding();
830         if (orgHiding) {
831                 for (var i = 0; i < nodes.length; i++) {
832                         if (orgHiding.depth == findOrgDepth(nodes[i])) {
833                                 start_here = i;
834                         }
835                 }
836         }
837
838         var node = nodes[start_here];
839         var type = findOrgType(node.ou_type());
840         ccell.id = "copy_count_cell_" + type.depth() + "_" + pagePosition;
841         ccell.title = type.opac_label();
842         //addCSSClass(ccell, config.css.result.cc_cell_even);
843
844         var lastcell = ccell;
845         var lastheadcell = null;
846
847         var cchead = null;
848         var ccheadcell = null;
849         if(!resultCCHeaderApplied && !getLasso()) {
850                 ccrow = $('result_thead_row');
851                 ccheadcell =  ccrow.removeChild($n(ccrow, "result_thead_ccell"));
852                 var t = ccheadcell.cloneNode(true);
853                 lastheadcell = t;
854                 t.appendChild(text(type.opac_label()));
855                 ccrow.appendChild(t);
856                 resultCCHeaderApplied = true;
857         }
858
859         if(nodes[start_here+1]) {
860
861                 var x = start_here+1;
862                 var d = findOrgDepth(nodes[start_here+1]);
863                 var d2 = findOrgDepth(nodes[nodes.length -1]);
864
865                 for( var i = d; i <= d2 ; i++ ) {
866         
867                         ccell = ccell.cloneNode(true);
868
869                         //if((i % 2)) removeCSSClass(ccell, "copy_count_cell_even");
870                         //else addCSSClass(ccell, "copy_count_cell_even");
871
872                         var node = nodes[x++];
873                         var type = findOrgType(node.ou_type());
874         
875                         ccell.id = "copy_count_cell_" + type.depth() + "_" + pagePosition;
876                         ccell.title = type.opac_label();
877                         countsrow.insertBefore(ccell, lastcell);
878                         lastcell = ccell;
879
880                         if(ccheadcell) {
881                                 var t = ccheadcell.cloneNode(true);
882                                 t.appendChild(text(type.opac_label()));
883                                 ccrow.insertBefore(t, lastheadcell);
884                                 lastheadcell = t;
885                         }
886                 }
887         }
888
889         unHideMe($("search_info_table"));
890 }
891
892 /* collect copy counts for a record using method 'methodName' */
893 function resultCollectCopyCounts(rec, pagePosition, methodName) {
894         if(rec == null || rec.doc_id() == null) return;
895
896         var loc = getLasso();
897         if (loc) loc = -loc;
898         else loc= getLocation();
899
900         var req = new Request(methodName, loc, rec.doc_id(), getForm() );
901         req.request.userdata = [ rec, pagePosition ];
902         req.callback(resultHandleCopyCounts);
903         req.send();
904 }
905
906 function resultHandleCopyCounts(r) {
907         runEvt('result', 'copyCountsReceived', r.userdata[0], r.userdata[1], r.getResultObject()); 
908 }
909
910
911 /* XXX Needs to understand Lasso copy counts... */
912 /* display the collected copy counts */
913 function resultDisplayCopyCounts(rec, pagePosition, copy_counts) {
914         if(copy_counts == null || rec == null) return;
915
916         if (getLasso()) {
917                 var copy_counts_lasso = {
918                         transcendant : null,
919                         count : 0,
920                         unshadow : 0,
921                         available : 0,
922                         depth : -1,
923                         org_unit : getLasso()
924                 };
925
926                 for (var i in copy_counts) {
927                         copy_counts_lasso.transcendant = copy_counts[i].transcendant;
928                         copy_counts_lasso.count += parseInt(copy_counts[i].count);
929                         copy_counts_lasso.unshadow += parseInt(copy_counts[i].unshadow);
930                         copy_counts_lasso.available += parseInt(copy_counts[i].available);
931                 }
932
933                 copy_counts = [ copy_counts_lasso ];
934         }
935
936         var i = 0;
937         while(copy_counts[i] != null) {
938                 var cell = $("copy_count_cell_" + i +"_" + pagePosition);
939                 if (cell) {
940                         var cts = copy_counts[i];
941                         cell.appendChild(text(cts.available + " / " + cts.count));
942
943                         if(isXUL()) {
944                                 /* here we style opac-invisible records for xul */
945
946                                 if( cts.depth == 0 ) {
947                                         if(cts.transcendant == null && cts.unshadow == 0) {
948                                                 _debug("found an opac-shadowed record: " + rec.doc_id());
949                                                 var row = cell.parentNode.parentNode.parentNode.parentNode.parentNode; 
950                                                 if( cts.count == 0 ) 
951                                                         addCSSClass( row, 'no_copies' );
952                                                 else 
953                                                         addCSSClass( row, 'shadowed' );
954                                         }
955                                 }
956                         }
957                 }
958                 i++;
959         }
960 }
961
962