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