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