]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/javascript/opac/RecordDetailPage.js
d8aa4cd9efa2888939a353d5d93ac59a59a254da
[Evergreen.git] / Open-ILS / src / javascript / opac / RecordDetailPage.js
1 var globalRecordDetailPage = null;
2 RecordDetailPage.prototype                                      = new Page();
3 RecordDetailPage.prototype.constructor  = RecordDetailPage;
4 RecordDetailPage.baseClass                                      = Page.constructor;
5
6 var globalDetailRecord;
7
8 function RecordDetailPage() {
9         if( globalRecordDetailPage != null )
10                 return globalRecordDetailPage;
11         this.searchBar  = new SearchBarChunk();
12 }
13
14 RecordDetailPage.prototype.setPageTrail = function() {
15         var box = getById("page_trail");
16         if(!box) return;
17
18         var d = this.buildTrailLink("start",true);
19         if(d) {
20                 box.appendChild(d);
21         } else {
22                 d = this.buildTrailLink("advanced_search",true);
23                 if(d)
24                         box.appendChild(d);
25         }
26
27         var b = this.buildTrailLink("mr_result", true);
28
29         if(b) {
30                 box.appendChild(this.buildDivider());
31                 box.appendChild(b);
32         }
33
34         box.appendChild(this.buildDivider());
35         try {
36                 box.appendChild(this.buildTrailLink("record_result", true));
37         } catch(E) {} /* doesn't work when deep linking */
38
39         box.appendChild(this.buildDivider());
40         box.appendChild(
41                 this.buildTrailLink("record_detail",false));
42 }
43
44
45 RecordDetailPage.prototype.buildContextMenu = function(record) {
46
47         var menu_name = "record_detail_menu";
48         var menu = globalMenuManager.buildMenu(menu_name);
49
50         globalMenuManager.setContext(getById("record_detail_main_box"), menu);
51         var func = buildViewMARCWindow(record);
52         menu.addItem("View MARC", func);
53
54         if(isXUL())
55                 xulEvtRecordDetailDisplayed( menu, record );
56         getDocument().body.appendChild(menu.getNode());
57 }
58
59
60 RecordDetailPage.instance = function() {
61         if( globalRecordDetailPage != null )
62                 return globalRecordDetailPage;
63         return new RecordDetailPage();
64 }
65
66 RecordDetailPage.prototype.init = function() {
67         debug("Initing RecordDetailPage");
68         this.draw();
69 }
70
71 RecordDetailPage.prototype.draw = function() {
72
73         this.mainBox = getById("record_detail_copy_info");
74
75         this.copyLocationTree = elem("select");
76         var opt =  new Option(
77                 "Select a location whose Volumes/Copies you wish to see");
78         this.copyLocationTree.options[this.copyLocationTree.options.length] = opt;
79         var tree = this.copyLocationTree;
80
81         var obj = this;
82
83         tree.onchange = function() {
84
85                 var idx = tree.selectedIndex;
86                 debug("INDEX is " + idx);
87                 var org_id = tree.options[idx].value;   
88                 if(org_id == null) return;
89                 obj.drawCopyTrees(findOrgUnit(org_id), obj.record);
90
91                 tree.selectedIndex = idx;
92                 var opt = tree.options[idx];
93                 if(opt) opt.selected = true;    
94
95                 obj.displayParentLink(findOrgUnit(org_id), obj.record);
96                 
97         }
98
99         var table = elem("table", { width: "100%" } );
100         table.width = "100%";
101
102         var linksDiv = table.insertRow(0);
103         var leftLink = linksDiv.insertCell(0);
104         var rightLink = linksDiv.insertCell(1);
105
106         leftLink.width = "50%";
107         rightLink.width = "50%";
108         leftLink.align = "left";
109         rightLink.align = "right";
110
111         this.parentLink = elem("a",
112                 { href : "javascript:void(0)",
113                         id : "parent_link",
114                   style : "text-decoration:underline" } );
115
116         leftLink.appendChild(this.copyLocationTree);
117         rightLink.appendChild(this.parentLink);
118         this.mainBox.appendChild(table);
119         /* --------------------------------------------- */
120
121
122         this.treeDiv = elem("div");
123         this.mainBox.appendChild(this.treeDiv);
124
125         this.fetchRecord(paramObj.__record); /* sets this.record */
126         this.viewMarc = getById("record_detail_view_marc");
127
128         this.buildNavBox();
129         
130
131 }
132
133
134 RecordDetailPage.prototype.buildCustomOrgTree = function(record) {
135
136         var req = new RemoteRequest(
137                 "open-ils.search",
138                 "open-ils.search.biblio.copy_counts.retrieve",
139                 record.doc_id() );
140
141         var obj = this;
142         req.setCompleteCallback(
143                 function(req) {
144                         _fleshOrgTree(req.getResultObject(), obj.copyLocationTree);}
145         );
146         debug("Sending copy tree request");
147         req.send();
148 }
149
150 /* builds the select list with the appropriate org units */
151 function _fleshOrgTree(org_array, selector) {
152
153         debug("Fleshing org tree selector with " + org_array);
154
155         for( var idx in org_array ) {
156                 var slot = org_array[idx];
157                 var org = findOrgUnit(slot[0]);
158                 _addOrgAndParents(selector, org);
159         }
160
161         /* clear out the state flags we added after the tree is built */
162         setTimeout(function(){_clearOrgFlags();}, 500);
163
164         debug("Tree is built..");
165 }
166
167 function _clearOrgFlags(node) {
168         if(node == null)
169                 node = globalOrgTree;
170         node.added = false;
171         for(var c in node.children()) 
172                 _clearOrgFlags(node.children()[c]);
173 }
174
175
176 function _addOrgAndParents(selector, org) {
177
178         if(!org || org.added) return;
179
180         debug("Checking org " + org.name());
181
182         if(org.ou_type() == "1") {
183                 org.added = true;
184                 return;
185         }
186
187         var par = findOrgUnit(org.parent_ou());
188         if(par && !par.added)
189                 _addOrgAndParents(selector, par);
190
191
192         /* build the selector text part */
193         if(IE) {
194                 var node = elem("pre");
195                 for(var x=2; x <= findOrgType(org.ou_type()).depth(); x++) {
196                         node.appendChild(mktext("   "));
197                 }
198                 node.appendChild(mktext(org.name()));
199
200                 var select = new Option("", org.id());
201                 selector.options[selector.options.length] = select;
202                 select.appendChild(node);
203
204         } else {
205
206                 var pad = (findOrgType(org.ou_type()).depth() - 1) * 10;
207                 var select = new Option(org.name(), org.id());
208                 select.setAttribute("style", "padding-left: " + pad);
209                 selector.options[selector.options.length] = select;
210         }
211
212         org.added = true;
213 }
214
215
216 function _buildCustomOrgTree(org_node, root) {
217
218         var item;
219
220         if(root) {
221                 item = new WebFXTree(org_node.name());
222                 item.setBehavior('classic');
223         } else {
224                 item = new WebFXTreeItem(org_node.name());
225         }
226
227         item.action = 
228                 "javascript:globalPage.drawCopyTrees(" + 
229                 org_node.id() + ", logicNode.globalDetailRecord );" +
230                 "globalPage.copyLocationTree.hide();"; 
231                 
232         
233         for( var index in org_node.children()) {
234                 var childorg = org_node.children()[index];
235                 if( childorg != null ) {
236                         var tree_node = buildCustomOrgTree(childorg);
237                         if(tree_node != null)
238                                 item.add(tree_node);
239                 }
240         }
241
242         return item;
243 }
244
245
246 RecordDetailPage.prototype.setViewMarc = function(record) {
247         var marcb = elem( "a", 
248                 {       href:"javascript:void(0)", 
249                         style: "text-decoration:underline;color:#EFF;" }, 
250                 {}, "View MARC" );
251
252         debug(".ou_type()Setting up view marc callback with record " + record.doc_id());
253
254         var func = buildViewMARCWindow(record);
255         marcb.onclick = func;
256         this.viewMarc.appendChild(marcb);
257 }
258
259 RecordDetailPage.prototype.setPlaceHold = function(record) {
260         var holds = elem( "a", 
261                 { 
262                         href:"javascript:void(0)", 
263                         style: "text-decoration:underline;color:#EFF;" 
264                 }, 
265                 {}, "Place Hold" );
266
267         var user = UserSession.instance();
268         var win;
269         if(user.verifySession()) {
270                 win = new HoldsWindow(record.doc_id(), 
271                         "T", user.userObject, user.userObject, user.session_id);
272         } else {
273                 win = new HoldsWindow(record.doc_id(), 
274                         "T", null, null, null);
275         }
276         holds.onclick = function() { win.toggle(holds); }
277
278         var space = elem("span", {style:"padding:5px"},null, " ");
279         this.viewMarc.appendChild(space);
280         this.viewMarc.appendChild(holds);
281 }
282
283
284 RecordDetailPage.prototype.fetchRecord = function(id) {
285         if(!id) {
286                 debug("No ID in fetchRecord");
287                 return;
288         }
289
290         var req = new RemoteRequest(
291                 "open-ils.search",
292                 "open-ils.search.biblio.record.mods_slim.retrieve",
293                 id );
294
295         var obj = this;
296         req.setCompleteCallback(
297                 function() { 
298                         obj.record = req.getResultObject();
299                         globalDetailRecord = obj.record;
300                         obj.buildCustomOrgTree(obj.record);
301                         obj.drawRecord(obj.record); 
302                         obj.setViewMarc(obj.record);
303                         obj.setPlaceHold(obj.record);
304                 } 
305         );
306
307         req.send();
308 }
309
310
311 RecordDetailPage.prototype.drawRecord = function(record) {
312
313         var title_cell                  = getById("record_detail_title_cell");
314         var author_cell         = getById("record_detail_author_cell");
315         var isbn_cell                   = getById("record_detail_isbn_cell");
316
317         var edition_cell                = getById("record_detail_edition_cell");
318         var pubdate_cell                = getById("record_detail_pubdate_cell");
319         var publisher_cell      = getById("record_detail_publisher_cell");
320
321         var subject_cell                = getById("record_detail_subject_cell");
322         var tcn_cell                    = getById("record_detail_tcn_cell");
323         var resource_cell               = getById("record_detail_resource_cell");
324         var pic_cell                    = getById("record_detail_pic_cell");
325         var abstract_cell               = getById("record_detail_abstract_cell");
326
327         add_css_class(title_cell,               "detail_item_cell");
328         add_css_class(author_cell,              "detail_item_cell");
329         add_css_class(isbn_cell,                "detail_item_cell");
330         add_css_class(edition_cell,     "detail_item_cell");
331         add_css_class(pubdate_cell,     "detail_item_cell");
332         add_css_class(publisher_cell, "detail_item_cell");
333         add_css_class(subject_cell,     "detail_item_cell");
334         add_css_class(tcn_cell,                 "detail_item_cell");
335         add_css_class(resource_cell,    "detail_item_cell");
336         add_css_class(abstract_cell,    "detail_item_cell");
337
338         title_cell.appendChild(
339                 createAppTextNode(normalize(record.title())));
340         author_cell.appendChild(
341                 createAppTextNode(normalize(record.author())));
342         isbn_cell.appendChild(
343                 createAppTextNode(record.isbn()));
344
345         edition_cell.appendChild(
346                 createAppTextNode(record.edition()));
347         pubdate_cell.appendChild(
348                 createAppTextNode(record.pubdate()));
349         publisher_cell.appendChild(
350                 createAppTextNode(record.publisher()));
351
352         subject_cell.appendChild(
353                 createAppTextNode(record.subject()));
354         tcn_cell.appendChild(
355                 createAppTextNode(record.tcn()));
356
357         var abs = record.synopsis();
358         if(abs == null || abs == "") abs = "N/A";
359         abstract_cell.appendChild(mktext(abs));
360
361
362
363         var resource = record.types_of_resource()[0];
364         if(resource.indexOf("sound recording") != -1) 
365                 resource = "sound recording";
366         var r_pic = elem("img", 
367                 { src: "/images/" + resource + ".jpg" } );
368         resource_cell.appendChild(r_pic);
369         resource_cell.appendChild(createAppTextNode(" "));
370
371         resource_cell.appendChild(
372                 createAppTextNode(record.types_of_resource()));
373
374         pic_cell.appendChild(this.mkImage(record));
375
376
377         var locs = record.online_loc();
378         if(locs && locs.length > 0){ 
379                 var tab = pic_cell.parentNode.parentNode;
380                 var loc_row = tab.insertRow(tab.rows.length);
381                 var desc_cell =loc_row.insertCell(0);
382                 add_css_class(desc_cell, "detail_item_label");
383                 desc_cell.appendChild(mktext("Other Resources"));
384                 var links_cell =loc_row.insertCell(1);
385
386                 var found = new Array(); /* weed out duplicates */
387                 /* online location field is of the form [link, title, link, title, ...] */
388                 for(var i = 0; i!= locs.length; i++ ) {
389                         var ref = locs[i++]; 
390                         var ttl = locs[i];
391                         if(find_list(found,function(f){return (f==ref);}))
392                                 continue;
393                         found.push(ref);
394                         var a = elem("a", {style:"text-decoration:underline",
395                                         target:"_blank",href:ref,title:ttl}, null, ttl);
396                         links_cell.appendChild(a);
397                         links_cell.appendChild(mktext(" "));
398                 }
399         }
400
401         var orgUnit = globalSelectedLocation;
402         if(!orgUnit) orgUnit = globalLocation;
403
404         this.drawCopyTrees(orgUnit, record);
405         this.buildContextMenu(record);
406 }
407
408 /* sets up the cover art image */
409 RecordDetailPage.prototype.mkImage = function(record) {
410
411         var isbn = record.isbn();
412         /*
413         if(isbn) isbn = isbn.replace(/\s+/,"");
414         else isbn = "";
415         */
416
417         var big_pic = elem("a", {
418                 href : "http://images.amazon.com/images/P/" + cleanISBN(isbn) + ".01.LZZZZZZZ.jpg",
419                 title : "Click for larger image" } );
420
421         var img_src = buildISBNSrc(cleanISBN(record.isbn()));
422         //var img_src = "http://images.amazon.com/images/P/" +isbn + ".01.MZZZZZZZ.jpg";
423         var pic = elem ( "img", { src : img_src }, { border : "0px none" });
424         big_pic.appendChild(pic);
425
426         return big_pic;
427 }
428
429
430 /* if sync, it is a synchronous call */
431 RecordDetailPage.prototype.grabCopyTree = function(record, orgUnit, callback, sync) {
432
433         var orgIds = new Array();
434         if(orgUnit.constructor == Array) {
435                 for(var x = 0; x < orgUnit.length; x++) {
436                         orgIds.push(orgUnit[x].id());
437                 }
438         } else {
439                 orgIds.push(orgUnit.id());
440         }
441
442         debug("Grabbing copy tree for " + orgIds);
443
444         var req = new RemoteRequest(
445                 "open-ils.cat",
446                 "open-ils.cat.asset.copy_tree.retrieve",
447                 null, record.doc_id(), orgIds );        
448
449         var obj = this;
450
451         if(sync) { /* synchronous call */
452                 req.send(true);
453                 callback(req.getResultObject());
454
455         } else {
456                 req.setCompleteCallback( 
457                         function(r) { callback(r.getResultObject()); });
458                 req.send();
459         }
460 }
461
462
463 /* entry point for displaying the copy details pane */
464 RecordDetailPage.prototype.drawCopyTrees = function(orgUnit, record) {
465
466         debug("Got ORG unit " + orgUnit);
467         orgUnit = findOrgUnit(orgUnit);
468         if(orgUnit == null) return;
469
470         debug("OrgUnit depth is: " + findOrgType(orgUnit.ou_type()).depth());
471         removeChildren(this.treeDiv);
472
473         /* display a 'hold on' message */
474         this.treeDiv.appendChild(elem("br"));
475         this.treeDiv.appendChild(elem("br"));
476
477         var depth = parseInt(findOrgType(orgUnit.ou_type()).depth());
478         if(depth != 0) {
479                 this.treeDiv.appendChild(elem("div", null, null, "Loading copy information..."));
480                 if(parseInt(findOrgType(orgUnit.ou_type()).can_have_vols()))
481                         this.displayParentLink(orgUnit, record);
482                 this.displayTrees(orgUnit, record);
483         }
484 }
485
486
487 /* displays a link to view info for the parent org 
488         if showMe == true, we don't search for the parent, 
489         but use the given orgUnit as the link point */
490 RecordDetailPage.prototype.displayParentLink = function(orgUnit, record) {
491
492         var href = this.parentLink;
493         removeChildren(href);
494         var region = orgUnit;
495         if(region == null) return;
496
497         var depth = parseInt(findOrgType(region.ou_type()).depth());
498
499         if(depth < 2) return;
500
501         region = findOrgUnit(orgUnit.parent_ou());
502
503         href.appendChild(createAppTextNode(
504                 "View Volumes/Copies for " + region.name()));
505
506         var obj = this;
507         href.onclick = function() { 
508
509                 removeChildren(obj.treeDiv);
510                 obj.treeDiv.appendChild(elem("br"));
511                 obj.treeDiv.appendChild(elem("br"));
512                 obj.treeDiv.appendChild(elem("div", null, null, "Loading copy information..."));
513
514                 /* allows the above message to be displayed */
515                 setTimeout(function() { obj.displayTrees(region, record, true) }, 100); 
516
517                 obj.displayParentLink(null);
518         }
519
520         var reg_div = createAppElement("div");
521         //reg_div.appendChild(href);
522         this.mainBox.insertBefore(reg_div, this.treeDiv);
523 }
524
525 /* displays copy info for orgUnit and all of it's children.
526         if orgUnit is a region (depth == 1), then we just show
527         all of our children.  if it's a branch, sub-branch, etc.
528         the current branch as well as all of it's children are displayed */
529 RecordDetailPage.prototype.displayTrees = function(orgUnit, record, sync) {
530         var obj = this;
531         var orgs = orgUnit.children();
532         if(!orgs) orgs = [];
533
534         if(parseInt(findOrgType(orgUnit.ou_type()).can_have_vols()))
535                 orgs.unshift(orgUnit);
536
537         this.grabCopyTree(record, orgs, 
538                 function(tree) {
539                         obj.displayCopyTree(tree, "Volumes/Copies for " + orgUnit.name() );
540                 }, sync );
541 }
542
543
544 /*  displays a single copy tree */
545 RecordDetailPage.prototype.displayCopyTree = function(tree, title) {
546         
547         debug("Displaying copy tree for " + title);
548
549         if(!globalCopyStatus) grabCopyStatus(); /* just to be safe */
550
551         var treeDiv =  this.treeDiv;
552         removeChildren(treeDiv);
553         add_css_class( treeDiv, "copy_tree_div" );
554
555         var table = createAppElement("table");
556         add_css_class(table, "copy_tree_table");
557         var header_row = table.insertRow(table.rows.length);
558         add_css_class(header_row, "top_header_row");
559         var header = header_row.insertCell(header_row.cells.length);
560         header.colSpan = 3;
561         header.setAttribute("colspan", 3);
562         var bold = createAppElement("b");
563         bold.appendChild(createAppTextNode(title));
564         header.appendChild(bold);
565
566         var row2                = table.insertRow(table.rows.length);
567         var cell1       = row2.insertCell(row2.cells.length);
568         var cell2       = row2.insertCell(row2.cells.length);
569         var cell3       = row2.insertCell(row2.cells.length);
570         var cell4       = row2.insertCell(row2.cells.length);
571         var cell5       = row2.insertCell(row2.cells.length);
572
573         cell1.appendChild(createAppTextNode("Library"));
574         cell2.appendChild(createAppTextNode("Callnumber"));
575         cell3.appendChild(createAppTextNode("Barcode(s)"));
576         cell4.appendChild(createAppTextNode("Location"));
577         cell5.appendChild(createAppTextNode("Availability"));
578
579         add_css_class(cell1, "detail_header_cell");
580         add_css_class(cell2, "detail_header_cell");
581         add_css_class(cell3, "detail_header_cell");
582         add_css_class(cell4, "detail_header_cell");
583         add_css_class(cell5, "detail_header_cell");
584
585         if(tree.length == 0) {
586                 var row = table.insertRow(table.rows.length);
587                 row.insertCell(0).appendChild(
588                         createAppTextNode("No copies available for this location"));
589         }
590
591         var libsVisited = new Array();
592         var x = 0;
593         for( var i in tree ) {
594                 var row = table.insertRow(table.rows.length);
595                 if(x%2) add_css_class(row, "copy_tree_row_highlight");
596                 var volume = tree[i];
597
598                 var cell1 = row.insertCell(row.cells.length);
599                 add_css_class(cell1, "detail_item_cell");
600
601
602                 /* here we don't want to repeat the same libs name */
603                 if(find_list( libsVisited,
604                                 function(name) { 
605
606                                 return (name == findOrgUnit(volume.owning_lib()).name()); })) {
607                         cell1.appendChild(createAppTextNode(" "));
608
609                 } else {
610                         var name = findOrgUnit(volume.owning_lib()).name();
611                         cell1.appendChild(createAppTextNode(name));
612                         libsVisited.push(name);
613                 }
614
615                 var cell2 = row.insertCell(row.cells.length);
616                 add_css_class(cell2, "detail_item_cell");
617                 cell2.appendChild(createAppTextNode(volume.label()));
618
619                 var cell3 = row.insertCell(row.cells.length);
620                 add_css_class(cell3, "detail_item_cell");
621                 cell3.appendChild(createAppTextNode(" "));
622
623                 var cell4 = row.insertCell(row.cells.length);
624                 add_css_class(cell4, "detail_item_cell");
625                 cell4.appendChild(createAppTextNode(" "));
626
627                 var cell5 = row.insertCell(row.cells.length);
628                 add_css_class(cell4, "detail_item_cell");
629                 cell5.appendChild(createAppTextNode(" "));
630                 
631                 var copies = volume.copies();
632                 var c = 0;
633
634                 while(c < copies.length) {
635
636                         var copy = copies[c];
637                         var loc = findCopyLocation(copy.location()).name();
638
639                         if(c == 0) { /* put the first barcode in the same row as the callnumber */
640
641                                 removeChildren(cell3);
642                                 cell3.appendChild(createAppTextNode(copy.barcode()));
643
644                                 removeChildren(cell4);
645                                 cell4.appendChild(createAppTextNode(loc));
646
647                                 removeChildren(cell5);
648                                 var status = find_list(globalCopyStatus, 
649                                                 function(i) { return (i.id() == copy.status());} );
650
651                                 var sname = "";
652                                 if(status) sname = status.name();
653                                 cell5.appendChild(createAppTextNode(sname));
654
655                         } else {
656
657                                 var row = table.insertRow(table.rows.length);
658                                 if(x%2) add_css_class(row, "copy_tree_row_highlight");
659                                 row.insertCell(0).appendChild(createAppTextNode(" "));
660                                 row.insertCell(1).appendChild(createAppTextNode(" "));
661
662                                 var ce = row.insertCell(2);
663                                 var loc_cell = row.insertCell(3);
664                                 var status_cell = row.insertCell(4);
665
666                                 add_css_class(ce, "detail_item_cell");
667                                 add_css_class(loc_cell, "detail_item_cell");
668                                 add_css_class(status_cell, "detail_item_cell");
669
670                                 ce.appendChild(createAppTextNode(copy.barcode()));
671                                 loc_cell.appendChild(createAppTextNode(loc));
672
673                                 var status = find_list(globalCopyStatus, 
674                                                 function(i) { return (i.id() == copy.status());} );
675                                 var sname = "";
676                                 if(status) sname = status.name();
677                                 status_cell.appendChild(mktext(sname))
678                         }
679
680                         c++;
681                 }
682                 x++;
683         }
684
685         treeDiv.appendChild(table);
686 }
687
688