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