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