]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/xul/staff_client/server/cat/volume_copy_creator.js
Merge remote-tracking branch 'eg-working/collab/phasefx/merged_bill_and_receipt_fixes'
[Evergreen.git] / Open-ILS / xul / staff_client / server / cat / volume_copy_creator.js
1 const g_max_copies_that_can_be_added_at_a_time_per_volume = 999;
2 const rel_vert_pos_volume_count = 1;
3 const rel_vert_pos_call_number_classification = 2;
4 const rel_vert_pos_call_number_prefix = 3;
5 const rel_vert_pos_call_number = 4;
6 const rel_vert_pos_call_number_suffix = 5;
7 const rel_vert_pos_copy_count = 6;
8 const rel_vert_pos_barcode = 7;
9 const rel_vert_pos_part = 8;
10 const update_timer = 1000;
11 var g = {};
12 g.use_defaults = true;
13 g.acn_map = {}; // store retrieved acn objects here by id
14
15 function my_init() {
16     try {
17
18         /***********************************************************************************************************/
19         /* Initial setup */
20
21         netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
22         if (typeof JSAN == 'undefined') { throw( $("commonStrings").getString('common.jsan.missing') ); }
23         JSAN.errorLevel = "die"; // none, warn, or die
24         JSAN.addRepository('/xul/server/');
25         JSAN.use('util.error'); g.error = new util.error();
26         g.error.sdump('D_TRACE','my_init() for cat/volume_copy_creator.xul');
27
28         JSAN.use('OpenILS.data'); g.data = new OpenILS.data(); g.data.init({'via':'stash'});
29         JSAN.use('util.widgets'); JSAN.use('util.functional'); JSAN.use('util.fm_utils');
30
31         JSAN.use('util.network'); g.network = new util.network();
32
33         g.refresh = xul_param('onrefresh');
34
35         if (xulG.unified_interface) {
36             $('non_unified_buttons').hidden = true;
37             xulG.reset_batch_menus = function() {
38                 $('batch_class_menulist').value = false;
39                 util.widgets.dispatch('command',$('batch_class_menulist'));
40                 $('batch_prefix_menulist').value = false;
41                 util.widgets.dispatch('command',$('batch_prefix_menulist'));
42                 $('batch_suffix_menulist').value = false;
43                 util.widgets.dispatch('command',$('batch_suffix_menulist'));
44             }
45             xulG.apply_template_to_batch = function(id,value) {
46                 if (!isNaN(Number(value))) {
47                     $(id).value = value;
48                     util.widgets.dispatch('command',$(id));
49                 }
50                 setTimeout(
51                     function() {
52                         // TODO:  Only apply batch to columns that haven't been adjusted manually?
53                         util.widgets.dispatch('command',$('batch_button'));
54                     },0
55                 );
56             }
57             xulG.lock_save_button = function() {
58                 g.save_button_locked = true;
59                 document.getElementById("Create").disabled = true;
60             }
61             xulG.unlock_save_button = function() {
62                 g.save_button_locked = false;
63                 document.getElementById("Create").disabled = false;
64             }
65             xulG.clear_update_copy_editor_timeout = function() {
66                 if (g.update_copy_editor_timeoutID) {
67                     clearTimeout(g.update_copy_editor_timeoutID);
68                     g.gather_copies();
69                 }
70             }
71         } else {
72             $('Create').hidden = true;
73         }
74
75         /***********************************************************************************************************/
76         /* Am I adding just copies or copies and volumes?  Or am I rebarcoding existing copies? */
77
78         // g.copy_shortcut = { ou_id : { callnumber_composite_key : callnumber_id, callnumber_label : callnumber_id, ... }, ... }
79         g.copy_shortcut = xul_param('copy_shortcut');
80         // g.existing_copies = [ copy1, copy2, ... ]
81         g.existing_copies = xul_param('existing_copies') || [];
82
83         function set_attr(id,attr,msgcat_key) {
84             var x = $(id);
85             if (x) {
86                 x.setAttribute(
87                     attr,
88                     $('catStrings').getString(msgcat_key)
89                 );
90             }
91         }
92         if (g.existing_copies.length > 0) {
93             set_attr('EditThenCreate','label','staff.cat.volume_copy_creator.edit_then_rebarcode.btn.label');
94             set_attr('EditThenCreate','accesskey','staff.cat.volume_copy_creator.edit_then_rebarcode.btn.accesskey');
95             set_attr('CreateWithDefaults','label','staff.cat.volume_copy_creator.rebarcode.btn.label');
96             set_attr('CreateWithDefaults','accesskey','staff.cat.volume_copy_creator.rebarcode.btn.accesskey');
97             set_attr('Create','label','staff.cat.volume_copy_creator.rebarcode.btn.label');
98             set_attr('Create','accesskey','staff.cat.volume_copy_creator.rebarcode.btn.accesskey');
99         } else {
100             set_attr('EditThenCreate','label','staff.cat.volume_copy_creator.edit_then_create.btn.label');
101             set_attr('EditThenCreate','accesskey','staff.cat.volume_copy_creator.edit_then_create.btn.accesskey');
102             set_attr('CreateWithDefaults','label','staff.cat.volume_copy_creator.create_with_defaults.btn.label');
103             set_attr('CreateWithDefaults','accesskey','staff.cat.volume_copy_creator.create_with_defaults.btn.accesskey');
104             set_attr('Create','label','staff.cat.volume_copy_creator.create.btn.label');
105             set_attr('Create','accesskey','staff.cat.volume_copy_creator.create.btn.accesskey');
106         }
107
108         //g.error.sdump('D_ERROR','location.href = ' + location.href + '\n\ncopy_short cut = ' + g.copy_shortcut + '\n\nou_ids = ' + xul_param('ou_ids'));
109
110         var ou_ids = xul_param('ou_ids',{'concat' : true}) || [];
111
112         // Get the default callnumber classification scheme from OU settings
113         // or a reasonable fall-back
114         function get_default_label_class() {
115             g.label_class = g.data.hash.aous['cat.default_classification_scheme'];
116
117             // Assign a default value if none was returned
118             // Begin by looking for the "Generic" label class by name
119             if (!g.label_class) {
120                 for (var i = 0; i < g.data.list.acnc.length; i++) {
121                     if (g.data.list.acnc[i].name() == 'Generic') {
122                         g.label_class = g.data.list.acnc[i].id();
123                         break;
124                     }
125                 }
126             }
127             // Maybe this database has renamed or removed their Generic
128             // entry; in that case, just return the first one that we
129             // know exists
130             if (!g.label_class) {
131                 g.label_class = g.data.list.acnc[0].id();
132             }
133         }
134
135         get_default_label_class();
136
137         /***********************************************************************************************************/
138         /* If we're passed existing_copies, rig up a copy_shortcut object to leverage existing code for rendering the volume labels, etc.
139          * Also make a lookup object for existing copies keyed on org id and callnumber composite key, and another keyed on copy id. */
140
141         // g.org_label_existing_copy_map = { ou_id : { callnumber_composite_key : [ copy1, copy2, ... ] }, ... }
142         g.org_label_existing_copy_map = {};
143         // g.id_copy_map = { acp_id : acp, ... }
144         g.id_copy_map = {};
145         for (var i = 0; i < g.existing_copies.length; i++) {
146             if (! g.copy_shortcut) { g.copy_shortcut = {}; }
147             var copy = g.existing_copies[i];
148             g.id_copy_map[ copy.id() ] = copy;
149             var call_number = copy.call_number();
150             if (typeof call_number != 'object') {
151                 if (typeof g.acn_map[call_number] == 'undefined') {
152                     var temp_acn = g.network.simple_request(
153                         'FM_ACN_RETRIEVE.authoritative',
154                         [ call_number ]
155                     );
156                     if (typeof temp_acn.ilsevent != 'undefined') {
157                         alert('Error in my_init(), acn_id = ' + call_number + ' temp_acn = ' + js2JSON(temp_acn));
158                         continue;
159                     }
160                     g.acn_map[ call_number ] = temp_acn;
161                 }
162                 call_number = g.acn_map[call_number];
163             }
164             g.doc_id = call_number.record();
165             if (!g.copy_shortcut[ call_number.owning_lib() ]) {
166                 ou_ids.push( call_number.owning_lib() );
167                 g.copy_shortcut[ call_number.owning_lib() ] = {};
168                 g.org_label_existing_copy_map[ call_number.owning_lib() ] = {};
169             }
170             var acnc_id = call_number.label_class() ?
171                 ( typeof call_number.label_class() == 'object' ? call_number.label_class().id() : call_number.label_class() )
172                 : g.label_class;
173             var acnp_id = typeof call_number.prefix() == 'object' ? call_number.prefix().id() : call_number.prefix();
174             var acns_id = typeof call_number.suffix() == 'object' ? call_number.suffix().id() : call_number.suffix();
175             var callnumber_composite_key = acnc_id + ':' + acnp_id + ':' + call_number.label() + ':' + acns_id;
176             g.copy_shortcut[ call_number.owning_lib() ][ callnumber_composite_key ] = call_number.id();
177             if (! g.org_label_existing_copy_map[ call_number.owning_lib() ][ callnumber_composite_key ]) {
178                 g.org_label_existing_copy_map[ call_number.owning_lib() ][ callnumber_composite_key ] = [];
179             }
180             g.org_label_existing_copy_map[ call_number.owning_lib() ][ callnumber_composite_key ].push( copy );
181         }
182
183         /***********************************************************************************************************/
184         /* What record am I dealing with?  */
185
186         g.doc_id = g.doc_id || xul_param('doc_id');
187         if (! g.doc_id) {
188             alert('Error in volume_copy_creator.js, g.doc_id not valid');
189             window.close(); return;
190         }
191
192         var sb = document.getElementById('summary_box');
193         if (xul_param('no_bib_summary')) {
194             sb.hidden = true;
195             sb.nextSibling.hidden = true; /* splitter */
196         } else {
197             while(sb.firstChild) sb.removeChild(sb.lastChild);
198             var summary = document.createElement('iframe'); sb.appendChild(summary);
199             summary.setAttribute('src',urls.XUL_BIB_BRIEF);
200             summary.setAttribute('flex','1');
201             get_contentWindow(summary).xulG = { 'docid' : g.doc_id };
202         }
203
204         /***********************************************************************************************************/
205         /* Setup pcrud and fetch the monographic parts for this bib */
206
207         dojo.require('openils.PermaCrud');
208         g.pcrud = new openils.PermaCrud({'authtoken':ses()});
209         g.parts = g.pcrud.search('bmp',{'record':g.doc_id},{'order_by': { 'bmp' : 'label_sortkey' } });
210         g.parts_hash = util.functional.convert_object_list_to_hash( g.parts );
211
212         /***********************************************************************************************************/
213         /* For the batch drop downs */
214
215         g.list_classes();
216         JSAN.use('cat.util');
217         cat.util.render_callnumbers_for_bib_menu('marc_cn',g.doc_id, g.label_class);
218         g.render_batch_button();
219
220         /***********************************************************************************************************/
221         /* render the orgs and volumes/input */
222
223         var rows = document.getElementById('rows');
224
225         g.ou_ids = [];
226         for (var i = 0; i < ou_ids.length; i++) {
227             try {
228                 var org = g.data.hash.aou[ ou_ids[i] ];
229                 if ( get_bool( g.data.hash.aout[ org.ou_type() ].can_have_vols() ) ) {
230                     var row = document.createElement('row'); rows.appendChild(row); row.setAttribute('ou_id',ou_ids[i]);
231                     g.render_library_label(row,ou_ids[i]);
232                     g.render_volume_count_entry( row, ou_ids[i] );
233                     g.ou_ids.push( ou_ids[i] );
234                 }
235             } catch(E) {
236                 g.error.sdump('D_ERROR',E);
237             }
238         }
239         g.common_ancestor_ou_ids = util.fm_utils.find_common_aou_ancestors( g.ou_ids ).reverse();
240
241         /***********************************************************************************************************/
242         /* For the remainder batch drop downs */
243
244         g.list_prefixes();
245         g.list_suffixes();
246
247         /************/
248
249         g.load_prefs();
250
251         if (g.existing_copies.length > 0) {
252             g.gather_copies_soon(true);
253         }
254
255         try {
256             $('main').parentNode.scrollLeft = 9999;
257         } catch(E) {
258             dump('Error in volume_copy_creator.js, my_init(), trying to auto-scroll to the far right: ' + E + '\n');
259         }
260
261         if (typeof xulG.volume_ui_callback_for_unified_interface == 'function') {
262             xulG.volume_ui_callback_for_unified_interface();
263         }
264
265     } catch(E) {
266         var err_msg = $("commonStrings").getFormattedString('common.exception', ['cat/volume_copy_creator.js', E]);
267         try { g.error.sdump('D_ERROR',err_msg); } catch(E) { dump(err_msg); dump(js2JSON(E)); }
268         alert(err_msg);
269     }
270 }
271
272 g.render_library_label = function(row,ou_id) {
273     dump('g.render_library_label(row='+row+',ou_id='+ou_id+')\n');
274     var label = document.createElement('label'); row.appendChild(label);
275     label.setAttribute('ou_id',ou_id);
276     label.setAttribute('value',g.data.hash.aou[ ou_id ].shortname());
277 }
278
279 g.render_volume_count_entry = function(row,ou_id) {
280     dump('g.render_volume_count_entry(row='+row+',ou_id='+ou_id+')\n');
281     var hb = document.createElement('vbox'); row.appendChild(hb);
282     var tb = document.createElement('textbox'); hb.appendChild(tb);
283     if (g.use_defaults) {
284         tb.value = 1; // default to 1 volume per org
285         tb.select();
286     }
287     tb.setAttribute('ou_id',ou_id); tb.setAttribute('size','3'); tb.setAttribute('cols','3');
288     tb.setAttribute('rel_vert_pos',rel_vert_pos_volume_count);
289     if ( (!g.copy_shortcut) && (!g.last_focus) ) { tb.focus(); g.last_focus = tb; }
290     var node;
291     function render_copy_count_entry(ev) {
292         dump('\t\trender_copy_count_entry()\n');
293         if (ev.target.disabled) return;
294         if (! isNaN( Number( ev.target.value) ) ) {
295             if ( Number( ev.target.value ) > g_max_copies_that_can_be_added_at_a_time_per_volume ) {
296                 g.error.yns_alert($("catStrings").getFormattedString('staff.cat.volume_copy_creator.render_volume_count_entry.message', [g_max_copies_that_can_be_added_at_a_time_per_volume]),
297                     $("catStrings").getString('staff.cat.volume_copy_creator.render_volume_count_entry.title'),
298                     $("catStrings").getString('staff.cat.volume_copy_creator.render_volume_count_entry.ok_label'),null,null,'');
299                 return;
300             }
301             if (node) { row.removeChild(node); node = null; }
302             node = g.render_callnumber_copy_count_entry(row,ou_id,ev.target.value);
303         }
304     }
305     util.widgets.apply_vertical_tab_on_enter_handler(
306         tb,
307         function() { render_copy_count_entry({'target':tb}); setTimeout(function(){util.widgets.vertical_tab(tb);},0); }
308         ,function() { g.delay_gather_copies_soon(false); }
309     );
310     tb.addEventListener( 'change', render_copy_count_entry, false);
311     //tb.addEventListener( 'change', g.gather_copies_soon, false);
312     tb.addEventListener( 'focus', function(ev) { g.last_focus = ev.target; }, false );
313     setTimeout(
314         function() {
315             try {
316                 if (g.copy_shortcut) {
317                     dump('\t\tg.render_volume_count_entry, using g.copy_shortcut\n');
318                     JSAN.use('util.functional');
319                     tb.value = util.functional.map_object_to_list(
320                         g.copy_shortcut[ou_id],
321                         function(o,i) {
322                             return g.copy_shortcut[ou_id][i];
323                         }
324                     ).length;
325                     dump('\t\tnumber of volumes = ' + tb.value + '\n');
326                     render_copy_count_entry({'target':tb});
327                     tb.disabled = true;
328                 } else if (tb.value) {
329                     dump('\t\tg.render_volume_count_entry, number of volumes = ' + tb.value + '\n');
330                     // since we're now supplying a default
331                     render_copy_count_entry({'target':tb});
332                     setTimeout(
333                         function() {
334                             util.widgets.vertical_tab(tb);
335                         }, 0
336                     );
337                 }
338             } catch(E) {
339                 alert(E);
340             }
341         }, 0
342     );
343 }
344
345 g.render_callnumber_copy_count_entry = function(row,ou_id,count) {
346     dump('g.render_call_number_copy_count_entry(row='+row+',ou_id='+ou_id+',count='+count+')\n');
347     var grid = util.widgets.make_grid( [ {}, {} ] ); row.appendChild(grid);
348     grid.setAttribute('flex','1');
349     grid.setAttribute('ou_id',ou_id);
350     var rows = grid.lastChild;
351     var r = document.createElement('row'); rows.appendChild( r );
352     var x = document.createElement('label'); r.appendChild(x);
353         x.setAttribute('value', $("catStrings").getString('staff.cat.volume_copy_creator.render_callnumber_copy_count_entry.classification'));
354         x.setAttribute('style','font-weight: bold');
355         x.setAttribute('class','cn_class');
356     x = document.createElement('label'); r.appendChild(x);
357         x.setAttribute('value', $("catStrings").getString('staff.cat.volume_copy_creator.render_callnumber_copy_count_entry.prefix'));
358         x.setAttribute('style','font-weight: bold');
359         x.setAttribute('class','cn_prefix');
360     x = document.createElement('label'); r.appendChild(x);
361         x.setAttribute('value', $("catStrings").getString('staff.cat.volume_copy_creator.render_callnumber_copy_count_entry.call_nums'));
362         x.setAttribute('style','font-weight: bold');
363     x = document.createElement('label'); r.appendChild(x);
364         x.setAttribute('value', $("catStrings").getString('staff.cat.volume_copy_creator.render_callnumber_copy_count_entry.suffix'));
365         x.setAttribute('style','font-weight: bold');
366         x.setAttribute('class','cn_suffix');
367     x = document.createElement('label'); r.appendChild(x);
368         x.setAttribute('value',$("catStrings").getString('staff.cat.volume_copy_creator.render_callnumber_copy_count_entry.num_of_copies'));
369         x.setAttribute('style','font-weight: bold');
370     x = document.createElement('label'); r.appendChild(x);
371         x.setAttribute('value',$("catStrings").getString('staff.cat.volume_copy_creator.render_callnumber_copy_count_entry.barcodes_and_parts'));
372         x.setAttribute('style','font-weight: bold');
373
374     function handle_change_precipitating_barcode_rendering(
375         callnumber_composite_key,
376         number_of_copies_column_textbox,
377         barcode_column_box
378     ) {
379         dump('handle_change_precipitating_barcode_rendering('+callnumber_composite_key+',number_of_copies = '+number_of_copies_column_textbox.value+','+ barcode_column_box + ')\n');
380
381         if (isNaN( Number( number_of_copies_column_textbox.value ) )) {
382             dump('1:handle_change_precipitating_barcode_rendering early return\n');
383             return;
384         }
385         if ( Number( number_of_copies_column_textbox.value ) > g_max_copies_that_can_be_added_at_a_time_per_volume ) {
386             g.error.yns_alert($("catStrings").getFormattedString('staff.cat.volume_copy_creator.render_volume_count_entry.message', [g_max_copies_that_can_be_added_at_a_time_per_volume]),
387                 $("catStrings").getString('staff.cat.volume_copy_creator.render_volume_count_entry.title'),
388                 $("catStrings").getString('staff.cat.volume_copy_creator.render_volume_count_entry.ok_label'),null,null,'');
389             return;
390         }
391
392         while (barcode_column_box.childNodes.length > Number(number_of_copies_column_textbox.value)) {
393             barcode_column_box.removeChild( barcode_column_box.lastChild );
394         }
395         g.render_barcode_entry(
396             barcode_column_box,
397             callnumber_composite_key,
398             Number(number_of_copies_column_textbox.value),
399             ou_id
400         );
401
402         if (! xulG.unified_interface) {
403             document.getElementById("EditThenCreate").disabled = false;
404             document.getElementById("CreateWithDefaults").disabled = false;
405         } else {
406             if (! g.save_button_locked) {
407                 document.getElementById("Create").disabled = false;
408             }
409         }
410     }
411
412     function handle_change_to_callnumber_data(ev) {
413         dump('handle_change_to_callnumber_data\n');
414         var _call_number_column_textbox = ev.target;
415         var _call_number_column_box = _call_number_column_textbox.parentNode;
416
417         var _classification_column_box = _call_number_column_box.previousSibling.previousSibling; /* two over to the left */
418         var _classification_column_menulist = _classification_column_box.firstChild;
419
420         var _prefix_column_box = _call_number_column_box.previousSibling; /* one over to the left */
421         var _prefix_column_menulist = _prefix_column_box.firstChild;
422
423         var _suffix_column_box = _call_number_column_box.nextSibling; /* one over to the right */
424         var _suffix_column_menulist = _suffix_column_box.firstChild;
425
426         var _number_of_copies_column_box = _call_number_column_box.nextSibling.nextSibling; /* two over to the right */
427         var _number_of_copies_column_textbox = _number_of_copies_column_box.firstChild;
428
429         var _barcode_column_box = _number_of_copies_column_box.nextSibling;
430
431         var acn_label = _call_number_column_textbox.value;
432         var acnc_id = _classification_column_menulist.value;
433         var acnp_id = _prefix_column_menulist.value;
434         var acns_id = _suffix_column_menulist.value;
435         var callnumber_composite_key = acnc_id + ':' + acnp_id + ':' + acn_label + ':' + acns_id;
436         dump('\tcomposite_key = ' + callnumber_composite_key + '\n');
437
438         _call_number_column_textbox.setAttribute('callkey',callnumber_composite_key);
439         //_call_number_column_textbox.setAttribute('tooltiptext',callnumber_composite_key);
440         _call_number_column_textbox.setAttribute('acnc_id',acnc_id);
441         _call_number_column_textbox.setAttribute('acnp_id',acnp_id);
442         _call_number_column_textbox.setAttribute('acns_id',acns_id);
443
444         handle_change_precipitating_barcode_rendering(
445             callnumber_composite_key,
446             _number_of_copies_column_textbox,
447             _barcode_column_box
448         );
449     }
450
451     function handle_change_number_of_copies_column_textbox(ev) {
452         dump('handle_change_number_of_copies_column_textbox\n');
453         var _number_of_copies_column_textbox = ev.target;
454         var _number_of_copies_column_box = _number_of_copies_column_textbox.parentNode;
455         var _call_number_column_box = _number_of_copies_column_box.previousSibling.previousSibling; /* two over */
456         var _call_number_column_textbox = _call_number_column_box.firstChild;
457         handle_change_to_callnumber_data({'target':_call_number_column_textbox}); // let this guy do the work
458     }
459
460     for (var i = 0; i < count; i++) {
461         var r = document.createElement('row'); rows.appendChild(r);
462
463             /**** CLASSIFICATION COLUMN ****/
464             var classification_column_box = document.createElement('vbox');
465             classification_column_box.setAttribute('class','cn_class');
466             r.appendChild(classification_column_box);
467             classification_column_box.width = $('batch_class').parentNode.boxObject.width;
468
469             /**** PREFIX COLUMN ****/
470             var prefix_column_box = document.createElement('vbox');
471             prefix_column_box.setAttribute('class','cn_prefix');
472             r.appendChild(prefix_column_box);
473             prefix_column_box.width = $('batch_prefix').parentNode.boxObject.width;
474
475             /**** CALLNUMBER COLUMN ****/
476             var call_number_column_box = document.createElement('vbox');
477             r.appendChild(call_number_column_box);
478             call_number_column_box.width = $('marc_cn').parentNode.boxObject.width;
479                 var call_number_column_textbox = document.createElement('textbox');
480                 call_number_column_box.appendChild(call_number_column_textbox);
481                     if (g.use_defaults && $('marc_cn').firstChild) {
482                         // default to first real value from batch callnumber menu
483                         var menupopup = $('marc_cn').firstChild.firstChild;
484                         if (menupopup.childNodes.length > 1) {
485                             call_number_column_textbox.value = menupopup.childNodes[1].getAttribute('label');
486                             call_number_column_textbox.select();
487                         }
488                     }
489                     call_number_column_textbox.setAttribute('rel_vert_pos',rel_vert_pos_call_number);
490                     call_number_column_textbox.setAttribute('ou_id',ou_id);
491                     util.widgets.apply_vertical_tab_on_enter_handler(
492                         call_number_column_textbox,
493                         function() {
494                             handle_change_to_callnumber_data({'target':call_number_column_textbox});
495                             setTimeout(
496                                 function(){
497                                     util.widgets.vertical_tab(call_number_column_textbox);
498                                 },0
499                             );
500                         }
501                         ,function() { g.delay_gather_copies_soon(false); }
502                     );
503                     call_number_column_textbox.addEventListener( 'change', handle_change_to_callnumber_data, false);
504                     //call_number_column_textbox.addEventListener( 'change', g.gather_copies_soon, false);
505                     call_number_column_textbox.addEventListener( 'focus', function(ev) { g.last_focus = ev.target; }, false );
506
507                     /**** CLASSIFICATION COLUMN revisited ****/
508                     var classification_column_menulist = g.render_class_menu(
509                         call_number_column_textbox,
510                         handle_change_to_callnumber_data
511                     );
512                     classification_column_box.appendChild(classification_column_menulist);
513                     classification_column_menulist.value = g.label_class;
514
515                     /**** PREFIX COLUMN revisited ****/
516                     var prefix_column_menulist = g.render_prefix_menu(
517                         call_number_column_textbox,
518                         handle_change_to_callnumber_data
519                     );
520
521                     prefix_column_box.appendChild(prefix_column_menulist);
522
523             /**** SUFFIX COLUMN ****/
524             var suffix_column_box = document.createElement('vbox');
525             suffix_column_box.setAttribute('class','cn_suffix');
526             r.appendChild(suffix_column_box);
527             suffix_column_box.width = $('batch_suffix').parentNode.boxObject.width;
528                 var suffix_column_menulist = g.render_suffix_menu(
529                     call_number_column_textbox,
530                     handle_change_to_callnumber_data
531                 );
532                 suffix_column_box.appendChild(suffix_column_menulist);
533
534             /**** NUMBER OF COPIES COLUMN ****/
535             var number_of_copies_column_box = document.createElement('vbox');
536             r.appendChild(number_of_copies_column_box);
537                 var number_of_copies_column_textbox = document.createElement('textbox');
538                 number_of_copies_column_box.appendChild(number_of_copies_column_textbox);
539                     if (g.use_defaults) {
540                         // default to one copy per call number
541                         number_of_copies_column_textbox.value = 1;
542                         number_of_copies_column_textbox.select();
543                     }
544                     number_of_copies_column_textbox.setAttribute('size','3'); number_of_copies_column_textbox.setAttribute('cols','3');
545                     number_of_copies_column_textbox.setAttribute('rel_vert_pos',rel_vert_pos_copy_count);
546                     number_of_copies_column_textbox.setAttribute('ou_id',ou_id);
547                     util.widgets.apply_vertical_tab_on_enter_handler(
548                         number_of_copies_column_textbox,
549                         function() {
550                             handle_change_number_of_copies_column_textbox({'target':number_of_copies_column_textbox});
551                             setTimeout(
552                                 function(){
553                                     util.widgets.vertical_tab(number_of_copies_column_textbox);
554                                 },0
555                             );
556                         }
557                         ,function() { g.delay_gather_copies_soon(false); }
558                     );
559                     number_of_copies_column_textbox.addEventListener( 'change', handle_change_number_of_copies_column_textbox, false);
560                     //number_of_copies_column_textbox.addEventListener( 'change', g.gather_copies_soon, false);
561                     number_of_copies_column_textbox.addEventListener( 'focus', function(ev) { g.last_focus = ev.target; }, false );
562                     if ( !g.last_focus ) { number_of_copies_column_textbox.focus(); g.last_focus = number_of_copies_column_textbox; }
563
564             /**** BARCODE COLUMN ****/
565             var barcode_column_box = document.createElement('vbox');
566             r.appendChild(barcode_column_box);
567
568         setTimeout(
569             function(idx,call_number_column_textbox,number_of_copies_column_textbox){
570                 return function() {
571                     try {
572                         JSAN.use('util.functional');
573                         if (g.copy_shortcut) {
574                             dump('\t\tg.render_call_number_copy_count_entry() using g.copy_shortcut\n');
575                             var callnumber_composite_key = util.functional.map_object_to_list(
576                                 g.copy_shortcut[ou_id],
577                                 function(o,i) {
578                                     return i;
579                                 }
580                             )[idx];
581                             dump('\tcallnumber_composite_key = ' + callnumber_composite_key + '\n');
582                             if (g.org_label_existing_copy_map[ou_id]) {
583                                 var num_of_copies = g.org_label_existing_copy_map[ou_id][callnumber_composite_key].length;
584                                 if (num_of_copies>0) {
585                                     number_of_copies_column_textbox.value = num_of_copies;
586                                     number_of_copies_column_textbox.disabled = true;
587                                 }
588                             }
589                             var acn_label = callnumber_composite_key.split(/:/).slice(2,-1).join(':');
590                             var acnc_id = callnumber_composite_key.split(/:/)[0];
591                             var acnp_id = callnumber_composite_key.split(/:/)[1];
592                             var acns_id = callnumber_composite_key.split(/:/).slice(-1)[0];
593                             call_number_column_textbox.value = acn_label;
594
595                             var _call_number_column_box = call_number_column_textbox.parentNode;
596
597                             var _classification_column_box =
598                                 _call_number_column_box.previousSibling.previousSibling; /* two over to the left */
599                             var _classification_column_menulist =
600                                 _classification_column_box.firstChild;
601                             var _prefix_column_box =
602                                 _call_number_column_box.previousSibling; /* one over to the left */
603                             var _prefix_column_menulist =
604                                 _prefix_column_box.firstChild;
605                             var _suffix_column_box =
606                                 _call_number_column_box.nextSibling; /* one over to the right */
607                             var _suffix_column_menulist =
608                                 _suffix_column_box.firstChild;
609
610                             _classification_column_menulist.value = acnc_id;
611                             _prefix_column_menulist.value = acnp_id;
612                             _suffix_column_menulist.value = acns_id;
613                             dump('\tacn_label = ' + acn_label + ' acnc_id = ' + acnc_id + ' acnp_id = ' + acnp_id + ' acns_id = ' + acns_id + '\n');
614                             handle_change_to_callnumber_data({'target':call_number_column_textbox});
615                         } else {
616                             dump('\t\tg.render_call_number_copy_count_entry() using defaults\n');
617
618                             // if we're providing defaults, keep on rendering
619                             if (call_number_column_textbox.value) {
620                                 util.widgets.dispatch('change',call_number_column_textbox);
621                             }
622                             if (number_of_copies_column_textbox.value) {
623                                 util.widgets.dispatch('change',number_of_copies_column_textbox);
624                             }
625                         }
626                     } catch(E) {
627                         alert(E);
628                     }
629                 }
630             }(i,call_number_column_textbox,number_of_copies_column_textbox),0
631         );
632     }
633
634     return grid;
635 }
636
637 g.render_part_menu = function(barcode_tb) {
638     var hbox = document.createElement('hbox');
639     var menulist = document.createElement('menulist');
640         menulist.setAttribute('editable','true');
641         hbox.appendChild(menulist);
642     var button = document.createElement('button');
643         button.setAttribute('label',$('catStrings').getString('staff.cat.volume_copy_creator.create_part.btn.label'));
644         button.hidden = true;
645         hbox.appendChild(button);
646
647     var menupopup = document.createElement('menupopup');
648         menulist.appendChild(menupopup);
649         g.render_part_menuitems(menupopup);
650
651     button.addEventListener(
652         'command',
653         function(ev) {
654             var new_part = new bmp();
655                 new_part.isnew(1);
656                 new_part.label(menulist.value);
657                 new_part.record(g.doc_id);
658             g.pcrud.create(new_part, {
659                 "oncomplete": function (r, objs) {
660                     var db_part = objs[0];
661                     if (!db_part) { return; }
662                     g.parts.push( db_part );
663                     g.parts_hash[ db_part.id() ] = db_part;
664                     g.render_part_menuitems(menupopup);
665                     if (menulist.selectedItem) {
666                         barcode_tb.setAttribute('bmp_id',menulist.selectedItem.value);
667                         button.hidden = true;
668                     }
669                     g.gather_copies_soon(true);
670                 }
671             });
672         },
673         false
674     );
675
676     menulist.addEventListener(
677         'change',
678         function(ev) {
679             if (! ev.target.selectedItem) {
680                 button.hidden = false;
681             }
682         },
683         false
684     );
685     menulist.addEventListener('change',function() { g.gather_copies_soon(true); },false);
686     menulist.addEventListener(
687         'command',
688         function(ev) {
689             barcode_tb.setAttribute('bmp_id',menulist.selectedItem.value);
690             button.hidden = true;
691         },
692         false
693     );
694     menulist.addEventListener('command',function() { g.gather_copies_soon(true); },false);
695
696     return hbox;
697 }
698
699 g.render_part_menuitems = function(menupopup) {
700     util.widgets.remove_children(menupopup);
701     var menuitem = document.createElement('menuitem');
702     menuitem.setAttribute('label','');
703     menuitem.setAttribute('value','');
704     menupopup.appendChild(menuitem);
705     for (var i = 0; i < g.parts.length; i++) {
706         var menuitem = document.createElement('menuitem');
707         menuitem.setAttribute('label',g.parts[i].label());
708         menuitem.setAttribute('value',g.parts[i].id());
709         menupopup.appendChild(menuitem);
710     }
711
712 }
713
714 g.render_barcode_entry = function(node,callnumber_composite_key,count,ou_id) {
715     try {
716         dump('g.render_barcode_entry(node,'+callnumber_composite_key+',count='+count+',ou_id='+ou_id+'\n');
717         function ready_to_create(ev) {
718             if (! xulG.unified_interface) {
719                 document.getElementById("EditThenCreate").disabled = false;
720                 document.getElementById("CreateWithDefaults").disabled = false;
721             } else {
722                 if (! g.save_button_locked) {
723                     document.getElementById("Create").disabled = false;
724                 }
725             }
726         }
727
728         JSAN.use('util.barcode');
729
730         for (var i = 0; i < count; i++) {
731             var tb_part_box;
732             var tb;
733             var part_menu;
734             var set_handlers = false;
735             if (typeof node.childNodes[i] == 'undefined') {
736                 tb_part_box = document.createElement('hbox');
737                 node.appendChild(tb_part_box);
738                 tb = document.createElement('textbox');
739                 tb_part_box.appendChild(tb);
740                 part_menu = g.render_part_menu(tb);
741                 part_menu.setAttribute('class','part_column');
742                 tb_part_box.appendChild(part_menu);
743                 set_handlers = true;
744             } else {
745                 tb_part_box = node.childNodes[i];
746                 tb = tb_part_box.firstChild;
747                 part_menu = tb_part_box.lastChild;
748             }
749             tb.setAttribute('ou_id',ou_id);
750             tb.setAttribute('callkey',callnumber_composite_key);
751             //tb.setAttribute('tooltiptext',callnumber_composite_key);
752             tb.setAttribute('rel_vert_pos',rel_vert_pos_barcode);
753             part_menu.firstChild.setAttribute('rel_vert_pos',rel_vert_pos_part);
754             if (!tb.value && g.org_label_existing_copy_map[ ou_id ]) {
755                 tb.value = g.org_label_existing_copy_map[ ou_id ][ callnumber_composite_key ][i].barcode();
756                 tb.setAttribute('acp_id', g.org_label_existing_copy_map[ ou_id ][ callnumber_composite_key ][i].id());
757                 var temp_parts = g.org_label_existing_copy_map[ ou_id ][ callnumber_composite_key ][i].parts();
758                 temp_parts = util.functional.filter_list(
759                     temp_parts || [],
760                     function(p) {
761                         return p.record() == g.doc_id; // filter out foreign parts
762                     }
763                 );
764                 if (temp_parts.length > 0) {
765                     tb.setAttribute('bmp_id',temp_parts[0].id());
766                     part_menu.firstChild.value = g.parts_hash[ temp_parts[0].id() ].label();
767                 }
768                 tb.select();
769                 if (! g.first_focus) { g.first_focus = tb; }
770             }
771             if (g.use_defaults && ! g.first_focus) {
772                 g.first_focus = tb;
773                 tb.focus();
774             }
775             if (set_handlers) {
776                 util.widgets.apply_vertical_tab_on_enter_handler(
777                     tb,
778                     function() { ready_to_create({'target':tb}); setTimeout(function(){util.widgets.vertical_tab(tb);},0); },
779                     function() { g.delay_gather_copies_soon(true); }
780                 );
781                 util.widgets.apply_vertical_tab_on_enter_handler(
782                     part_menu.firstChild,
783                     function() { setTimeout(function(){util.widgets.vertical_tab(part_menu.firstChild);},0); },
784                     function() { g.delay_gather_copies_soon(true); }
785                 );
786                 tb.addEventListener('change', function(ev) {
787                     var barcode = String( ev.target.value ).replace(/\s/g,'');
788                     if (barcode != ev.target.value) ev.target.value = barcode;
789                     if ($('check_barcodes').checked && ! util.barcode.check(barcode) ) {
790                         g.error.yns_alert($("catStrings").getFormattedString('staff.cat.volume_copy_creator.render_barcode_entry.alert_message', [barcode]),
791                             $("catStrings").getString('staff.cat.volume_copy_creator.render_barcode_entry.alert_title'),
792                             $("catStrings").getString('staff.cat.volume_copy_creator.render_barcode_entry.alert_ok_button'),null,null,
793                             $("catStrings").getString('staff.cat.volume_copy_creator.render_barcode_entry.alert_confirm'));
794                         setTimeout( function() { ev.target.select(); ev.target.focus(); }, 0);
795                     }
796                 }, false);
797                 //tb.addEventListener('change', g.gather_copies_soon, false);
798                 tb.addEventListener( 'focus', function(ev) { g.last_focus = ev.target; }, false );
799             }
800         }
801
802         g.gather_copies_soon(true);
803         setTimeout( function() { if (g.first_focus) { g.first_focus.focus(); } }, 0 );
804
805     } catch(E) {
806         g.error.sdump('D_ERROR','g.render_barcode_entry: ' + E);
807     }
808 }
809
810 g.generate_barcodes = function() {
811     try {
812         var nodes = document.getElementsByAttribute('rel_vert_pos',rel_vert_pos_barcode);
813         if (nodes.length < 1) { return; }
814         var first_barcode = nodes[0].value;
815
816         if (! first_barcode) { return; }
817
818         var barcodes = g.network.simple_request(
819             'AUTOGENERATE_BARCODES',
820             [
821                 ses(),
822                 first_barcode,
823                 nodes.length - 1,
824                 $('check_barcodes').checked ? {} : { "checkdigit" : false }
825             ]
826         );
827
828         if (typeof barcodes.ilsevent != 'undefined') {
829             throw(barcodes);
830         }
831
832         for (var i = 0; i < barcodes.length; i++) {
833             nodes[i+1].value = barcodes[i];
834             nodes[i+1].select();
835             util.widgets.dispatch('change',nodes[i+1]);
836         }
837
838         setTimeout(
839             function() {
840                 g.gather_copies_soon(true);
841             },0
842         );
843
844     } catch(E) {
845         g.error.sdump('D_ERROR','g.generate_barcodes: ' + E);
846     }
847 }
848
849 g.delay_gather_copies_soon = function(enable_copy_editor) {
850     if (xulG.unified_interface) {
851         dump('g.delay_gather_copies_soon()\n');
852         g.gather_copies_soon(enable_copy_editor);
853     }
854 }
855
856 g.gather_copies_soon = function(enable_copy_editor) {
857     try {
858         if (!xulG.unified_interface) { return; }
859         dump('g.gather_copies_soon()\n');
860         if (typeof xulG.disable_copy_editor == 'function') {
861             xulG.disable_copy_editor();
862         }
863         if (g.update_copy_editor_timeoutID) {
864             clearTimeout(g.update_copy_editor_timeoutID);
865         }
866         // This function is expensive when it comes to keeping the UI responsive, so let's give it a delay
867         // that quick entry of consecutive fields can override
868         g.update_copy_editor_timeoutID = setTimeout(
869             function() {
870                 try {
871                     g.gather_copies();
872                     if (enable_copy_editor) {
873                         xulG.enable_copy_editor();
874                     }
875                     xulG.refresh_copy_editor();
876                 } catch(E) {
877                     dump('Error in volume_copy_editor.js with g.gather_copies_soon setTimeout func(): ' + E + '\n');
878                 }
879             }, update_timer
880         );
881     } catch(E) {
882         alert('Error in volume_copy_creator.js, g.gather_copies_soon(): ' + E);
883     }
884 }
885
886 g.new_acp_id = -1;
887 g.new_acn_id = -1;
888
889 g.gather_copies = function() {
890     dump('g.gather_copies()\n');
891     try {
892         var nl = document.getElementsByTagName('textbox');
893
894         g.volumes_scaffold = {};
895         /*
896             g.volumes_scaffold = {
897                 '#ou_id' : {
898                     '#class_id:#prefix_id:#callnumber label:#suffix_id' : {
899                         'callnumber_data' : {
900                             'acn_id' : '#callnumber id',
901                             'acn_label' : '#callnumber label',
902                             'acnc_id' : '#classification_id',
903                             'acnp_id' : '#prefix_id',
904                             'acns_id' : '#suffix_id'
905                         },
906                         'barcode_data' :
907                             [
908                                 {
909                                     'barcode' : '#barcode',
910                                     'acp_id' : '#copy_id',
911                                     'bmp_id' : '#part_id'
912                                 }, ...
913                             ]
914                     }
915                 }, ...
916             }
917         */
918
919         var barcodes = [];
920         var v_count = 0;
921         for (var i = 0; i < nl.length; i++) {
922             if ( nl[i].getAttribute('rel_vert_pos') == rel_vert_pos_barcode ) barcodes.push( nl[i] );
923             if ( nl[i].getAttribute('rel_vert_pos') == rel_vert_pos_call_number )  {
924                 v_count++;
925                 var ou_id = nl[i].getAttribute('ou_id');
926                 var acn_id = nl[i].getAttribute('acn_id');
927                 if (!acn_id) {
928                     acn_id = g.new_acn_id--;
929                     nl[i].setAttribute('acn_id',acn_id);
930                 }
931                 var acnc_id = nl[i].getAttribute('acnc_id') || g.label_class;
932                 var acnp_id = nl[i].getAttribute('acnp_id') || -1;
933                 var acns_id = nl[i].getAttribute('acns_id') || -1;
934                 var callnumber = nl[i].value;
935                 if (typeof g.volumes_scaffold[ou_id] == 'undefined') {
936                     g.volumes_scaffold[ou_id] = {}
937                 }
938                 var composite_key = acnc_id + ':' + acnp_id + ':' + callnumber + ':' + acns_id;
939                 if (typeof g.volumes_scaffold[ou_id][composite_key] == 'undefined') {
940                     g.volumes_scaffold[ou_id][composite_key] = {
941                         //'node' : nl[i],
942                         'callnumber_data' : {
943                             'acn_id' : acn_id,
944                             'acn_label' : callnumber,
945                             'acnc_id' : acnc_id,
946                             'acnp_id' : acnp_id,
947                             'acns_id' : acns_id
948                         },
949                         'barcode_data' : []
950                     }
951                     dump('fleshing volumes scaffold with ou_id = ' + ou_id + ' composite_key = ' + composite_key + ' acn_id = ' + acn_id + '\n');
952                 }
953             }
954         };
955         dump('volume_copy_creator: processed ' + nl.length + ' textbox nodes, consisting of ' + barcodes.length + ' barcodes and ' + v_count + 'volumes\n');
956         dump('volume scaffold = ' + js2JSON(g.volumes_scaffold) + '\n');
957
958         for (var i = 0; i < barcodes.length; i++) {
959             var acp_id = barcodes[i].getAttribute('acp_id') || g.new_acp_id--;
960             if (acp_id < 0) {
961                 barcodes[i].setAttribute('acp_id',acp_id);
962             }
963             var ou_id = barcodes[i].getAttribute('ou_id');
964             var callnumber_composite_key = barcodes[i].getAttribute('callkey');
965             var barcode = barcodes[i].value;
966             var bmp_id = barcodes[i].getAttribute('bmp_id');
967
968             dump('placing ' + barcode + ' for ou = ' + ou_id + ' into composite_key bin ' + callnumber_composite_key + '\n');
969
970             if (typeof g.volumes_scaffold[ou_id] == 'undefined') {
971                 dump('1: I want to remove this soon, so alert me if it is getting used, ou_id = ' + ou_id + '\n');
972                 g.volumes_scaffold[ou_id] = {}
973             }
974             if (typeof g.volumes_scaffold[ou_id][callnumber_composite_key] == 'undefined') {
975                 dump('2: when does this happen, and why? ou_id = ' + ou_id + ' callnumber_composite_key = ' + callnumber_composite_key + '\n');
976                 // one way this can happen, race condition between this function and editing a widget
977                 g.volumes_scaffold[ou_id][callnumber_composite_key] = {
978                     'callnumber_data' : {
979                         // not ideal, but hey...
980                         'acn_label' : callnumber_composite_key.split(/:/).slice(2,-1).join(':'),
981                         'acnc_id' : callnumber_composite_key.split(/:/)[0],
982                         'acnp_id' : callnumber_composite_key.split(/:/)[1],
983                         'acns_id' : callnumber_composite_key.split(/:/).slice(-1)[0]
984                     },
985                     'barcode_data' : []
986                 }
987             }
988
989             if (barcode != '') {
990                 g.volumes_scaffold[ou_id][callnumber_composite_key].barcode_data.push(
991                     {
992                         'barcode' : barcode,
993                         'acp_id' : acp_id,
994                         'bmp_id' : bmp_id
995                     }
996                 );
997             }
998         }
999
1000         var volumes = [];
1001         var copies = [];
1002         var volume_data = {};
1003
1004         // Get the default copy status; default to "In Process" if unset, per 1.6
1005         var normal_ccs = g.data.hash.aous['cat.default_copy_status_normal'] || 5;
1006
1007         function new_copy(acp_id,ou_id,acn_id,barcode) {
1008             var copy = new acp();
1009             copy.id( acp_id );
1010             copy.isnew('1');
1011             copy.barcode( barcode );
1012             copy.call_number( acn_id );
1013             copy.circ_lib(ou_id);
1014             /* FIXME -- use constants */
1015             copy.deposit(0);
1016             copy.price(0);
1017             copy.deposit_amount(0);
1018             copy.fine_level(2); // Normal
1019             copy.loan_duration(2); // Normal
1020             copy.location(1); // Stacks
1021             copy.status(normal_ccs);
1022             copy.circulate(get_db_true());
1023             copy.holdable(get_db_true());
1024             copy.opac_visible(get_db_true());
1025             copy.ref(get_db_false());
1026             copy.mint_condition(get_db_true());
1027             return copy;
1028         }
1029
1030         for (var ou_id in g.volumes_scaffold) {
1031             for (var composite_key in g.volumes_scaffold[ou_id]) {
1032                 for (var i = 0; i < g.volumes_scaffold[ou_id][composite_key].barcode_data.length; i++) {
1033                     var barcode = g.volumes_scaffold[ou_id][composite_key].barcode_data[i].barcode;
1034                     var acp_id = g.volumes_scaffold[ou_id][composite_key].barcode_data[i].acp_id;
1035                     var bmp_id = g.volumes_scaffold[ou_id][composite_key].barcode_data[i].bmp_id;
1036                     var acn_id = g.volumes_scaffold[ou_id][composite_key].callnumber_data.acn_id;
1037                     dump('gather_copies(): barcode = ' + barcode + ' acp_id = ' + acp_id + ' bmp_id = ' + bmp_id + ' acn_id = ' + acn_id + ' composite_key = ' + composite_key + '\n');
1038                     var copy = g.id_copy_map[ acp_id ];
1039                     if (!copy) {
1040                         copy = new_copy(acp_id,ou_id,acn_id,barcode);
1041                         g.id_copy_map[ acp_id ] = copy;
1042                     } else {
1043                         copy.ischanged( get_db_true() );
1044                     }
1045                     copy.barcode( barcode );
1046                     copy.call_number( acn_id );
1047                     var temp_parts = util.functional.filter_list(
1048                         copy.parts() || [],
1049                         function(p) {
1050                             return (p.record() != g.doc_id); // filter out parts for this bib
1051                         }
1052                     );
1053                     if (bmp_id) {
1054                         temp_parts.push( g.parts_hash[ bmp_id ] );
1055                     }
1056                     copy.parts( temp_parts );
1057                     copies.push( copy );
1058                 }
1059             }
1060         }
1061
1062         xulG.copies = copies;
1063         return copies;
1064
1065     } catch(E) {
1066         alert('Error in volume_copy_creator.js, g.gather_copies():' + E);
1067     }
1068 }
1069
1070 g.vivicate_update_volumes = function() {
1071     try {
1072         var volumes = [];
1073         for (var ou_id in g.volumes_scaffold) {
1074             for (var composite_key in g.volumes_scaffold[ou_id]) {
1075
1076                 var callnumber_data = g.volumes_scaffold[ou_id][composite_key].callnumber_data;
1077                 var acn_id = callnumber_data.acn_id;
1078                 var acnp_id = callnumber_data.acnp_id;
1079                 var acns_id = callnumber_data.acns_id;
1080                 var acnc_id = callnumber_data.acnc_id;
1081
1082                 if (acn_id < 0) {
1083
1084                     var acn_blob = g.network.simple_request(
1085                         'FM_ACN_FIND_OR_CREATE',
1086                         [ ses(), callnumber_data.acn_label, g.doc_id, ou_id, acnp_id, acns_id, acnc_id ]
1087                     );
1088                     dump('FM_ACN_FIND_OR_CREATE: label = ' + callnumber_data.acn_label
1089                         + ' doc = ' + g.doc_id + ' ou = ' + ou_id + ' acnp = ' + acnp_id + ' acns = ' + acns_id + ' acnc = ' + acnc_id + '\n');
1090
1091                     if (typeof acn_blob.ilsevent != 'undefined') {
1092                         alert('Error in g.vivicate_update_volumes, acn_id = ' + acn_id + ' acn_blob = ' + js2JSON(acn_blob));
1093                         continue;
1094                     }
1095
1096                     acn_id = acn_blob.acn_id;
1097
1098                     if (typeof g.acn_map[ acn_id ] == 'undefined') {
1099                         var temp_acn = g.network.simple_request(
1100                             'FM_ACN_RETRIEVE.authoritative',
1101                             [ acn_id ]
1102                         );
1103                         if (typeof temp_acn.ilsevent != 'undefined') {
1104                             alert('Error in g.vivicate_update_volumes, acn_id = ' + acn_id + ' temp_acn = ' + js2JSON(temp_acn));
1105                             continue;
1106                         }
1107                         g.acn_map[ acn_id ] = temp_acn;
1108                     }
1109
1110                     if (typeof g.acn_map[ callnumber_data.acn_id ] == 'undefined') {
1111                         g.acn_map[ callnumber_data.acn_id ] = g.acn_map[ acn_id ];
1112                     }
1113
1114                 }
1115             }
1116         }
1117         if (volumes.length > 0) {
1118             if (typeof xul_param('update_volume') == 'function') {
1119                 xul_param('update_volume')(volumes);
1120             } else {
1121                  var r = g.network.simple_request(
1122                     'FM_ACN_TREE_UPDATE',
1123                     [ ses(),volumes, false, { 'auto_merge_vols' : false } ]
1124                 );
1125                 if (typeof r.ilsevent != 'undefined') {
1126                     alert('error with volume update: ' + js2JSON(r));
1127                 }
1128             }
1129         }
1130     } catch(E) {
1131         alert('Error in volume_copy_creator.js, vivicate_volumes(): ' + E);
1132     }
1133 }
1134
1135 g.stash_and_close = function(param) {
1136
1137     try {
1138
1139         if (g.update_copy_editor_timeoutID) {
1140             clearTimeout(g.update_copy_editor_timeoutID);
1141         }
1142
1143         var copies;
1144         if (xulG.unified_interface) {
1145             g.gather_copies();
1146             xulG.refresh_copy_editor();
1147             copies = xulG.copies;
1148         } else {
1149             copies = g.gather_copies();
1150         }
1151
1152         var dont_close = false;
1153
1154         g.vivicate_update_volumes();
1155         for (var i = 0; i < copies.length; i++) {
1156             var acn_id = copies[i].call_number();
1157             if (typeof g.acn_map[acn_id] != 'undefined') {
1158                 // handle vivicated-callnumbers
1159                 copies[i].call_number( g.acn_map[acn_id].id() );
1160             } else {
1161                 alert('error in stash and close, acn_id = ' + acn_id);
1162             }
1163         }
1164
1165         var label_editor_func;
1166         if (copies.length > 0) {
1167             if (param == 'edit') {
1168                 JSAN.use('cat.util');
1169                 copies = cat.util.spawn_copy_editor( { 'edit' : true, 'docid' : g.doc_id, 'copies' : copies, 'caller_handles_update' : true });
1170             }
1171             if (typeof xul_param('update_copy') == 'function') {
1172                 xul_param('update_copy')(copies);
1173             } else {
1174                  var r = g.network.simple_request(
1175                     'FM_ACP_FLESHED_BATCH_UPDATE',
1176                     [ ses(),copies, true ]
1177                 );
1178                 if (typeof r.ilsevent != 'undefined') {
1179                     alert('error with copy update:' + js2JSON(r));
1180                 }
1181             }
1182             try {
1183                 //case 1706 /* ITEM_BARCODE_EXISTS */ :
1184                 if (copies && copies.length > 0 && $('print_labels').checked) {
1185                     dont_close = true;
1186                     var tab_name = $("catStrings").getString('staff.cat.util.spine_editor.tab_name');
1187                     var tab_method = xul_param('labels_in_new_tab') ? 'new_tab' : 'set_tab';
1188                     label_editor_func = function() {
1189                         JSAN.use('util.functional');
1190                         xulG[tab_method](
1191                             urls.XUL_SPINE_LABEL,
1192                             { 'tab_name' : tab_name },
1193                             {
1194                                 'barcodes' : util.functional.map_list( copies, function(o){return o.barcode();})
1195                             }
1196                         );
1197                     };
1198                 }
1199             } catch(E) {
1200                 alert('2: Error in volume_copy_creator.js with g.stash_and_close(): ' + E);
1201             }
1202         }
1203
1204         try { if (typeof window.refresh == 'function') { window.refresh(); } } catch(E) { dump(E+'\n'); }
1205         try { if (typeof g.refresh == 'function') { g.refresh(); } } catch(E) { dump(E+'\n'); }
1206
1207         if (typeof xulG.unlock_copy_editor == 'function') {
1208             xulG.unlock_copy_editor();
1209         }
1210
1211         if (xul_param('load_opac_when_done')) {
1212             var opac_url = xulG.url_prefix( urls.opac_rdetail ) + g.doc_id;
1213             var content_params = {
1214                 'session' : ses(),
1215                 'authtime' : ses('authtime'),
1216                 'opac_url' : opac_url
1217             };
1218             xulG.set_tab(
1219                 xulG.url_prefix(urls.XUL_OPAC_WRAPPER),
1220                 {
1221                     'tab_name':'Retrieving title...',
1222                     'on_tab_load' : function(cw) {
1223                         if (typeof label_editor_func == 'function') {
1224                             label_editor_func();
1225                         }
1226                     }
1227                 },
1228                 content_params
1229             );
1230         } else {
1231             if (typeof label_editor_func == 'function') {
1232                 label_editor_func();
1233             }
1234             if (! dont_close) { xulG.close_tab(); }
1235         }
1236
1237     } catch(E) {
1238         alert('3: Error in volume_copy_creator.js with g.stash_and_close(): ' + E);
1239     }
1240 }
1241
1242 g.load_prefs = function() {
1243     try {
1244         netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
1245         JSAN.use('util.file'); var file = new util.file('volume_copy_creator.prefs');
1246         if (file._file.exists()) {
1247             var prefs = file.get_object(); file.close();
1248             if (prefs.check_barcodes) {
1249                 if ( prefs.check_barcodes == 'false' ) {
1250                     $('check_barcodes').checked = false;
1251                 } else {
1252                     $('check_barcodes').checked = prefs.check_barcodes;
1253                 }
1254             } else {
1255                 $('check_barcodes').checked = false;
1256             }
1257             if (prefs.print_labels) {
1258                 if ( prefs.print_labels == 'false' ) {
1259                     $('print_labels').checked = false;
1260                 } else {
1261                     $('print_labels').checked = prefs.print_labels;
1262                 }
1263             } else {
1264                 $('print_labels').checked = false;
1265             }
1266
1267         }
1268     } catch(E) {
1269         alert('Error in volume_copy_creator.js with g.load_prefs(): ' + E);
1270     }
1271 }
1272
1273 g.save_prefs = function () {
1274     try {
1275         netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
1276         JSAN.use('util.file'); var file = new util.file('volume_copy_creator.prefs');
1277         file.set_object(
1278             {
1279                 'check_barcodes' : $('check_barcodes').checked,
1280                 'print_labels' : $('print_labels').checked,
1281             }
1282         );
1283         file.close();
1284     } catch(E) {
1285         alert('Error in volume_copy_creator.js with g.save_prefs(): ' + E);
1286     }
1287 }
1288
1289 g.render_class_menu = function(call_number_tb,update_func) {
1290     var ml = cat.util.render_cn_class_menu();
1291     ml.setAttribute('rel_vert_pos',rel_vert_pos_call_number_classification);
1292     ml.addEventListener(
1293         'command',
1294         function() {
1295             call_number_tb.setAttribute('acnc_id',ml.value);
1296             update_func({'target':call_number_tb});
1297         },
1298         false
1299     );
1300     return ml;
1301 }
1302
1303 g.render_prefix_menu = function(call_number_tb,update_func) {
1304     var ou_id = call_number_tb.getAttribute('ou_id');
1305     var menulist = cat.util.render_cn_prefix_menu([ou_id]);
1306     menulist.setAttribute('rel_vert_pos',rel_vert_pos_call_number_prefix);
1307     menulist.addEventListener(
1308         'command',
1309         function() {
1310             call_number_tb.setAttribute('acnp_id',menulist.value);
1311             update_func({'target':call_number_tb});
1312         },
1313         false
1314     );
1315     return menulist;
1316 }
1317
1318 g.render_suffix_menu = function(call_number_tb,update_func) {
1319     var ou_id = call_number_tb.getAttribute('ou_id');
1320     var menulist = cat.util.render_cn_suffix_menu([ou_id]);
1321     menulist.setAttribute('rel_vert_pos',rel_vert_pos_call_number_suffix);
1322     menulist.addEventListener(
1323         'command',
1324         function() {
1325             call_number_tb.setAttribute('acns_id',menulist.value);
1326             update_func({'target':call_number_tb});
1327         },
1328         false
1329     );
1330     return menulist;
1331 }
1332
1333 g.list_classes = function() {
1334     var hbox = $('batch_class');
1335     var ml = cat.util.render_cn_class_menu(
1336         [
1337             [ '<No Change>', false ]
1338         ]
1339     ); hbox.appendChild(ml);
1340     ml.setAttribute('id','batch_class_menulist');
1341     ml.addEventListener(
1342         'command',
1343         function() {
1344             if (!isNaN(Number(ml.value))) {
1345                 addCSSClass(hbox,'copy_editor_field_changed');
1346                 if (xulG.unified_interface) {
1347                     xulG.notify_of_templatable_field_change('batch_class_menulist',ml.value);
1348                 }
1349             } else {
1350                 removeCSSClass(hbox,'copy_editor_field_changed');
1351             }
1352         },
1353         false
1354     );
1355 }
1356
1357 g.list_prefixes = function() {
1358     var hbox = $('batch_prefix');
1359     var ml = cat.util.render_cn_prefix_menu(
1360         g.common_ancestor_ou_ids,
1361         [
1362             [ '<No Change>', false ]
1363         ]
1364     );
1365     ml.setAttribute('id','batch_prefix_menulist');
1366     hbox.appendChild(ml);
1367     ml.addEventListener(
1368         'command',
1369         function() {
1370             if (!isNaN(Number(ml.value))) {
1371                 addCSSClass(hbox,'copy_editor_field_changed');
1372                 if (xulG.unified_interface) {
1373                     xulG.notify_of_templatable_field_change('batch_prefix_menulist',ml.value);
1374                 }
1375             } else {
1376                 removeCSSClass(hbox,'copy_editor_field_changed');
1377             }
1378         },
1379         false
1380     );
1381 }
1382
1383 g.list_suffixes = function() {
1384     var hbox = $('batch_suffix');
1385     var ml = cat.util.render_cn_suffix_menu(
1386         g.common_ancestor_ou_ids,
1387         [
1388             [ '<No Change>', false ]
1389         ]
1390     );
1391     ml.setAttribute('id','batch_suffix_menulist');
1392     hbox.appendChild(ml);
1393     ml.addEventListener(
1394         'command',
1395         function() {
1396             if (!isNaN(Number(ml.value))) {
1397                 addCSSClass(hbox,'copy_editor_field_changed');
1398                 if (xulG.unified_interface) {
1399                     xulG.notify_of_templatable_field_change('batch_suffix_menulist',ml.value);
1400                 }
1401             } else {
1402                 removeCSSClass(hbox,'copy_editor_field_changed');
1403             }
1404         },
1405         false
1406     );
1407 }
1408
1409 g.render_batch_button = function() {
1410     var hbox = $('batch_button_box');
1411     var btn = document.createElement('button');
1412     btn.setAttribute('id','batch_button');
1413     btn.setAttribute('label',$('catStrings').getString('staff.cat.volume_copy_creator.my_init.btn.label'));
1414     btn.setAttribute('accesskey',$('catStrings').getString('staff.cat.volume_copy_creator.my_init.btn.accesskey'));
1415     btn.setAttribute('image','/xul/server/skin/media/images/down_arrow.gif');
1416     hbox.appendChild(btn);
1417     btn.addEventListener(
1418         'command',
1419         function() {
1420             var nl = document.getElementsByTagName('textbox');
1421             for (var i = 0; i < nl.length; i++) {
1422                 /* label */
1423                 if (nl[i].getAttribute('rel_vert_pos')==rel_vert_pos_call_number && !nl[i].disabled) {
1424                     var label =  $('marc_cn').firstChild.value;
1425                     if (label != '') {
1426                         nl[i].value = label;
1427                         util.widgets.dispatch('change',nl[i]);
1428                     }
1429                 }
1430             }
1431             nl = document.getElementsByTagName('menulist');
1432             for (var i = 0; i < nl.length; i++) {
1433                 /* classification */
1434                 if (nl[i].getAttribute('rel_vert_pos')==rel_vert_pos_call_number_classification && !nl[i].disabled) {
1435                     var value =  $('batch_class_menulist').value;
1436                     if (!isNaN( Number(value) )) {
1437                         nl[i].value = value;
1438                         util.widgets.dispatch('command',nl[i]);
1439                     }
1440                 }
1441                 /* prefix */
1442                 if (nl[i].getAttribute('rel_vert_pos')==rel_vert_pos_call_number_prefix && !nl[i].disabled) {
1443                     var value =  $('batch_prefix_menulist').value;
1444                     if (!isNaN( Number(value) )) {
1445                         nl[i].value = value;
1446                         util.widgets.dispatch('command',nl[i]);
1447                     }
1448                 }
1449                 /* suffix */
1450                 if (nl[i].getAttribute('rel_vert_pos')==rel_vert_pos_call_number_suffix && !nl[i].disabled) {
1451                     var value =  $('batch_suffix_menulist').value;
1452                     if (!isNaN( Number(value) )) {
1453                         nl[i].value = value;
1454                         util.widgets.dispatch('command',nl[i]);
1455                     }
1456                 }
1457             }
1458             setTimeout(
1459                 function() {
1460                     g.gather_copies_soon(true);
1461                 },0
1462             );
1463             if (g.last_focus) setTimeout( function() { g.last_focus.focus(); }, 0 );
1464         },
1465         false
1466     );
1467 }