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