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