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