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