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