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