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