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