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