]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/xul/staff_client/server/cat/util.js
Improve Firefox/XULRunner Support
[working/Evergreen.git] / Open-ILS / xul / staff_client / server / cat / util.js
1 dump('entering cat/util.js\n');
2
3 function $(id) { return document.getElementById(id); }
4
5 if (typeof cat == 'undefined') var cat = {};
6 cat.util = {};
7
8 cat.util.EXPORT_OK    = [ 
9     'spawn_copy_editor', 'add_copies_to_bucket', 'show_in_opac', 'spawn_spine_editor', 'transfer_copies', 
10     'transfer_title_holds', 'mark_item_missing', 'mark_item_damaged', 'replace_barcode', 'fast_item_add', 
11     'make_bookable', 'edit_new_brsrc', 'edit_new_bresv', 'batch_edit_volumes', 'render_fine_level',
12     'render_loan_duration', 'mark_item_as_missing_pieces', 'render_callnumbers_for_bib_menu',
13     'render_cn_prefix_menuitems', 'render_cn_suffix_menuitems', 'render_cn_class_menu',
14     'render_cn_prefix_menu', 'render_cn_suffix_menu', 'transfer_specific_title_holds',
15     'request_items', 'mark_for_overlay', 'get_cbs_for_bre_id'
16 ];
17 cat.util.EXPORT_TAGS    = { ':all' : cat.util.EXPORT_OK };
18
19 cat.util.replace_barcode = function(old_bc) {
20     try {
21         JSAN.use('util.network');
22         var network = new util.network();
23
24         if (!old_bc) old_bc = window.prompt($("catStrings").getString('staff.cat.util.replace_barcode.old_bc_window_prompt.prompt'),
25             '',
26             $("catStrings").getString('staff.cat.util.replace_barcode.old_bc_window_prompt.title'));
27         if (!old_bc) return;
28
29         var copy;
30         try {
31             copy = network.simple_request('FM_ACP_RETRIEVE_VIA_BARCODE',[ old_bc ]);
32             if (typeof copy.ilsevent != 'undefined') throw(copy); 
33             if (!copy) throw(copy);
34         } catch(E) {
35             alert($("catStrings").getFormattedString('staff.cat.util.replace_barcode.error_alert', [old_bc]) + '\n');
36             return old_bc;
37         }
38     
39         // Why did I want to do this twice?  Because this copy is more fleshed?
40         try {
41             copy = network.simple_request('FM_ACP_RETRIEVE',[ copy.id() ]);
42             if (typeof copy.ilsevent != 'undefined') throw(copy);
43             if (!copy) throw(copy);
44         } catch(E) {
45             try {
46                 alert($("catStrings").getFormattedString('staff.cat.util.replace_barcode.error_alert', [old_bc]) +
47                      '\n' + (typeof E.ilsevent == 'undefined' ? '' : E.textcode + ' : ' + E.desc));
48             } catch(F) {
49                 alert(E + '\n' + F);
50             }
51             return old_bc;
52         }
53     
54         var new_bc = window.prompt($("catStrings").getString('staff.cat.util.replace_barcode.new_bc_window_prompt.prompt'),
55             '',
56             $("catStrings").getString('staff.cat.util.replace_barcode.new_bc_window_prompt.title'));
57         new_bc = String( new_bc ).replace(/\s/g,'');
58         /* Casting a possibly null input value to a String turns it into "null" */
59         if (!new_bc || new_bc == 'null') {
60             alert($("catStrings").getString('staff.cat.util.replace_barcode.new_bc.failed'));
61             return old_bc;
62         }
63     
64         var test = network.simple_request('FM_ACP_RETRIEVE_VIA_BARCODE',[ new_bc ]);
65         if (typeof test.ilsevent == 'undefined') {
66             alert('Rename aborted.  Another copy has barcode "' + new_bc + '".');
67             return old_bc;
68         } else {
69             if (test.ilsevent != 1502 /* ASSET_COPY_NOT_FOUND */) {
70                 obj.error.standard_unexpected_error_alert($("catStrings").getFormattedString('staff.cat.util.replace_barcode.testing_error', [new_bc]), test);
71                 return old_bc;
72             }    
73         }
74
75         copy.barcode(new_bc); copy.ischanged('1');
76         var r = network.simple_request('FM_ACP_FLESHED_BATCH_UPDATE', [ ses(), [ copy ] ]);
77         if (typeof r.ilsevent != 'undefined') { 
78             if (r.ilsevent != 0) {
79                 if (r.ilsevent == 5000 /* PERM_FAILURE */) {
80                     alert($("catStrings").getString('staff.cat.util.replace_barcode.insufficient_permission_for_rename'));
81                     return old_bc;
82                 } else {
83                     obj.error.standard_unexpected_error_alert($("catStrings").getString('staff.cat.util.replace_barcode.item_rename_error'),r);
84                     return old_bc;
85                 }
86             }
87         }
88
89         return new_bc;
90     } catch(E) {
91         JSAN.use('util.error'); var error = new util.error();
92         error.standard_unexpected_error_alert($("catStrings").getString('staff.cat.util.replace_barcode.rename_error'),E);
93         return old_bc;
94     }
95 }
96
97 cat.util.transfer_title_holds = function(old_targets) {
98     JSAN.use('OpenILS.data'); var data = new OpenILS.data();
99     JSAN.use('util.network'); var network = new util.network();
100     try {
101         data.stash_retrieve();
102         var target = data.marked_record_for_hold_transfer;
103         if (!target) {
104             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.destination_needed.label');
105             alert(m);
106             return;
107         }
108         var robj = network.simple_request('TRANSFER_TITLE_HOLDS',[ ses(), target, old_targets ]);
109         if (robj == 1) {
110             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.success.label');
111             alert(m);
112         } else {
113             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.failure.label');
114             alert(m);
115         }
116     } catch(E) {
117         alert('Error in cat.util.transfer_title.holds(): ' + E);
118     }
119 }
120
121 cat.util.transfer_specific_title_holds = function(hold_ids,unique_targets) {
122     JSAN.use('OpenILS.data'); var data = new OpenILS.data();
123     JSAN.use('util.network'); var network = new util.network();
124     try {
125         data.stash_retrieve();
126         var target = data.marked_record_for_hold_transfer;
127         if (!target) {
128             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.destination_needed.label');
129             alert(m);
130             return;
131         }
132         if (unique_targets.length > 1) {
133             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.many_bibs.warning');
134             if (! window.confirm(m)) {
135                 return;
136             }
137         }
138         var robj = network.simple_request('TRANSFER_SPECIFIC_TITLE_HOLDS',[ ses(), target, hold_ids ]);
139         if (robj == 1) {
140             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.success.label');
141             alert(m);
142         } else {
143             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.failure.label');
144             alert(m);
145         }
146     } catch(E) {
147         alert('Error in cat.util.transfer_title.holds(): ' + E);
148     }
149 }
150
151
152 cat.util.transfer_copies = function(params) {
153     JSAN.use('util.error'); var error = new util.error();
154     JSAN.use('OpenILS.data'); var data = new OpenILS.data();
155     JSAN.use('util.network'); var network = new util.network();
156     try {
157         data.stash_retrieve();
158         if (!data.marked_volume) {
159             alert($("catStrings").getString('staff.cat.util.transfer_copies.unmarked_volume_alert'));
160             return;
161         }
162         var xml = '<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" flex="1" style="overflow: auto">';
163         if (!params.message) {
164             params.message = $("catStrings").getFormattedString('staff.cat.util.transfer_copies.params_message', [data.hash.aou[ params.owning_lib ].shortname(), params.volume_label]);
165             //params.message = 'Transfer items from their original volumes to ';
166             //params.message += data.hash.aou[ params.owning_lib ].shortname() + "'s volume labelled ";
167             //params.message += '"' + params.volume_label + '" on the following record (and change their circ libs to match)?';
168         }
169
170         xml += '<description>' + params.message.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;') + '</description>';
171         xml += '<hbox><button label="' + $("catStrings").getString('staff.cat.util.transfer_copies.transfer.label')+ '" name="fancy_submit"/>';
172         xml += '<button label="' + $("catStrings").getString('staff.cat.util.transfer_copies.cancel.label');
173         xml += '" accesskey="'+ $("catStrings").getString('staff.cat.util.transfer_copies.cancel.accesskey') +'" name="fancy_cancel"/></hbox>';
174         xml += '<iframe style="overflow: scroll" flex="1" src="' + urls.XUL_BIB_BRIEF + '?docid=' + params.docid + '" oils_force_external="true"/>';
175         xml += '</vbox>';
176         //data.temp_transfer = xml; data.stash('temp_transfer');
177         JSAN.use('util.window'); var win = new util.window();
178         var fancy_prompt_data = win.open(
179             urls.XUL_FANCY_PROMPT,
180             //+ '?xml_in_stash=temp_transfer'
181             //+ '&title=' + window.escape('Item Transfer'),
182             'fancy_prompt', 'chrome,resizable,modal,width=500,height=300',
183             { 'xml' : xml, 'title' : $("catStrings").getString('staff.cat.util.transfer_copies.window_title') }
184         );
185         if (fancy_prompt_data.fancy_status == 'incomplete') { alert($("catStrings").getString('staff.cat.util.transfer_copies.aborted_transfer')); return; }
186
187         JSAN.use('util.functional');
188
189         var copies = network.simple_request('FM_ACP_FLESHED_BATCH_RETRIEVE.authoritative', [ params.copy_ids ]);
190
191         for (var i = 0; i < copies.length; i++) {
192             copies[i].call_number( data.marked_volume );
193             copies[i].circ_lib( params.owning_lib );
194             copies[i].ischanged( 1 );
195         }
196
197         var robj = network.simple_request(
198             'FM_ACP_FLESHED_BATCH_UPDATE', 
199             [ ses(), copies, true ], 
200             null,
201             {
202                 'title' : $("catStrings").getString('staff.cat.util.transfer_copies.override_transfer_failure'),
203                 'overridable_events' : [
204                     1208 /* TITLE_LAST_COPY */,
205                     1227 /* COPY_DELETE_WARNING */,
206                 ]
207             }
208         );
209         
210         if (typeof robj.ilsevent != 'undefined') {
211             if (
212                 (robj.ilsevent != 0)
213                 && (robj.ilsevent != 1227 /* COPY_DELETE_WARNING */)
214                 && (robj.ilsevent != 1208 /* TITLE_LAST_COPY */)
215                 && (robj.ilsevent != 5000 /* PERM_DENIED */)
216             ) {
217                 throw(robj);
218             }
219         } else {
220             alert($("catStrings").getString('staff.cat.util.transfer_copies.successful_transfer'));
221         }
222
223     } catch(E) {
224         error.standard_unexpected_error_alert($("catStrings").getString('staff.cat.util.transfer_copies.transfer_error'),E);
225     }
226 }
227
228 cat.util.spawn_spine_editor = function(selection_list) {
229     JSAN.use('util.error'); var error = new util.error();
230     try {
231         JSAN.use('util.functional');
232         xulG.new_tab(
233             xulG.url_prefix('XUL_SPINE_LABEL'),
234             { 'tab_name' : $("catStrings").getString('staff.cat.util.spine_editor.tab_name') },
235             {
236                 'barcodes' : util.functional.map_list( selection_list, function(o){return o.barcode;}) 
237             }
238         );
239     } catch(E) {
240         error.standard_unexpected_error_alert($("catStrings").getString('staff.cat.util.spine_editor.spine_editor_error'),E);
241     }
242 }
243
244 cat.util.show_in_opac = function(selection_list) {
245     JSAN.use('util.error'); var error = new util.error();
246     JSAN.use('util.network'); var network = new util.network();
247     var doc_id; var seen = {};
248     try {
249         for (var i = 0; i < selection_list.length; i++) {
250             doc_id = selection_list[i].doc_id;
251             if (!doc_id) {
252                 var barcode = selection_list[i].barcode;
253                 doc_id = network.simple_request('FM_BRE_ID_VIA_BARCODE',[barcode]);
254                 if (typeof doc_id.ilsevent != 'undefined' || doc_id == -1) {
255                     alert($("catStrings").getFormattedString('staff.cat.util.show_in_opac.unknown_barcode', [barcode]));
256                     continue;
257                 }
258             }
259             if (doc_id == -1 ) {
260                 continue; /* pre-cat */
261             }
262             if (typeof seen[doc_id] != 'undefined') {
263                 continue;
264             }
265             seen[doc_id] = true;
266             var opac_url = xulG.url_prefix('opac_rdetail') + doc_id;
267             var content_params = { 
268                 'session' : ses(),
269                 'authtime' : ses('authtime'),
270                 'opac_url' : opac_url,
271             };
272             xulG.new_tab(
273                 xulG.url_prefix('XUL_OPAC_WRAPPER'), 
274                 {'tab_name':$('catStrings').getString('staff.cat.util.show_in_opac.retrieving_title')}, 
275                 content_params
276             );
277         }
278     } catch(E) {
279         error.standard_unexpected_error_alert($("catStrings").getFormattedString('staff.cat.util.show_in_opac.catalog_error_for_doc_id', [doc_id]),E);
280     }
281 }
282
283 cat.util.add_copies_to_bucket = function(selection_list) {
284     JSAN.use('util.functional');
285     JSAN.use('util.window'); var win = new util.window();
286     JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.init({'via':'stash'});
287     data.cb_temp_copy_ids = js2JSON(
288         util.functional.map_list(
289             selection_list,
290             function (o) {
291                 if (typeof o.copy_id != 'undefined' && o.copy_id != null) {
292                     return o.copy_id;
293                 } else {
294                     return o;
295                 }
296             }
297         )
298     );
299     data.stash('cb_temp_copy_ids');
300     win.open( 
301         xulG.url_prefix('XUL_COPY_BUCKETS_QUICK'),
302         '_blank',
303         'chrome,resizable,center'
304     );
305 }
306
307 cat.util.add_titles_to_bucket = function(record_ids) {
308     JSAN.use('util.window'); var win = new util.window();
309     JSAN.use('util.functional');
310     var filtered_record_ids = util.functional.filter_list(
311         record_ids,
312         function(o) {
313             return o != -1; // don't allow the magic pre-cat bib
314         }
315     );
316     if (filtered_record_ids.length != record_ids.length) {
317         alert($("catStrings").getFormattedString(
318             'staff.cat.util.add_titles_to_bucket.number_of_precats_skipped',
319             [ record_ids.length - filtered_record_ids.length ]
320         ));
321     }
322     if (filtered_record_ids.length > 0) {
323         win.open(
324             xulG.url_prefix('XUL_RECORD_BUCKETS_QUICK'),
325             '_blank',
326             'chrome,resizable,modal,center',
327             {
328                 record_ids: filtered_record_ids
329             }
330         );
331     }
332 }
333
334 cat.util.spawn_copy_editor = function(params) {
335     try {
336         if (!params.copy_ids && !params.copies) return;
337         if (params.copy_ids && params.copy_ids.length == 0) return;
338         if (params.copies && params.copies.length == 0) return;
339         if (params.copy_ids) params.copy_ids = js2JSON(params.copy_ids); // legacy
340         if (!params.caller_handles_update) params.handle_update = 1; // legacy
341
342         var obj = {};
343         JSAN.use('util.network'); obj.network = new util.network();
344         JSAN.use('util.error'); obj.error = new util.error();
345     
346         var title = '';
347         if (params.copy_ids && params.copy_ids.length > 1 && params.edit == 1)
348             title = $("catStrings").getString('staff.cat.util.copy_editor.batch_edit');
349         else if(params.copies && params.copies.length > 1 && params.edit == 1)
350             title = $("catStrings").getString('staff.cat.util.copy_editor.batch_view');
351         else if(params.copy_ids && params.copy_ids.length == 1)
352             title = $("catStrings").getString('staff.cat.util.copy_editor.edit');
353         else
354             title = $("catStrings").getString('staff.cat.util.copy_editor.view');
355
356         JSAN.use('util.window'); var win = new util.window();
357         var my_xulG = win.open(
358             (urls.XUL_COPY_EDITOR),
359             title,
360             'chrome,modal,resizable',
361             params
362         );
363         if (!my_xulG.copies && params.edit) {
364         } else {
365             return my_xulG.copies;
366         }
367         return [];
368     } catch(E) {
369         JSAN.use('util.error'); var error = new util.error();
370         error.standard_unexpected_error_alert('error in cat.util.spawn_copy_editor',E);
371     }
372 }
373
374 cat.util.mark_item_damaged = function(copy_ids) {
375     var error;
376     try {
377         JSAN.use('util.error'); error = new util.error();
378         JSAN.use('util.functional'); JSAN.use('util.date');
379         JSAN.use('util.network'); var network = new util.network();
380         if (!copy_ids) { return; }
381         copy_ids = util.functional.filter_list( copy_ids, function(o) { return o != null; } );
382         if (copy_ids.length < 1) { return; }
383         var copies = network.simple_request('FM_ACP_FLESHED_BATCH_RETRIEVE.authoritative', [ copy_ids ]);
384         if (typeof copies.ilsevent != 'undefined') throw(copies);
385         var magic_status = false;
386         for (var i = 0; i < copies.length; i++) {
387             var status = copies[i].status(); if (typeof status == 'object') status = status.id();
388             if (typeof my_constants.magical_statuses[ status ] != 'undefined') 
389                 if (my_constants.magical_statuses[ status ].block_mark_item_damaged) magic_status = true;
390         }
391         if (magic_status) {
392         
393             error.yns_alert($("catStrings").getString('staff.cat.util.mark_item_damaged.af_message'),
394                 $("catStrings").getString('staff.cat.util.mark_item_damaged.af_title'),
395                 $("catStrings").getString('staff.cat.util.mark_item_damaged.af_ok_label'), null, null,
396                 $("catStrings").getString('staff.cat.util.mark_item_damaged.af_confirm_action'));
397
398         } else {
399
400             var r = error.yns_alert($("catStrings").getFormattedString('staff.cat.util.mark_item_damaged.md_message', [util.functional.map_list( copies, function(o) { return o.barcode(); } ).join(", ")]),
401                 $("catStrings").getString('staff.cat.util.mark_item_damaged.md_title'),
402                 $("catStrings").getString('staff.cat.util.mark_item_damaged.md_ok_label'),
403                 $("catStrings").getString('staff.cat.util.mark_item_damaged.md_cancel_label'), null,
404                 $("catStrings").getString('staff.cat.util.mark_item_damaged.md_confirm_action'));
405
406             if (r == 0) {
407                 var count = 0;
408                 for (var i = 0; i < copies.length; i++) {
409                     try {
410
411                         var my_circ = network.simple_request('FM_CIRC_RETRIEVE_VIA_COPY',[ses(),copies[i].id(),1]);
412                         if (typeof my_circ.ilsevent == 'undefined') { 
413                             JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.stash_retrieve();
414                             my_circ = my_circ[0];
415                             if (typeof my_circ != 'undefined') {
416                                 if (! my_circ.checkin_time() ) {
417                                     var due_date = my_circ.due_date() ? util.date.formatted_date( my_circ.due_date(), '%F' ) : null;
418                                     var auto_checkin = String( data.hash.aous['circ.auto_checkin_on_mark_damage'] ) == 'true';
419                                     /* short-circuit this behavior.  We don't want to mark an item damaged and still have it circulating.  At least for now.  Wait until someone asks for it. */
420                                     auto_checkin = true; 
421                                     JSAN.use('patron.util');
422                                     var patron_obj = patron.util.retrieve_fleshed_au_via_id( ses(), my_circ.usr() );
423                                     var patron_name = patron.util.format_name( patron_obj ) + ' : ' + patron_obj.card().barcode();
424                                     var msg = $("catStrings").getFormattedString('staff.cat.util.mark_item_damaged.item_circulating_to_patron', [ 
425                                         copies[i].barcode(),
426                                         patron_name,
427                                         util.date.formatted_date( my_circ.due_date(), '%{localized}' )]);
428                                     JSAN.use('util.date'); var today = util.date.formatted_date(new Date(),'%F');
429                                     var r2 = auto_checkin ? 1 : error.yns_alert(
430                                         msg,
431                                         document.getElementById('catStrings').getString('staff.cat.util.mark_item_damaged.checkin.title'),
432                                         document.getElementById('catStrings').getString('staff.cat.util.mark_item_damaged.checkin.no_checkin'),
433                                         document.getElementById('catStrings').getString('staff.cat.util.mark_item_damaged.checkin.normal_checkin'),
434                                         due_date ? (today > due_date ? document.getElementById('catStrings').getString('staff.cat.util.mark_item_damaged.checkin.forgiving_checkin') : null) : null,
435                                         document.getElementById('catStrings').getString('staff.cat.util.mark_item_damaged.checkin.confirm_action')
436                                     );
437                                     JSAN.use('circ.util');
438                                     switch(r2) {
439                                         case 1:
440                                             circ.util.checkin_via_barcode( ses(), { 'barcode' : copies[i].barcode(), 'noop' : 1 } );
441                                         break;
442                                         case 2:
443                                             circ.util.checkin_via_barcode( ses(), { 'barcode' : copies[i].barcode(), 'noop' : 1 }, due_date );
444                                         break;
445                                     }
446                                 }
447                             }
448                         }
449
450                         var robj = network.simple_request('MARK_ITEM_DAMAGED',[ses(),copies[i].id()]);
451                         if (typeof robj.ilsevent != 'undefined') {
452                             switch(robj.textcode) {
453                                 case 'DAMAGE_CHARGE' :
454                                     var params = {};
455                                     JSAN.use('util.money');
456                                     var circ_obj = robj.payload.circ;
457                                     var patron_obj = circ_obj.usr();
458                                     JSAN.use('patron.util'); 
459                                     var patron_name = patron.util.format_name( patron_obj ) + ' : ' + patron_obj.card().barcode(); 
460                                     var r1 = error.yns_alert( 
461                                         $("catStrings").getFormattedString('staff.cat.util.mark_item_damaged.charge_patron_prompt.message', [  
462                                             copies[i].barcode(),  
463                                             patron_name,  
464                                             util.date.formatted_date( circ_obj.checkin_time(), '%{localized}' ),
465                                             util.money.sanitize(robj.payload.charge) ]), 
466                                         $("catStrings").getString('staff.cat.util.mark_item_damaged.charge_patron_prompt.title'), 
467                                         $("catStrings").getString('staff.cat.util.mark_item_damaged.charge_patron_prompt.ok_label'), 
468                                         $("catStrings").getString('staff.cat.util.mark_item_damaged.charge_patron_prompt.change_amount_label'), 
469                                         $("catStrings").getString('staff.cat.util.mark_item_damaged.charge_patron_prompt.cancel_label'), 
470                                         $("catStrings").getString('staff.cat.util.mark_item_damaged.charge_patron_prompt.confirm_action')); 
471                                     if (r1 == 0) {
472                                         params.apply_fines = 'apply';
473                                     } else if (r1 == 1) { 
474                                         JSAN.use('util.window'); var win = new util.window();
475                                         var my_xulG = win.open(
476                                             urls.XUL_PATRON_BILL_WIZARD,
477                                             'billwizard',
478                                             'chrome,resizable,modal',
479                                             { 
480                                                 'patron' : patron_obj, 
481                                                 'patron_id' : patron_obj.id(), 
482                                                 'circ' : circ_obj, 
483                                                 'xact_id' : circ_obj.id(), 
484                                                 'do_not_process_bill' : true,
485                                                 /* 'override_default_billing_type' : 7, FIXME: maybe reintroduce this with an org setting for the specific btype? */
486                                                 'override_default_price' : util.money.sanitize( robj.payload.charge ) 
487                                             }
488                                         );
489
490                                         params.apply_fines = my_xulG.proceed ? 'apply' : 'noapply';
491                                         if (my_xulG.proceed) {
492                                             params.override_amount = my_xulG.amount;
493                                             params.override_btype = my_xulG.cbt_id;
494                                             params.override_note = my_xulG.note;
495                                         }
496                                     } else {
497                                         params.apply_fines = 'noapply';
498                                     }
499                                     robj = network.simple_request('MARK_ITEM_DAMAGED',[ ses(), copies[i].id(), params ]);
500                                     if (typeof robj.ilsevent != 'undefined') { throw(robj); }
501                                     break;
502                                 default: throw(robj);
503                             }
504                         }
505                         count++;
506                     } catch(E) {
507                         error.standard_unexpected_error_alert($("catStrings").getFormattedString('staff.cat.util.mark_item_damaged.marking_error', [copies[i].barcode()]),E);
508                     }
509                 }
510                 alert(count == 1 ? $("catStrings").getString('staff.cat.util.mark_item_damaged.one_item_damaged') :
511                     $("catStrings").getFormattedString('staff.cat.util.mark_item_damaged.multiple_item_damaged', [count]));
512             }
513         }
514
515     } catch(E) {
516         if (error) error.standard_unexpected_error_alert('cat.util.mark_item_damaged',E); else alert('FIXME: ' + E);
517     }
518 }
519
520 cat.util.mark_item_missing = function(copy_ids) {
521     var error;
522     try {
523         JSAN.use('util.error'); error = new util.error();
524         JSAN.use('util.functional');
525         JSAN.use('util.network'); var network = new util.network();
526         if (!copy_ids) { return; }
527         copy_ids = util.functional.filter_list( copy_ids, function(o) { return o != null; } );
528         if (copy_ids.length < 1) { return; }
529         var copies = network.simple_request('FM_ACP_FLESHED_BATCH_RETRIEVE.authoritative', [ copy_ids ]);
530         if (typeof copies.ilsevent != 'undefined') throw(copies);
531         var magic_status = false;
532         for (var i = 0; i < copies.length; i++) {
533             var status = copies[i].status(); if (typeof status == 'object') status = status.id();
534             if (typeof my_constants.magical_statuses[ status ] != 'undefined') 
535                 if (my_constants.magical_statuses[ status ].block_mark_item_action) magic_status = true;
536         }
537         if (magic_status) {
538         
539             error.yns_alert($("catStrings").getString('staff.cat.util.mark_item_missing.af_message'),
540                 $("catStrings").getString('staff.cat.util.mark_item_missing.af_title'),
541                 $("catStrings").getString('staff.cat.util.mark_item_missing.af_ok_label'), null, null,
542                 $("catStrings").getString('staff.cat.util.mark_item_missing.af_confirm_action'));
543
544         } else {
545
546             var r = error.yns_alert($("catStrings").getFormattedString('staff.cat.util.mark_item_missing.ms_message', [util.functional.map_list( copies, function(o) { return o.barcode(); } ).join(", ")]),
547                 $("catStrings").getString('staff.cat.util.mark_item_missing.ms_title'),
548                 $("catStrings").getString('staff.cat.util.mark_item_missing.ms_ok_label'),
549                 $("catStrings").getString('staff.cat.util.mark_item_missing.ms_cancel_label'), null,
550                 $("catStrings").getString('staff.cat.util.mark_item_missing.ms_confirm_action'));
551
552             if (r == 0) {
553                 var count = 0;
554                 for (var i = 0; i < copies.length; i++) {
555                     try {
556                         var robj = network.simple_request('MARK_ITEM_MISSING',[ses(),copies[i].id()]);
557                         if (typeof robj.ilsevent != 'undefined') throw(robj);
558                         count++;
559                     } catch(E) {
560                         error.standard_unexpected_error_alert($("catStrings").getFormattedString('staff.cat.util.mark_item_missing.marking_error', [copies[i].barcode()]),E);
561                     }
562                 }
563                 alert(count == 1 ? $("catStrings").getString('staff.cat.util.mark_item_missing.one_item_missing') :
564                     $("catStrings").getFormattedString('staff.cat.util.mark_item_missing.multiple_item_missing', [count]));
565             }
566         }
567
568     } catch(E) {
569         if (error) error.standard_unexpected_error_alert('cat.util.mark_item_missing',E); else alert('FIXME: ' + E);
570     }
571 }
572
573 cat.util.fast_item_add = function(doc_id,cn_label,cp_barcode) {
574     var error;
575     JSAN.use('OpenILS.data'); var data = new OpenILS.data();
576     try {
577
578         JSAN.use('util.error'); error = new util.error();
579         JSAN.use('util.network'); var network = new util.network();
580
581         var acn_blob = network.simple_request(
582             'FM_ACN_FIND_OR_CREATE',
583             [ ses(), cn_label, doc_id, ses('ws_ou') ]
584         );
585
586         if (typeof acn_blob.ilsevent != 'undefined') {
587             error.standard_unexpected_error_alert($("catStrings").getFormattedString('staff.cat.volume_copy_creator.stash_and_close.problem_with_volume', [cn]), acn_blob);
588             return;
589         }
590
591         // Get the default copy status; default to available if unset, per 1.6
592         var fast_ccs = data.hash.aous['cat.default_copy_status_fast'] || 0;
593
594         var copy_obj = new acp();
595         copy_obj.id( -1 );
596         copy_obj.isnew('1');
597         copy_obj.barcode( cp_barcode );
598         copy_obj.call_number( acn_blob.acn_id );
599         copy_obj.circ_lib( ses('ws_ou') );
600         /* FIXME -- use constants */
601         copy_obj.deposit(0);
602         copy_obj.price(0);
603         copy_obj.deposit_amount(0);
604         copy_obj.fine_level(2); // Normal
605         copy_obj.loan_duration(2); // Normal
606         copy_obj.location(1); // Stacks
607         copy_obj.status(fast_ccs);
608         copy_obj.circulate(get_db_true());
609         copy_obj.holdable(get_db_true());
610         copy_obj.opac_visible(get_db_true());
611         copy_obj.ref(get_db_false());
612         copy_obj.mint_condition(get_db_true());
613
614         JSAN.use('util.window'); var win = new util.window();
615         JSAN.use('cat.util');
616
617         var unified_interface = String( data.hash.aous['ui.unified_volume_copy_editor'] ) == 'true';
618         if (unified_interface) {
619             var horizontal_interface = String( data.hash.aous['ui.cat.volume_copy_editor.horizontal'] ) == 'true';
620             var url = window.xulG.url_prefix( horizontal_interface ? 'XUL_VOLUME_COPY_CREATOR_HORIZONTAL' : 'XUL_VOLUME_COPY_CREATOR' );
621             var w = xulG.set_tab(
622                 url,
623                 {
624                     'tab_name' : document.getElementById('offlineStrings').getFormattedString(
625                         'cat.bib_record',
626                         [ doc_id ]
627                     )
628                 },
629                 {
630                     'doc_id' : doc_id, 
631                     'existing_copies' : [ copy_obj ],
632                     'load_opac_when_done' : true,
633                     'labels_in_new_tab' : true
634                 }
635             );
636
637         } else {
638             return cat.util.spawn_copy_editor( { 'handle_update' : 1, 'edit' : 1, 'docid' : doc_id, 'copies' : [ copy_obj ] });
639         }
640
641     } catch(E) {
642         if (error) error.standard_unexpected_error_alert('cat.util.fast_item_add',E); else alert('FIXME: ' + E);
643     }
644 }
645
646 cat.util.make_bookable = function(copy_ids) {
647     if (!copy_ids) { return; }
648     copy_ids = util.functional.filter_list( copy_ids, function(o) { return o != null; } );
649     if (copy_ids.length < 1) { return; }
650     var results = fieldmapper.standardRequest(
651         ["open-ils.booking", "open-ils.booking.resources.create_from_copies"],
652         [ses(), copy_ids]
653     );
654     if (results == null) {
655         alert(document.getElementById("catStrings").getString(
656             "staff.cat.copy_browser.make_bookable.create_failed_silent"
657         ));
658     }
659     else if (typeof results.ilsevent != "undefined") {
660         alert(document.getElementById("catStrings").getFormattedString(
661             "staff.cat.copy_browser.make_bookable.create_failed",
662             [results.ilsevent, results.textcode, results.desc, results.debug]
663         ));
664     }
665     return results;
666 }
667
668 cat.util.edit_new_brsrc = function(brsrc_list) {
669     /* Spawn new tab to allow editing new resources. */
670     try {
671         xulG.resultant_brsrc = brsrc_list.map(function(o) { return o[0]; });
672         xulG.new_tab(
673             urls.XUL_BROWSER + "?url=" + window.escape(
674                 xulG.url_prefix("BOOKING_RESOURCE")
675             ), {
676                 "tab_name": offlineStrings.getString(
677                     "menu.cmd_booking_resource.tab"
678                  ),
679                 "browser" : true
680             }, {
681                 "no_xulG": false,
682                 "show_print_button": false,
683                 "show_nav_buttons": true,
684                 "passthru_content_params": xulG
685             }
686         );
687     } catch(E) {
688         alert(
689             document.getElementById("catStrings").getFormattedString(
690                 "staff.cat.copy_browser.make_bookable.newtab_failed"
691             ), E
692         );
693     }
694 }
695
696 cat.util.edit_new_bresv = function(booking_results) {
697     /* Spawn new tab to allow editing new reservations. */
698     try {
699         if (xulG.auth == undefined) {
700             xulG.auth = {"session": {"key": ses()}};
701         }
702         xulG.bresv_interface_opts = {"booking_results": booking_results};
703         xulG.new_tab(
704             xulG.url_prefix("/eg/booking/reservation"),
705             {
706                 "tab_name": offlineStrings.getString(
707                     "menu.cmd_booking_reservation.tab"
708                  ),
709                 "browser" : false
710             }, xulG
711         );
712     } catch(E) {
713         alert(
714             document.getElementById("catStrings").getString(
715                 "staff.cat.copy_browser.make_bookable.newtab_failed"
716             ) + E
717         );
718     }
719 }
720
721 cat.util.batch_edit_volumes = function(fleshed_volumes) {
722     try {
723         if (!fleshed_volumes || fleshed_volumes.length < 1) { return false; }
724
725         JSAN.use('util.functional');
726         JSAN.use('util.network'); var net = new util.network();
727         JSAN.use('util.window'); var win = new util.window();
728
729         var can_edit = net.simple_request(
730             'PERM_MULTI_ORG_CHECK',
731             [
732                 ses(),
733                 ses('staff_id'),
734                 util.functional.map_list(
735                     fleshed_volumes,
736                     function(v) {
737                         return v.owning_lib();
738                     }
739                 ),
740                 ['UPDATE_VOLUME']
741             ]
742         );
743         if (!can_edit) {
744             alert(document.getElementById('catStrings').getString('staff.cat.edit_volume.permission_error'));
745             return false;
746         }
747         var title;
748         if (fleshed_volumes.length == 1) {
749             title = document.getElementById('catStrings').getString('staff.cat.edit_volume.title');
750         } else {
751             title = document.getElementById('catStrings').getString('staff.cat.edit_volume.title.plural');
752         }
753
754         function clone_list(o) {
755             var list = JSON2js( js2JSON( o ) );
756             // now that it is safe to clear copies, let's do so, otherwise may get an error from volume edit method
757             for (var i = 0; i < list.length; i++) { list[i].copies( [] ); } 
758             return list;
759         }
760
761         var my_xulG = win.open(
762             xulG.url_prefix('XUL_VOLUME_EDITOR'),
763             title,
764             'chrome,modal,resizable',
765             { 'volumes' : clone_list( fleshed_volumes ) }
766         );
767
768         if (typeof my_xulG.update_these_volumes == 'undefined') { return false; }
769
770         var volumes = util.functional.filter_list(
771             my_xulG.volumes,
772             function(v) {
773                 return get_bool( v.ischanged() );
774             }
775         );
776
777         if (volumes.length < 1) { return false; }
778
779         volumes = util.functional.map_list( volumes, function(o){
780             if (typeof o.suffix() == 'object') { o.suffix( o.suffix().id() ); }
781             if (typeof o.prefix() == 'object') { o.prefix( o.prefix().id() ); }
782             if (typeof o.label_class() == 'object') { o.label_class( o.label_class().id() ); }
783             return o;
784         });
785
786         var r = net.simple_request(
787             'FM_ACN_TREE_UPDATE',
788             [ ses(), volumes, false, { 'auto_merge_vols' : my_xulG.auto_merge } ],
789             null,
790             {
791                 'title' : document.getElementById('catStrings').getString('staff.cat.edit_volumes.override.confirm'),
792                 'overridable_events' : [
793                     1705 /* VOLUME_LABEL_EXISTS */
794                 ],
795                 'text' : {
796                     '1705' : function(r) {
797                         var payload_acn = util.functional.find_id_object_in_list( volumes, r.payload );
798                         return document.getElementById('catStrings').getFormattedString('staff.cat.edit_volumes.label_exists.details',[payload_acn.label()]);
799                     }
800                 }
801             }
802         );
803         if (!r) { throw('Update method returned null or false.'); }
804         if (typeof r.ilsevent != 'undefined') {
805             if (r.ilsevent == 1705 /* VOLUME_LABEL_EXISTS */) {
806                /* not overriden, but otherwise handled, so ignore */
807                 return false;
808             } else {
809                 throw(r);
810             }
811         }
812
813         return true;
814
815     } catch(E) {
816         alert('Error in cat.util.batch_edit_volumes: ' + E);
817         return false;
818     }
819 }
820
821 cat.util.render_fine_level = function(value) {
822     var text;
823     switch(Number(value)){
824         case 1: text = document.getElementById("catStrings").getString("staff.cat.copy_editor.field.fine_level.low"); break;
825         case 2: text = document.getElementById("catStrings").getString("staff.cat.copy_editor.field.fine_level.normal"); break;
826         case 3: text = document.getElementById("catStrings").getString("staff.cat.copy_editor.field.fine_level.high"); break; 
827     }
828     return text;
829 }
830 cat.util.render_loan_duration = function(value) {
831     var text;
832     switch(Number(value)){
833         case 1: text = document.getElementById("catStrings").getString("staff.cat.copy_editor.field.loan_duration.short"); break;
834         case 2: text = document.getElementById("catStrings").getString("staff.cat.copy_editor.field.loan_duration.normal"); break;
835         case 3: text = document.getElementById("catStrings").getString("staff.cat.copy_editor.field.loan_duration.extended"); break;
836     }
837     return text;
838 }
839
840 cat.util.mark_item_as_missing_pieces = function(copy_ids) {
841     var error;
842     try {
843         JSAN.use('util.error'); error = new util.error();
844         JSAN.use('util.functional'); JSAN.use('util.date');
845         JSAN.use('util.network'); var network = new util.network();
846         JSAN.use('util.print'); var print = new util.print();
847         JSAN.use('util.window'); var win = new util.window();
848         if (!copy_ids) { return; }
849         copy_ids = util.functional.filter_list( copy_ids, function(o) { return o != null; } );
850         if (copy_ids.length < 1) { return; }
851         var copies = network.simple_request('FM_ACP_FLESHED_BATCH_RETRIEVE.authoritative', [ copy_ids ]);
852         if (typeof copies.ilsevent != 'undefined') throw(copies);
853
854         var r = error.yns_alert($("catStrings").getFormattedString('staff.cat.util.mark_item_missing_pieces.ms_message', [util.functional.map_list( copies, function(o) { return o.barcode(); } ).join(", ")]),
855             $("catStrings").getString('staff.cat.util.mark_item_missing_pieces.ms_title'),
856             $("catStrings").getString('staff.cat.util.mark_item_missing_pieces.ms_ok_label'),
857             $("catStrings").getString('staff.cat.util.mark_item_missing_pieces.ms_cancel_label'), null,
858             $("catStrings").getString('staff.cat.util.mark_item_missing_pieces.ms_confirm_action'));
859
860         if (r == 0) {
861             var count = 0;
862             JSAN.use('cat.util');
863             for (var i = 0; i < copies.length; i++) {
864                 try {
865                     var robj = network.simple_request('MARK_ITEM_MISSING_PIECES',[ses(),copies[i].id()]);
866                     if (typeof robj.ilsevent != 'undefined') {
867                         if (robj.ilsevent == 0 /* SUCCESS */) {
868                             count++;
869                             // Print Slip
870                             if (robj.payload && robj.payload.slip) {
871                                 print.simple( robj.payload.slip.template_output().data() );
872                             }
873                             // Item Note
874                             cat.util.spawn_copy_editor( { 'copy_ids' : [ copies[i].id() ], 'edit' : 1 } );
875                             // Patron Message
876                             var my_xulG = win.open(
877                                 urls.XUL_NEW_STANDING_PENALTY,
878                                 'new_standing_penalty',
879                                 'chrome,resizable,modal',
880                                 {}
881                             );
882                             if (my_xulG.id) {
883                                 var penalty = new ausp();
884                                 penalty.usr( robj.payload.circ.usr() );
885                                 penalty.isnew( 1 );
886                                 penalty.standing_penalty( my_xulG.id );
887                                 penalty.org_unit( ses('ws_ou') );
888                                 penalty.note( my_xulG.note );
889                                 network.simple_request(
890                                     'FM_AUSP_APPLY',
891                                     [ ses(), penalty ]
892                                 );
893                             }
894                             // Patron Letter
895
896                             var txt_file = new util.file('letter.txt');
897                             txt_file.write_content('truncate',robj.payload.letter.template_output().data());
898                             var text_path = '"' + txt_file._file.path + '"';
899                             txt_file.close();
900
901                             var prefs = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces['nsIPrefBranch']);
902                             var key = 'oils.text_editor.external.cmd';
903                             var has_key = prefs.prefHasUserValue(key);
904                             var oils_external_letter_opener_cmd = has_key ? prefs.getCharPref(key) : 'C:\\Windows\\notepad.exe %letter.txt%';
905
906                             var cmd = oils_external_letter_opener_cmd.replace('%letter.txt%',text_path);
907
908                             var file = new util.file('letter.bat');
909                             file.write_content('truncate+exec',cmd);
910                             file.close();
911                             file = new util.file('letter.bat');
912
913                             dump('letter exec: ' + cmd + '\n');
914                             var process = Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess);
915                             process.init(file._file);
916
917                             var args = [];
918
919                             dump('process.run = ' + process.run(false, args, args.length) + '\n');
920
921                             file.close();
922
923                         } else if (robj.ilsevent == 1500 /* ACTION_CIRCULATION_NOT_FOUND */) {
924                             alert( $("catStrings").getFormattedString('staff.cat.util.mark_item_missing_pieces.circ_not_found',[ copies[i].barcode() ]) );
925                         } else {
926                             throw(robj);
927                         }
928                     } else {
929                         throw(robj);
930                     }
931                 } catch(E) {
932                     error.standard_unexpected_error_alert($("catStrings").getFormattedString('staff.cat.util.mark_item_missing_pieces.marking_error', [copies[i].barcode()]),E);
933                 }
934             }
935             /*alert(count == 1 ? $("catStrings").getString('staff.cat.util.mark_item_missing_pieces.one_item_missing_pieces') :
936                 $("catStrings").getFormattedString('staff.cat.util.mark_item_missing_pieces.multiple_item_missing_pieces', [count]));*/
937         }
938
939         return true;
940     } catch(E) {
941         alert('Error in cat.util.mark_item_as_missing_pieces: ' + E);
942         return false;
943     }
944 }
945
946 cat.util.render_callnumbers_for_bib_menu = function(node, doc_id, label_class) {
947     try {
948         var cn_blob;
949         try {
950             cn_blob = g.network.simple_request('BLOB_MARC_CALLNUMBERS_RETRIEVE',[doc_id, label_class]);
951         } catch(E) {
952             cn_blob = [];
953         }
954         var hbox = typeof node == 'string' ? document.getElementById(node) : node;
955         JSAN.use('util.widgets');
956         JSAN.use('util.functional');
957         var ml = util.widgets.make_menulist(
958             [
959                 [ '', '' ]
960             ].concat(
961                 util.functional.map_list(
962                     cn_blob,
963                     function(o) {
964                         for (var i in o) {
965                             return [ o[i], i ];
966                         }
967                     }
968                 )
969             )
970         ); hbox.appendChild(ml);
971         ml.setAttribute('editable','true');
972         ml.setAttribute('width', '200');
973         ml.setAttribute('id', hbox.id + '_menulist');
974     } catch(E) {
975         alert('Error in cat.util.render_callnumbers_for_bib_menu: ' + E);
976     }
977 }
978
979 cat.util.render_cn_prefix_menuitems = function(menupopup,ou_id) {
980     try {
981         JSAN.use('OpenILS.data');
982         var data = new OpenILS.data(); data.stash_retrieve();
983         JSAN.use('util.network');
984         var network = new util.network();
985
986         if (typeof data.list['acnp_for_lib_'+ou_id] == 'undefined') {
987             data.list['acnp_for_lib_'+ou_id] = network.simple_request(
988                 'FM_ACNP_RETRIEVE_VIA_PCRUD',
989                 [ ses(), {"owning_lib":{"=":ou_id}}, {"order_by":{"acnp":"label_sortkey"}} ]
990             );
991             data.stash('list');
992         }
993         for (var i = 0; i < data.list['acnp_for_lib_'+ou_id].length; i++) {
994             var my_acnp = data.list['acnp_for_lib_'+ou_id][i];
995             var menuitem = document.createElement('menuitem');
996             menupopup.appendChild(menuitem);
997                 menuitem.setAttribute(
998                     'label',
999                     my_acnp.id() == -1 ? '' :
1000                     $('catStrings').getFormattedString(
1001                         'staff.cat.volume_copy_creator.call_number_prefix.menuitem_label',
1002                         [
1003                             my_acnp.label(),
1004                             data.hash.aou[ ou_id ].shortname()
1005                         ]
1006                     )
1007                 );
1008                 menuitem.setAttribute('value',my_acnp.id());
1009         }
1010     } catch(E) {
1011         alert('Error in cat.util.render_cn_prefix_menuitems: ' + E);
1012     }
1013 }
1014
1015 cat.util.render_cn_suffix_menuitems = function(menupopup,ou_id) {
1016     try {
1017         JSAN.use('OpenILS.data');
1018         var data = new OpenILS.data(); data.stash_retrieve();
1019         JSAN.use('util.network');
1020         var network = new util.network();
1021
1022         if (typeof data.list['acns_for_lib_'+ou_id] == 'undefined') {
1023             data.list['acns_for_lib_'+ou_id] = network.simple_request(
1024                 'FM_ACNS_RETRIEVE_VIA_PCRUD',
1025                 [ ses(), {"owning_lib":{"=":ou_id}}, {"order_by":{"acns":"label_sortkey"}} ]
1026             );
1027             data.stash('list');
1028         }
1029         for (var i = 0; i < data.list['acns_for_lib_'+ou_id].length; i++) {
1030             var my_acns = data.list['acns_for_lib_'+ou_id][i];
1031             var menuitem = document.createElement('menuitem');
1032             menupopup.appendChild(menuitem);
1033                 menuitem.setAttribute(
1034                     'label',
1035                     my_acns.id() == -1 ? '' :
1036                     $('catStrings').getFormattedString(
1037                         'staff.cat.volume_copy_creator.call_number_suffix.menuitem_label',
1038                         [
1039                             my_acns.label(),
1040                             data.hash.aou[ ou_id ].shortname()
1041                         ]
1042                     )
1043                 );
1044                 menuitem.setAttribute('value',my_acns.id());
1045         }
1046     } catch(E) {
1047         alert('Error in cat.util.render_cn_suffix_menuitems: ' + E);
1048     }
1049 }
1050
1051 cat.util.render_cn_class_menu = function(extra_menuitems,menu_default) {
1052     try {
1053         JSAN.use('util.widgets');
1054         JSAN.use('OpenILS.data');
1055         var data = new OpenILS.data(); data.stash_retrieve();
1056
1057         var menulist = util.widgets.make_menulist(
1058             (extra_menuitems || []).concat(
1059                 util.functional.map_list(
1060                     data.list.acnc,
1061                     function(o) {
1062                         return [ o.name(), o.id() ];
1063                     }
1064                 )
1065             )
1066         );
1067
1068         if (typeof menu_default != 'undefined') {
1069             menulist.setAttribute('value',menu_default);
1070         }
1071         return menulist;
1072
1073     } catch(E) {
1074         alert('Error in cat.util.render_cn_class_menu: ' + E);
1075     }
1076 }
1077
1078 cat.util.render_cn_prefix_menu = function(ou_ids,extra_menuitems,menu_default) {
1079     try {
1080         JSAN.use('util.widgets');
1081         var menulist = util.widgets.make_menulist(extra_menuitems||[],menu_default);
1082             var menupopup = menulist.firstChild;
1083             var org_list;
1084             if (ou_ids.length == 1) {
1085                 JSAN.use('OpenILS.data');
1086                 var data = new OpenILS.data(); data.stash_retrieve();
1087                 var org = data.hash.aou[ ou_ids[0] ];
1088                 org_list = []; // order from top of consortium to owning lib
1089                 while(org) {
1090                     org_list.unshift(org.id());
1091                     org = org.parent_ou();
1092                     if (org && typeof org != 'object') {
1093                         org = data.hash.aou[ org ];
1094                     }
1095                 }
1096             } else {
1097                 org_list = ou_ids;
1098             }
1099             for (var i = 0; i < org_list.length; i++) {
1100                 cat.util.render_cn_prefix_menuitems(menupopup,org_list[i]);
1101             }
1102         if (typeof menu_default != 'undefined') {
1103             menulist.setAttribute('value',menu_default);
1104         }
1105         return menulist;
1106     } catch(E) {
1107         alert('Error in cat.util.render_cn_prefix_menu('+ou_id+'): ' + E);
1108     }
1109 }
1110
1111 cat.util.render_cn_suffix_menu = function(ou_ids,extra_menuitems,menu_default) {
1112     try {
1113         JSAN.use('util.widgets');
1114         var menulist = util.widgets.make_menulist(extra_menuitems||[],menu_default);
1115             var menupopup = menulist.firstChild;
1116             var org_list;
1117             if (ou_ids.length == 1) {
1118                 JSAN.use('OpenILS.data');
1119                 var data = new OpenILS.data(); data.stash_retrieve();
1120                 var org = data.hash.aou[ ou_ids[0] ];
1121                 org_list = []; // order from top of consortium to owning lib
1122                 while(org) {
1123                     org_list.unshift(org.id());
1124                     org = org.parent_ou();
1125                     if (org && typeof org != 'object') {
1126                         org = data.hash.aou[ org ];
1127                     }
1128                 }
1129             } else {
1130                 org_list = ou_ids;
1131             }
1132             for (var i = 0; i < org_list.length; i++) {
1133                 cat.util.render_cn_suffix_menuitems(menupopup,org_list[i]);
1134             }
1135         if (typeof menu_default != 'undefined') {
1136             menulist.setAttribute('value',menu_default);
1137         }
1138         return menulist;
1139     } catch(E) {
1140         alert('Error in cat.util.render_cn_suffix_menu('+ou_id+'): ' + E);
1141     }
1142 }
1143
1144 cat.util.request_items = function(copy_ids) {
1145     var error;
1146     try {
1147         JSAN.use('util.error');
1148         error = new util.error();
1149
1150         JSAN.use('util.functional');
1151         if (!copy_ids) { return; }
1152         copy_ids = util.functional.filter_list(
1153             copy_ids,
1154             function(o) { return o != null; }
1155         );
1156         if (copy_ids.length < 1) { return; }
1157
1158         xulG.new_tab(
1159             urls.XUL_HOLD_PLACEMENT,
1160             {},
1161             {
1162                 'copy_ids' : copy_ids
1163             }
1164         );
1165
1166     } catch(E) {
1167         alert('Error in cat.util.request_items: ' + E);
1168     }
1169 }
1170
1171 cat.util.mark_for_overlay = function(doc_id,doc_mvr) {
1172
1173     try {
1174
1175         JSAN.use('OpenILS.data'); var data = new OpenILS.data();
1176         data.stash_retrieve();
1177         JSAN.use('util.network'); var network = new util.network();
1178
1179         function gen_statusbar_click_handler(data_key) {
1180             return function (ev) {
1181
1182                 if (! data[data_key]) {
1183                     return;
1184                 }
1185
1186                 if (ev.button == 0 /* left click, spawn opac */) {
1187                     var opac_url = xulG.url_prefix('opac_rdetail')
1188                         + data[data_key];
1189                     var content_params = {
1190                         'session' : ses(),
1191                         'authtime' : ses('authtime'),
1192                         'opac_url' : opac_url,
1193                     };
1194                     xulG.new_tab(
1195                         xulG.url_prefix('XUL_OPAC_WRAPPER'),
1196                         {'tab_name':'Retrieving title...'},
1197                         content_params
1198                     );
1199                 }
1200
1201                 if (ev.button == 2 /* right click, remove mark */) {
1202                     if ( window.confirm( $('offlineStrings').getString(
1203                             'cat.opac.clear_statusbar')
1204                     ) ) {
1205                         data[data_key] = null;
1206                         data.stash(data_key);
1207                         ev.target.setAttribute('label','');
1208                         if (ev.target.hasAttribute('tooltiptext')) {
1209                             ev.target.removeAttribute('tooltiptext');
1210                         }
1211                     }
1212                 }
1213             }
1214         }
1215
1216         data.marked_record = doc_id;
1217         data.stash('marked_record');
1218         if (!doc_mvr) {
1219             var robj = network.simple_request(
1220                 'MODS_SLIM_RECORD_RETRIEVE.authoritative',[doc_id]);
1221             if (typeof robj.ilsevent == 'undefined') {
1222                 data.marked_record_mvr = robj;
1223             } else {
1224                 data.marked_record_mvr = null;
1225                 alert('Error in cat.util.mark_for_overlay #2: ', js2JSON(robj));
1226             }
1227         } else {
1228             data.marked_record_mvr = doc_mvr;
1229         }
1230         data.stash('marked_record_mvr');
1231         if (data.marked_record_mvr) {
1232             alert(
1233                 $('offlineStrings').getFormattedString(
1234                     'cat.opac.record_marked_for_overlay.tcn.alert',
1235                     [ data.marked_record_mvr.tcn() ]
1236                 )
1237             );
1238             xulG.set_statusbar(
1239                 1,
1240                 $("offlineStrings").getFormattedString(
1241                     'staff.cat.z3950.marked_record_for_overlay_indicator.tcn.label',
1242                     [data.marked_record_mvr.tcn()]
1243                 ),
1244                 $("offlineStrings").getFormattedString(
1245                     'staff.cat.z3950.marked_record_for_overlay_indicator.record_id.label',
1246                     [data.marked_record]
1247                 ),
1248                 gen_statusbar_click_handler('marked_record')
1249             );
1250         } else {
1251             alert(
1252                 $('offlineStrings').getFormattedString(
1253                     'cat.opac.record_marked_for_overlay.record_id.alert',
1254                     [ data.marked_record  ]
1255                 )
1256             );
1257             xulG.set_statusbar(
1258                 1,
1259                 $("offlineStrings").getFormattedString(
1260                     'staff.cat.z3950.marked_record_for_overlay_indicator.record_id.label',
1261                     [data.marked_record]
1262                 ),
1263                 '',
1264                 gen_statusbar_click_handler('marked_record')
1265             );
1266         }
1267     } catch(E) {
1268         alert('Error in cat.util.mark_for_overlay(): ' + E);
1269     }
1270 }
1271
1272 cat.util.get_cbs_for_bre_id = function(doc_id) {
1273     try {
1274         JSAN.use('util.network'); var network = new util.network();
1275         var bibObj = network.simple_request(
1276             'FM_BRE_RETRIEVE_VIA_ID',
1277             [ ses(), [ doc_id ] ]
1278         );
1279         bibObj = bibObj[0];
1280         var cbsObj = network.simple_request(
1281             'FM_CBS_RETRIEVE_VIA_PCRUD',
1282             [ ses(), bibObj.source() ]
1283         );
1284         return cbsObj;
1285     } catch(E) {
1286         alert('Error in cat.util.cbs_can_have_copies(): ' + E);
1287     }
1288 }
1289
1290 dump('exiting cat/util.js\n');