]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/web/opac/skin/default/js/rdetail.js
Serials: When the fully compressed serial holdings are active in the OPAC,
[Evergreen.git] / Open-ILS / web / opac / skin / default / js / rdetail.js
1
2 /* */
3
4 detachAllEvt('common', 'run');
5 attachEvt("common", "run", rdetailDraw);
6 attachEvt("rdetail", "recordDrawn", rdetailBuildStatusColumns);
7 attachEvt("rdetail", "recordDrawn", rdetailBuildInfoRows);
8 attachEvt("rdetail", "recordDrawn", rdetailGetPageIds);
9
10 /* Per-skin configuration settings */
11 var rdetailLocalOnly = true;
12 var rdetailShowLocal = true;
13 var rdetailShowCopyLocation = true;
14 var rdetailGoogleBookPreview = true;
15 var rdetailDisplaySerialHoldings = true;
16 var rdetailEnableRefWorks = false;
17 var rdetailRefWorksHost = 'http://www.refworks.com';
18
19 /* vars vars vars */
20 var record = null;
21 var cp_statuses = null;
22 var recordsCache = [];
23
24 var copyRowParent = null;
25 var copyRow = null;
26 var statusRow = null;
27 var numStatuses = null;
28 var defaultCN;
29 var callnumberCache = {};
30 var globalCNCache = {};
31 var localTOC;
32 var cachedRecords;
33 var _statusPositions = {};
34 var opac_strings;
35
36 var nextContainerIndex;
37
38 var nextRecord;
39 var prevRecord;
40
41 var rdetailPrev = null;
42 var rdetailNext = null;
43 var rdetailStart = null;
44 var rdetailEnd = null;
45
46 var mfhdDetails = [];
47 var orgHiding = false;
48
49 if(location.href.match(/&place_hold=1/)) {
50     // prevent load flicker between canvases
51     hideMe(dojo.byId('canvas_main'));
52 }
53
54 /* serials are currently the only use of Dojo strings in the OPAC */
55 if (rdetailDisplaySerialHoldings) {
56         dojo.require("dijit.Menu");
57         dojo.require("dijit.form.Button");
58         dojo.requireLocalization("openils.opac", "opac");
59         opac_strings = dojo.i18n.getLocalization("openils.opac", "opac");
60 }
61
62 function rdetailReload() {
63         var args = {};
64         args[PARAM_LOCATION] = getNewSearchLocation();
65         args[PARAM_DEPTH] = depthSelGetDepth();
66         goTo(buildOPACLink(args));
67 }
68
69 /* looks to see if we have a next and/or previous record in the
70    record cache, if so, set up the nav links */
71 function rdetailSetPaging(ids) {
72
73         cachedRecords = {};
74         cachedRecords.ids = ids;
75
76         for( var i = 0; i < cachedRecords.ids.length; i++ ) {
77                 var rec = cachedRecords.ids[i];
78                 if( rec == getRid() ) {
79                         if( i > 0 ) prevRecord = cachedRecords.ids[i-1];
80                         if( i < cachedRecords.ids.length - 1 )
81                                 nextRecord = cachedRecords.ids[i+1];
82                         break;
83                 }
84         }
85
86         $('np_offset').appendChild(text(i + 1));
87         $('np_count').appendChild(text(getHitCount()));
88
89         if(prevRecord) {
90                 unHideMe($('np_table'));
91                 unHideMe($('np_prev'));
92                 unHideMe($('np_start'));
93                 rdetailPrev = function() { _rdetailNav(prevRecord); };
94                 rdetailStart = function() { _rdetailNav(cachedRecords.ids[0]); };
95         }
96
97         if(nextRecord) {
98                 unHideMe($('np_table'));
99                 unHideMe($('np_next'));
100                 unHideMe($('np_end'));
101                 rdetailNext = function() { _rdetailNav(nextRecord); };
102                 rdetailEnd = function() { _rdetailNav(cachedRecords.ids[cachedRecords.ids.length-1]); };
103         }
104
105         runEvt('rdetail', 'nextPrevDrawn', i, cachedRecords.ids.length);
106 }
107
108
109 function _rdetailNav(id, offset) {
110         var args = {};
111         args[PARAM_RID] = id;
112         goTo(buildOPACLink(args));
113 }
114
115 function rdetailHandlePlaceHold() {
116     function reload() {
117         location.href = location.href.replace(/&place_hold=1/, '');
118     }
119     attachEvt("common", "holdUpdated", reload);
120     attachEvt("common", "holdUpdateCanceled", reload);
121     attachEvt("common", "loginCanceled", reload);
122     holdsDrawEditor({record:getRid(), type: 'T'});
123 }
124
125 function rdetailDraw() {
126
127     if(new CGI().param('place_hold')) {
128         rdetailHandlePlaceHold();
129         return;
130     }
131
132         detachAllEvt('common','depthChanged');
133         detachAllEvt('common','locationUpdated');
134         attachEvt('common','depthChanged', rdetailReload);
135         attachEvt('common','locationUpdated', rdetailReload);
136         attachEvt('common','holdUpdated', rdetailReload);
137         attachEvt('common','holdUpdateCanceled', rdetailReload);
138
139         copyRowParent = G.ui.rdetail.cp_info_row.parentNode;
140         copyRow = copyRowParent.removeChild(G.ui.rdetail.cp_info_row);
141         statusRow = G.ui.rdetail.cp_status.parentNode;
142         statusRow.id = '__rdsrow';
143
144         G.ui.rdetail.cp_info_local.onclick = rdetailShowLocalCopies;
145         G.ui.rdetail.cp_info_all.onclick = rdetailShowAllCopies;
146
147         if(getLocation() == globalOrgTree.id())
148                 hideMe(G.ui.rdetail.cp_info_all);
149
150     if(getRid()) {
151
152             var req = new Request(FETCH_RMODS, getRid());
153             req.callback(_rdetailDraw);
154             req.send();
155
156     } else { // No record ID was specified
157
158        // If we have an ISBN in the URL, let's try to find that record
159        // This allows direct linking by ISBN.
160        // Note, this uses the first record it finds
161        if(getRtype() == RTYPE_ISBN) { 
162             var req = new Request(FETCH_ADV_ISBN_RIDS, getAdvTerm() );
163             req.callback(
164                 function(r) {
165                     var blob = r.getResultObject();
166                     if(blob && blob.count > 0) 
167                         RID = blob.ids[0]; 
168                     var req2 = new Request(FETCH_RMODS, getRid());
169                     req2.callback(_rdetailDraw);
170                     req2.send();
171                 }
172             );
173             req.send();
174         }
175     }
176
177
178         if (rdetailDisplaySerialHoldings && (
179         isXUL() || !fetchOrgSettingDefault(
180             getLocation(), "opac.fully_compressed_serial_holdings")
181         )
182     ) {
183                 var req = new Request(FETCH_MFHD_SUMMARY, getRid());
184                 req.callback(_holdingsDraw);
185                 req.send();
186                 if (isXUL()) {
187                         var here = findOrgUnit(getLocation());
188                         dojo.place("<div id='mfhd_ad_menu'></div>", "rdetail_details_table", "after");
189                         var mfhd_add = new dijit.Menu({style:"float: right;"});
190                         new dijit.MenuItem({onClick:function(){
191                                 var req = new Request(CREATE_MFHD_RECORD, G.user.session, 1, here.id(), getRid());
192                                 var res = req.send();
193                                 alert(dojo.string.substitute(opac_strings.CREATED_MFHD_RECORD, [here.name()]));
194                         }, label:opac_strings.CREATE_MFHD}).placeAt(mfhd_add);
195                         mfhd_add.placeAt(mfhd_ad_menu);
196                 }
197         }
198
199         detachAllEvt("result", "idsReceived");
200         G.evt.result.hitCountReceived = [];
201         G.evt.result.recordReceived = [];
202         G.evt.result.copyCountsReceived = [];
203         G.evt.result.allRecordsReceived = [];
204
205     if(isXUL()) 
206         unHideMe($('rdetail_show_orders'));
207 }
208
209 function rdetailGetPageIds() {
210         attachEvt("result", "idsReceived", rdetailSetPaging );
211         resultFetchAllRecords = true;
212         rresultCollectIds(true);
213 }
214
215
216 function buildunAPISpan (span, type, id) {
217         var cgi = new CGI();
218         var d = new Date();
219
220         addCSSClass(span,'unapi-id');
221
222         span.setAttribute(
223                         'title', 'tag:' + cgi.server_name + ',' +
224                         d.getFullYear() + ':' + type + '/' + id
225                         );
226 }
227
228 function rdetailViewMarc(r,id) {
229         hideMe($('rdetail_extras_loading'));
230         $('rdetail_view_marc_box').innerHTML = r.getResultObject();
231
232         var div = elem('div', { "class" : 'hide_me' });
233         var span = div.appendChild( elem('abbr') );
234
235         buildunAPISpan( span, 'biblio-record_entry', record.doc_id() );
236
237         $('rdetail_view_marc_box').insertBefore(span, $('rdetail_view_marc_box').firstChild);
238 }
239
240
241 function rdetailShowLocalCopies() {
242         rdetailShowLocal = true;
243         rdetailBuildInfoRows();
244         hideMe(G.ui.rdetail.cp_info_local);
245         unHideMe(G.ui.rdetail.cp_info_all);
246         hideMe(G.ui.rdetail.cp_info_none); 
247 }
248
249 function rdetailShowAllCopies() {
250
251         rdetailShowLocal = false;
252         rdetailBuildInfoRows();
253         hideMe(G.ui.rdetail.cp_info_all);
254         unHideMe(G.ui.rdetail.cp_info_local);
255         hideMe(G.ui.rdetail.cp_info_none); 
256 }
257
258 function OpenMarcEditWindow(pcrud, rec) {
259         /*
260            To run in Firefox directly, must set signed.applets.codebase_principal_support
261            to true in about:config
262          */
263         netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
264         win = window.open('/xul/server/cat/marcedit.xul'); // XXX version?
265         dojo.require('openils.PermaCrud');
266
267         win.xulG = {
268                 "record": {"marc": rec.marc(), "rtype": "sre"},
269                 "save": {
270                         "label": opac_strings.SAVE_MFHD_LABEL,
271                         "func": function(xmlString) {
272                                 rec.marc(xmlString);
273                                 rec.edit_date('now');
274                                 rec.ischanged(true);
275                                 pcrud.update(rec);
276                         }
277                 }
278         };
279 }
280
281 function loadMarcEditor(recId) {
282         var pcrud = new openils.PermaCrud({"authtoken": G.user.session});
283         var rec = pcrud.retrieve("sre", recId);
284         if (rec) {
285                 OpenMarcEditWindow(pcrud, rec);
286         }
287 }
288
289 /*
290  * This function could be written much more intelligently
291  * Limited brain power means that I'm brute-forcing it for now
292  */
293 function _holdingsDraw(h) {
294         holdings = h.getResultObject();
295         if (!holdings) { return null; }
296
297         dojo.forEach(holdings, _holdingsDrawMFHD);
298
299         // Populate XUL menus
300         if (isXUL()) {
301                 runEvt('rdetail','MFHDDrawn');
302         }
303 }
304
305 function _holdingsDrawMFHD(holdings, entryNum) {
306
307         var here = findOrgUnit(getLocation());
308         if (getDepth() > 0 || getDepth === 0 ) {
309                 while (getDepth() < findOrgDepth(here))
310                 here = findOrgUnit( here.parent_ou() );
311                 if (!orgIsMine(findOrgUnit(here), findOrgUnit(holdings.owning_lib()))) {
312                         return null;
313                 }
314         }
315
316         var hb = holdings.basic_holdings();
317         var hba = holdings.basic_holdings_add();
318         var hs = holdings.supplement_holdings();
319         var hsa = holdings.supplement_holdings_add();
320         var hi = holdings.index_holdings();
321         var hia = holdings.index_holdings_add();
322         var ho = holdings.online();
323         var hm = holdings.missing();
324         var hinc = holdings.incomplete();
325         var hloc = holdings.location() || 'MFHD';
326
327         if (    hb.length == 0 && hba.length == 0 && hs.length == 0 &&
328                 hsa.length == 0 && hi.length == 0 && hia.length == 0 &&
329                 ho.length == 0 && hm.length == 0 && hinc.length == 0
330         ) {
331
332                 if (isXUL()) {
333                         /* 
334                          * If we have a record, but nothing to show for it, then the
335                          * record is likely empty or corrupt. This gives cataloguers a
336                          * chance to add holdings or correct the record
337                          */
338                         hb = ['PLACEHOLDER'];
339                 } else {
340                         return null;
341                 }
342         }
343
344         // Show entryNum + 1 in staff client for better menu correlation
345         // Maybe this should be holdings.sre_id() instead? (which could get long after time)
346         var entryNumString = '';
347         if (isXUL()) {
348                 var entryNumInc = entryNum + 1;
349                 entryNumString = ' [Entry #'+entryNumInc+'] ';
350         }
351
352         var refNode;
353         if (entryNum > 0) {
354                 refNode = 'rdetail_holdings_table_' + (entryNum - 1);
355         } else {
356                 refNode = 'rdetail_details_table';
357         }
358
359         dojo.place("<table style='width: 100%;' id='rdetail_holdings_table_"+entryNum+"'><caption id='mfhdHoldingsCaption" + entryNum + "' class='rdetail_header color_1'>" +
360                 dojo.string.substitute(opac_strings.HOLDINGS_TABLE_CAPTION, [hloc]) + entryNumString +
361                 "</caption><tbody id='rdetail_holdings_tbody_" + entryNum +
362                 "'></tbody></table>", refNode, "after"
363         );
364         if (hb.length > 0) { _holdingsDrawMFHDEntry(entryNum, opac_strings.BASIC_HOLDINGS, hb); }
365         if (hba.length > 0) { _holdingsDrawMFHDEntry(entryNum, opac_strings.BASIC_HOLDINGS_ADD, hba); }
366         if (hs.length > 0) { _holdingsDrawMFHDEntry(entryNum, opac_strings.SUPPLEMENT_HOLDINGS, hs); }
367         if (hsa.length > 0) { _holdingsDrawMFHDEntry(entryNum, opac_strings.SUPPLEMENT_HOLDINGS_ADD, hsa); }
368         if (hi.length > 0) { _holdingsDrawMFHDEntry(entryNum, opac_strings.INDEX_HOLDINGS, hi); }
369         if (hia.length > 0) { _holdingsDrawMFHDEntry(entryNum, opac_strings.INDEX_HOLDINGS_ADD, hia); }
370         if (ho.length > 0) { _holdingsDrawMFHDEntry(entryNum, opac_strings.ONLINE_VOLUMES, ho); }
371         if (hm.length > 0) { _holdingsDrawMFHDEntry(entryNum, opac_strings.MISSING_VOLUMES, hm); }
372         if (hinc.length > 0) { _holdingsDrawMFHDEntry(entryNum, opac_strings.INCOMPLETE_VOLUMES, hinc); }
373
374         if (isXUL()) {
375                 mfhdDetails.push({ 'id' : holdings.sre_id(), 'label' : hloc, 'entryNum' : entryNum, 'owning_lib' : holdings.owning_lib() });
376                 dojo.require('openils.Event');
377                 dojo.require('openils.PermaCrud');
378                 var mfhd_edit = new dijit.Menu({});
379                 new dijit.MenuItem({onClick: function(){loadMarcEditor(holdings.sre_id())}, label:opac_strings.EDIT_MFHD_RECORD}).placeAt(mfhd_edit, "first");
380                 new dijit.MenuItem({onClick:function(){
381                         // Avoid accidental deletion of MFHD records
382                         if (!confirm(opac_strings.DELETE_MFHD_CONFIRM)) {
383                                 return;
384                         }
385                         var pcrud = new openils.PermaCrud({"authtoken": G.user.session});
386                         var mfhd_rec = pcrud.retrieve("sre", holdings.sre_id());
387                         if (mfhd_rec) {
388                                 pcrud.eliminate(mfhd_rec);
389                                 alert(dojo.string.substitute(opac_strings.DELETED_MFHD_RECORD, [holdings.sre_id()]));
390                         }
391                 }, label:opac_strings.DELETE_MFHD}).placeAt(mfhd_edit, "last");
392                 // new dijit.MenuItem({onClick:function(){alert("Edit properties " + holdings.sre_id());}, label:opac_strings.EDIT_PROPERTIES}).placeAt(mfhd_edit, "last");
393                 var mfhd_mb = new dijit.form.DropDownButton({dropDown: mfhd_edit, label:opac_strings.EDIT_MFHD_MENU, style:"float:right"});
394                 mfhd_mb.placeAt("mfhdHoldingsCaption" + entryNum, "last");
395                 mfhd_edit.startup();
396         }
397 }
398
399 function _holdingsDrawMFHDEntry(entryNum, entryName, entry) {
400         var flatEntry = entry.toString().replace(/,/g, ', ');
401         dojo.place("<tr><td> </td><td nowrap='nowrap' class='rdetail_desc'>" + entryName + "</td><td class='rdetail_item'>" + flatEntry + "</td></tr>", "rdetail_holdings_tbody_" + entryNum, "last");
402 }
403
404 function _rdetailDraw(r) {
405         record = r.getResultObject();
406
407         runEvt('rdetail', 'recordRetrieved', record.doc_id());
408
409         G.ui.rdetail.title.appendChild(text(record.title()));
410         buildSearchLink(STYPE_AUTHOR, record.author(), G.ui.rdetail.author);
411         G.ui.rdetail.isbn.appendChild(text(cleanISBN(record.isbn())));
412         G.ui.rdetail.edition.appendChild(text(record.edition()));
413         G.ui.rdetail.pubdate.appendChild(text(record.pubdate()));
414         G.ui.rdetail.publisher.appendChild(text(record.publisher()));
415         $('rdetail_physical_desc').appendChild(text(record.physical_description()));
416         r = record.types_of_resource();
417         if(r) {
418                 G.ui.rdetail.tor.appendChild(text(r[0]));
419                 setResourcePic( G.ui.rdetail.tor_pic, r[0]);
420         }
421         G.ui.rdetail.abstr.appendChild(text(record.synopsis()));
422
423         try{
424                 if(record.isbn()) {
425                         if(ENABLE_ADDED_CONTENT_ATTRIB_LINKS) {
426                                 unHideMe($('rdetail.jacket_attrib_div'));
427                                 var href = $('rdetail.jacket_attrib_link').getAttribute('href') +cleanISBN(record.isbn());
428                                 $('rdetail.jacket_attrib_link').setAttribute('href', href);
429                         }
430                         rdetailCheckForGBPreview();
431
432                 } else {
433                         hideMe($("rdetail.jacket_attrib_div"));
434                         hideMe($("rdetail_img_link"));
435                 }
436         } catch(E) {}
437
438
439         // see if the record has any external links 
440         var links = record.online_loc();
441         for( var i = 0; links && links.length > 0 && i < links.length; i = i + 3 ) {
442                 var href = links[i];
443                 // avoid matching "HTTP: The Complete Reference"
444                 if( href.match(/https?:\/|ftps?:\/|mailto:/i) ) {
445                         unHideMe($('rdetail_online_row'));
446                         // MODS can contain a display label (used for the text of the link)
447                         // as well as a note about the URL; many legacy systems conflate the
448                         // two and generate MARC records that expect the note to be used as
449                         // the text of the link, with no display label; here's the canonical
450                         // format:
451                         //
452                         // 856 40 $uhttp://localhost$yDisplay label$zPublic note
453                         //
454                         // Note that the MARC21slim2MODS XSL concatenates $3 and $y together
455                         // (as $y was defined later in MARC21's life as the display label)
456                         var displayLabel = '' + links[i+1];
457                         var note = '' + links[i+2];
458                         if(!displayLabel || displayLabel.match(/https?:\/|ftps?:\/|mailto:/i)) {
459                                 if(!note || note.match(/https?:\/|ftps?:\/|mailto:/i)) {
460                                         displayLabel = href;
461                                 } else {
462                                         displayLabel = note;
463                                 }
464                         }
465                         $('rdetail_online').appendChild(elem('a', {href:href,'class':'classic_link'}, displayLabel));
466                         if (note && note != displayLabel) {
467                                 $('rdetail_online').appendChild(elem('span', {'class':'url_note'}, ' - ' + note));
468                         }
469                         $('rdetail_online').appendChild(elem('br'));
470                 }
471         }
472
473         // Fill in our unAPI ID, if anyone cares
474         var abbrs = document.getElementsByTagName('abbr');
475         var span;
476         for (var i = 0; i < abbrs.length; i++) {
477                 if (abbrs[i].getAttribute('name') == 'unapi') {
478                         span = abbrs[i];
479                         break;
480                 }
481         }
482         buildunAPISpan( span, 'biblio-record_entry', record.doc_id() );
483
484         $('rdetail_place_hold').onclick = function() {
485         var src = location.href;
486
487         if(forceLoginSSL && src.match(/^http:/)) {
488
489             src = src.replace(/^http:/, 'https:');
490
491             if(!src.match(/&place_hold=1/)) {
492                 src += '&place_hold=1';
493             }
494
495             location.href = src;
496
497         } else {
498             holdsDrawEditor({record:record.doc_id(), type:'T'});
499         }
500     }
501
502
503         var RW = $('rdetail_exp_refworks');
504         if (RW && rdetailEnableRefWorks) {
505
506                 var here = (findOrgUnit(getLocation())).name();
507                 var org_name = here.replace(" ", "+");
508                 var cgi = new CGI();
509
510                 RW.setAttribute(
511                         'href',
512                         rdetailRefWorksHost + '/express/expressimport.asp?vendor='
513                         + org_name
514                         + '&filter=MARC+Format&database=All+MARC+Formats&encoding=65001&url=http%3A%2F%2F'
515                         + cgi.server_name + '/opac/extras/supercat/marctxt/record/'
516                         + record.doc_id()
517                );
518
519                 RW.setAttribute('target', 'RefWorksMain');
520
521                 unHideMe($('rdetail_exp_refworks_span'));
522         }
523
524         $('rdetail_img_link').setAttribute('href', buildISBNSrc(cleanISBN(record.isbn()), 'large'));
525         G.ui.rdetail.image.setAttribute("src", buildISBNSrc(cleanISBN(record.isbn())));
526         runEvt("rdetail", "recordDrawn");
527         recordsCache.push(record);
528
529         rdetailSetExtrasSelector();
530
531         var breq = new Request(FETCH_BRE, [getRid()]);
532         breq.callback( rdetailCheckDeleted );
533         breq.send();
534
535         //resultBuildCaches( [ record ] );
536         //resultDrawSubjects();
537         //resultDrawSeries();
538
539         // grab added content 
540
541     // Proxied through Evergreen AddedContent module
542         acCollectData(cleanISBN(record.isbn()), rdetailhandleAC);
543
544     var currentISBN = cleanISBN(record.isbn());
545
546     // Not proxied, cross-site javascript
547
548     // ChiliFresh
549     if (chilifresh && chilifresh != '(none)' && currentISBN) {
550         $('chilifreshReviewLink').setAttribute('id','isbn_'+currentISBN);
551         $('chilifreshReviewResult').setAttribute('id','chili_review_'+currentISBN);
552         unHideMe($('rdetail_reviews_link'));
553         unHideMe($('rdetail_chilifresh_reviews'));
554         try {
555             chili_init();
556         } catch(E) {
557             dump(E + '\n');
558             hideMe($('rdetail_reviews_link'));
559             hideMe($('rdetail_chilifresh_reviews'));
560         }
561     }
562
563     // Novelist
564     if (novelist && currentISBN) {
565         unHideMe($('rdetail_novelist_link'));
566     }
567 }
568
569
570
571 function rdetailCheckDeleted(r) {
572         var br = r.getResultObject()[0];
573         if( isTrue(br.deleted()) ) {
574                 hideMe($('rdetail_place_hold'));
575                 $('rdetail_more_actions_selector').disabled = true;
576                 unHideMe($('rdetail_deleted_exp'));
577         }
578 }
579
580 function rdetailSetExtrasSelector() {
581         if(!grabUser()) return;
582         unHideMe($('rdetail_more_actions'));
583
584         var req = new Request( 
585                         FETCH_CONTAINERS, G.user.session, G.user.id(), 'biblio', 'bookbag' );
586         req.callback(rdetailAddBookbags);
587         req.send();
588 }
589
590 function rdetailAddBookbags(r) {
591
592         var containers = r.getResultObject();
593         var selector = $('rdetail_more_actions_selector');
594         var found = false;
595         var index = 3;
596         doSelectorActions(selector);
597
598         for( var i = 0; i < containers.length; i++ ) {
599                 found = true;
600                 var container = containers[i];
601                 insertSelectorVal( selector, index++, container.name(), 
602                                 "container_" + container.id(), rdetailAddToBookbag,  1 );
603         }
604
605         nextContainerIndex = index;
606 }
607
608 var _actions = {};
609 function rdetailNewBookbag() {
610         var name = prompt($('rdetail_bb_new').innerHTML,"");
611         if(!name) return;
612
613         var id;
614         if( id = containerCreate( name ) ) {
615                 alert($('rdetail_bb_success').innerHTML);
616                 var selector = $('rdetail_more_actions_selector');
617                 insertSelectorVal( selector, nextContainerIndex++, name, 
618                                 "container_" + id, rdetailAddToBookbag, 1 );
619                 setSelector( selector, 'start' );
620         }
621 }
622
623
624 function rdetailAddToBookbag() {
625         var selector = $('rdetail_more_actions_selector');
626         var id = selector.options[selector.selectedIndex].value;
627         setSelector( selector, 'start' );
628
629         if( containerCreateItem( id.substring(10), record.doc_id() )) {
630                 alert($('rdetail_bb_item_success').innerHTML);
631         }
632 }
633
634
635 var rdetailMarcFetched = false;
636 function rdetailShowExtra(type, args) {
637
638         hideMe($('rdetail_copy_info_div'));
639         hideMe($('rdetail_summary_div'));
640         hideMe($('rdetail_reviews_div'));
641         hideMe($('rdetail_toc_div'));
642         hideMe($('rdetail_anotes_div'));
643         hideMe($('rdetail_excerpt_div'));
644         hideMe($('rdetail_preview_div'));
645         hideMe($('rdetail_marc_div'));
646         hideMe($('cn_browse'));
647         hideMe($('rdetail_cn_browse_div'));
648         hideMe($('rdetail_novelist_div'));
649         hideMe($('rdetail_notes_div'));
650
651         removeCSSClass($('rdetail_copy_info_link'), 'rdetail_extras_selected');
652         removeCSSClass($('rdetail_viewcn_link'), 'rdetail_extras_selected');
653         removeCSSClass($('rdetail_summary_link'), 'rdetail_extras_selected');
654         removeCSSClass($('rdetail_reviews_link'), 'rdetail_extras_selected');
655         removeCSSClass($('rdetail_toc_link'), 'rdetail_extras_selected');
656         removeCSSClass($('rdetail_excerpt_link'), 'rdetail_extras_selected');
657         removeCSSClass($('rdetail_preview_link'), 'rdetail_extras_selected');
658         removeCSSClass($('rdetail_anotes_link'), 'rdetail_extras_selected');
659         removeCSSClass($('rdetail_annotation_link'), 'rdetail_extras_selected');
660         removeCSSClass($('rdetail_viewmarc_link'), 'rdetail_extras_selected');
661         removeCSSClass($('rdetail_novelist_link'), 'rdetail_extras_selected');
662
663         switch(type) {
664
665                 case "copyinfo": 
666                         unHideMe($('rdetail_copy_info_div')); 
667                         addCSSClass($('rdetail_copy_info_link'), 'rdetail_extras_selected');
668                         break;
669
670         case "summary":
671             addCSSClass($('rdetail_summary_link'), 'rdetail_extras_selected');
672             unHideMe($('rdetail_summary_div'));
673             break;
674
675                 case "reviews": 
676                         addCSSClass($('rdetail_reviews_link'), 'rdetail_extras_selected');
677                         unHideMe($('rdetail_reviews_div')); 
678                         break;
679
680                 case "excerpt": 
681                         addCSSClass($('rdetail_excerpt_link'), 'rdetail_extras_selected');
682                         unHideMe($('rdetail_excerpt_div'));
683                         break;
684
685                 case "preview": 
686                         addCSSClass($('rdetail_preview_link'), 'rdetail_extras_selected');
687                         unHideMe($('rdetail_preview_div'));
688                         rdetailDisplayGBPreview();
689                         break;
690
691                 case "anotes": 
692                         addCSSClass($('rdetail_anotes_link'), 'rdetail_extras_selected');
693                         unHideMe($('rdetail_anotes_div'));
694                         break;
695
696                 case "toc": 
697                         addCSSClass($('rdetail_toc_link'), 'rdetail_extras_selected');
698                         unHideMe($('rdetail_toc_div'));
699                         break;
700
701                 case "marc": 
702                         addCSSClass($('rdetail_viewmarc_link'), 'rdetail_extras_selected');
703                         unHideMe($('rdetail_marc_div')); 
704                         if(rdetailMarcFetched) return;
705                         unHideMe($('rdetail_extras_loading'));
706                         rdetailMarcFetched = true;
707                         var req = new Request( FETCH_MARC_HTML, record.doc_id() );
708                         req.callback(rdetailViewMarc); 
709                         req.send();
710                         break;
711
712                 case "novelist": 
713                         addCSSClass($('rdetail_novelist_link'), 'rdetail_extras_selected');
714                         unHideMe($('rdetail_novelist_div')); 
715                         break;
716
717                 case 'cn':
718                         addCSSClass($('rdetail_viewcn_link'), 'rdetail_extras_selected');
719                         unHideMe($('rdetail_cn_browse_div'));
720                         rdetailShowCNBrowse(defaultCN, getLocation(), null, true);
721                         break;
722
723         }
724 }
725
726 function rdetailVolumeDetails(args) {
727         var row = $(args.rowid);
728         var tbody = row.parentNode;
729         cpdBuild( tbody, row, record, args.cn, args.org, args.depth, args.copy_location );
730         return;
731 }
732
733 function rdetailBuildCNList() {
734
735         var select = $('cn_browse_selector');
736         var index = 0;
737         var arr = [];
738         for( var cn in callnumberCache ) arr.push( cn );
739         arr.sort();
740
741         if( arr.length == 0 ) {
742                 hideMe($('rdetail_cn_browse_select_div'));
743                 return;
744         }
745
746         for( var i = 0; i < arr.length; i++ ) {
747                 var cn = arr[i];
748                 var opt = new Option(cn);
749                 select.options[index++] = opt;
750         }
751         select.onchange = rdetailGatherCN;
752 }
753
754 function rdetailGatherCN() {
755         var cn = getSelectorVal($('cn_browse_selector'));
756         rdetailShowCNBrowse( cn, getLocation(), getDepth(), true );
757         setSelector( $('cn_browse_selector'), cn );
758 }
759
760
761 function rdetailShowCNBrowse( cn, loc, depth, fromOnclick ) {
762
763         if(!cn) {
764                 unHideMe($('cn_browse_none'));
765                 hideMe($('rdetail_cn_browse_select_div'));
766                 return;
767         }
768
769         unHideMe($('rdetail_cn_browse_select_div'));
770         rdetailBuildCNList();
771         setSelector( $('cn_browse_selector'), cn );
772         hideMe($('rdetail_copy_info_div'));
773         hideMe($('rdetail_reviews_div'));
774         hideMe($('rdetail_summary_div'));
775         hideMe($('rdetail_toc_div'));
776         hideMe($('rdetail_marc_div'));
777         unHideMe($('rdetail_cn_browse_div'));
778         unHideMe($('cn_browse'));
779         if( !rdetailLocalOnly && ! fromOnclick ) depth = findOrgDepth(globalOrgTree);
780         cnBrowseGo(cn, loc, depth);
781 }
782
783 function rdetailhandleAC(data) {
784
785         if( data.summary.html ) {
786                 $('rdetail_summary_div').innerHTML = data.summary.html;
787                 unHideMe($('rdetail_summary_link'));
788         }
789
790         if( data.reviews.html ) {
791                 $('rdetail_review_container').innerHTML = data.reviews.html;
792                 unHideMe($('rdetail_reviews_link'));
793         }
794
795         if( data.toc.html ) {
796                 $('rdetail_toc_div').innerHTML = data.toc.html;
797                 unHideMe($('rdetail_toc_link'));
798         }
799
800         if( data.excerpt.html ) {
801                 $('rdetail_excerpt_div').innerHTML = data.excerpt.html;
802                 unHideMe($('rdetail_excerpt_link'));
803         }
804
805         if( data.anotes.html ) {
806                 $('rdetail_anotes_div').innerHTML = data.anotes.html;
807                 unHideMe($('rdetail_anotes_link'));
808         }
809 }
810
811 function rdetailShowReviews(r) {
812         hideMe($('rdetail_extras_loading'));
813         var res = r.getResultObject();
814         var par = $('rdetail_reviews_div');
815         var template = par.removeChild($('rdetail_review_template'));
816         if( res && res.length > 0 ) {
817                 unHideMe($('rdetail_reviews_link'));
818                 for( var i = 0; i < res.length; i++ ) {
819                         var rev = res[i];       
820                         if( rev.text && rev.info ) {
821                                 var node = template.cloneNode(true);
822                                 $n(node, 'review_header').appendChild(text(rev.info));
823                                 $n(node, 'review_text').appendChild(text(rev.text));
824                                 par.appendChild(node);
825                         }
826                 }
827         }
828 }
829
830
831 function rdetailShowTOC(r) {
832         hideMe($('rdetail_extras_loading'));
833         var resp = r.getResultObject();
834         if(resp) {
835                 unHideMe($('rdetail_toc_link'));
836                 $('rdetail_toc_div').innerHTML = resp;
837         }
838 }
839
840 function rdetailBuildInfoRows() {
841         var req;
842         var method = FETCH_COPY_COUNTS_SUMMARY;
843         if (rdetailShowCopyLocation)
844                 method = FETCH_COPY_LOCATION_COUNTS_SUMMARY;
845
846         if( rdetailShowLocal ) 
847                 req = new Request(method, record.doc_id(), getLocation(), getDepth())
848         else
849                 req = new Request(method, record.doc_id());
850         req.callback(_rdetailBuildInfoRows);
851         req.send();
852 }
853
854 function _rdetailRows(node) {
855
856         if( rdetailShowLocal && getLocation() != globalOrgTree.id() ) {
857                 var loc = findOrgUnit(getLocation());
858                 if( node ) {
859                         if( !orgIsMine(node, loc) && !orgIsMine(loc,node) ) return;
860                 } else {
861             var kids = globalOrgTree.children();
862             if (kids) {
863                         for( var i = 0; i < kids.length; i++ ) {
864                                 var org = findOrgUnit(kids[i]);
865                                 if( orgIsMine(org, loc) ) {
866                                         node = org;
867                                         break;
868                                 }
869                 }
870                         }
871                 } 
872         }
873
874         if(!node && findOrgType(globalOrgTree.ou_type()).can_have_vols())
875                 node = globalOrgTree;
876
877
878         /* don't show hidden orgs */
879
880         if(node) {
881
882                 if(!isXUL() && !isTrue(node.opac_visible())) return;
883
884                 if (orgHiding) {
885                         if (isTrue( findOrgType(node.ou_type()).can_have_vols() )) {
886                                 if ( ! orgIsMine( orgHiding.org, node, orgHiding.depth ) ) {
887                                         return;
888                                 }
889                         }
890                 }
891
892                 var row = copyRow.cloneNode(true);
893                 row.id = "cp_info_" + node.id();
894
895                 var libtd = findNodeByName( row, config.names.rdetail.lib_cell );
896                 var cntd  = findNodeByName( row, config.names.rdetail.cn_cell );
897                 var cpctd = findNodeByName( row, config.names.rdetail.cp_count_cell );
898                 var actions = $n(row, 'rdetail_actions_cell');
899
900                 var p = libtd.getElementsByTagName('a')[0];
901                 libtd.insertBefore(text(node.name()), p);
902                 libtd.setAttribute("style", "padding-left: " + ((findOrgDepth(node) - 1)  * 9) + "px;");
903
904                 if(!findOrgType(node.ou_type()).can_have_vols()) {
905
906                         row.removeChild(cntd);
907                         row.removeChild(cpctd);
908                         row.removeChild(actions);
909                         row.setAttribute('novols', '1');
910
911                         libtd.setAttribute("colspan", numStatuses + 3 );
912                         libtd.colSpan = numStatuses + 3;
913                         addCSSClass(row, 'copy_info_region_row');
914                 } 
915
916                 copyRowParent.appendChild(row);
917
918         } else { node = globalOrgTree; }
919
920     var kids = node.children();
921     if (kids) {
922         for( var c = 0; c < kids.length; c++ ) 
923                 _rdetailRows(kids[c]);
924     }
925 }
926
927 function rdetailCNPrint(orgid, cn) {
928         var div = cpdBuildPrintWindow( record, orgid);
929         var template = div.removeChild($n(div, 'cnrow'));
930         var rowNode = $("cp_info_" + orgid);
931         cpdStylePopupWindow(div);
932         openWindow(div.innerHTML);
933 }
934
935 var localCNFound = false;
936 var ctr = 0;
937 function _rdetailBuildInfoRows(r) {
938
939         if (rdetailShowCopyLocation)
940                 unHideMe( $n( $('rdetail_copy_info_table'), 'rdetail_copylocation_header' ) );
941
942         removeChildren(copyRowParent);
943
944         orgHiding = checkOrgHiding();
945
946         _rdetailRows();
947
948         var summary = r.getResultObject();
949         if(!summary) return;
950
951         var found = false;
952         for( var i = 0; i < summary.length; i++ ) {
953
954                 var arr = summary[i];
955                 globalCNCache[arr[1]] = 1;
956                 var thisOrg = findOrgUnit(arr[0]);
957                 var rowNode = $("cp_info_" + thisOrg.id());
958                 if(!rowNode) continue;
959
960                 if(rowNode.getAttribute("used")) {
961
962                         if( rowNode.nextSibling ) {
963                                 sib = rowNode.nextSibling;
964                                 o ='cp_info_'+thisOrg.id()+'_';
965                                 /* push the new row on as the last row for this org unit */
966                                 while( sib && sib.id.match(o) ) {
967                                         sib = sib.nextSibling;
968                                 }
969                                 if(sib)
970                                         rowNode = copyRowParent.insertBefore(copyRow.cloneNode(true), sib);
971                                 else
972                                         rowNode = copyRowParent.appendChild(copyRow.cloneNode(true));
973                         } else {
974                                 rowNode = copyRowParent.appendChild(copyRow.cloneNode(true));
975                         }
976
977                         var n = findNodeByName( rowNode, config.names.rdetail.lib_cell );
978                         n.appendChild(text(thisOrg.name()));
979                         n.setAttribute("style", "padding-left: " + ((findOrgDepth(thisOrg) - 1)  * 9) + "px;");
980                         rowNode.id = "cp_info_" + thisOrg.id() + '_' + (++ctr); 
981
982                 } else {
983                         rowNode.setAttribute("used", "1");
984                 }
985
986                 var cpc_temp = rowNode.removeChild(
987                                 findNodeByName(rowNode, config.names.rdetail.cp_count_cell));
988
989                 var statuses = arr[2];
990                 var cl = '';
991                 if (rdetailShowCopyLocation) {
992                         cl = arr[2];
993                         statuses = arr[3];
994                 }
995
996
997                 rdetailApplyStatuses(rowNode, cpc_temp, statuses);
998
999                 var isLocal = false;
1000                 if( orgIsMine( findOrgUnit(getLocation()), thisOrg ) ) { 
1001                         found = true; 
1002                         isLocal = true; 
1003                         if(!localCNFound) {
1004                                 localCNFound = true;
1005                                 defaultCN = arr[1];
1006                         }
1007                 }
1008
1009                 //if(isLocal) unHideMe(rowNode);
1010                 unHideMe(rowNode);
1011
1012                 rdetailSetPath( thisOrg, isLocal );
1013                 rdetailBuildBrowseInfo( rowNode, arr[1], isLocal, thisOrg, cl );
1014
1015                 if( i == summary.length - 1 && !defaultCN) defaultCN = arr[1];
1016         }
1017
1018         if(!found) unHideMe(G.ui.rdetail.cp_info_none);
1019 }
1020
1021 function rdetailBuildBrowseInfo(row, cn, local, orgNode, cl) {
1022
1023         if(local) {
1024                 var cache = callnumberCache[cn];
1025                 if( cache ) cache.count++;
1026                 else callnumberCache[cn] = { count : 1 };
1027         }
1028
1029         var depth = getDepth();
1030         if( !local ) depth = findOrgDepth(globalOrgTree);
1031
1032         $n(row, 'rdetail_callnumber_cell').appendChild(text(cn));
1033
1034         if (rdetailShowCopyLocation) {
1035                 var cl_cell = $n(row, 'rdetail_copylocation_cell');
1036                 cl_cell.appendChild(text(cl));
1037                 unHideMe(cl_cell);
1038         }
1039
1040         _debug('setting action clicks for cn ' + cn);
1041
1042         var dHref = 'javascript:rdetailVolumeDetails('+
1043                         '{copy_location : "'+cl.replace(/\"/g, '\\"')+'", rowid : "'+row.id+'", cn :"'+cn.replace(/\"/g, '\\"')+'", depth:"'+depth+'", org:"'+orgNode.id()+'", local: '+local+'});';
1044
1045         var bHref = 'javascript:rdetailShowCNBrowse("' + cn.replace(/\"/g, '\\"') + '", '+orgNode.id()+', "'+depth+'");'; 
1046
1047         unHideMe( $n(row, 'details') )
1048                 $n(row, 'details').setAttribute('href', dHref);
1049         unHideMe( $n(row, 'browse') )
1050                 $n(row, 'browse').setAttribute('href', bHref);
1051
1052         if(isXUL()) {
1053                 unHideMe($n(row, 'hold_div'));
1054                 $n(row, 'hold').onclick = function() {
1055                         var req = new Request(FETCH_VOLUME_BY_INFO, cn, record.doc_id(), orgNode.id());
1056                         req.callback(
1057                                         function(r) {
1058                                         var vol = r.getResultObject();
1059                                         holdsDrawEditor({type: 'V', volumeObject : vol});
1060                                         }
1061                                     );
1062                         req.send();
1063                 };
1064         }
1065 }
1066
1067 // sets the path to org as 'active' and displays the path if it's local 
1068 function rdetailSetPath(org, local) {
1069         if( findOrgDepth(org) == 0 ) return;
1070         var row = $("cp_info_" + org.id());
1071         row.setAttribute("hasinfo", "1");
1072         unHideMe(row);
1073         rdetailSetPath(findOrgUnit(org.parent_ou()), local);
1074 }
1075
1076 //Append all the statuses for a given summary to the 
1077 //copy summary table 
1078 function rdetailApplyStatuses( row, template, statuses ) {
1079         for( var j in _statusPositions ) {
1080                 var stat = _statusPositions[j];
1081                 var val = statuses[stat.id()];
1082                 var nn = template.cloneNode(true);
1083                 if(val) nn.appendChild(text(val));
1084                 else nn.appendChild(text(0));
1085                 row.appendChild(nn);
1086         }
1087 }
1088
1089 //Add one td (creating a new column) to the copy summary
1090 //table for each opac_visible copy status
1091 function rdetailBuildStatusColumns() {
1092
1093         rdetailGrabCopyStatuses();
1094         var parent = statusRow;
1095         var template = parent.removeChild(G.ui.rdetail.cp_status);
1096
1097         var i = 0;
1098         for( i = 0; i < cp_statuses.length; i++ ) {
1099
1100                 var c = cp_statuses[i];
1101                 if( c && isTrue(c.opac_visible()) ) {
1102                         var name = c.name();
1103                         _statusPositions[i] = c;
1104                         var node = template.cloneNode(true);
1105                         var data = findNodeByName( node, config.names.rdetail.cp_status);
1106
1107                         data.appendChild(text(name));
1108                         parent.appendChild(node);
1109                 }
1110         }       
1111
1112         numStatuses = 0;
1113         for(x in _statusPositions) numStatuses++; 
1114 }
1115
1116 function rdetailGrabCopyStatuses() {
1117         if(cp_statuses) return cp_statuses;
1118         var req = new Request(FETCH_COPY_STATUSES);
1119         req.send(true);
1120         cp_statuses = req.result();
1121         cp_statuses = cp_statuses.sort(_rdetailSortStatuses);
1122 }
1123
1124 function _rdetailSortStatuses(a, b) {
1125         return parseInt(a.id()) - parseInt(b.id());
1126 }
1127
1128 /**
1129  * Check for a Google Book preview after the main page loads
1130  */
1131 function rdetailCheckForGBPreview() {
1132         if (!rdetailGoogleBookPreview) return;
1133         dojo.addOnLoad(function() {
1134                 searchForGBPreview( cleanISBN(record.isbn()) );
1135         });
1136 }
1137
1138 /**
1139  *
1140  * @param {DOM object} isbn The form element containing the input parameters "isbns"
1141  */
1142 function searchForGBPreview( isbn ) {
1143         dojo.require("dojo.io.script");
1144         dojo.io.script.get({"url": "https://www.google.com/jsapi"});
1145         dojo.io.script.get({"url": "http://books.google.com/books", "content": { "bibkeys": isbn, "jscmd": "viewapi", "callback": "GBPreviewCallback"}});
1146 }
1147
1148 /**
1149  * This function is the call-back function for the JSON scripts which 
1150  * executes a Google book search response.
1151  *
1152  * XXX I18N of text needed
1153  *
1154  * @param {JSON} GBPBookInfo is the JSON object pulled from the Google books service.
1155  */
1156 function GBPreviewCallback(GBPBookInfo) {
1157         var GBPreviewDiv = document.getElementById("rdetail_preview_div");
1158         var GBPBook;
1159
1160         for ( i in GBPBookInfo ) {
1161                 GBPBook = GBPBookInfo[i];
1162         }
1163
1164         if ( !GBPBook ) {
1165                 return;
1166         }
1167
1168         if ( GBPBook.preview != "noview" ) {
1169                 // Add a button below the book cover image to load the preview.
1170                 GBPBadge = document.createElement( 'img' );
1171                 GBPBadge.src = 'http://books.google.com/intl/en/googlebooks/images/gbs_preview_button1.gif';
1172                 GBPBadge.title = $('rdetail_preview_badge').innerHTML;
1173                 GBPBadge.style.border = 0;
1174                 GBPBadgelink = document.createElement( 'a' );
1175                 GBPBadgelink.href = 'javascript:rdetailShowExtra("preview");';
1176                 GBPBadgelink.appendChild( GBPBadge );
1177                 $('rdetail_image_cell').appendChild( GBPBadgelink );
1178                 $('rdetail_preview_div').style.height = 600;
1179
1180                 /* Display the "Preview" tab in the Extras section */
1181                 unHideMe( $('rdetail_preview_link' ) );
1182         }
1183 }
1184
1185 /**
1186  *  This is called when the user clicks on the 'Preview' link.  We assume
1187  *  a preview is available from Google if this link was made visible.
1188  *
1189  * XXX I18N of Google Book Preview language attribute needed
1190  */
1191 function rdetailDisplayGBPreview() {
1192         unHideMe($('rdetail_extras_loading'));
1193         GBPreviewPane = $('rdetail_preview_div');
1194         if ( GBPreviewPane.getAttribute('loaded') == null ||
1195                 GBPreviewPane.getAttribute('loaded') == "false" ) {
1196                 google.load("books", "0", {"callback" : rdetailGBPViewerLoadCallback, "language": "en"} );
1197                 GBPreviewPane.setAttribute('loaded', 'true');
1198         }
1199 }
1200
1201 function rdetailGBPViewerLoadCallback() {
1202         hideMe($('rdetail_extras_loading'));
1203         var GBPViewer = new google.books.DefaultViewer(document.getElementById('rdetail_preview_div'));
1204         GBPViewer.load('ISBN:' + cleanISBN(record.isbn()) );
1205
1206 }
1207
1208 function rdetailDrawExpandedHoldings(anchor, bibid, type) {
1209     var offsets = {"basic": 0, "index": 0, "supplement": 0};
1210     var limit = 10; /* XXX give user control over this? */
1211     var target_id = "holding_type_" + type;
1212     var target = dojo.byId(target_id);
1213
1214     anchor.innerHTML = "[-]";
1215     anchor.oldonclick = anchor.onclick;
1216     anchor.onclick = function() {
1217         anchor.onclick = anchor.oldonclick;
1218         anchor.innerHTML = "[+]";
1219         dojo.empty(target);
1220     };
1221
1222     function _load() {
1223         dojo.empty(target);
1224         fieldmapper.standardRequest(
1225             ["open-ils.serial",
1226                 "open-ils.serial.received_siss.retrieve.by_bib.atomic"], {
1227                 "params": [bibid, {"offset": offsets[type], "limit": limit}],
1228                 "async": true,
1229                 "oncomplete": function(r) {
1230                     try {
1231                         if (msg = r.recv().content()) { /* sic, assignment */
1232                             offsets[type] += msg.length;
1233                             dojo.forEach(
1234                                 msg, function(o) {
1235                                     dojo.create("br", null, target);
1236                                     dojo.create(
1237                                         "span", {
1238                                             "innerHTML": o.issuance.label(),
1239                                             "style": {"padding": "0 2em"}
1240                                         }, target
1241                                     );
1242
1243                                     if (!o.has_units) return;
1244                                     /* can't place holds if no units */
1245                                     dojo.create(
1246                                         "a", {
1247                                             "href":"javascript:void(0);",
1248                                             "onclick": function() {
1249                                                 holdsDrawEditor({
1250                                                     "type": "I",
1251                                                     "issuance": o.issuance.id()
1252                                                 });
1253                                             },
1254                                             "innerHTML": "[" +
1255                                                 opac_strings.PLACE_HOLD + "]"
1256                                         }, target
1257                                     );
1258                                 }
1259                             );
1260                             if (msg.length == limit) {
1261                                 dojo.create("br", null, target);
1262                                 dojo.create(
1263                                     "a", {
1264                                         "href": "javascript:void(0);",
1265                                         "innerHTML":
1266                                             "[" + opac_strings.MORE + "]",
1267                                         "onclick": _load
1268                                     }, target
1269                                 );
1270                             }
1271                         }
1272                     } catch (E) {
1273                         void(0);
1274                     }
1275                 }
1276             }
1277         );
1278     }
1279     _load();
1280 }