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