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