Fix LP949249, Edit, then Create button creates a new item in all cases
[transitory.git] / Open-ILS / xul / staff_client / server / cat / volume_copy_creator.js
index dcaac78..0b16308 100644 (file)
@@ -18,7 +18,6 @@ function my_init() {
         /***********************************************************************************************************/
         /* Initial setup */
 
-        netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
         if (typeof JSAN == 'undefined') { throw( $("commonStrings").getString('common.jsan.missing') ); }
         JSAN.errorLevel = "die"; // none, warn, or die
         JSAN.addRepository('/xul/server/');
@@ -54,6 +53,20 @@ function my_init() {
                     },0
                 );
             }
+            xulG.lock_save_button = function() {
+                g.save_button_locked = true;
+                document.getElementById("Create").disabled = true;
+            }
+            xulG.unlock_save_button = function() {
+                g.save_button_locked = false;
+                document.getElementById("Create").disabled = false;
+            }
+            xulG.clear_update_copy_editor_timeout = function() {
+                if (g.update_copy_editor_timeoutID) {
+                    clearTimeout(g.update_copy_editor_timeoutID);
+                    g.gather_copies();
+                }
+            }
         } else {
             $('Create').hidden = true;
         }
@@ -96,15 +109,30 @@ function my_init() {
         var ou_ids = xul_param('ou_ids',{'concat' : true}) || [];
 
         // Get the default callnumber classification scheme from OU settings
-        dojo.require('fieldmapper.OrgUtils');
-        //fieldmapper.aou.fetchOrgSettingDefault(ses('ws_ou'), 'cat.default_classification_scheme');
-        g.label_class = g.data.hash.aous['cat.default_classification_scheme'];
-
-        // Assign a default value if none was returned
-        if (!g.label_class) {
-            g.label_class = g.data.list.acnc[0].id();
+        // or a reasonable fall-back
+        function get_default_label_class() {
+            g.label_class = g.data.hash.aous['cat.default_classification_scheme'];
+
+            // Assign a default value if none was returned
+            // Begin by looking for the "Generic" label class by name
+            if (!g.label_class) {
+                for (var i = 0; i < g.data.list.acnc.length; i++) {
+                    if (g.data.list.acnc[i].name() == 'Generic') {
+                        g.label_class = g.data.list.acnc[i].id();
+                        break;
+                    }
+                }
+            }
+            // Maybe this database has renamed or removed their Generic
+            // entry; in that case, just return the first one that we
+            // know exists
+            if (!g.label_class) {
+                g.label_class = g.data.list.acnc[0].id();
+            }
         }
 
+        get_default_label_class();
+
         /***********************************************************************************************************/
         /* If we're passed existing_copies, rig up a copy_shortcut object to leverage existing code for rendering the volume labels, etc.
          * Also make a lookup object for existing copies keyed on org id and callnumber composite key, and another keyed on copy id. */
@@ -118,6 +146,20 @@ function my_init() {
             var copy = g.existing_copies[i];
             g.id_copy_map[ copy.id() ] = copy;
             var call_number = copy.call_number();
+            if (typeof call_number != 'object') {
+                if (typeof g.acn_map[call_number] == 'undefined') {
+                    var temp_acn = g.network.simple_request(
+                        'FM_ACN_RETRIEVE.authoritative',
+                        [ call_number ]
+                    );
+                    if (typeof temp_acn.ilsevent != 'undefined') {
+                        alert('Error in my_init(), acn_id = ' + call_number + ' temp_acn = ' + js2JSON(temp_acn));
+                        continue;
+                    }
+                    g.acn_map[ call_number ] = temp_acn;
+                }
+                call_number = g.acn_map[call_number];
+            }
             g.doc_id = call_number.record();
             if (!g.copy_shortcut[ call_number.owning_lib() ]) {
                 ou_ids.push( call_number.owning_lib() );
@@ -170,7 +212,8 @@ function my_init() {
         /* For the batch drop downs */
 
         g.list_classes();
-        g.list_callnumbers(g.doc_id, g.label_class);
+        JSAN.use('cat.util');
+        cat.util.render_callnumbers_for_bib_menu('marc_cn',g.doc_id, g.label_class);
         g.render_batch_button();
 
         /***********************************************************************************************************/
@@ -205,7 +248,7 @@ function my_init() {
         g.load_prefs();
 
         if (g.existing_copies.length > 0) {
-            g.gather_copies_soon();
+            g.gather_copies_soon(true);
         }
 
         try {
@@ -260,11 +303,11 @@ g.render_volume_count_entry = function(row,ou_id) {
     }
     util.widgets.apply_vertical_tab_on_enter_handler(
         tb,
-        function() { render_copy_count_entry({'target':tb}); setTimeout(function(){util.widgets.vertical_tab(tb);},0); },
-        g.delay_gather_copies_soon
+        function() { render_copy_count_entry({'target':tb}); setTimeout(function(){util.widgets.vertical_tab(tb);},0); }
+        ,function() { g.delay_gather_copies_soon(false); }
     );
     tb.addEventListener( 'change', render_copy_count_entry, false);
-    tb.addEventListener( 'change', g.gather_copies_soon, false);
+    //tb.addEventListener( 'change', g.gather_copies_soon, false);
     tb.addEventListener( 'focus', function(ev) { g.last_focus = ev.target; }, false );
     setTimeout(
         function() {
@@ -359,7 +402,9 @@ g.render_callnumber_copy_count_entry = function(row,ou_id,count) {
             document.getElementById("EditThenCreate").disabled = false;
             document.getElementById("CreateWithDefaults").disabled = false;
         } else {
-            document.getElementById("Create").disabled = false;
+            if (! g.save_button_locked) {
+                document.getElementById("Create").disabled = false;
+            }
         }
     }
 
@@ -390,6 +435,7 @@ g.render_callnumber_copy_count_entry = function(row,ou_id,count) {
         dump('\tcomposite_key = ' + callnumber_composite_key + '\n');
 
         _call_number_column_textbox.setAttribute('callkey',callnumber_composite_key);
+        //_call_number_column_textbox.setAttribute('tooltiptext',callnumber_composite_key);
         _call_number_column_textbox.setAttribute('acnc_id',acnc_id);
         _call_number_column_textbox.setAttribute('acnp_id',acnp_id);
         _call_number_column_textbox.setAttribute('acns_id',acns_id);
@@ -417,15 +463,18 @@ g.render_callnumber_copy_count_entry = function(row,ou_id,count) {
             var classification_column_box = document.createElement('vbox');
             classification_column_box.setAttribute('class','cn_class');
             r.appendChild(classification_column_box);
+            classification_column_box.width = $('batch_class').parentNode.boxObject.width;
 
             /**** PREFIX COLUMN ****/
             var prefix_column_box = document.createElement('vbox');
             prefix_column_box.setAttribute('class','cn_prefix');
             r.appendChild(prefix_column_box);
+            prefix_column_box.width = $('batch_prefix').parentNode.boxObject.width;
 
             /**** CALLNUMBER COLUMN ****/
             var call_number_column_box = document.createElement('vbox');
             r.appendChild(call_number_column_box);
+            call_number_column_box.width = $('marc_cn').parentNode.boxObject.width;
                 var call_number_column_textbox = document.createElement('textbox');
                 call_number_column_box.appendChild(call_number_column_textbox);
                     if (g.use_defaults && $('marc_cn').firstChild) {
@@ -447,33 +496,25 @@ g.render_callnumber_copy_count_entry = function(row,ou_id,count) {
                                     util.widgets.vertical_tab(call_number_column_textbox);
                                 },0
                             );
-                        },
-                        g.delay_gather_copies_soon
+                        }
+                        ,function() { g.delay_gather_copies_soon(false); }
                     );
                     call_number_column_textbox.addEventListener( 'change', handle_change_to_callnumber_data, false);
-                    call_number_column_textbox.addEventListener( 'change', g.gather_copies_soon, false);
+                    //call_number_column_textbox.addEventListener( 'change', g.gather_copies_soon, false);
                     call_number_column_textbox.addEventListener( 'focus', function(ev) { g.last_focus = ev.target; }, false );
 
                     /**** CLASSIFICATION COLUMN revisited ****/
-                    var classification_column_menulist = g.render_class_menu(call_number_column_textbox);
-                    classification_column_menulist.addEventListener(
-                        'command',
-                        function() {
-                            handle_change_to_callnumber_data({'target':call_number_column_textbox});
-                        }
-                        ,false
+                    var classification_column_menulist = g.render_class_menu(
+                        call_number_column_textbox,
+                        handle_change_to_callnumber_data
                     );
                     classification_column_box.appendChild(classification_column_menulist);
                     classification_column_menulist.value = g.label_class;
 
                     /**** PREFIX COLUMN revisited ****/
-                    var prefix_column_menulist = g.render_prefix_menu(call_number_column_textbox);
-                    prefix_column_menulist.addEventListener(
-                        'command',
-                        function() {
-                            handle_change_to_callnumber_data({'target':call_number_column_textbox});
-                        }
-                        ,false
+                    var prefix_column_menulist = g.render_prefix_menu(
+                        call_number_column_textbox,
+                        handle_change_to_callnumber_data
                     );
 
                     prefix_column_box.appendChild(prefix_column_menulist);
@@ -482,13 +523,10 @@ g.render_callnumber_copy_count_entry = function(row,ou_id,count) {
             var suffix_column_box = document.createElement('vbox');
             suffix_column_box.setAttribute('class','cn_suffix');
             r.appendChild(suffix_column_box);
-                var suffix_column_menulist = g.render_suffix_menu(call_number_column_textbox);
-                suffix_column_menulist.addEventListener(
-                    'command',
-                    function() {
-                        handle_change_to_callnumber_data({'target':call_number_column_textbox});
-                    }
-                    ,false
+            suffix_column_box.width = $('batch_suffix').parentNode.boxObject.width;
+                var suffix_column_menulist = g.render_suffix_menu(
+                    call_number_column_textbox,
+                    handle_change_to_callnumber_data
                 );
                 suffix_column_box.appendChild(suffix_column_menulist);
 
@@ -514,11 +552,11 @@ g.render_callnumber_copy_count_entry = function(row,ou_id,count) {
                                     util.widgets.vertical_tab(number_of_copies_column_textbox);
                                 },0
                             );
-                        },
-                        g.delay_gather_copies_soon
+                        }
+                        ,function() { g.delay_gather_copies_soon(false); }
                     );
                     number_of_copies_column_textbox.addEventListener( 'change', handle_change_number_of_copies_column_textbox, false);
-                    number_of_copies_column_textbox.addEventListener( 'change', g.gather_copies_soon, false);
+                    //number_of_copies_column_textbox.addEventListener( 'change', g.gather_copies_soon, false);
                     number_of_copies_column_textbox.addEventListener( 'focus', function(ev) { g.last_focus = ev.target; }, false );
                     if ( !g.last_focus ) { number_of_copies_column_textbox.focus(); g.last_focus = number_of_copies_column_textbox; }
 
@@ -552,9 +590,25 @@ g.render_callnumber_copy_count_entry = function(row,ou_id,count) {
                             var acnp_id = callnumber_composite_key.split(/:/)[1];
                             var acns_id = callnumber_composite_key.split(/:/).slice(-1)[0];
                             call_number_column_textbox.value = acn_label;
-                            classification_column_menulist.value = acnc_id;
-                            prefix_column_menulist.value = acnp_id;
-                            suffix_column_menulist.value = acns_id;
+
+                            var _call_number_column_box = call_number_column_textbox.parentNode;
+
+                            var _classification_column_box =
+                                _call_number_column_box.previousSibling.previousSibling; /* two over to the left */
+                            var _classification_column_menulist =
+                                _classification_column_box.firstChild;
+                            var _prefix_column_box =
+                                _call_number_column_box.previousSibling; /* one over to the left */
+                            var _prefix_column_menulist =
+                                _prefix_column_box.firstChild;
+                            var _suffix_column_box =
+                                _call_number_column_box.nextSibling; /* one over to the right */
+                            var _suffix_column_menulist =
+                                _suffix_column_box.firstChild;
+
+                            _classification_column_menulist.value = acnc_id;
+                            _prefix_column_menulist.value = acnp_id;
+                            _suffix_column_menulist.value = acns_id;
                             dump('\tacn_label = ' + acn_label + ' acnc_id = ' + acnc_id + ' acnp_id = ' + acnp_id + ' acns_id = ' + acns_id + '\n');
                             handle_change_to_callnumber_data({'target':call_number_column_textbox});
                         } else {
@@ -611,7 +665,7 @@ g.render_part_menu = function(barcode_tb) {
                         barcode_tb.setAttribute('bmp_id',menulist.selectedItem.value);
                         button.hidden = true;
                     }
-                    g.gather_copies_soon();
+                    g.gather_copies_soon(true);
                 }
             });
         },
@@ -627,7 +681,7 @@ g.render_part_menu = function(barcode_tb) {
         },
         false
     );
-    menulist.addEventListener('change',g.gather_copies_soon,false);
+    menulist.addEventListener('change',function() { g.gather_copies_soon(true); },false);
     menulist.addEventListener(
         'command',
         function(ev) {
@@ -636,7 +690,7 @@ g.render_part_menu = function(barcode_tb) {
         },
         false
     );
-    menulist.addEventListener('command',g.gather_copies_soon,false);
+    menulist.addEventListener('command',function() { g.gather_copies_soon(true); },false);
 
     return hbox;
 }
@@ -664,7 +718,9 @@ g.render_barcode_entry = function(node,callnumber_composite_key,count,ou_id) {
                 document.getElementById("EditThenCreate").disabled = false;
                 document.getElementById("CreateWithDefaults").disabled = false;
             } else {
-                document.getElementById("Create").disabled = false;
+                if (! g.save_button_locked) {
+                    document.getElementById("Create").disabled = false;
+                }
             }
         }
 
@@ -691,6 +747,7 @@ g.render_barcode_entry = function(node,callnumber_composite_key,count,ou_id) {
             }
             tb.setAttribute('ou_id',ou_id);
             tb.setAttribute('callkey',callnumber_composite_key);
+            //tb.setAttribute('tooltiptext',callnumber_composite_key);
             tb.setAttribute('rel_vert_pos',rel_vert_pos_barcode);
             part_menu.firstChild.setAttribute('rel_vert_pos',rel_vert_pos_part);
             if (!tb.value && g.org_label_existing_copy_map[ ou_id ]) {
@@ -698,7 +755,7 @@ g.render_barcode_entry = function(node,callnumber_composite_key,count,ou_id) {
                 tb.setAttribute('acp_id', g.org_label_existing_copy_map[ ou_id ][ callnumber_composite_key ][i].id());
                 var temp_parts = g.org_label_existing_copy_map[ ou_id ][ callnumber_composite_key ][i].parts();
                 temp_parts = util.functional.filter_list(
-                    temp_parts,
+                    temp_parts || [],
                     function(p) {
                         return p.record() == g.doc_id; // filter out foreign parts
                     }
@@ -718,12 +775,12 @@ g.render_barcode_entry = function(node,callnumber_composite_key,count,ou_id) {
                 util.widgets.apply_vertical_tab_on_enter_handler(
                     tb,
                     function() { ready_to_create({'target':tb}); setTimeout(function(){util.widgets.vertical_tab(tb);},0); },
-                    g.delay_gather_copies_soon
+                    function() { g.delay_gather_copies_soon(true); }
                 );
                 util.widgets.apply_vertical_tab_on_enter_handler(
                     part_menu.firstChild,
                     function() { setTimeout(function(){util.widgets.vertical_tab(part_menu.firstChild);},0); },
-                    g.delay_gather_copies_soon
+                    function() { g.delay_gather_copies_soon(true); }
                 );
                 tb.addEventListener('change', function(ev) {
                     var barcode = String( ev.target.value ).replace(/\s/g,'');
@@ -736,12 +793,12 @@ g.render_barcode_entry = function(node,callnumber_composite_key,count,ou_id) {
                         setTimeout( function() { ev.target.select(); ev.target.focus(); }, 0);
                     }
                 }, false);
-                tb.addEventListener('change', g.gather_copies_soon, false);
+                //tb.addEventListener('change', g.gather_copies_soon, false);
                 tb.addEventListener( 'focus', function(ev) { g.last_focus = ev.target; }, false );
             }
         }
 
-        g.gather_copies_soon();
+        g.gather_copies_soon(true);
         setTimeout( function() { if (g.first_focus) { g.first_focus.focus(); } }, 0 );
 
     } catch(E) {
@@ -779,7 +836,7 @@ g.generate_barcodes = function() {
 
         setTimeout(
             function() {
-                g.gather_copies_soon();
+                g.gather_copies_soon(true);
             },0
         );
 
@@ -788,17 +845,20 @@ g.generate_barcodes = function() {
     }
 }
 
-g.delay_gather_copies_soon = function() {
+g.delay_gather_copies_soon = function(enable_copy_editor) {
     if (xulG.unified_interface) {
         dump('g.delay_gather_copies_soon()\n');
-        g.gather_copies_soon();
+        g.gather_copies_soon(enable_copy_editor);
     }
 }
 
-g.gather_copies_soon = function(ev) {
+g.gather_copies_soon = function(enable_copy_editor) {
     try {
         if (!xulG.unified_interface) { return; }
         dump('g.gather_copies_soon()\n');
+        if (typeof xulG.disable_copy_editor == 'function') {
+            xulG.disable_copy_editor();
+        }
         if (g.update_copy_editor_timeoutID) {
             clearTimeout(g.update_copy_editor_timeoutID);
         }
@@ -808,6 +868,9 @@ g.gather_copies_soon = function(ev) {
             function() {
                 try {
                     g.gather_copies();
+                    if (enable_copy_editor) {
+                        xulG.enable_copy_editor();
+                    }
                     xulG.refresh_copy_editor();
                 } catch(E) {
                     dump('Error in volume_copy_editor.js with g.gather_copies_soon setTimeout func(): ' + E + '\n');
@@ -959,6 +1022,7 @@ g.gather_copies = function() {
             copy.holdable(get_db_true());
             copy.opac_visible(get_db_true());
             copy.ref(get_db_false());
+            copy.mint_condition(get_db_true());
             return copy;
         }
 
@@ -1040,37 +1104,13 @@ g.vivicate_update_volumes = function() {
                             continue;
                         }
                         g.acn_map[ acn_id ] = temp_acn;
-                        if (callnumber_data.acn_id < 0) {
-                            g.acn_map[ callnumber_data.acn_id ] = temp_acn;
-                        }
                     }
 
-                }
-/*
-                var my_acn = g.acn_map[ acn_id ];
-
-                var node = g.volumes_scaffold[ou_id][composite_key].node;
-                var class_menulist = node.parentNode.previousSibling.previousSibling.firstChild;
-                var prefix_menulist = node.parentNode.previousSibling.firstChild;
-                var suffix_menulist = node.parentNode.nextSibling.firstChild;
-
-                if ( String(class_menulist.value) != String(my_acn.label_class()) {
-                    my_acn.label_class( class_menulist.value );
-                    my_acn.ischanged( get_db_true() );
-                }
-                if ( String(prefix_menulist.value) != String(my_acn.prefix()) {
-                    my_acn.prefix( prefix_menulist.value );
-                    my_acn.ischanged( get_db_true() );
-                }
-                if ( String(suffix_menulist.value) != String(my_acn.suffix()) {
-                    my_acn.suffix( suffix_menulist.value );
-                    my_acn.ischanged( get_db_true() );
-                }
+                    if (typeof g.acn_map[ callnumber_data.acn_id ] == 'undefined') {
+                        g.acn_map[ callnumber_data.acn_id ] = g.acn_map[ acn_id ];
+                    }
 
-                if (get_bool( my_acn.ischanged() )) {
-                    volumes.push( my_acn );
                 }
-*/
             }
         }
         if (volumes.length > 0) {
@@ -1121,34 +1161,50 @@ g.stash_and_close = function(param) {
             }
         }
 
+        var label_editor_func;
         if (copies.length > 0) {
-            if (param == 'edit') {
+            if (param === 'edit') {
                 JSAN.use('cat.util');
-                copies = cat.util.spawn_copy_editor( { 'edit' : true, 'docid' : g.doc_id, 'copies' : copies, 'caller_handles_update' : true });
+                copies = cat.util.spawn_copy_editor({
+                      'edit' : true
+                    , 'docid' : g.doc_id
+                    , 'copies' : copies
+                    , 'caller_handles_update' : false
+                });
             }
-            if (typeof xul_param('update_copy') == 'function') {
-                xul_param('update_copy')(copies);
-            } else {
-                 var r = g.network.simple_request(
-                    'FM_ACP_FLESHED_BATCH_UPDATE',
-                    [ ses(),copies, true ]
-                );
-                if (typeof r.ilsevent != 'undefined') {
-                    alert('error with copy update:' + js2JSON(r));
+            else {
+                if (typeof xul_param('update_copy') === 'function') {
+                    xul_param('update_copy')(copies);
+                } else {
+                     var r = g.network.simple_request(
+                        'FM_ACP_FLESHED_BATCH_UPDATE',
+                        [ ses(),copies, true ]
+                    );
+                    if (r.textcode === 'ITEM_BARCODE_EXISTS') {
+                        alert('error with item update: ' + r.desc);
+                        dont_close = true;
+                    }
+                    else if (typeof r.ilsevent != 'undefined') {
+                        alert('error with copy update:' + js2JSON(r));
+                    }
                 }
             }
             try {
                 //case 1706 /* ITEM_BARCODE_EXISTS */ :
                 if (copies && copies.length > 0 && $('print_labels').checked) {
-                    JSAN.use('util.functional');
                     dont_close = true;
-                    xulG.set_tab(
-                        urls.XUL_SPINE_LABEL,
-                        { 'tab_name' : $("catStrings").getString('staff.cat.util.spine_editor.tab_name') },
-                        {
-                            'barcodes' : util.functional.map_list( copies, function(o){return o.barcode();})
-                        }
-                    );
+                    var tab_name = $("catStrings").getString('staff.cat.util.spine_editor.tab_name');
+                    var tab_method = xul_param('labels_in_new_tab') ? 'new_tab' : 'set_tab';
+                    label_editor_func = function() {
+                        JSAN.use('util.functional');
+                        xulG[tab_method](
+                            urls.XUL_SPINE_LABEL,
+                            { 'tab_name' : tab_name },
+                            {
+                                'barcodes' : util.functional.map_list( copies, function(o){return o.barcode();})
+                            }
+                        );
+                    };
                 }
             } catch(E) {
                 alert('2: Error in volume_copy_creator.js with g.stash_and_close(): ' + E);
@@ -1162,7 +1218,34 @@ g.stash_and_close = function(param) {
             xulG.unlock_copy_editor();
         }
 
-        if (! dont_close) { xulG.close_tab(); }
+        if (typeof xulG.reload_opac == 'function') {
+            xulG.reload_opac();
+        }
+        if (xul_param('load_opac_when_done')) {
+            var opac_url = xulG.url_prefix('opac_rdetail') + g.doc_id;
+            var content_params = {
+                'session' : ses(),
+                'authtime' : ses('authtime'),
+                'opac_url' : opac_url
+            };
+            xulG.set_tab(
+                xulG.url_prefix('XUL_OPAC_WRAPPER'),
+                {
+                    'tab_name':'Retrieving title...',
+                    'on_tab_load' : function(cw) {
+                        if (typeof label_editor_func == 'function') {
+                            label_editor_func();
+                        }
+                    }
+                },
+                content_params
+            );
+        } else {
+            if (typeof label_editor_func == 'function') {
+                label_editor_func();
+            }
+            if (! dont_close) { xulG.close_tab(); }
+        }
 
     } catch(E) {
         alert('3: Error in volume_copy_creator.js with g.stash_and_close(): ' + E);
@@ -1171,7 +1254,6 @@ g.stash_and_close = function(param) {
 
 g.load_prefs = function() {
     try {
-        netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
         JSAN.use('util.file'); var file = new util.file('volume_copy_creator.prefs');
         if (file._file.exists()) {
             var prefs = file.get_object(); file.close();
@@ -1202,7 +1284,6 @@ g.load_prefs = function() {
 
 g.save_prefs = function () {
     try {
-        netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
         JSAN.use('util.file'); var file = new util.file('volume_copy_creator.prefs');
         file.set_object(
             {
@@ -1216,179 +1297,56 @@ g.save_prefs = function () {
     }
 }
 
-g.render_class_menu = function(call_number_tb) {
-    var ml = util.widgets.make_menulist(
-        util.functional.map_list(
-            g.data.list.acnc,
-            function(o) {
-                return [ o.name(), o.id() ];
-            }
-        )
-    );
+g.render_class_menu = function(call_number_tb,update_func) {
+    var ml = cat.util.render_cn_class_menu();
     ml.setAttribute('rel_vert_pos',rel_vert_pos_call_number_classification);
     ml.addEventListener(
         'command',
         function() {
             call_number_tb.setAttribute('acnc_id',ml.value);
+            update_func({'target':call_number_tb});
         },
         false
     );
     return ml;
 }
 
-g.render_prefix_menu = function(call_number_tb) {
+g.render_prefix_menu = function(call_number_tb,update_func) {
     var ou_id = call_number_tb.getAttribute('ou_id');
-    var org = g.data.hash.aou[ ou_id ];
-    var menulist = document.createElement('menulist');
-        var menupopup = document.createElement('menupopup');
-        menulist.appendChild(menupopup);
-        var org_list = []; // order from top of consortium to owning lib
-        while(org) {
-            org_list.unshift(org.id());
-            org = org.parent_ou();
-            if (org && typeof org != 'object') {
-                org = g.data.hash.aou[ org ];
-            }
-        }
-        for (var i = 0; i < org_list.length; i++) {
-            g.render_prefix_menu_items(menupopup,org_list[i]);
-        }
-
+    var menulist = cat.util.render_cn_prefix_menu([ou_id]);
     menulist.setAttribute('rel_vert_pos',rel_vert_pos_call_number_prefix);
     menulist.addEventListener(
         'command',
         function() {
             call_number_tb.setAttribute('acnp_id',menulist.value);
+            update_func({'target':call_number_tb});
         },
         false
     );
     return menulist;
 }
 
-g.render_prefix_menu_items = function(menupopup,ou_id) {
-    if (typeof g.data.list['acnp_for_lib_'+ou_id] == 'undefined') {
-        g.data.list['acnp_for_lib_'+ou_id] = g.network.simple_request(
-            'FM_ACNP_RETRIEVE_VIA_PCRUD',
-            [ ses(), {"owning_lib":{"=":ou_id}}, {"order_by":{"acnp":"label_sortkey"}} ]
-        );
-        g.data.stash('list');
-    }
-    for (var i = 0; i < g.data.list['acnp_for_lib_'+ou_id].length; i++) {
-        var my_acnp = g.data.list['acnp_for_lib_'+ou_id][i];
-        var menuitem = document.createElement('menuitem');
-        menupopup.appendChild(menuitem);
-            menuitem.setAttribute(
-                'label',
-                my_acnp.id() == -1 ? '' :
-                $('catStrings').getFormattedString(
-                    'staff.cat.volume_copy_creator.call_number_prefix.menuitem_label',
-                    [
-                        my_acnp.label(),
-                        g.data.hash.aou[ ou_id ].shortname()
-                    ]
-                )
-            );
-            menuitem.setAttribute('value',my_acnp.id());
-    }
-}
-
-g.render_suffix_menu = function(call_number_tb) {
+g.render_suffix_menu = function(call_number_tb,update_func) {
     var ou_id = call_number_tb.getAttribute('ou_id');
-    var org = g.data.hash.aou[ ou_id ];
-    var menulist = document.createElement('menulist');
-        var menupopup = document.createElement('menupopup');
-        menulist.appendChild(menupopup);
-        var org_list = []; // order from top of consortium to owning lib
-        while(org) {
-            org_list.unshift(org.id());
-            org = org.parent_ou();
-            if (org && typeof org != 'object') {
-                org = g.data.hash.aou[ org ];
-            }
-        }
-        for (var i = 0; i < org_list.length; i++) {
-            g.render_suffix_menu_items(menupopup,org_list[i]);
-        }
-
+    var menulist = cat.util.render_cn_suffix_menu([ou_id]);
     menulist.setAttribute('rel_vert_pos',rel_vert_pos_call_number_suffix);
     menulist.addEventListener(
         'command',
         function() {
             call_number_tb.setAttribute('acns_id',menulist.value);
+            update_func({'target':call_number_tb});
         },
         false
     );
     return menulist;
 }
 
-g.render_suffix_menu_items = function(menupopup,ou_id) {
-    if (typeof g.data.list['acns_for_lib_'+ou_id] == 'undefined') {
-        g.data.list['acns_for_lib_'+ou_id] = g.network.simple_request(
-            'FM_ACNS_RETRIEVE_VIA_PCRUD',
-            [ ses(), {"owning_lib":{"=":ou_id}}, {"order_by":{"acns":"label_sortkey"}} ]
-        );
-        g.data.stash('list');
-    }
-    for (var i = 0; i < g.data.list['acns_for_lib_'+ou_id].length; i++) {
-        var my_acns = g.data.list['acns_for_lib_'+ou_id][i];
-        var menuitem = document.createElement('menuitem');
-        menupopup.appendChild(menuitem);
-            menuitem.setAttribute(
-                'label',
-                my_acns.id() == -1 ? '' :
-                $('catStrings').getFormattedString(
-                    'staff.cat.volume_copy_creator.call_number_suffix.menuitem_label',
-                    [
-                        my_acns.label(),
-                        g.data.hash.aou[ ou_id ].shortname()
-                    ]
-                )
-            );
-            menuitem.setAttribute('value',my_acns.id());
-    }
-}
-
-
-g.list_callnumbers = function(doc_id, label_class) {
-    var cn_blob;
-    try {
-        cn_blob = g.network.simple_request('BLOB_MARC_CALLNUMBERS_RETRIEVE',[g.doc_id, label_class]);
-    } catch(E) {
-        cn_blob = [];
-    }
-    var hbox = document.getElementById('marc_cn');
-    var ml = util.widgets.make_menulist(
-        [
-            [ '', '' ]
-        ].concat(
-            util.functional.map_list(
-                cn_blob,
-                function(o) {
-                    for (var i in o) {
-                        return [ o[i], i ];
-                    }
-                }
-            )
-        )
-    ); hbox.appendChild(ml);
-    ml.setAttribute('editable','true');
-    ml.setAttribute('width', '200');
-    ml.setAttribute('id', 'marc_cn_menulist');
-}
-
 g.list_classes = function() {
     var hbox = $('batch_class');
-    var ml = util.widgets.make_menulist(
+    var ml = cat.util.render_cn_class_menu(
         [
             [ '<No Change>', false ]
-        ].concat(
-            util.functional.map_list(
-                g.data.list.acnc,
-                function(o) {
-                    return [ o.name(), o.id() ];
-                }
-            )
-        )
+        ]
     ); hbox.appendChild(ml);
     ml.setAttribute('id','batch_class_menulist');
     ml.addEventListener(
@@ -1409,15 +1367,14 @@ g.list_classes = function() {
 
 g.list_prefixes = function() {
     var hbox = $('batch_prefix');
-    var ml = util.widgets.make_menulist(
+    var ml = cat.util.render_cn_prefix_menu(
+        g.common_ancestor_ou_ids,
         [
             [ '<No Change>', false ]
         ]
-    ); hbox.appendChild(ml);
-    for (var i = 0; i < g.common_ancestor_ou_ids.length; i++) {
-        g.render_prefix_menu_items(ml.firstChild,g.common_ancestor_ou_ids[i]);
-    }
+    );
     ml.setAttribute('id','batch_prefix_menulist');
+    hbox.appendChild(ml);
     ml.addEventListener(
         'command',
         function() {
@@ -1436,15 +1393,14 @@ g.list_prefixes = function() {
 
 g.list_suffixes = function() {
     var hbox = $('batch_suffix');
-    var ml = util.widgets.make_menulist(
+    var ml = cat.util.render_cn_suffix_menu(
+        g.common_ancestor_ou_ids,
         [
             [ '<No Change>', false ]
         ]
-    ); hbox.appendChild(ml);
-    for (var i = 0; i < g.common_ancestor_ou_ids.length; i++) {
-        g.render_suffix_menu_items(ml.firstChild,g.common_ancestor_ou_ids[i]);
-    }
+    );
     ml.setAttribute('id','batch_suffix_menulist');
+    hbox.appendChild(ml);
     ml.addEventListener(
         'command',
         function() {
@@ -1512,7 +1468,7 @@ g.render_batch_button = function() {
             }
             setTimeout(
                 function() {
-                    g.gather_copies_soon();
+                    g.gather_copies_soon(true);
                 },0
             );
             if (g.last_focus) setTimeout( function() { g.last_focus.focus(); }, 0 );