]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/xul/staff_client/server/cat/copy_editor.js
wire up util.hide in the item attribute editor
[working/Evergreen.git] / Open-ILS / xul / staff_client / server / cat / copy_editor.js
1 // vim:et:sw=4:ts=4
2 var g = { 'disabled' : false };
3 g.map_acn = {};
4
5 function $(id) { return document.getElementById(id); }
6
7 function my_init() {
8     try {
9         /******************************************************************************************************/
10         /* setup JSAN and some initial libraries */
11
12         netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
13         if (typeof JSAN == 'undefined') {
14             throw( $('commonStrings').getString('common.jsan.missing') );
15         }
16         JSAN.errorLevel = "die"; // none, warn, or die
17         JSAN.addRepository('/xul/server/');
18         JSAN.use('util.error'); g.error = new util.error();
19         g.error.sdump('D_TRACE','my_init() for cat/copy_editor.xul');
20
21         JSAN.use('util.functional');
22         JSAN.use('OpenILS.data'); g.data = new OpenILS.data(); g.data.init({'via':'stash'});
23         JSAN.use('util.network'); g.network = new util.network();
24
25         if (xulG.unified_interface) {
26             $('non_unified_buttons').hidden = true;
27         }
28
29         g.docid = xul_param('docid',{'modal_xulG':true});
30         g.handle_update = xul_param('handle_update',{'modal_xulG':true});
31
32         /******************************************************************************************************/
33         /* Get the copy ids from various sources and flesh them */
34
35         var copy_ids = xul_param('copy_ids',{'concat':true,'JSON2js_if_cgi':true,'JSON2js_if_xulG':true,'JSON2js_if_xpcom':true,'stash_name':'temp_copy_ids','clear_xpcom':true,'modal_xulG':true});
36         if (!copy_ids) copy_ids = [];
37
38         if (copy_ids.length > 0) g.copies = g.network.simple_request(
39             'FM_ACP_FLESHED_BATCH_RETRIEVE.authoritative',
40             [ copy_ids ]
41         );
42
43         /******************************************************************************************************/
44         /* And other fleshed copies if any */
45
46         if (!g.copies) g.copies = [];
47         var c = xul_param('copies',{'concat':true,'JSON2js_if_cgi':true,'JSON2js_if_xpcom':true,'stash_name':'temp_copies','clear_xpcom':true,'modal_xulG':true})
48         if (c) g.copies = g.copies.concat(c);
49
50         /******************************************************************************************************/
51         /* We try to retrieve callnumbers for existing copies, but for new copies, we rely on this */
52
53         g.callnumbers = xul_param('callnumbers',{'concat':true,'JSON2js_if_cgi':true,'JSON2js_if_xpcom':true,'stash_name':'temp_callnumbers','clear_xpcom':true,'modal_xulG':true});
54
55         /******************************************************************************************************/
56         /* Get preference (if it exists) for copy location label order */
57
58         g.cl_first = false; // Default to legacy OU first mode
59         var prefs = Components.classes['@mozilla.org/preferences-service;1']
60             .getService(Components.interfaces['nsIPrefBranch']);
61         try {
62             g.cl_first = prefs.getBoolPref('oils.copy_editor.copy_location_name_first');
63         } catch(E) { }
64
65         /******************************************************************************************************/
66         /* Quick fix, this was defined inline in the global scope but now needs g.error and g.copies from my_init */
67         /* Quick fix, messagecatalog only usable during/after onload */
68
69         init_panes0();
70         init_panes();
71
72         /******************************************************************************************************/
73         /* Is the interface an editor or a viewer, single or multi copy, existing copies or new copies? */
74
75         if (xul_param('edit',{'modal_xulG':true}) == '1') { 
76
77             g.edit = false;
78
79             if (g.copies.length > 0) { // When loaded in the unified interface, there may be no copies yet (from the volum/item creator) 
80
81                 // Editor desired, but let's check permissions
82
83                 try {
84                     var check = g.network.simple_request(
85                         'PERM_MULTI_ORG_CHECK',
86                         [ 
87                             ses(), 
88                             g.data.list.au[0].id(), 
89                             util.functional.map_list(
90                                 g.copies,
91                                 function (o) {
92                                     var lib;
93                                     var cn_id = o.call_number();
94                                     if (cn_id == -1) {
95                                         lib = o.circ_lib(); // base perms on circ_lib instead of owning_lib if pre-cat
96                                     } else {
97                                         if (! g.map_acn[ cn_id ]) {
98                                             var req = g.network.simple_request('FM_ACN_RETRIEVE.authoritative',[ cn_id ]);
99                                             if (typeof req.ilsevent == 'undefined') {
100                                                 g.map_acn[ cn_id ] = req;
101                                                 lib = g.map_acn[ cn_id ].owning_lib();
102                                             } else {
103                                                 lib = o.circ_lib();
104                                             }
105                                         } else {
106                                             lib = g.map_acn[ cn_id ].owning_lib();
107                                         }
108                                     }
109                                     return typeof lib == 'object' ? lib.id() : lib;
110                                 }
111                             ),
112                             g.copies.length == 1 ? [ 'UPDATE_COPY' ] : [ 'UPDATE_COPY', 'UPDATE_BATCH_COPY' ]
113                         ]
114                     );
115                     g.edit = check.length == 0;
116                 } catch(E) {
117                     g.error.standard_unexpected_error_alert('batch permission check',E);
118                 }
119
120             }
121
122             if (g.edit) {
123                 $('caption').setAttribute('label', $('catStrings').getString('staff.cat.copy_editor.caption')); 
124                 $('save').setAttribute('hidden','false'); 
125             } else {
126                 $('top_nav').setAttribute('hidden','true');
127             }
128
129             g.retrieve_templates();
130
131         } else {
132             $('top_nav').setAttribute('hidden','true');
133         }
134
135         g.panes_and_field_names.left_pane = 
136             [
137                 [
138                     $('catStrings').getString('staff.cat.copy_editor.status'),
139                     { 
140                         render: 'typeof fm.status() == "object" ? fm.status().name() : g.data.hash.ccs[ fm.status() ].name()', 
141                         input: g.safe_to_edit_copy_status() ? 'c = function(v){ g.apply("status",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( util.functional.map_list( g.data.list.ccs, function(obj) { return [ obj.name(), obj.id(), typeof my_constants.magical_statuses[obj.id()] != "undefined" ? true : false ]; } ).sort() ); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);' : undefined,
142                         //input: 'c = function(v){ g.apply("status",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( util.functional.map_list( util.functional.filter_list( g.data.list.ccs, function(obj) { return typeof my_constants.magical_statuses[obj.id()] == "undefined"; } ), function(obj) { return [ obj.name(), obj.id() ]; } ).sort() ); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
143                     }
144                 ]
145             ].concat(g.panes_and_field_names.left_pane);
146
147
148         /******************************************************************************************************/
149         /* Show the Record Details? */
150
151         var bdb = document.getElementById('brief_display_box'); while(bdb.firstChild) bdb.removeChild(bdb.lastChild);
152         if (g.docid) {
153             var brief_display = document.createElement('iframe'); bdb.appendChild(brief_display); 
154             brief_display.setAttribute( 'src', urls.XUL_BIB_BRIEF + '?docid=' + g.docid); // this is a modal window, so can't push in xulG
155             brief_display.setAttribute( 'flex','1' );
156         }
157
158         /******************************************************************************************************/
159         /* Add stat cats to the panes_and_field_names.right_pane4 */
160
161         g.populate_stat_cats();
162
163         /******************************************************************************************************/
164         /* Backup copies :) */
165
166         g.original_copies = js2JSON( g.copies );
167
168         /******************************************************************************************************/
169         /* Do it */
170
171         g.summarize( g.copies );
172         g.render();
173         g.check_for_unmet_required_fields();
174
175         if (xulG.unified_interface) {
176             xulG.disable_copy_editor = function(c) {
177                 addCSSClass(document.documentElement,'disabled_copy_editor');
178                 g.disabled = true;
179             }
180             xulG.enable_copy_editor = function(c) {
181                 removeCSSClass(document.documentElement,'disabled_copy_editor');
182                 g.disabled = false;
183                 xulG.refresh_copy_editor();
184             }
185             xulG.refresh_copy_editor = function() {
186                 dump('refresh_copy_editor\n');
187                 addCSSClass(document.documentElement,'enabling_copy_editor');
188                 try {
189                     xulG.clear_update_copy_editor_timeout();
190                     g.copies = xulG.copies;
191                     g.edit = g.copies.length > 0;
192                     if (g.edit) {
193                         $('caption').setAttribute('label', $('catStrings').getString('staff.cat.copy_editor.caption'));
194                     }
195                     g.original_copies = js2JSON( g.copies );
196                     g.hide_copy_notes_button();
197                     for (var i = 0; i < g.applied_templates.length; i++) {
198                         g._apply_template( g.applied_templates[i], false);
199                     }
200                     if (g.copies.length > 0) {
201                         // Stop tracking these templates once they're applied
202                         // to actual copies
203                         g.applied_templates = [];
204                     }
205                     g.summarize( g.copies );
206                     g.render();
207                     g.check_for_unmet_required_fields();
208                     setTimeout(
209                         function() {
210                             removeCSSClass(document.documentElement,'enabling_copy_editor');
211                         }, 1000
212                     );
213                 } catch(E) {
214                     alert('Error in copy_editor.js, xulG.refresh_copy_editor(): ' + E);
215                 }
216             };
217             xulG.unlock_copy_editor = function() {
218                 oils_unlock_page();
219             };
220             xulG.notify_of_templatable_field_change = function(id,v) {
221                 g.changed[ 'volume_copy_creator.'+id ] = { 'type' : 'volume_copy_creator', 'field' : id, 'value' : v };
222             }
223         } else {
224             g.hide_copy_notes_button();
225         }
226
227         JSAN.use('util.hide');
228         util.hide.generate_css('ui.hide_copy_editor_fields');
229
230     } catch(E) {
231         var err_msg = $("commonStrings").getFormattedString('common.exception', ['cat/copy_editor.js', E]);
232         try { g.error.sdump('D_ERROR',err_msg); } catch(E) { dump(err_msg); dump(js2JSON(E)); }
233         alert(err_msg);
234     }
235 }
236
237 /******************************************************************************************************/
238 /* Show copy notes button */
239 g.hide_copy_notes_button = function() {
240     if (g.copies.length > 0 && g.copies[0].id() < 0) {
241         document.getElementById('copy_notes').setAttribute('hidden','true');
242         $('save').setAttribute('label', $('catStrings').getString('staff.cat.copy_editor.create_copies'));
243         $('save').setAttribute('accesskey', $('catStrings').getString('staff.cat.copy_editor.create_copies.accesskey'));
244     }
245     if (g.copies.length != 1) {
246         document.getElementById('copy_notes').setAttribute('hidden','true');
247     }
248 }
249
250 /******************************************************************************************************/
251 /* Retrieve Templates */
252
253 g.retrieve_templates = function() {
254     try {
255         JSAN.use('util.widgets'); JSAN.use('util.functional');
256         g.templates = {};
257         var robj = g.network.simple_request('FM_AUS_RETRIEVE',[ses(),g.data.list.au[0].id()]);
258         if (typeof robj['staff_client.copy_editor.templates'] != 'undefined') {
259             g.templates = robj['staff_client.copy_editor.templates'];
260         }
261         util.widgets.remove_children('template_placeholder');
262         var list = util.functional.map_object_to_list( g.templates, function(obj,i) { return [i, i]; } ).sort();
263
264         g.template_menu = util.widgets.make_menulist( list );
265         g.template_menu.setAttribute('id','template_menu');
266         $('template_placeholder').appendChild(g.template_menu);
267         g.template_menu.addEventListener(
268             'command',
269             function() { g.copy_editor_prefs[ 'template_menu' ] = { 'value' : g.template_menu.value }; g.save_attributes(); },
270             false
271         );
272
273         if (xulG.unified_interface) {
274             if (typeof xulG.update_unified_template_list == 'function') {
275                 xulG.update_unified_template_list(list);
276                 // functions the unified wrapper should use to let the item attribute editor do the heavy lifting for templates
277                 xulG.update_item_editor_template_selection = function(new_value) {
278                     g.template_menu.setAttribute('value', new_value);
279                     g.template_menu.value = new_value;
280                     g.copy_editor_prefs[ 'template_menu' ] = { 'value' : g.template_menu.value };
281                     g.save_attributes();
282                 }
283                 xulG.item_editor_apply_template = function() { g.apply_template(true); };
284                 xulG.item_editor_delete_template = function() { g.delete_template(); };
285                 xulG.item_editor_save_template = function() { g.save_template(); };
286                 xulG.item_editor_import_templates = function() { g.import_templates(); };
287                 xulG.item_editor_export_templates = function() { g.export_templates(); };
288                 xulG.item_editor_reset = function() { g.reset(); };
289             }
290         }
291
292     } catch(E) {
293         g.error.standard_unexpected_error_alert($('catStrings').getString('staff.cat.copy_editor.retrieve_templates.error'), E);
294     }
295 }
296
297 /******************************************************************************************************/
298 /* Apply Template */
299
300 g.applied_templates = [];
301
302 g.apply_template = function(apply_volume_editor_template_changes) {
303     try {
304         var name = g.template_menu.value;
305         if (g.templates[ name ] != 'undefined') {
306             if (g.copies == 0) {
307                 // We're only tracking these applied templates temporarily,
308                 // specifically when they're used prior to copies being
309                 // created in the unified interface.
310                 g.applied_templates.push( name );
311             }
312             g._apply_template(name,apply_volume_editor_template_changes);
313             g.summarize( g.copies );
314             g.render();
315             g.check_for_unmet_required_fields();
316         }
317     } catch(E) {
318         g.error.standard_unexpected_error_alert($('catStrings').getString('staff.cat.copy_editor.apply_templates.error'), E);
319     }
320 }
321
322 g._apply_template = function(name,apply_volume_editor_template_changes) {
323     try {
324         if (g.templates[ name ] != 'undefined') {
325             var template = g.templates[ name ];
326             for (var i in template) {
327                 g.changed[ i ] = template[ i ];
328                 switch( template[i].type ) {
329                     case 'attribute' :
330                         g.apply(template[i].field,template[i].value);
331                     break;
332                     case 'stat_cat' :
333                         if (g.stat_cat_seen[ template[i].field ]) g.apply_stat_cat(template[i].field,template[i].value);
334                     break;
335                     case 'owning_lib' :
336                         g.apply_owning_lib(template[i].value);
337                     break;
338                     case 'volume_copy_creator' :
339                         if (xulG.unified_interface && apply_volume_editor_template_changes) {
340                             xulG.apply_template_to_batch(template[i].field,template[i].value);
341                         }
342                     break;
343                 }
344             }
345         }
346     } catch(E) {
347         alert('Error in copy_editor.js, g._apply_template('+name+'): ' + E);
348     }
349 }
350
351 /******************************************************************************************************/
352 /* Save as Template */
353
354 g.save_template = function() {
355     try {
356         var name = window.prompt(
357             $('catStrings').getString('staff.cat.copy_editor.save_as_template.prompt'),
358             '',
359             $('catStrings').getString('staff.cat.copy_editor.save_as_template.title')
360         );
361         if (!name) return;
362         g.templates[name] = g.changed;
363         var robj = g.network.simple_request(
364             'FM_AUS_UPDATE',[ses(),g.data.list.au[0].id(), { 'staff_client.copy_editor.templates' : g.templates }]
365         );
366         if (typeof robj.ilsevent != 'undefined') {
367             throw(robj);
368         } else {
369             alert($('catStrings').getFormattedString('staff.cat.copy_editor.save_as_template.success', [name]));
370             setTimeout(
371                 function() {
372                     try {
373                         g.retrieve_templates();
374                     } catch(E) {
375                         g.error.standard_unexpected_error_alert($('catStrings').getString('staff.cat.copy_editor.save_as_template.error'), E);
376                     }
377                 },0
378             );
379         }
380     } catch(E) {
381         g.error.standard_unexpected_error_alert($('catStrings').getString('staff.cat.copy_editor.save_as_template.error'), E);
382     }
383 }
384
385 /******************************************************************************************************/
386 /* Delete Template */
387
388 g.delete_template = function() {
389     try {
390         var name = g.template_menu.value;
391         if (!name) return;
392         if (! window.confirm($('catStrings').getFormattedString('staff.cat.copy_editor.delete_template.confirm', [name]))) return;
393         delete(g.templates[name]);
394         var robj = g.network.simple_request(
395             'FM_AUS_UPDATE',[ses(),g.data.list.au[0].id(), { 'staff_client.copy_editor.templates' : g.templates }]
396         );
397         if (typeof robj.ilsevent != 'undefined') {
398             throw(robj);
399         } else {
400             alert($('catStrings').getFormattedString('staff.cat.copy_editor.delete_template.confirm', [name]));
401             setTimeout(
402                 function() {
403                     try {
404                         g.retrieve_templates();
405                     } catch(E) {
406                         g.error.standard_unexpected_error_alert($('catStrings').getString('staff.cat.copy_editor.delete_template.error'), E);
407                     }
408                 },0
409             );
410         }
411     } catch(E) {
412         g.error.standard_unexpected_error_alert($('catStrings').getString('staff.cat.copy_editor.delete_template.error'), E);
413     }
414 }
415
416 /******************************************************************************************************/
417 /* Export Templates */
418
419 g.export_templates = function() {
420     try {
421         netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
422         JSAN.use('util.file'); var f = new util.file('');
423         f.export_file( { 'title' : $('catStrings').getString('staff.cat.copy_editor.export_templates.title'), 'data' : g.templates } );
424     } catch(E) {
425         g.error.standard_unexpected_error_alert($('catStrings').getString('staff.cat.copy_editor.export_templates.error'), E);
426     }
427 }
428
429 /******************************************************************************************************/
430 /* Import Templates */
431
432 g.import_templates = function() {
433     try {
434         netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
435         JSAN.use('util.file'); var f = new util.file('');
436         var temp = f.import_file( { 'title' : $('catStrings').getString('staff.cat.copy_editor.import_templates.title') } );
437         if (temp) {
438             for (var i in temp) {
439
440                 if (g.templates[i]) {
441
442                     var r = g.error.yns_alert(
443                         $('catStrings').getString('staff.cat.copy_editor.import_templates.replace.prompt') + '\n' + g.error.pretty_print( js2JSON( temp[i] ) ),
444                         $('catStrings').getFormattedString('staff.cat.copy_editor.import_templates.replace.title', [i]),
445                         $('catStrings').getString('staff.cat.copy_editor.import_templates.replace.yes'),
446                         $('catStrings').getString('staff.cat.copy_editor.import_templates.replace.no'),
447                         null,
448                         $('catStrings').getString('staff.cat.copy_editor.import_templates.replace.click_here')
449                     );
450
451                     if (r == 0 /* Yes */) g.templates[i] = temp[i];
452
453                 } else {
454
455                     g.templates[i] = temp[i];
456
457                 }
458
459             }
460
461             var r = g.error.yns_alert(
462                 $('catStrings').getString('staff.cat.copy_editor.import_templates.save.prompt'),
463                 $('catStrings').getFormattedString('staff.cat.copy_editor.import_templates.save.title'),
464                 $('catStrings').getString('staff.cat.copy_editor.import_templates.save.yes'),
465                 $('catStrings').getString('staff.cat.copy_editor.import_templates.save.no'),
466                 null,
467                 $('catStrings').getString('staff.cat.copy_editor.import_templates.save.click_here')
468             );
469
470             if (r == 0 /* Yes */) {
471                 var robj = g.network.simple_request(
472                     'FM_AUS_UPDATE',[ses(),g.data.list.au[0].id(), { 'staff_client.copy_editor.templates' : g.templates }]
473                 );
474                 if (typeof robj.ilsevent != 'undefined') {
475                     throw(robj);
476                 } else {
477                     alert($('catStrings').getString('staff.cat.copy_editor.import_templates.save.success'));
478                     setTimeout(
479                         function() {
480                             try {
481                                 g.retrieve_templates();
482                             } catch(E) {
483                                 g.error.standard_unexpected_error_alert($('catStrings').getString('staff.cat.copy_editor.import_templates.save.error'), E);
484                             }
485                         },0
486                     );
487                 }
488             } else {
489                 util.widgets.remove_children('template_placeholder');
490                 var list = util.functional.map_object_to_list( g.templates, function(obj,i) { return [i, i]; } );
491                 g.template_menu = util.widgets.make_menulist( list );
492                 $('template_placeholder').appendChild(g.template_menu);
493                 alert($('catStrings').getString('staff.cat.copy_editor.import_templates.note'));
494             }
495
496         }
497     } catch(E) {
498         g.error.standard_unexpected_error_alert($('catStrings').getString('staff.cat.copy_editor.import_templates.error'), E);
499     }
500 }
501
502
503 /******************************************************************************************************/
504 /* Restore backup copies */
505
506 g.reset = function() {
507     g.applied_templates = [];
508     g.changed = {};
509     g.copies = JSON2js( g.original_copies );
510     g.summarize( g.copies );
511     g.render();
512     g.check_for_unmet_required_fields();
513     oils_unlock_page();
514     if (xulG.unified_interface) {
515         xulG.reset_batch_menus();
516     }
517 }
518
519 /******************************************************************************************************/
520 /* Apply a value to a specific field on all the copies being edited */
521
522 g.apply = function(field,value) {
523     g.error.sdump('D_TRACE','applying field = <' + field + '>  value = <' + value + '>\n');
524     if (value == '<HACK:KLUDGE:NULL>') {
525         value = null;
526     }
527     if (field == 'alert_message') { value = value.replace(/^\W+$/g,''); }
528     if (field == 'price' || field == 'deposit_amount') {
529         if (value == '') {
530             value = null;
531         } else {
532             JSAN.use('util.money'); value = util.money.sanitize( value );
533         }
534     }
535     for (var i = 0; i < g.copies.length; i++) {
536         var copy = g.copies[i];
537         try {
538             copy[field]( value ); copy.ischanged('1');
539         } catch(E) {
540             alert(E);
541         }
542     }
543
544     oils_lock_page();
545 }
546
547 /******************************************************************************************************/
548 /* Apply a stat cat entry to all the copies being edited.  An entry_id of < 0 signifies the stat cat is being removed. */
549
550 g.apply_stat_cat = function(sc_id,entry_id) {
551     g.error.sdump('D_TRACE','sc_id = ' + sc_id + '  entry_id = ' + entry_id + '\n');
552     for (var i = 0; i < g.copies.length; i++) {
553         var copy = g.copies[i];
554         try {
555             copy.ischanged('1');
556             var temp = copy.stat_cat_entries();
557             if (!temp) temp = [];
558             temp = util.functional.filter_list(
559                 temp,
560                 function (obj) {
561                     return (obj.stat_cat() != sc_id);
562                 }
563             );
564             if (entry_id > -1) {
565                 temp.push( 
566                     util.functional.find_id_object_in_list( 
567                         g.data.hash.asc[sc_id].entries(), 
568                         entry_id
569                     )
570                 );
571             }
572             copy.stat_cat_entries( temp );
573
574         } catch(E) {
575             g.error.standard_unexpected_error_alert('apply_stat_cat',E);
576         }
577     }
578
579     oils_lock_page();
580 }
581
582 /******************************************************************************************************/
583 /* Apply an "owning lib" to all the copies being edited.  That is, change and auto-vivicating volumes */
584
585 g.apply_owning_lib = function(ou_id) {
586     g.error.sdump('D_TRACE','ou_id = ' + ou_id + '\n');
587     // but don't allow this when bundled with the volume/copy creator UI, or if we're editing pre-cats
588     if (! g.safe_to_change_owning_lib() ) { return; }
589     for (var i = 0; i < g.copies.length; i++) {
590         var copy = g.copies[i];
591         try {
592             if (!g.map_acn[copy.call_number()]) {
593                 var volume = g.network.simple_request('FM_ACN_RETRIEVE.authoritative',[ copy.call_number() ]);
594                 if (typeof volume.ilsevent != 'undefined') {
595                     g.error.standard_unexpected_error_alert($('catStrings').getFormattedString('staff.cat.copy_editor.apply_owning_lib.undefined_volume.error', [copy.barcode()]), volume);
596                     continue;
597                 }
598                 g.map_acn[copy.call_number()] = volume;
599             }
600             var old_volume = g.map_acn[copy.call_number()];
601             var acn_blob = g.network.simple_request(
602                 'FM_ACN_FIND_OR_CREATE',
603                 [ses(),old_volume.label(),old_volume.record(),ou_id,old_volume.prefix().id(),old_volume.suffix().id(),old_volume.label_class().id()]
604             );
605             if (typeof acn_blob.ilsevent != 'undefined') {
606                 g.error.standard_unexpected_error_alert($('catStrings').getFormattedString('staff.cat.copy_editor.apply_owning_lib.call_number.error', [copy.barcode()]), acn_blob);
607                 continue;
608             }
609             copy.call_number(acn_blob.acn_id);
610             copy.ischanged('1');
611         } catch(E) {
612             g.error.standard_unexpected_error_alert('apply_stat_cat',E);
613         }
614     }
615
616     oils_lock_page();
617 }
618
619 /******************************************************************************************************/
620 /* This returns false if any of the copies being edited are pre-cats, or if we're embedded in the unified volume/copy UI */
621
622 g.safe_to_change_owning_lib = function() {
623     try {
624         if (xulG.unified_interface) { return false; }
625         var safe = true;
626         for (var i = 0; i < g.copies.length; i++) {
627             var cn = g.copies[i].call_number();
628             if (typeof cn == 'object') { cn = cn.id(); }
629             if (cn == -1) { safe = false; }
630         }
631         return safe;
632     } catch(E) {
633         g.error.standard_unexpected_error_alert('safe_to_change_owning_lib?',E);
634         return false;
635     }
636 }
637
638 /******************************************************************************************************/
639 /* This returns true if none of the copies being edited have a magical status found in my_constants.magical_statuses */
640
641 g.safe_to_edit_copy_status = function() {
642     try {
643         var safe = true;
644         for (var i = 0; i < g.copies.length; i++) {
645             var status = g.copies[i].status(); if (typeof status == 'object') status = status.id();
646             if (typeof my_constants.magical_statuses[ status ] != 'undefined') safe = false;
647         }
648         return safe;
649     } catch(E) {
650         g.error.standard_unexpected_error_alert('safe_to_edit_copy_status?',E);
651         return false;
652     }
653 }
654
655 /******************************************************************************************************/
656 /* This concats and uniques all the alert messages for use as the default value for a new alert message */
657
658 g.populate_alert_message_input = function(tb) {
659     try {
660         var seen = {}; var s = '';
661         for (var i = 0; i < g.copies.length; i++) {
662             var msg = g.copies[i].alert_message(); 
663             if (msg) {
664                 if (typeof seen[msg] == 'undefined') {
665                     s += msg + '\n';
666                     seen[msg] = true;
667                 }
668             }
669         }
670         tb.setAttribute('value',s);
671     } catch(E) {
672         g.error.standard_unexpected_error_alert('populate_alert_message_input',E);
673     }
674 }
675
676 /***************************************************************************************************************/
677 /* This returns a list of acpl's appropriate for the copies being edited (and caches them in the global stash) */
678
679 g.get_acpl_list_for_lib = function(lib_id,but_only_these) {
680     g.data.stash_retrieve();
681     var label = 'acpl_list_for_lib_'+lib_id;
682     if (typeof g.data[label] == 'undefined') {
683         var robj = g.network.simple_request('FM_ACPL_RETRIEVE', [ lib_id ]); // This returns acpl's for all ancestors and descendants as well as the lib
684         if (typeof robj.ilsevent != 'undefined') throw(robj);
685         var temp_list = [];
686         for (var j = 0; j < robj.length; j++) {
687             var my_acpl = robj[j];
688             if (typeof g.data.hash.acpl[ my_acpl.id() ] == 'undefined') {
689                 g.data.hash.acpl[ my_acpl.id() ] = my_acpl;
690                 g.data.list.acpl.push( my_acpl );
691             }
692             var only_this_lib = my_acpl.owning_lib(); if (!only_this_lib) continue;
693             if (typeof only_this_lib == 'object') only_this_lib = only_this_lib.id();
694             if (but_only_these.indexOf( String( only_this_lib ) ) != -1) { // This filters out some of the libraries (usually the descendants)
695                 temp_list.push( my_acpl );
696             }
697         }
698         g.data[label] = temp_list; g.data.stash(label,'hash','list');
699     }
700     return g.data[label];
701 }
702
703 /******************************************************************************************************/
704 /* This returns a list of acpl's appropriate for the copies being edited */
705
706 g.get_acpl_list = function() {
707     try {
708
709         JSAN.use('util.functional');
710
711         var my_acpls = {};
712
713         /**************************************/
714         /* get owning libs from call numbers */
715
716         var owning_libs = {}; 
717         for (var i = 0; i < g.copies.length; i++) {
718             var callnumber = g.copies[i].call_number();
719             if (!callnumber) continue;
720             var cn_id = typeof callnumber == 'object' ? callnumber.id() : callnumber;
721             if (cn_id > 0) {
722                 if (! g.map_acn[ cn_id ]) {
723                     var req = g.network.simple_request('FM_ACN_RETRIEVE.authoritative',[ cn_id ]);
724                     if (typeof req.ilsevent == 'undefined') {
725                         g.map_acn[ cn_id ] = req;
726                     } else {
727                         continue;
728                     }
729                 }
730                 var consider_lib = g.map_acn[ cn_id ].owning_lib();
731                 if (!consider_lib) continue;
732                 owning_libs[ typeof consider_lib == 'object' ? consider_lib.id() : consider_lib ] = true;
733             }
734         }
735         if (g.callnumbers) {
736             for (var i in g.callnumbers) {
737                 var consider_lib = g.callnumbers[i].owning_lib;
738                 if (!consider_lib) continue;
739                 owning_libs[ typeof consider_lib == 'object' ? consider_lib.id() : consider_lib ] = true;
740             }
741         }
742
743         /***************************************************************************************************/
744         /* now find the first ancestor they all have in common, get the acpl's for it and higher ancestors */
745
746         JSAN.use('util.fm_utils');
747         var libs = []; for (var i in owning_libs) libs.push(i);
748         if (libs.length > 0) {
749             var ancestor = util.fm_utils.find_common_aou_ancestor( libs );
750             if (typeof ancestor == 'object' && ancestor != null) ancestor = ancestor.id();
751
752             if (ancestor) {
753                 var ancestors = util.fm_utils.find_common_aou_ancestors( libs );
754                 var acpl_list = g.get_acpl_list_for_lib(ancestor, ancestors);
755                 if (acpl_list) for (var i = 0; i < acpl_list.length; i++) {
756                     if (acpl_list[i] != null) {
757                         my_acpls[ typeof acpl_list[i] == 'object' ? acpl_list[i].id() : acpl_list[i] ] = true;
758                     }
759                 }
760             }
761         }
762         
763         /*****************/
764         /* get circ libs */
765
766         var circ_libs = {};
767
768         for (var i = 0; i < g.copies.length; i++) {
769             var consider_lib = g.copies[i].circ_lib();
770             if (!consider_lib) continue;
771             circ_libs[ typeof consider_lib == 'object' ? consider_lib.id() : consider_lib ] = true;
772         }
773
774         /***************************************************************************************************/
775         /* now find the first ancestor they all have in common, get the acpl's for it and higher ancestors */
776
777         libs = []; for (var i in circ_libs) libs.push(i);
778         if (libs.length > 0) {
779             var ancestor = util.fm_utils.find_common_aou_ancestor( libs );
780             if (typeof ancestor == 'object' && ancestor != null) ancestor = ancestor.id();
781
782             if (ancestor) {
783                 var ancestors = util.fm_utils.find_common_aou_ancestors( libs );
784                 var acpl_list = g.get_acpl_list_for_lib(ancestor, ancestors);
785                 if (acpl_list) for (var i = 0; i < acpl_list.length; i++) {
786                     if (acpl_list[i] != null) {
787                         my_acpls[ typeof acpl_list[i] == 'object' ? acpl_list[i].id() : acpl_list[i] ] = true;
788                     }
789                 }
790             }
791         }
792
793         var acpl_list = []; for (var i in my_acpls) acpl_list.push( g.data.hash.acpl[ i ] );
794         return acpl_list.sort(
795             function(a,b) {
796                 var label_a = g.data.hash.aou[ a.owning_lib() ].shortname() + ' : ' + a.name();
797                 var label_b = g.data.hash.aou[ b.owning_lib() ].shortname() + ' : ' + b.name();
798                 if (label_a < label_b) return -1;
799                 if (label_a > label_b) return 1;
800                 return 0;
801             }
802         );
803     
804     } catch(E) {
805         g.error.standard_unexpected_error_alert('get_acpl_list',E);
806         return [];
807     }
808 }
809
810
811 /******************************************************************************************************/
812 /* This keeps track of which fields have been edited for styling purposes */
813
814 g.changed = {};
815
816 /******************************************************************************************************/
817 /* This keeps track of which fields are required, and which fields have been populated */
818
819 g.required = {};
820 g.populated = {};
821
822 /******************************************************************************************************/
823 /* These need data from the middle layer to render */
824
825 function init_panes0() {
826 g.special_exception = {};
827 g.special_exception[$('catStrings').getString('staff.cat.copy_editor.field.owning_library.label')] = function(label,value) {
828         JSAN.use('util.widgets');
829         if (value>0) { /* an existing call number */
830             g.network.simple_request(
831                 'FM_ACN_RETRIEVE.authoritative',
832                 [ value ],
833                 function(req) {
834                     var cn = '??? id = ' + value;
835                     try {
836                         cn = req.getResultObject();
837                     } catch(E) {
838                         g.error.sdump('D_ERROR','callnumber retrieve: ' + E);
839                     }
840                     util.widgets.set_text(label,g.data.hash.aou[ cn.owning_lib() ].shortname() + ' : ' + cn.label());
841                 }
842             );
843         } else { /* a yet to be created call number */
844             if (g.callnumbers) {
845                 util.widgets.set_text(label,g.data.hash.aou[ g.callnumbers[value].owning_lib ].shortname() + ' : ' + g.callnumbers[value].label);
846             }
847         }
848     };
849 g.special_exception[$('catStrings').getString('staff.cat.copy_editor.field.creator.label')] = function(label,value) {
850         if (!Number(value)) return;
851         g.network.simple_request(
852             'FM_AU_RETRIEVE_VIA_ID',
853             [ ses(), value ],
854             function(req) {
855                 var p = '??? id = ' + value;
856                 try {
857                     p = req.getResultObject();
858                     p = p.usrname();
859
860                 } catch(E) {
861                     g.error.sdump('D_ERROR','patron retrieve: ' + E);
862                 }
863                 JSAN.use('util.widgets');
864                 util.widgets.set_text(label,p);
865             }
866         );
867     };
868 g.special_exception[$('catStrings').getString('staff.cat.copy_editor.field.last_editor.label')] = function(label,value) {
869         if (!Number(value)) return;
870         g.network.simple_request(
871             'FM_AU_RETRIEVE_VIA_ID',
872             [ ses(), value ],
873             function(req) {
874                 var p = '??? id = ' + value;
875                 try {
876                     p = req.getResultObject();
877                     p = p.usrname();
878
879                 } catch(E) {
880                     g.error.sdump('D_ERROR','patron retrieve: ' + E);
881                 }
882                 util.widgets.set_text(label,p);
883             }
884         );
885     };
886 }
887
888 /******************************************************************************************************/
889 g.readonly_stat_cat_names = [];
890 g.editable_stat_cat_names = [];
891
892 /******************************************************************************************************/
893 /* These get show in the left panel */
894
895 function init_panes() {
896 g.panes_and_field_names = {
897
898     'left_pane' :
899 [
900     [
901         $('catStrings').getString('staff.cat.copy_editor.field.barcode.label'),
902         {
903             render: 'fm.barcode();',
904         }
905     ], 
906     [
907         $('catStrings').getString('staff.cat.copy_editor.field.creation_date.label'),
908         { 
909             render: 'util.date.formatted_date( fm.create_date(), "%F");',
910         }
911     ],
912     [
913         $('catStrings').getString('staff.cat.copy_editor.field.active_date.label'),
914         { 
915             render: 'util.date.formatted_date( fm.active_date(), "%F");',
916         }
917     ],
918     [
919         $('catStrings').getString('staff.cat.copy_editor.field.creator.label'),
920         { 
921             render: 'fm.creator();',
922         }
923     ],
924     [
925         $('catStrings').getString('staff.cat.copy_editor.field.last_edit_date.label'),
926         { 
927             render: 'util.date.formatted_date( fm.edit_date(), "%F");',
928         }
929     ],
930     [
931         $('catStrings').getString('staff.cat.copy_editor.field.last_editor.label'),
932         {
933             render: 'fm.editor();',
934         }
935     ],
936
937 ],
938
939 'right_pane' :
940 [
941     [
942         $('catStrings').getString('staff.cat.copy_editor.field.location.label'),
943         { 
944             render: 'typeof fm.location() == "object" ? fm.location().name() : g.data.lookup("acpl",fm.location()).name()', 
945             input: 'c = function(v){ g.apply("location",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( util.functional.map_list( g.get_acpl_list(), function(obj) { return [ ' + (g.cl_first ? 'obj.name() + " : " + g.data.hash.aou[ obj.owning_lib() ].shortname()' : 'g.data.hash.aou[ obj.owning_lib() ].shortname() + " : " + obj.name()') + ', obj.id() ]; }).sort()); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
946
947         }
948     ],
949     [
950         $('catStrings').getString('staff.cat.copy_editor.field.circulation_library.label'),
951         {     
952             render: 'typeof fm.circ_lib() == "object" ? fm.circ_lib().shortname() : g.data.hash.aou[ fm.circ_lib() ].shortname()',
953             //input: 'c = function(v){ g.apply("circ_lib",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( util.functional.map_list( util.functional.filter_list(g.data.list.my_aou, function(obj) { return g.data.hash.aout[ obj.ou_type() ].can_have_vols(); }), function(obj) { return [ obj.shortname(), obj.id() ]; }).sort() ); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
954             input: 'c = function(v){ g.apply("circ_lib",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( util.functional.map_list( g.data.list.aou, function(obj) { var sname = obj.shortname(); for (i = sname.length; i < 20; i++) sname += " "; return [ obj.name() ? sname + " " + obj.name() : obj.shortname(), obj.id(), ( ! get_bool( g.data.hash.aout[ obj.ou_type() ].can_have_vols() ) ), ( g.data.hash.aout[ obj.ou_type() ].depth() * 2), ]; }), g.data.list.au[0].ws_ou()); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
955         } 
956     ],
957     [
958         $('catStrings').getString('staff.cat.copy_editor.field.owning_library.label'),
959         {
960             render: 'fm.call_number();',
961             input: g.safe_to_change_owning_lib() ? 'c = function(v){ g.apply_owning_lib(v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( util.functional.map_list( g.data.list.aou, function(obj) { var sname = obj.shortname(); for (i = sname.length; i < 20; i++) sname += " "; return [ obj.name() ? sname + " " + obj.name() : obj.shortname(), obj.id(), ( ! get_bool( g.data.hash.aout[ obj.ou_type() ].can_have_vols() ) ), ( g.data.hash.aout[ obj.ou_type() ].depth() * 2), ]; }), g.data.list.au[0].ws_ou()); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);' : undefined,
962         }
963     ],
964     [
965         $('catStrings').getString('staff.cat.copy_editor.field.copy_number.label'),
966         { 
967             render: 'fm.copy_number() == null ? $("catStrings").getString("staff.cat.copy_editor.field.unset_or_null") : fm.copy_number()',
968             input: 'c = function(v){ g.apply("copy_number",v); if (typeof post_c == "function") post_c(v); }; x = document.createElement("textbox"); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
969         }
970     ],
971
972
973 ],
974
975 'right_pane2' :
976 [
977     [
978         $('catStrings').getString('staff.cat.copy_editor.field.circulate.label'),
979         {     
980             render: 'fm.circulate() == null ? $("catStrings").getString("staff.cat.copy_editor.field.unset_or_null") : ( get_bool( fm.circulate() ) ? $("catStrings").getString("staff.cat.copy_editor.field.circulate.yes_or_true") : $("catStrings").getString("staff.cat.copy_editor.field.circulate.no_or_false") )',
981             input: 'c = function(v){ g.apply("circulate",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( [ [ $("catStrings").getString("staff.cat.copy_editor.field.circulate.yes_or_true"), get_db_true() ], [ $("catStrings").getString("staff.cat.copy_editor.field.circulate.no_or_false"), get_db_false() ] ] ); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
982         }
983     ],
984     [
985         $('catStrings').getString('staff.cat.copy_editor.field.holdable.label'),
986         { 
987             render: 'fm.holdable() == null ? $("catStrings").getString("staff.cat.copy_editor.field.unset_or_null") : ( get_bool( fm.holdable() ) ? $("catStrings").getString("staff.cat.copy_editor.field.holdable.yes_or_true") : $("catStrings").getString("staff.cat.copy_editor.field.holdable.no_or_false") )',
988             input: 'c = function(v){ g.apply("holdable",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( [ [ $("catStrings").getString("staff.cat.copy_editor.field.holdable.yes_or_true"), get_db_true() ], [ $("catStrings").getString("staff.cat.copy_editor.field.holdable.no_or_false"), get_db_false() ] ] ); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
989         }
990     ],
991     [
992         $('catStrings').getString('staff.cat.copy_editor.field.age_based_hold_protection.label'),
993         {
994             render: 'fm.age_protect() == null ? $("catStrings").getString("staff.cat.copy_editor.field.unset_or_null") : ( typeof fm.age_protect() == "object" ? fm.age_protect().name() : g.data.hash.crahp[ fm.age_protect() ].name() )', 
995             input: 'c = function(v){ g.apply("age_protect",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( [ [ $("catStrings").getString("staff.cat.copy_editor.remove_age_based_hold_protection"), "<HACK:KLUDGE:NULL>" ] ].concat( util.functional.map_list( g.data.list.crahp, function(obj) { return [ obj.name(), obj.id() ]; }).sort() ) ); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
996         }
997
998     ],
999     [
1000         $('catStrings').getString('staff.cat.copy_editor.field.floating.label'),
1001         { 
1002             render: 'fm.floating() == null ? $("catStrings").getString("staff.cat.copy_editor.field.unset_or_null") : ( get_bool( fm.floating() ) ? $("catStrings").getString("staff.cat.copy_editor.field.floating.yes_or_true") : $("catStrings").getString("staff.cat.copy_editor.field.floating.no_or_false") )',
1003             input: 'c = function(v){ g.apply("floating",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( [ [ $("catStrings").getString("staff.cat.copy_editor.field.floating.yes_or_true"), get_db_true() ], [ $("catStrings").getString("staff.cat.copy_editor.field.floating.no_or_false"), get_db_false() ] ] ); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
1004         }
1005     ],
1006     [
1007         $('catStrings').getString('staff.cat.copy_editor.field.loan_duration.label'),
1008         { 
1009             render: 'switch(Number(fm.loan_duration())){ case 1: $("catStrings").getString("staff.cat.copy_editor.field.loan_duration.short"); break; case 2: $("catStrings").getString("staff.cat.copy_editor.field.loan_duration.normal"); break; case 3: $("catStrings").getString("staff.cat.copy_editor.field.loan_duration.extended"); break; }',
1010             input: 'c = function(v){ g.apply("loan_duration",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( [ [ $("catStrings").getString("staff.cat.copy_editor.field.loan_duration.short"), "1" ], [ $("catStrings").getString("staff.cat.copy_editor.field.loan_duration.normal"), "2" ], [ $("catStrings").getString("staff.cat.copy_editor.field.loan_duration.extended"), "3" ] ] ); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
1011
1012         }
1013     ],
1014     [
1015         $('catStrings').getString('staff.cat.copy_editor.field.fine_level.label'),
1016         {
1017             render: 'switch(Number(fm.fine_level())){ case 1: $("catStrings").getString("staff.cat.copy_editor.field.fine_level.low"); break; case 2: $("catStrings").getString("staff.cat.copy_editor.field.fine_level.normal"); break; case 3: $("catStrings").getString("staff.cat.copy_editor.field.fine_level.high"); break; }',
1018             input: 'c = function(v){ g.apply("fine_level",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( [ [ $("catStrings").getString("staff.cat.copy_editor.field.fine_level.low"), "1" ], [ $("catStrings").getString("staff.cat.copy_editor.field.fine_level.normal"), "2" ], [ $("catStrings").getString("staff.cat.copy_editor.field.fine_level.high"), "3" ] ] ); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
1019         }
1020     ],
1021
1022      [
1023         $('catStrings').getString('staff.cat.copy_editor.field.circulate_as_type.label'),
1024         {     
1025             render: 'fm.circ_as_type() == null ? $("catStrings").getString("staff.cat.copy_editor.field.unset_or_null") : g.data.hash.citm[ fm.circ_as_type() ].value',
1026             input: 'c = function(v){ g.apply("circ_as_type",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( [ [ $("catStrings").getString("staff.cat.copy_editor.remove_circulate_as_type"), "<HACK:KLUDGE:NULL>" ] ].concat( util.functional.map_list( g.data.list.citm, function(n){return [ n.code + " - " + n.value, n.code];} ).sort() ) ); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
1027         } 
1028     ],
1029     [
1030         $('catStrings').getString('staff.cat.copy_editor.field.circulation_modifier.label'),
1031         {    
1032             render: 'fm.circ_modifier() == null ? $("catStrings").getString("staff.cat.copy_editor.field.unset_or_null") : $("commonStrings").getFormattedString("staff.circ_modifier.display",[fm.circ_modifier(),g.data.hash.ccm[fm.circ_modifier()].name(),g.data.hash.ccm[fm.circ_modifier()].description()])',
1033             input: 'c = function(v){ g.apply("circ_modifier",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( [ [ $("catStrings").getString("staff.cat.copy_editor.field.unset_or_null"), "<HACK:KLUDGE:NULL>" ] ].concat( util.functional.map_list( g.data.list.ccm, function(obj) { return [ $("commonStrings").getFormattedString("staff.circ_modifier.display",[obj.code(),obj.name(),obj.description()]), obj.code() ]; } ).sort() ) ); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
1034         }
1035     ],
1036 ],
1037
1038 'right_pane3' :
1039 [    [
1040         $('catStrings').getString('staff.cat.copy_editor.field.alert_message.label'),
1041         {
1042             render: 'fm.alert_message() == null ? $("catStrings").getString("staff.cat.copy_editor.field.unset_or_null") : fm.alert_message()',
1043             input: 'c = function(v){ g.apply("alert_message",v); if (typeof post_c == "function") post_c(v); }; x = document.createElement("textbox"); x.setAttribute("multiline",true); g.populate_alert_message_input(x); x.addEventListener("apply",function(f){ return function(ev) { f( ev.target.value ); } }(c), false);',
1044         }
1045     ],
1046
1047     [
1048         $('catStrings').getString('staff.cat.copy_editor.field.deposit.label'),
1049         { 
1050             render: 'fm.deposit() == null ? $("catStrings").getString("staff.cat.copy_editor.field.unset_or_null") : ( get_bool( fm.deposit() ) ? $("catStrings").getString("staff.cat.copy_editor.field.deposit.yes_or_true") : $("catStrings").getString("staff.cat.copy_editor.field.deposit.no_or_false") )',
1051             input: 'c = function(v){ g.apply("deposit",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( [ [ $("catStrings").getString("staff.cat.copy_editor.field.deposit.yes_or_true"), get_db_true() ], [ $("catStrings").getString("staff.cat.copy_editor.field.deposit.no_or_false"), get_db_false() ] ] ); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
1052         }
1053     ],
1054     [
1055         $('catStrings').getString('staff.cat.copy_editor.field.deposit_amount.label'),
1056         { 
1057             render: 'if (fm.deposit_amount() == null) { $("catStrings").getString("staff.cat.copy_editor.field.unset_or_null"); } else { util.money.sanitize( fm.deposit_amount() ); }',
1058             input: 'c = function(v){ g.apply("deposit_amount",v); if (typeof post_c == "function") post_c(v); }; x = document.createElement("textbox"); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
1059         }
1060     ],
1061     [
1062         $('catStrings').getString('staff.cat.copy_editor.field.price.label'),
1063         { 
1064             render: 'if (fm.price() == null) { $("catStrings").getString("staff.cat.copy_editor.field.unset_or_null"); } else { util.money.sanitize( fm.price() ); }', 
1065             input: 'c = function(v){ g.apply("price",v); if (typeof post_c == "function") post_c(v); }; x = document.createElement("textbox"); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
1066         }
1067     ],
1068
1069     [
1070         $('catStrings').getString('staff.cat.copy_editor.field.opac_visible.label'),
1071         { 
1072             render: 'fm.opac_visible() == null ? $("catStrings").getString("staff.cat.copy_editor.field.unset_or_null") : ( get_bool( fm.opac_visible() ) ? $("catStrings").getString("staff.cat.copy_editor.field.opac_visible.yes_or_true") : $("catStrings").getString("staff.cat.copy_editor.field.opac_visible.no_or_false") )', 
1073             input: 'c = function(v){ g.apply("opac_visible",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( [ [ $("catStrings").getString("staff.cat.copy_editor.field.opac_visible.yes_or_true"), get_db_true() ], [ $("catStrings").getString("staff.cat.copy_editor.field.opac_visible.no_or_false"), get_db_false() ] ] ); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
1074         }
1075     ],
1076     [
1077         $('catStrings').getString('staff.cat.copy_editor.field.reference.label'),
1078         { 
1079             render: 'fm.ref() == null ? $("catStrings").getString("staff.cat.copy_editor.field.unset_or_null") : ( get_bool( fm.ref() ) ? $("catStrings").getString("staff.cat.copy_editor.field.reference.yes_or_true") : $("catStrings").getString("staff.cat.copy_editor.field.reference.no_or_false") )', 
1080             input: 'c = function(v){ g.apply("ref",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( [ [ $("catStrings").getString("staff.cat.copy_editor.field.reference.yes_or_true"), get_db_true() ], [ $("catStrings").getString("staff.cat.copy_editor.field.reference.no_or_false"), get_db_false() ] ] ); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
1081         }
1082     ],
1083     [
1084         $('catStrings').getString('staff.cat.copy_editor.field.mint_condition.label'),
1085         { 
1086             render: 'get_bool( fm.mint_condition() ) ? $("catStrings").getString("staff.cat.copy_editor.field.mint_condition.yes_or_true") : $("catStrings").getString("staff.cat.copy_editor.field.mint_condition.no_or_false")', 
1087             input: 'c = function(v){ g.apply("mint_condition",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( [ [ $("catStrings").getString("staff.cat.copy_editor.field.mint_condition.yes_or_true"), get_db_true() ], [ $("catStrings").getString("staff.cat.copy_editor.field.mint_condition.no_or_false"), get_db_false() ] ] ); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
1088         }
1089     ]
1090 ],
1091
1092 'right_pane4' : 
1093 [
1094 ]
1095
1096 };
1097 }
1098
1099 /******************************************************************************************************/
1100 /* This loops through all our fieldnames and all the copies, tallying up counts for the different values */
1101
1102 g.summarize = function( copies ) {
1103     /******************************************************************************************************/
1104     /* Setup */
1105
1106     JSAN.use('util.date'); JSAN.use('util.money');
1107     g.summary = {};
1108     g.field_names = [];
1109     for (var i in g.panes_and_field_names) {
1110         g.field_names = g.field_names.concat( g.panes_and_field_names[i] );
1111     }
1112     g.field_names = g.field_names.concat( g.editable_stat_cat_names );
1113     g.field_names = g.field_names.concat( g.readonly_stat_cat_names );
1114
1115     /******************************************************************************************************/
1116     /* Loop through the field names */
1117
1118     for (var i = 0; i < g.field_names.length; i++) {
1119
1120         var field_name = g.field_names[i][0];
1121         var render = g.field_names[i][1].render;
1122         var attr = g.field_names[i][1].attr;
1123         g.summary[ field_name ] = {};
1124         g.populated[ field_name ] = 1; // delete later if we encounter a copy with the field unset
1125
1126         /******************************************************************************************************/
1127         /* Loop through the copies */
1128
1129         for (var j = 0; j < copies.length; j++) {
1130
1131             var fm = copies[j];
1132             var cmd = render || ('fm.' + field_name + '();');
1133             var value = $("catStrings").getString("staff.cat.copy_editor.field.unset_or_null");
1134
1135             /**********************************************************************************************/
1136             /* Try to retrieve the value for this field for this copy */
1137
1138             try { 
1139                 value = eval( cmd ); 
1140             } catch(E) { 
1141                 g.error.sdump('D_ERROR','Attempted ' + cmd + '\n' +  E + '\n'); 
1142             }
1143             if (typeof value == 'object' && value != null) {
1144                 alert('FIXME: field_name = <' + field_name + '>  value = <' + js2JSON(value) + '>\n');
1145             }
1146             if (value == $("catStrings").getString("staff.cat.copy_editor.field.unset_or_null")) {
1147                 delete g.populated[field_name];
1148             }
1149
1150             /**********************************************************************************************/
1151             /* Tally the count */
1152
1153             if (g.summary[ field_name ][ value ]) {
1154                 g.summary[ field_name ][ value ]++;
1155             } else {
1156                 g.summary[ field_name ][ value ] = 1;
1157             }
1158         }
1159     }
1160     g.error.sdump('D_TRACE','summary = ' + js2JSON(g.summary) + '\n');
1161 }
1162
1163 /******************************************************************************************************/
1164 /* Display the summarized data and inputs for editing */
1165
1166 g.render = function() {
1167
1168     /******************************************************************************************************/
1169     /* Library setup and clear any existing interface */
1170
1171     JSAN.use('util.widgets'); JSAN.use('util.date'); JSAN.use('util.money'); JSAN.use('util.functional');
1172
1173     for (var i in g.panes_and_field_names) {
1174         var p = document.getElementById(i);
1175         if (p) util.widgets.remove_children(p);
1176     }
1177
1178     /******************************************************************************************************/
1179     /* Populate the library filter menu for stat cats */
1180
1181     var sc_libs = {};
1182     for (var i = 0; i < g.panes_and_field_names.right_pane4.length; i++) {
1183         sc_libs[ g.panes_and_field_names.right_pane4[i][1].attr.sc_lib ] = true;
1184     }
1185     var sc_libs2 = [];
1186     for (var i in sc_libs) { sc_libs2.push( [ g.data.hash.aou[ i ].shortname(), i ] ); }
1187     sc_libs2.sort();
1188     var x = document.getElementById("stat_cat_lib_filter_menu").firstChild;
1189     JSAN.use('util.widgets'); util.widgets.remove_children(x);
1190     for (var i = 0; i < sc_libs2.length; i++) {
1191         var menuitem = document.createElement('menuitem');
1192         menuitem.setAttribute('id','filter_'+sc_libs2[i][1]);
1193         menuitem.setAttribute('type','checkbox');
1194         menuitem.setAttribute('checked','true');
1195         menuitem.setAttribute('label',sc_libs2[i][0]);
1196         menuitem.setAttribute('value',sc_libs2[i][1]);
1197         menuitem.setAttribute('oncommand','try{g.toggle_stat_cat_display(this);}catch(E){alert(E);}');
1198         x.appendChild(menuitem);
1199     }
1200
1201     /******************************************************************************************************/
1202     /* Prepare the panes */
1203
1204     var groupbox; var caption; var vbox; var grid; var rows;
1205     
1206     /******************************************************************************************************/
1207     /* Loop through the field names */
1208
1209     for (h in g.panes_and_field_names) {
1210         if (!document.getElementById(h)) continue;
1211         for (var i = 0; i < g.panes_and_field_names[h].length; i++) {
1212             try {
1213                 var f = g.panes_and_field_names[h][i]; var fn = f[0]; var attr = f[1].attr;
1214                 groupbox = document.createElement('groupbox'); document.getElementById(h).appendChild(groupbox);
1215                 groupbox.setAttribute('hideable',fn);
1216                 if (attr) {
1217                     for (var a in attr) {
1218                         groupbox.setAttribute(a,attr[a]);
1219                     }
1220                 }
1221                 caption = document.createElement('caption'); groupbox.appendChild(caption);
1222                 caption.setAttribute('label',fn);
1223                 caption.setAttribute('id','caption_'+fn); // used for focus/keyboard navigation
1224                 caption.setAttribute('hideable',fn);
1225                 vbox = document.createElement('vbox'); groupbox.appendChild(vbox); // main display widget goes here
1226                 if (typeof g.changed[fn] != 'undefined') { addCSSClass(vbox,'copy_editor_field_changed'); }
1227                 if (typeof g.required[fn] != 'undefined') { addCSSClass(vbox,'copy_editor_field_required'); }
1228                 grid = util.widgets.make_grid( [ { 'flex' : 1 }, {}, {} ] ); vbox.appendChild(grid);
1229                 grid.setAttribute('flex','1');
1230                 rows = grid.lastChild;
1231                 var row;
1232                 
1233                 /**************************************************************************************/
1234                 /* Loop through each value for the field */
1235
1236                 for (var j in g.summary[fn]) {
1237                     var value = j; var count = g.summary[fn][j];
1238                     row = document.createElement('row'); rows.appendChild(row);
1239                     var label1 = document.createElement('description'); row.appendChild(label1);
1240                     if (g.special_exception[ fn ]) {
1241                         g.special_exception[ fn ]( label1, value );
1242                     } else {
1243                         label1.appendChild( document.createTextNode(value) );
1244                     }
1245                     var label2 = document.createElement('description'); row.appendChild(label2);
1246                     var copy_count;
1247                     if (count == 1) {
1248                         copy_count = $('catStrings').getString('staff.cat.copy_editor.copy_count');
1249                     } else {
1250                         copy_count = $('catStrings').getFormattedString('staff.cat.copy_editor.copy_count.plural', [count]);
1251                     }
1252                     label2.appendChild( document.createTextNode(copy_count) );
1253                 }
1254                 groupbox.setAttribute('id','groupbox_'+fn); // this id is meant to be referenced by cat_custom.css for hiding fields
1255                 var hbox = document.createElement('hbox'); // main input controls go here
1256                 hbox.setAttribute('id',fn); // this id gets used to color areas green, etc.
1257                 groupbox.appendChild(hbox);
1258                 var hbox2 = document.createElement('hbox'); // cancel/apply buttons go here
1259                 groupbox.appendChild(hbox2);
1260
1261                 /**************************************************************************************/
1262                 /* Render the input widget */
1263
1264                 if (f[1].input && g.edit) {
1265                     g.render_input(hbox,f[1]);
1266                 }
1267
1268             } catch(E) {
1269                 g.error.sdump('D_ERROR','copy editor: ' + E + '\n');
1270             }
1271         }
1272     }
1273     
1274     
1275     /******************************************************************************************************/
1276     /* Synchronize stat cat visibility with library filter menu, and default template selection */
1277     JSAN.use('util.file'); 
1278     var file = new util.file('copy_editor_prefs.'+g.data.server_unadorned);
1279     g.copy_editor_prefs = util.widgets.load_attributes(file);
1280     for (var i in g.copy_editor_prefs) {
1281         if (i.match(/filter_/) && g.copy_editor_prefs[i].checked == '') {
1282             try { 
1283                 g.toggle_stat_cat_display( document.getElementById(i) ); 
1284             } catch(E) { alert(E); }
1285         }
1286     }
1287     if (g.template_menu) {
1288         g.template_menu.value = g.template_menu.getAttribute('value');
1289         if (xulG.unified_interface) {
1290             if (typeof xulG.update_unified_template_selection == 'function') {
1291                 xulG.update_unified_template_selection(g.template_menu.value);
1292             }
1293         }
1294     }
1295
1296 }
1297
1298 /******************************************************************************************************/
1299 /* This actually draws the change button and input widget for a given field */
1300 g.render_input = function(node,blob) {
1301     try {
1302         // node = hbox ;    groupbox ->  hbox, hbox
1303
1304         var groupbox = node.parentNode;
1305         var caption = groupbox.firstChild;
1306         var vbox = node.previousSibling;
1307         var hbox = node;
1308         var hbox2 = node.nextSibling;
1309
1310         var input_cmd = blob.input;
1311         var render_cmd = blob.render;
1312         var attr = blob.attr;
1313
1314         var block = false; var first = true;
1315
1316         function on_mouseover(ev) {
1317             groupbox.setAttribute('style','background: white');
1318         }
1319
1320         function on_mouseout(ev) {
1321             groupbox.setAttribute('style','');
1322         }
1323
1324         vbox.addEventListener('mouseover',on_mouseover,false);
1325         vbox.addEventListener('mouseout',on_mouseout,false);
1326         groupbox.addEventListener('mouseover',on_mouseover,false);
1327         groupbox.addEventListener('mouseout',on_mouseout,false);
1328         groupbox.firstChild.addEventListener('mouseover',on_mouseover,false);
1329         groupbox.firstChild.addEventListener('mouseout',on_mouseout,false);
1330
1331         function on_click(ev){
1332             try {
1333                 if (block || g.disabled || !g.edit) {
1334                     return;
1335                 }
1336                 block = true;
1337
1338                 oils_lock_page();
1339
1340                 function post_c(v) {
1341                     try {
1342                         /* FIXME - kludgy */
1343                         var t = input_cmd.match('apply_stat_cat') ? 'stat_cat' : ( input_cmd.match('apply_owning_lib') ? 'owning_lib' : 'attribute' );
1344                         var f;
1345                         switch(t) {
1346                             case 'attribute' :
1347                                 f = input_cmd.match(/apply\("(.+?)",/)[1];
1348                             break;
1349                             case 'stat_cat' :
1350                                 f = input_cmd.match(/apply_stat_cat\((.+?),/)[1];
1351                             break;
1352                             case 'owning_lib' :
1353                                 f = null;
1354                             break;
1355                         }
1356                         g.changed[ hbox.id ] = { 'type' : t, 'field' : f, 'value' : v };
1357                         block = false;
1358                         setTimeout(
1359                             function() {
1360                                 g.summarize( g.copies );
1361                                 g.render();
1362                                 g.check_for_unmet_required_fields();
1363                                 document.getElementById(caption.id).focus();
1364                             }, 0
1365                         );
1366                     } catch(E) {
1367                         g.error.standard_unexpected_error_alert('post_c',E);
1368                     }
1369                 }
1370                 var x; var c; eval( input_cmd );
1371                 if (x) {
1372                     util.widgets.remove_children(vbox);
1373                     util.widgets.remove_children(hbox);
1374                     util.widgets.remove_children(hbox2);
1375                     hbox.appendChild(x);
1376                     var apply = document.createElement('button');
1377                     apply.setAttribute('label', $('catStrings').getString('staff.cat.copy_editor.apply.label'));
1378                     apply.setAttribute('accesskey', $('catStrings').getString('staff.cat.copy_editor.apply.accesskey'));
1379                     hbox2.appendChild(apply);
1380                     apply.addEventListener('command',function() { c(x.value); },false);
1381                     var cancel = document.createElement('button');
1382                     cancel.setAttribute('label', $('catStrings').getString('staff.cat.copy_editor.cancel.label'));
1383                     cancel.addEventListener('command',function() {
1384                             setTimeout( function() {
1385                                     g.summarize( g.copies );
1386                                     g.render();
1387                                     g.check_for_unmet_required_fields();
1388                                     document.getElementById(caption.id).focus(); 
1389                                 }, 0
1390                             );
1391                         }, false
1392                     );
1393                     hbox2.appendChild(cancel);
1394                     setTimeout( function() { x.focus(); }, 0 );
1395                 }
1396             } catch(E) {
1397                 g.error.standard_unexpected_error_alert('render_input',E);
1398             }
1399         }
1400         vbox.addEventListener('click',on_click, false);
1401         hbox.addEventListener('click',on_click, false);
1402         caption.addEventListener('click',on_click, false);
1403         caption.addEventListener('keypress',function(ev) {
1404             if (ev.keyCode == 13 /* enter */ || ev.keyCode == 77 /* mac enter */) on_click();
1405         }, false);
1406         caption.setAttribute('style','-moz-user-focus: normal');
1407         caption.setAttribute('onfocus','this.setAttribute("class","outline_me")');
1408         caption.setAttribute('onblur','this.setAttribute("class","")');
1409
1410     } catch(E) {
1411         g.error.sdump('D_ERROR',E + '\n');
1412     }
1413 }
1414
1415 /******************************************************************************************************/
1416 /* store the copies in the global xpcom stash */
1417
1418 g.stash_and_close = function() {
1419     try {
1420         oils_unlock_page();
1421
1422         if (g.handle_update) {
1423             try {
1424                 var r = g.network.request(
1425                     api.FM_ACP_FLESHED_BATCH_UPDATE.app,
1426                     api.FM_ACP_FLESHED_BATCH_UPDATE.method,
1427                     [ ses(), g.copies, true ]
1428                 );
1429                 if (typeof r.ilsevent != 'undefined') {
1430                     g.error.standard_unexpected_error_alert('copy update',r);
1431                 }
1432                 /* FIXME -- revisit the return value here */
1433             } catch(E) {
1434                 alert($('catStrings').getString('staff.cat.copy_editor.handle_update.error') + ' ' + js2JSON(E));
1435             }
1436         }
1437         //g.data.temp_copies = js2JSON( g.copies );
1438         //g.data.stash('temp_copies');
1439         xulG.copies = g.copies;
1440         update_modal_xulG(xulG);
1441         JSAN.use('util.widgets');
1442         util.widgets.dispatch('close',window);
1443     } catch(E) {
1444         alert('Error in copy_editor.js, g.stash_and_close(): '+E);
1445     }
1446 }
1447
1448 /******************************************************************************************************/
1449 /* spawn copy notes interface */
1450
1451 g.copy_notes = function() {
1452     JSAN.use('util.window'); var win = new util.window();
1453     win.open(
1454         urls.XUL_COPY_NOTES, 
1455         //+ '?copy_id=' + window.escape(g.copies[0].id()),
1456         $("catStrings").getString("staff.cat.copy_editor.copy_notes"),'chrome,resizable,modal',
1457         { 'copy_id' : g.copies[0].id() }
1458     );
1459 }
1460
1461 /******************************************************************************************************/
1462 /* hides or unhides stat cats based on library stat cat filter menu */
1463 g.toggle_stat_cat_display = function(el) {
1464     if (!el) return;
1465     var visible = el.getAttribute('checked');
1466     var nl = document.getElementsByAttribute('sc_lib',el.getAttribute('value'));
1467     for (var n = 0; n < nl.length; n++) {
1468         if (visible) {
1469             nl[n].setAttribute('hidden','false');
1470         } else {
1471             nl[n].setAttribute('hidden','true');
1472         }
1473     }
1474     g.copy_editor_prefs[ el.getAttribute('id') ] = { 'checked' : visible };
1475     g.save_attributes();
1476 }
1477
1478 /******************************************************************************************************/
1479 /* This adds a stat cat definition to the stat cat pane for rendering */
1480 g.save_attributes = function() {
1481     JSAN.use('util.widgets'); JSAN.use('util.file'); var file = new util.file('copy_editor_prefs.'+g.data.server_unadorned);
1482     var what_to_save = {};
1483     for (var i in g.copy_editor_prefs) {
1484         what_to_save[i] = [];
1485         for (var j in g.copy_editor_prefs[i]) what_to_save[i].push(j);
1486     }
1487     util.widgets.save_attributes(file, what_to_save );
1488 }
1489
1490 /******************************************************************************************************/
1491 /* This adds a stat cat definition to the stat cat pane for rendering */
1492 g.add_stat_cat = function(sc) {
1493     try {
1494         if (typeof g.data.hash.asc == 'undefined') { g.data.hash.asc = {}; g.data.stash('hash'); }
1495
1496         var sc_id = sc;
1497
1498         if (typeof sc == 'object') {
1499
1500             sc_id = sc.id();
1501         }
1502
1503         if (typeof g.stat_cat_seen[sc_id] != 'undefined') { return; }
1504
1505         g.stat_cat_seen[ sc_id ] = 1;
1506
1507         if (typeof sc != 'object') {
1508
1509             sc = g.network.simple_request(
1510                 'FM_ASC_BATCH_RETRIEVE',
1511                 [ ses(), [ sc_id ] ]
1512             )[0];
1513
1514         }
1515
1516         g.data.hash.asc[ sc.id() ] = sc; g.data.stash('hash');
1517
1518         var label_name = g.data.hash.aou[ sc.owner() ].shortname() + " : " + sc.name();
1519
1520         if (get_bool( sc.required() )) {
1521             g.required[ label_name ] = 1;
1522         }
1523
1524         var temp_array = [
1525             label_name,
1526             {
1527                 render: 'var l = util.functional.find_list( fm.stat_cat_entries(), function(e){ return e.stat_cat() == ' 
1528                     + sc.id() + '; } ); l ? l.value() : $("catStrings").getString("staff.cat.copy_editor.field.unset_or_null");',
1529                 input: 'c = function(v){ g.apply_stat_cat(' + sc.id() + ',v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( [ [ $("catStrings").getString("staff.cat.copy_editor.remove_stat_cat_entry"), -1 ] ].concat( util.functional.map_list( g.data.hash.asc[' + sc.id() 
1530                     + '].entries(), function(obj){ return [ obj.value(), obj.id() ]; } ) ).sort() ); '
1531                     + 'x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c),false);',
1532                 attr: {
1533                     sc_lib: sc.owner(),
1534                 }
1535             }
1536         ];
1537
1538         g.panes_and_field_names.right_pane4.push( temp_array );
1539     } catch(E) {
1540         g.error.standard_unexpected_error_alert($('catStrings').getString('staff.cat.copy_editor.add_stat_cat.error'), E);
1541     }
1542 }
1543
1544 /******************************************************************************************************/
1545 /* Add stat cats to the panes_and_field_names.right_pane4 */
1546 g.populate_stat_cats = function() {
1547     try {
1548         g.data.stash_retrieve();
1549         g.stat_cat_seen = {}; // used for determining whether a stat cat is displayed (and is eligible to be manipulated via a template)
1550
1551         function get(lib_id,only_these) {
1552             g.data.stash_retrieve();
1553             var label = 'asc_list_for_lib_'+lib_id;
1554             if (typeof g.data[label] == 'undefined') {
1555                 var robj = g.network.simple_request('FM_ASC_RETRIEVE_VIA_AOU', [ ses(), lib_id ]);
1556                 if (typeof robj.ilsevent != 'undefined') throw(robj);
1557                 var temp_list = [];
1558                 for (var j = 0; j < robj.length; j++) {
1559                     var my_asc = robj[j];
1560                     if (typeof g.data.hash.asc == 'undefined') { g.data.hash.asc = {}; }
1561                     if (typeof g.data.hash.asc[ my_asc.id() ] == 'undefined') {
1562                         g.data.hash.asc[ my_asc.id() ] = my_asc;
1563                     }
1564                     var only_this_lib = my_asc.owner(); if (typeof only_this_lib == 'object') only_this_lib = only_this_lib.id();
1565                     if (only_these.indexOf( String( only_this_lib ) ) != -1) {
1566                         temp_list.push( my_asc );
1567                     }
1568                 }
1569                 g.data[label] = temp_list; g.data.stash(label,'hash','list');
1570             }
1571             return g.data[label];
1572         }
1573
1574         /* The stat cats for the pertinent library -- this is based on workstation ou */
1575         var label = 'asc_list_for_' + typeof g.data.ws_ou == 'object' ? g.data.ws_ou.id() : g.data.ws_ou;
1576         g.data[ label ] = g.data.list.my_asc; g.data.stash('label');
1577         for (var i = 0; i < g.data.list.my_asc.length; i++) {
1578             g.add_stat_cat( g.data.list.my_asc[i] );
1579         }
1580
1581         /* For the others, we want to consider the owning libs, circ libs, and any libs that have stat cats already on the copies,
1582             however, if batch editing, we only want to show the ones they have in common.  So let's compile the libs  */
1583
1584         function add_common_ancestors(sc_libs) {
1585             JSAN.use('util.fm_utils'); 
1586             var libs = []; for (var i in sc_libs) libs.push(i);
1587             var ancestor = util.fm_utils.find_common_aou_ancestor( libs );
1588             if (typeof ancestor == 'object' && ancestor != null) ancestor = ancestor.id();
1589             if (ancestor) {
1590                 var ancestors = util.fm_utils.find_common_aou_ancestors( libs );
1591                 var asc_list = get(ancestor, ancestors);
1592                 for (var i = 0; i < asc_list.length; i++) {
1593                     g.add_stat_cat( asc_list[i] );
1594                 }
1595             }
1596         }
1597
1598         /* stat cats based on stat cat entries present on these copies */
1599         var sc_libs = {};
1600         for (var i = 0; i < g.copies.length; i++) {
1601             var entries = g.copies[i].stat_cat_entries();
1602             if (!entries) entries = [];
1603             for (var j = 0; j < entries.length; j++) {
1604                 var lib = entries[j].owner(); if (typeof lib == 'object') lib = lib.id();
1605                 sc_libs[ lib ] = true;
1606             }
1607         }
1608         add_common_ancestors(sc_libs); // CAVEAT - if a copy has no stat_cat_entries, it basically gets no vote here
1609
1610         /* stat cats based on Circ Lib */
1611         sc_libs = {};
1612         for (var i = 0; i < g.copies.length; i++) {
1613             var circ_lib = g.copies[i].circ_lib(); if (typeof circ_lib == 'object') circ_lib = circ_lib.id();
1614             sc_libs[ circ_lib ] = true;
1615         }
1616         add_common_ancestors(sc_libs);
1617
1618         /* stat cats based on Owning Lib */
1619         sc_libs = {};
1620         for (var i = 0; i < g.copies.length; i++) {
1621             var cn_id = g.copies[i].call_number();
1622             if (cn_id > 0) {
1623                 if (! g.map_acn[ cn_id ]) {
1624                     var req = g.network.simple_request('FM_ACN_RETRIEVE.authoritative',[ cn_id ]);
1625                     if (typeof req.ilsevent == 'undefined') {
1626                         g.map_acn[ cn_id ] = req;
1627                     } else {
1628                         continue;
1629                     }
1630                 }
1631                 var owning_lib = g.map_acn[ cn_id ].owning_lib(); if (typeof owning_lib == 'object') owning_lib = owning_lib.id();
1632                 sc_libs[ owning_lib ] = true;
1633             }
1634         }
1635         add_common_ancestors(sc_libs); // CAVEAT - if a copy is a pre-cat, it basically gets no vote here
1636
1637         g.panes_and_field_names.right_pane4.sort();
1638
1639     } catch(E) {
1640         alert(E);
1641         g.error.standard_unexpected_error_alert($('catStrings').getString('staff.cat.copy_editor.populate_stat_cat.error'),E);
1642     }
1643 }
1644
1645 g.check_for_unmet_required_fields = function() {
1646     var abort = [];
1647     for (var fn in g.required) {
1648         if (typeof g.populated[fn] == 'undefined') {
1649             abort.push(fn);
1650         }
1651     }
1652     if (xulG.unified_interface) {
1653         if (abort.length > 0) {
1654             if (typeof xulG.lock_save_button == 'function') {
1655                 xulG.lock_save_button();
1656             }
1657         } else {
1658             if (typeof xulG.unlock_save_button == 'function') {
1659                 xulG.unlock_save_button();
1660             }
1661         }
1662     } else {
1663         if (abort.length > 0) {
1664             $('save').setAttribute('disabled','true');
1665         } else {
1666             $('save').setAttribute('disabled','false');
1667         }
1668     }
1669 }
1670
1671