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