1 var globalRecordDetailPage = null;
2 RecordDetailPage.prototype = new Page();
3 RecordDetailPage.prototype.constructor = RecordDetailPage;
4 RecordDetailPage.baseClass = Page.constructor;
6 var globalDetailRecord;
8 function RecordDetailPage() {
9 if( globalRecordDetailPage != null )
10 return globalRecordDetailPage;
11 this.searchBar = new SearchBarChunk();
14 RecordDetailPage.prototype.setPageTrail = function() {
15 var box = getById("page_trail");
18 var d = this.buildTrailLink("start",true);
22 d = this.buildTrailLink("advanced_search",true);
27 var b = this.buildTrailLink("mr_result", true);
30 box.appendChild(this.buildDivider());
34 box.appendChild(this.buildDivider());
36 box.appendChild(this.buildTrailLink("record_result", true));
37 } catch(E) {} /* doesn't work when deep linking */
39 box.appendChild(this.buildDivider());
41 this.buildTrailLink("record_detail",false));
45 RecordDetailPage.prototype.buildContextMenu = function(record) {
47 var menu_name = "record_detail_menu";
48 var menu = globalMenuManager.buildMenu(menu_name);
50 globalMenuManager.setContext(getById("record_detail_main_box"), menu);
51 var func = buildViewMARCWindow(record);
52 menu.addItem("View MARC", func);
55 xulEvtRecordDetailDisplayed( menu, record );
56 getDocument().body.appendChild(menu.getNode());
60 RecordDetailPage.instance = function() {
61 if( globalRecordDetailPage != null )
62 return globalRecordDetailPage;
63 return new RecordDetailPage();
66 RecordDetailPage.prototype.init = function() {
67 debug("Initing RecordDetailPage");
71 RecordDetailPage.prototype.draw = function() {
73 this.mainBox = getById("record_detail_copy_info");
75 this.copyLocationTree = elem("select");
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;
83 tree.onchange = function() {
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);
91 tree.selectedIndex = idx;
92 var opt = tree.options[idx];
93 if(opt) opt.selected = true;
95 obj.displayParentLink(findOrgUnit(org_id), obj.record);
99 var table = elem("table", { width: "100%" } );
100 table.width = "100%";
102 var linksDiv = table.insertRow(0);
103 var leftLink = linksDiv.insertCell(0);
104 var rightLink = linksDiv.insertCell(1);
106 leftLink.width = "50%";
107 rightLink.width = "50%";
108 leftLink.align = "left";
109 rightLink.align = "right";
111 this.parentLink = elem("a",
112 { href : "javascript:void(0)",
114 style : "text-decoration:underline" } );
116 leftLink.appendChild(this.copyLocationTree);
117 rightLink.appendChild(this.parentLink);
118 this.mainBox.appendChild(table);
119 /* --------------------------------------------- */
122 this.treeDiv = elem("div");
123 this.mainBox.appendChild(this.treeDiv);
125 this.fetchRecord(paramObj.__record); /* sets this.record */
126 this.viewMarc = getById("record_detail_view_marc");
134 RecordDetailPage.prototype.buildCustomOrgTree = function(record) {
136 var method = "open-ils.search.biblio.copy_counts.retrieve";
138 if(isXUL()) method += ".staff";
140 var req = new RemoteRequest(
141 "open-ils.search", method, record.doc_id() );
144 req.setCompleteCallback(
146 _fleshOrgTree(req.getResultObject(), obj.copyLocationTree);}
148 debug("Sending copy tree request");
152 /* builds the select list with the appropriate org units */
153 function _fleshOrgTree(org_array, selector) {
155 debug("Fleshing org tree selector with " + org_array);
157 for( var idx in org_array ) {
158 var slot = org_array[idx];
159 var org = findOrgUnit(slot[0]);
160 _addOrgAndParents(selector, org);
163 /* clear out the state flags we added after the tree is built */
164 setTimeout(function(){_clearOrgFlags();}, 500);
166 debug("Tree is built..");
169 function _clearOrgFlags(node) {
171 node = globalOrgTree;
173 for(var c in node.children())
174 _clearOrgFlags(node.children()[c]);
178 function _addOrgAndParents(selector, org) {
180 if(!org || org.added) return;
182 debug("Checking org " + org.name());
184 if(org.ou_type() == "1") {
189 var par = findOrgUnit(org.parent_ou());
190 if(par && !par.added)
191 _addOrgAndParents(selector, par);
194 /* build the selector text part */
196 var node = elem("pre");
197 for(var x=2; x <= findOrgType(org.ou_type()).depth(); x++) {
198 node.appendChild(mktext(" "));
200 node.appendChild(mktext(org.name()));
202 var select = new Option("", org.id());
203 selector.options[selector.options.length] = select;
204 select.appendChild(node);
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;
218 function _buildCustomOrgTree(org_node, root) {
223 item = new WebFXTree(org_node.name());
224 item.setBehavior('classic');
226 item = new WebFXTreeItem(org_node.name());
230 "javascript:globalPage.drawCopyTrees(" +
231 org_node.id() + ", logicNode.globalDetailRecord );" +
232 "globalPage.copyLocationTree.hide();";
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)
248 RecordDetailPage.prototype.setViewMarc = function(record) {
249 var marcb = elem( "a",
250 { href:"javascript:void(0)",
251 style: "text-decoration:underline;color:#EFF;" },
254 debug(".ou_type()Setting up view marc callback with record " + record.doc_id());
256 var func = buildViewMARCWindow(record);
258 marcb.onclick = func;
259 if(isXUL()) { xulEvtViewMARC(marcb, record); }
260 this.viewMarc.appendChild(marcb);
263 RecordDetailPage.prototype.setPlaceHold = function(record) {
264 var holds = elem( "a",
266 href:"javascript:void(0)",
267 style: "text-decoration:underline;color:#EFF;"
271 var user = UserSession.instance();
273 if(user.verifySession()) {
274 win = new HoldsWindow(record.doc_id(),
275 "T", user.userObject, user.userObject, user.session_id);
277 win = new HoldsWindow(record.doc_id(),
278 "T", null, null, null);
280 holds.onclick = function() { win.toggle(holds); }
282 var space = elem("span", {style:"padding:5px"},null, " ");
283 this.viewMarc.appendChild(space);
284 this.viewMarc.appendChild(holds);
288 RecordDetailPage.prototype.fetchRecord = function(id) {
290 debug("No ID in fetchRecord");
294 var req = new RemoteRequest(
296 "open-ils.search.biblio.record.mods_slim.retrieve",
300 req.setCompleteCallback(
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);
315 RecordDetailPage.prototype.drawRecord = function(record) {
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");
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");
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");
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");
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()));
349 edition_cell.appendChild(
350 createAppTextNode(record.edition()));
351 pubdate_cell.appendChild(
352 createAppTextNode(record.pubdate()));
353 publisher_cell.appendChild(
354 createAppTextNode(record.publisher()));
356 subject_cell.appendChild(
357 createAppTextNode(record.subject()));
358 tcn_cell.appendChild(
359 createAppTextNode(record.tcn()));
361 var abs = record.synopsis();
362 if(abs == null || abs == "") abs = "N/A";
363 abstract_cell.appendChild(mktext(abs));
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(" "));
375 resource_cell.appendChild(
376 createAppTextNode(record.types_of_resource()));
378 pic_cell.appendChild(this.mkImage(record));
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);
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++ ) {
395 if(find_list(found,function(f){return (f==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(" "));
405 var orgUnit = globalSelectedLocation;
406 if(!orgUnit) orgUnit = globalLocation;
408 this.drawCopyTrees(orgUnit, record);
409 this.buildContextMenu(record);
412 /* sets up the cover art image */
413 RecordDetailPage.prototype.mkImage = function(record) {
415 var isbn = record.isbn();
417 if(isbn) isbn = isbn.replace(/\s+/,"");
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" } );
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);
434 /* if sync, it is a synchronous call */
435 RecordDetailPage.prototype.grabCopyTree = function(record, orgUnit, callback, sync) {
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());
443 orgIds.push(orgUnit.id());
446 debug("Grabbing copy tree for " + orgIds);
448 var req = new RemoteRequest(
450 "open-ils.cat.asset.copy_tree.retrieve",
451 null, record.doc_id(), orgIds );
455 if(sync) { /* synchronous call */
457 callback(req.getResultObject());
460 req.setCompleteCallback(
461 function(r) { callback(r.getResultObject()); });
467 /* entry point for displaying the copy details pane */
468 RecordDetailPage.prototype.drawCopyTrees = function(orgUnit, record) {
470 debug("Got ORG unit " + orgUnit);
471 orgUnit = findOrgUnit(orgUnit);
472 if(orgUnit == null) return;
474 debug("OrgUnit depth is: " + findOrgType(orgUnit.ou_type()).depth());
475 removeChildren(this.treeDiv);
477 /* display a 'hold on' message */
478 this.treeDiv.appendChild(elem("br"));
479 this.treeDiv.appendChild(elem("br"));
481 var depth = parseInt(findOrgType(orgUnit.ou_type()).depth());
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);
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) {
496 var href = this.parentLink;
497 removeChildren(href);
498 var region = orgUnit;
499 if(region == null) return;
501 var depth = parseInt(findOrgType(region.ou_type()).depth());
503 if(depth < 2) return;
505 region = findOrgUnit(orgUnit.parent_ou());
507 href.appendChild(createAppTextNode(
508 "View Volumes/Copies for " + region.name()));
511 href.onclick = function() {
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..."));
518 /* allows the above message to be displayed */
519 setTimeout(function() { obj.displayTrees(region, record, true) }, 100);
521 obj.displayParentLink(null);
524 var reg_div = createAppElement("div");
525 //reg_div.appendChild(href);
526 this.mainBox.insertBefore(reg_div, this.treeDiv);
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) {
535 var orgs = orgUnit.children();
538 if(parseInt(findOrgType(orgUnit.ou_type()).can_have_vols()))
539 orgs.unshift(orgUnit);
541 this.grabCopyTree(record, orgs,
543 obj.displayCopyTree(tree, "Volumes/Copies for " + orgUnit.name() );
548 /* displays a single copy tree */
549 RecordDetailPage.prototype.displayCopyTree = function(tree, title) {
551 debug("Displaying copy tree for " + title);
553 if(!globalCopyStatus) grabCopyStatus(); /* just to be safe */
555 var treeDiv = this.treeDiv;
556 removeChildren(treeDiv);
557 add_css_class( treeDiv, "copy_tree_div" );
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);
565 header.setAttribute("colspan", 3);
566 var bold = createAppElement("b");
567 bold.appendChild(createAppTextNode(title));
568 header.appendChild(bold);
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);
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"));
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");
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"));
595 var libsVisited = new Array();
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];
602 var cell1 = row.insertCell(row.cells.length);
603 add_css_class(cell1, "detail_item_cell");
606 /* here we don't want to repeat the same libs name */
607 if(find_list( libsVisited,
610 return (name == findOrgUnit(volume.owning_lib()).name()); })) {
611 cell1.appendChild(createAppTextNode(" "));
614 var name = findOrgUnit(volume.owning_lib()).name();
615 cell1.appendChild(createAppTextNode(name));
616 libsVisited.push(name);
619 var cell2 = row.insertCell(row.cells.length);
620 add_css_class(cell2, "detail_item_cell");
621 cell2.appendChild(createAppTextNode(volume.label()));
623 var cell3 = row.insertCell(row.cells.length);
624 add_css_class(cell3, "detail_item_cell");
625 cell3.appendChild(createAppTextNode(" "));
627 var cell4 = row.insertCell(row.cells.length);
628 add_css_class(cell4, "detail_item_cell");
629 cell4.appendChild(createAppTextNode(" "));
631 var cell5 = row.insertCell(row.cells.length);
632 add_css_class(cell4, "detail_item_cell");
633 cell5.appendChild(createAppTextNode(" "));
635 var copies = volume.copies();
638 while(c < copies.length) {
640 var copy = copies[c];
641 var loc = findCopyLocation(copy.location()).name();
643 if(c == 0) { /* put the first barcode in the same row as the callnumber */
645 removeChildren(cell3);
646 cell3.appendChild(createAppTextNode(copy.barcode()));
648 removeChildren(cell4);
649 cell4.appendChild(createAppTextNode(loc));
651 removeChildren(cell5);
652 var status = find_list(globalCopyStatus,
653 function(i) { return (i.id() == copy.status());} );
656 if(status) sname = status.name();
657 cell5.appendChild(createAppTextNode(sname));
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(" "));
666 var ce = row.insertCell(2);
667 var loc_cell = row.insertCell(3);
668 var status_cell = row.insertCell(4);
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");
674 ce.appendChild(createAppTextNode(copy.barcode()));
675 loc_cell.appendChild(createAppTextNode(loc));
677 var status = find_list(globalCopyStatus,
678 function(i) { return (i.id() == copy.status());} );
680 if(status) sname = status.name();
681 status_cell.appendChild(mktext(sname))
689 treeDiv.appendChild(table);