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