]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/javascript/opac/AbstractRecordResultPage.js
fixin and makin purdy
[Evergreen.git] / Open-ILS / src / javascript / opac / AbstractRecordResultPage.js
1
2 AbstractRecordResultPage.prototype                                      = new Page();
3 AbstractRecordResultPage.prototype.constructor  = AbstractRecordResultPage;
4 AbstractRecordResultPage.baseClass                                      = Page.constructor;
5
6
7 /* constructor for our singleton object */
8 function AbstractRecordResultPage() {}
9
10
11 /* initialize all of the UI components and set up data structures */
12 AbstractRecordResultPage.prototype.init = function() {
13
14         debug( "Initing an AbstractRecordResultPage" );
15
16         /* included page chunks */
17         this.searchBar                  = new SearchBarChunk();
18
19         /* UI objects */
20         this.recordBox                  = getById("record_result_box");
21
22         this.authorBox = new Box();
23         this.authorBox.init("Relevant Authors", true, true, 15);
24         this.authorBox.sortByKey();
25
26         this.subjectBox = new Box();
27         this.subjectBox.init("Relevant Subjects", true, true, 15);
28         this.subjectBox.sortByCount();
29
30         this.seriesBox = new Box();
31         this.seriesBox.init("Relevant Series", true, true, 15);
32         this.seriesBox.sortByKey();
33
34         this.sidebarBox         = getById("record_sidebar_box");
35
36         this.sidebarBox.appendChild(this.buildNavBox());
37         this.sidebarBox.appendChild(elem("br"));
38
39         if(!this.hitsPerPage)
40                 this.hitsPerPage                = 10;    /* how many hits are displayed per page */
41
42         this.resetPage();
43
44         this.statusBar                  = getById("top_status_bar_table");
45         this.theadDrawn         = false;
46         this.bigOlBox                   = getById("big_ol_box");
47
48
49 }
50
51
52
53 /** Resets data structures for a new search */
54 AbstractRecordResultPage.prototype.resetPage = function() {
55         this.searchBar.reset();
56         var spot = getById("progress_bar_location");
57         var spot2 = getById("progress_bar_percent_location");
58         if(spot) {
59                 while(spot.lastChild) 
60                         spot.removeChild(spot.lastChild);
61
62                 /* progress items for each record and it's hit count listing */
63                 this.progressBar = new ProgressBar(parseInt(this.hitsPerPage) * 2);
64                 spot.appendChild(this.progressBar.getNode());
65         }
66         if(spot2 && this.progressBar)
67                 spot2.appendChild(this.progressBar.percentDiv);
68         this.received = 0;
69
70         RemoteRequest.cancelAll();
71
72         this.requestBatch = new RequestBatch();
73         this.finalized = false;
74         this.builtLinks = false;
75
76         this.hitsPerPageSelector = getById('hits_per_page');
77
78         var obj = this;
79         this.hitsPerPageSelector.onchange = function() {
80
81                 var hits;
82                 var hits_obj = obj.hitsPerPageSelector.options[
83                         obj.hitsPerPageSelector.selectedIndex]; 
84
85                 if(hits_obj == null)
86                         return;
87
88                 hits = hits_obj.value
89
90                 debug("Hits per page set to " + hits );
91
92                 obj.hitsPerPage = parseInt(hits);       
93
94
95                 var location = globalSelectedLocation;
96                 if(location == null) location = globalLocation.id();
97
98                 url_redirect(obj.URLRefresh());
99                 obj = null;
100         }
101
102
103         for( var i in this.hitsPerPageSelector.options ) {
104
105                 var hits_obj = obj.hitsPerPageSelector.options[i];
106                 if(hits_obj == null) continue;
107                 var hits = hits_obj.value;
108
109                 if( this.hitsPerPage == parseInt(hits) ) 
110                         this.hitsPerPageSelector.options[i].selected = true;
111         }
112
113 }
114
115
116 AbstractRecordResultPage.prototype.resetSearch = function() {
117         this.recordIDs                          = new Array();
118         this.ranks                                      = new Array();
119         this.hitCount                           = 0;                                    /* hits for the current search */
120         this.searchOffset                       = 0;                                    /* the offset for the search display */
121         this.page                                       = 0;
122
123 }
124
125 AbstractRecordResultPage.prototype.gatherIDs = function(result) {
126         if(result == null) return;
127
128         this.hitCount = parseInt(result.count);
129
130         if(result.ids.length < 1) {
131                 this.finalizePage();
132                 return false;
133         }
134         
135
136         /* the 'ids' field consist of [record, rank] */
137         /* gather all of the ID's */
138         if( result.ids  && typeof result.ids == 'object' 
139                         && result.ids[0] != null
140                         && result.ids[0].constructor == Array ) {
141
142                 for( var i in result.ids ) {
143                         if(result.ids[i]==null || result.ids[i][0] == null) break;
144                         var offset = parseInt(i) + parseInt(this.searchOffset);
145                         this.recordIDs[offset] = result.ids[i][0];
146                         var rank = parseFloat(result.ids[i][1]);
147                         if(rank == 0)
148                                 rank = 0.00000001; /* protect divide by 0 */
149                         this.ranks[offset] =  rank;
150                         /*
151                         debug("adding ranks[" + offset + "] = " + result.ids[i][1] + 
152                                         "  \nrecordIDs["+offset+"], result.ids["+i+"][0]");
153                                         */
154                 }
155
156         } else {
157
158                 for( var i in result.ids ) {
159                         if(result.ids[i]==null) break;
160                         var offset = parseInt(i) + parseInt(this.searchOffset);
161                         this.recordIDs[offset] = result.ids[i];
162                         debug("adding recordIDs["+offset+"], result.ids["+i+"]");
163                 }
164         }
165
166         return true;
167 }
168
169
170
171 AbstractRecordResultPage.prototype.complete = function() {
172
173 }
174
175
176 AbstractRecordResultPage.prototype.displayRecord = 
177         function( record, search_id, page_id ) {
178
179         if(record == null) return;
180         debug("Displaying record " + record.doc_id());
181
182         if(!instanceOf(record, Fieldmapper)) {
183                 debug(" * Received bogus record " + js2JSON(record));
184                 return;
185         }
186
187         if(page_id == 0)
188                 this.buildNextLinks();
189
190         this.received += 1;
191
192         this.progressBar.manualNext();
193
194         var id = parseInt(page_id);
195         var title_row = table_row_find_or_create(this.recordBox, id * 3 + 1 );
196         var author_row = table_row_find_or_create(this.recordBox, id * 3 + 2 );
197         var misc_row = table_row_find_or_create(this.recordBox, id * 3 + 3 );
198
199         add_css_class(misc_row, "record_misc_row");
200         add_css_class(title_row, "record_title_row");
201
202
203         var c = misc_row.insertCell(0);
204         /* shove in a div for each of the types of resource */
205         for( var i = 0; i!= 9; i++) {
206                 var div = createAppElement("div");
207                 div.innerHTML = "&nbsp;";
208                 add_css_class(div, "record_resource_div");
209                 c.appendChild(div);
210         }
211         //var options_cell = misc_row.insertCell(1);
212
213         c.className = "record_misc_cell";
214         var resources = record.types_of_resource();
215
216         for( var i in resources ) 
217                 this.buildResourcePic( c, resources[i]);
218
219         author_row.id = "record_result_author_row_" + id;
220         title_row.id = "record_result_title_row_" + id;
221
222         /* build the appropriate context node for this result */
223         var menu_name = "record_result_row_" + page_id;
224         var menu = globalMenuManager.buildMenu(menu_name);
225
226         this.addMenuItems( menu, record );
227
228         globalMenuManager.setContext(title_row, menu);
229         globalMenuManager.setContext(author_row, menu);
230         globalMenuManager.setContext(misc_row, menu);
231
232         getDocument().body.appendChild(menu.getNode());
233
234         //var optionsLink = this.buildExtendedLinks(record, page_id);
235         //if(optionsLink)
236         //      options_cell.appendChild(optionsLink);
237         /* ------------------------------------ */
238
239
240         var pic_cell = title_row.insertCell(0);
241         this.buildRecordImage( pic_cell, record, page_id, record.title());
242
243         var title_cell = title_row.insertCell(title_row.cells.length);
244         title_cell.id = "record_result_title_box_" + id;
245         add_css_class( title_cell, "record_result_title_box");
246
247         var author_cell = author_row.insertCell(author_row.cells.length);
248         author_cell.id = "record_result_author_box_" + id;
249         add_css_class(author_cell, "record_result_author_box");
250
251
252         /* limit the length of the title and author lines */
253         var tlength = 80;
254
255         var title = "";
256         if( record.title() ) {
257                 if(record.title().length > tlength) {
258                         record.title(record.title().substr(0,tlength));
259                         record.title(record.title() + "...");
260                 }
261                 title = normalize(record.title());
262         }
263
264
265         var author = "";
266         if( record.author() ) {
267                 if(record.author().length > tlength) {
268                         record.author( record.author().substr(0,tlength));
269                         record.author(record.author() + "...");
270                 }
271                 author = normalize(record.author());
272         }
273
274         title_cell.appendChild(this.mkLink(record.doc_id(), "title", title, record.title() ));
275         author_cell.innerHTML = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
276         author_cell.appendChild(this.mkLink(record.doc_id(), "author", author ));
277
278         if(instanceOf(this, RecordResultPage)) {
279                 var span = createAppElement("span");
280                 span.style.marginLeft = "10px";
281
282                 if(record.pubdate() || record.edition())
283                         span.appendChild(createAppTextNode(" -- "));
284
285                 if(record.pubdate())
286                         span.appendChild(createAppTextNode(" " + record.pubdate()));
287
288                 if(record.edition())
289                         span.appendChild(createAppTextNode(" " + record.edition()));
290
291                         author_cell.appendChild(span);
292
293                 var marcb = elem( "a",
294                         {
295                                 href:"javascript:void(0)",
296                                 style: "text-decoration:underline"
297                         },
298                         {}, "View MARC" );
299
300                 debug("Setting up view marc callback with record " + record.doc_id());
301                 var func = buildViewMARCWindow(record);
302                 marcb.onclick = func;
303
304                 var marcd = elem( "div", { style: "float:right" } );
305                 marcd.appendChild(marcb);
306                 //author_cell.appendChild(marcd);
307                 //misc_row.insertCell(misc_row.cells.length).appendChild(marcd);
308                 c.appendChild(marcd);
309
310
311         }
312
313         var classname = "result_even";
314         if((page_id%2) != 0) 
315                 classname = "result_odd";
316
317         add_css_class(title_row, classname);
318         add_css_class(author_row, classname);
319         add_css_class(misc_row, classname);
320
321         /* now grab the record authors and subjects */
322         if( author ) {
323                 this.authorBox.addItem( this.mkAuthorLink(author) , author);
324         }
325
326         /* gather the subjects.  subjects are either a string or an array of
327                 [subject, broader topic].  currently, they're all just treated like
328                 subjects */
329         var arr = record.subject();
330         var x = 0;
331         for( var sub in arr ) {
332                 if(x++ > 5) break; /* too many subjects makes things real sluggish */
333
334                 var ss = arr[sub];
335
336                 /* only taking first part of subject (non-topic, etc.) */
337                 if( ss.constructor == Array)
338                         ss = ss[0];
339
340                 if( ss.constructor != Array )
341                         ss = [ss];
342
343                 for( var i in ss ) {
344                         var s = normalize(ss[i]);
345                         this.subjectBox.addItem( this.mkSubjectLink(s), s );
346                 }
347         }
348
349         var series = record.series();
350         for( var s in  series ) {
351                 debug("Found series entry: " + series[s] );
352                 var ss = normalize(series[s]);
353                 this.seriesBox.addItem( this.mkSeriesLink(ss), ss );
354         }
355
356         /* requestBatch will only have one request in it when the current
357                 record is the last record requested */
358         if( this.requestBatch.pending() < 2  )
359                 this.finalizePage();
360
361         debug("Finished displaying record " + record.doc_id());
362 }
363
364 AbstractRecordResultPage.prototype.mkAuthorLink = function(auth) {
365         var href = createAppElement("a");
366         add_css_class(href,"record_result_sidebar_link");
367
368         href.setAttribute("href",
369                 "?target=mr_result&mr_search_type=author&page=0&mr_search_query=" +
370                 encodeURIComponent(auth) +
371                 "&mr_search_depth=" + this.searchDepth +
372                 "&mr_search_location=" + this.searchLocation +
373                 "&location=" +  this.searchLocation +
374                 "&depth=" +  this.searchDepth);
375
376         href.appendChild(createAppTextNode(auth));
377         href.title = "Author search for " + auth;
378         return href;
379 }
380
381 AbstractRecordResultPage.prototype.mkSeriesLink = function(series) {
382         var href = createAppElement("a");
383         add_css_class(href,"record_result_sidebar_link");
384
385         debug("Series: " + series + " : " + encodeURIComponent(series));
386
387         href.setAttribute("href",
388                 "?target=mr_result&mr_search_type=series&page=0&mr_search_query=" +
389                 encodeURIComponent(series) +
390                 "&mr_search_depth=" + this.searchDepth +
391                 "&mr_search_location=" + this.searchLocation +
392                 "&location=" +  this.searchLocation +
393                 "&depth=" +  this.searchDepth);
394
395         href.appendChild(createAppTextNode(series));
396         href.title = "Series search for " + series;
397         return href;
398 }
399
400 AbstractRecordResultPage.prototype.mkSubjectLink = function(sub) {
401         var href = createAppElement("a");
402         add_css_class(href,"record_result_sidebar_link");
403         href.setAttribute("href",
404                 "?target=mr_result&mr_search_type=subject&page=0&mr_search_query=" +
405                 encodeURIComponent(sub) + 
406                 "&mr_search_depth=" + this.searchDepth +
407                 "&mr_search_location=" + this.searchLocation +
408                 "&location=" +  this.searchLocation +
409                 "&depth=" +  this.searchDepth);
410
411         href.appendChild(createAppTextNode(sub));
412         href.title = "Subject search for " + sub;
413         return href;
414 }
415
416 AbstractRecordResultPage.prototype.finalizePage = function() {
417
418         if( this.finalized )
419                 return;
420         this.finalized = true;
421
422
423         this.subjectBox.finalize();
424         this.authorBox.finalize();
425         this.seriesBox.finalize();
426
427         this.sidebarBox.appendChild(this.subjectBox.getNode());
428         this.sidebarBox.appendChild(createAppElement("br"));
429
430         this.sidebarBox.appendChild(this.authorBox.getNode());
431         this.sidebarBox.appendChild(createAppElement("br"));
432
433         this.sidebarBox.appendChild(this.seriesBox.getNode());
434         this.sidebarBox.appendChild(createAppElement("br"));
435
436 //      showMe(this.buttonsBox);
437
438         var ses = UserSession.instance().getSessionId();
439         var box = this.sidebarBox;
440
441         if(ses) {
442                 Survey.retrieveOpacRandom(ses, 
443                         function(sur) { 
444                                 sur.setSubmitCallback(
445                                         function() { alert("Thanks!"); return true; });
446                                 box.appendChild( sur.getNode() ); 
447                                 sur.setHidden(false);
448                         }
449                 );
450         } else {
451                 Survey.retrieveOpacRandomGlobal( 
452                         function(sur) { 
453                                 sur.setSubmitCallback(
454                                         function() { alert("Thanks!"); return true; });
455                                 box.appendChild( sur.getNode() ); 
456                                 sur.setHidden(false);
457                         }
458                 );
459         }
460
461
462         if(this.hitCount < 1) {
463                 if(this.progressBar) this.progressBar.stop();
464         }
465
466         /* in case we're hidden */
467         showMe(this.bigOlBox);
468         showMe(getById("hit_count_cell_2"));
469
470 }
471
472
473 AbstractRecordResultPage.prototype.displayCopyCounts = 
474         function(copy_counts, search_id, page_id) {
475                 
476         this.progressBar.manualNext();
477         var titlerow  = getById("record_result_title_row_" + page_id );
478         var authorrow  = getById("record_result_author_row_" + page_id );
479
480         var tcell = getById("record_result_title_box_" + page_id );
481
482         if(!this.theadDrawn) {
483                 var trow = getById("record_result_thead_row");
484                 for( var i in copy_counts) {
485                         var cell = trow.insertCell(trow.cells.length);
486                         add_css_class(cell,"record_result_thead_header");
487                         cell.innerHTML = 
488                                 findOrgType(findOrgUnit(
489                                         copy_counts[i].org_unit).ou_type()).opac_label();
490                 }
491                 this.theadDrawn = true;
492         }
493
494         for( var i in copy_counts) {
495                 var cell = createAppElement("td");
496                 add_css_class(cell, "copy_count_cell");
497                 cell.innerHTML = copy_counts[i].available + " / " + copy_counts[i].count;
498                 cell.setAttribute("rowspan","3");
499                 cell.rowSpan = 3;
500                 cell.title = " Availabie Copies / Total Copies";
501                 titlerow.appendChild(cell);
502         }
503
504         if(page_id  == (parseInt(this.hitsPerPage) - 1) ) {
505                 if(this.progressBar) this.progressBar.stop();
506                 if(this.hitCount < 1)
507                         this.noHits();
508         }
509
510         if( (page_id  == ((parseInt(this.hitCount) - 1 ) - parseInt(this.searchOffset))) ||
511                         (page_id == (parseInt(this.hitsPerPage) - 1) )) 
512                 if(this.progressBar) this.progressBar.stop();
513 }
514
515
516
517 AbstractRecordResultPage.prototype.noHits = function() {
518         var hcell = getById("hit_count_cell");
519         //hcell.appendChild(createAppElement("br"));
520         hcell.appendChild(createAppTextNode("0 hits were returned for you search"));
521 }
522
523
524 AbstractRecordResultPage.prototype.buildNextLinks = function() {
525
526         if(this.builtLinks)
527                 return;
528         this.builtLinks = true;
529
530         var obj = this;
531         var next;
532         var prev;
533
534         debug("Building links");
535         if( this.searchOffset < (parseInt(this.hitCount) - this.hitsPerPage)) {
536                 next = createAppElement("a");
537                 add_css_class(next,"record_next_button");
538                 add_css_class(next,"record_next_button_active");
539                 next.href = "javascript:globalPage.next();";
540         } else {
541                 next = createAppElement("span");
542                 add_css_class(next,"record_next_button_inactive");
543         }
544
545         if(this.searchOffset > 0) {
546                 prev = createAppElement("a");
547                 add_css_class(prev,"record_next_button");
548                 add_css_class(prev,"record_next_button_active");
549                 prev.href = "javascript:globalPage.prev();";
550         } else {
551                 prev = createAppElement("span");
552                 add_css_class(prev,"record_next_button_inactive");
553         }
554
555         next.appendChild(createAppTextNode("Next"));
556         prev.appendChild(createAppTextNode("Previous"));
557
558
559         var i = this.searchOffset;
560         var max = parseInt(i) + this.hitsPerPage;
561         if( max > this.hitCount )
562                 max = this.hitCount;
563
564         var hcell = getById("hit_count_cell");
565         var hcell2 = getById("hit_count_cell_2");
566         hideMe(hcell2);
567
568         if(hcell) {
569
570                 var ident = "Titles";
571                 if(instanceOf(this, MRResultPage))
572                         ident = "Title Groups";
573         
574                 hcell.appendChild(
575                         createAppTextNode( "Displaying " + ident + " " +
576                         ( parseInt(i) + 1 ) + " to " + max + " of " + this.hitCount));
577         
578                 hcell.appendChild(createAppTextNode(" "));
579                 hcell.appendChild(createAppTextNode(" "));
580                 hcell.appendChild(createAppTextNode(" "));
581         
582                 hcell.appendChild(prev);
583                 var span = createAppElement("span");
584                 span.appendChild(createAppTextNode(" ... "));
585                 hcell.appendChild(span);
586                 hcell.appendChild(next);
587         
588                 hcell2.innerHTML = hcell.innerHTML;
589         
590         }
591         
592 }
593
594
595 AbstractRecordResultPage.prototype.buildResourcePic = function(c, resource) {
596         return buildResourcePic(c, resource);
597 }
598
599 function buildResourcePic(c, resource) {
600
601         var pic = createAppElement("img");
602
603         pic.setAttribute("src", "/images/" + resource + ".jpg");
604         pic.className = "record_resource_pic";
605         pic.setAttribute("width", "20");
606         pic.setAttribute("height", "20");
607         pic.setAttribute("title", resource);
608
609
610         var index;
611
612         switch(resource) {
613
614                 case "text":
615                         index = 0;
616                         break;
617
618                 case "moving image":
619                         index = 1;
620                         break;
621
622                 case "sound recording":
623                         index = 2;
624                         break;
625
626                 case "software, multimedia":
627                         index = 3;
628                         break;
629
630                 case "still images":
631                         index = 4;
632                         break;
633
634                 case "cartographic":
635                         index = 5;
636                         break;
637
638                 case "mixed material":
639                         index = 6;
640                         break;
641
642                 case "notated music":
643                         index = 7;
644                         break;
645
646                 case "three dimensional object":
647                         index = 8;
648                         break;
649
650                 default:
651                         index = 0;
652         }
653
654         c.childNodes[index].innerHTML = "";
655         c.childNodes[index].appendChild(pic);
656 }
657
658 AbstractRecordResultPage.prototype.buildRecordImage = function(pic_cell, record, page_id, title) {
659
660         debug("Building record image for " + page_id);
661         var isbn = record.isbn();
662         if(isbn) isbn = isbn.replace(/\s+/,"");
663         else isbn = "";
664
665         pic_cell.setAttribute("rowspan","3");
666         pic_cell.rowSpan = 3;
667
668         pic_cell.noWrap = 'nowrap';
669         pic_cell.setAttribute("nowrap", "nowrap");
670
671         pic_cell.width = "60";
672         pic_cell.className = "record_image_cell";
673
674
675         var rankBox;
676         if( this.ranks.length > 0 ) {
677                 var x = (parseInt(this.page) * parseInt(this.hitsPerPage)) + parseInt(page_id);
678                 var per = parseInt(this.ranks[x] / this.ranks[0] * 100.0);
679
680                 debug("Per is " + per);
681                 per = 100 - parseInt(per);
682
683                 rankBox = createAppElement("div");
684                 add_css_class(rankBox, "relevance_box");
685
686                 var d = createAppElement("div");
687                 d.setAttribute("height", per + "%");
688                 d.style.height = per + "%";
689
690                 add_css_class(d, "relevance");
691                 rankBox.appendChild(d);
692
693                 rankBox.setAttribute("title", parseInt((100 - parseInt(per))) + "% Relevant");
694         }
695
696         /* use amazon for now */
697         var img_src = "http://images.amazon.com/images/P/" +isbn + ".01.MZZZZZZZ.jpg";
698         var big_div = createAppElement("div");
699         add_css_class(big_div, "record_image_big hide_me");
700
701         var big_pic = createAppElement("img");
702         var pic = createAppElement("img");
703         
704         big_pic.setAttribute("src", img_src);
705         big_pic.setAttribute("border", "0");
706         pic.setAttribute("src", img_src);
707         add_css_class(big_pic, "record_image");
708         add_css_class(pic, "record_image");
709
710         pic.setAttribute("width", "45");
711         pic.setAttribute("height", "50");
712         pic.style.width = "45";
713         pic.style.height = "50";
714
715         if(IE) 
716                 big_div.style.left = 0;
717
718
719         var anch = this.mkLink(record.doc_id(), "img", title );
720         anch.appendChild(big_pic);
721         big_div.appendChild(anch);
722         pic_cell.appendChild(big_div);
723
724         pic_cell.appendChild(pic);
725
726         if(rankBox)
727                 pic_cell.appendChild(rankBox);
728
729         pic.onmouseover = function() {showMe(big_div);}
730         big_div.onmouseout = function(){hideMe(big_div);}
731
732 }
733