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