]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/xul/staff_client/server/cat/copy_editor.js
tweaks
[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 (!copy_ids) copy_ids = [];
30                 if (window.xulG && window.xulG.copy_ids) copy_ids = copy_ids.concat( window.xulG.copy_ids );
31
32                 if (copy_ids.length > 0) g.copies = g.network.request(
33                         api.FM_ACP_FLESHED_BATCH_RETRIEVE.app,
34                         api.FM_ACP_FLESHED_BATCH_RETRIEVE.method,
35                         [ copy_ids ]
36                 );
37
38                 /******************************************************************************************************/
39                 /* And other fleshed copies if any */
40
41                 if (!g.copies) g.copies = [];
42                 if (window.xulG && window.xulG.copies) g.copies = g.copies.concat( window.xulG.copies );
43                 if (g.cgi.param('copies')) g.copies = g.copies.concat( JSON2js( g.cgi.param('copies') ) );
44
45                 /******************************************************************************************************/
46                 /* We try to retrieve callnumbers for existing copies, but for new copies, we rely on this */
47
48                 if (window.xulG && window.xulG.callnumbers) g.callnumbers = window.xulG.callnumbers;
49                 if (g.cgi.param('callnumbers')) g.callnumbers =  JSON2js( g.cgi.param('callnumbers') );
50
51                 /******************************************************************************************************/
52                 /* Is the interface an editor or a viewer, single or multi copy, existing copies or new copies? */
53
54                 if (g.cgi.param('edit') == '1') { 
55                         g.edit = true;
56                         document.getElementById('caption').setAttribute('label','Copy Editor'); 
57                         document.getElementById('save').setAttribute('hidden','false'); 
58                 }
59
60                 if (g.cgi.param('single_edit') == '1') {
61                         g.single_edit = true;
62                         document.getElementById('caption').setAttribute('label','Copy Editor'); 
63                         document.getElementById('save').setAttribute('hidden','false'); 
64                 }
65
66                 if (g.copies.length > 0 && g.copies[0].id() < 0) {
67                         document.getElementById('copy_notes').setAttribute('hidden','true');
68                         g.apply("status",5 /* In Process */);
69                 } else {
70                         g.panes_and_field_names.left_pane = 
71                                 [
72                                         [
73                                                 "Status",
74                                                 { 
75                                                         render: 'fm.status().name();', 
76                                                         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( g.data.list.ccs, function(obj) { return [ obj.name(), obj.id() ]; } ).sort() ); x.addEventListener("command",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
77                                                 }
78                                         ]
79                                 ].concat(g.panes_and_field_names.left_pane);
80                 }
81
82                 if (g.copies.length != 1) {
83                         document.getElementById('copy_notes').setAttribute('hidden','true');
84                 }
85
86                 /******************************************************************************************************/
87                 /* Show the Record Details? */
88
89                 if (g.docid) {
90                         document.getElementById('brief_display').setAttribute(
91                                 'src',
92                                 urls.XUL_BIB_BRIEF + '?docid=' + g.docid
93                         );
94                 } else {
95                         document.getElementById('brief_display').setAttribute('hidden','true');
96                 }
97
98                 /******************************************************************************************************/
99                 /* Add stat cats to the panes_and_field_names.right_pane4 */
100
101                 var stat_cat_seen = {};
102
103                 function add_stat_cat(sc) {
104
105                         if (typeof g.data.hash.asc == 'undefined') { g.data.hash.asc = {}; g.data.stash('hash'); }
106
107                         var sc_id = sc;
108
109                         if (typeof sc == 'object') {
110
111                                 sc_id = sc.id();
112                         }
113
114                         if (typeof stat_cat_seen[sc_id] != 'undefined') { return; }
115
116                         stat_cat_seen[ sc_id ] = 1;
117
118                         if (typeof sc != 'object') {
119
120                                 sc = g.network.simple_request(
121                                         'FM_ASC_BATCH_RETRIEVE',
122                                         [ ses(), [ sc_id ] ]
123                                 )[0];
124
125                         }
126
127                         g.data.hash.asc[ sc.id() ] = sc; g.data.stash('hash');
128
129                         var label_name = g.data.hash.aou[ sc.owner() ].shortname() + " : " + sc.name();
130
131                         var temp_array = [
132                                 label_name,
133                                 {
134                                         render: 'var l = util.functional.find_list( fm.stat_cat_entries(), function(e){ return e.stat_cat() == ' 
135                                                 + sc.id() + '; } ); l ? l.value() : "<Unset>";',
136                                         input: 'c = function(v){ g.apply_stat_cat(' + sc.id() + ',v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( util.functional.map_list( g.data.hash.asc[' + sc.id() 
137                                                 + '].entries(), function(obj){ return [ obj.value(), obj.id() ]; } ).sort() ); '
138                                                 + 'x.addEventListener("command",function(f){ return function(ev) { f(ev.target.value); } }(c),false);',
139                                 }
140                         ];
141
142                         dump('temp_array = ' + js2JSON(temp_array) + '\n');
143
144                         g.panes_and_field_names.right_pane4.push( temp_array );
145                 }
146
147                 /* The stat cats for the pertinent library */
148                 for (var i = 0; i < g.data.list.my_asc.length; i++) {
149                         add_stat_cat( g.data.list.my_asc[i] );  
150                 }
151
152                 /* Other stat cats present on these copies */
153                 for (var i = 0; i < g.copies.length; i++) {
154                         var entries = g.copies[i].stat_cat_entries();
155                         if (!entries) entries = [];
156                         for (var j = 0; j < entries.length; j++) {
157                                 var sc_id = entries[j].stat_cat();
158                                 add_stat_cat( sc_id );
159                         }
160                 }
161
162                 /******************************************************************************************************/
163                 /* Do it */
164
165                 g.summarize( g.copies );
166                 g.render();
167
168         } catch(E) {
169                 var err_msg = "!! This software has encountered an error.  Please tell your friendly " +
170                         "system administrator or software developer the following:\ncat/copy_editor.xul\n" + E + '\n';
171                 try { g.error.sdump('D_ERROR',err_msg); } catch(E) { dump(err_msg); dump(js2JSON(E)); }
172                 alert(err_msg);
173         }
174 }
175
176 /******************************************************************************************************/
177 /* Apply a value to a specific field on all the copies being edited */
178
179 g.apply = function(field,value) {
180         g.error.sdump('D_TRACE','field = ' + field + '  value = ' + value + '\n');
181         for (var i = 0; i < g.copies.length; i++) {
182                 var copy = g.copies[i];
183                 try {
184                         copy[field]( value ); copy.ischanged('1');
185                 } catch(E) {
186                         alert(E);
187                 }
188         }
189 }
190
191 /******************************************************************************************************/
192 /* Apply a stat cat entry to all the copies being edited */
193
194 g.apply_stat_cat = function(sc_id,entry_id) {
195         g.error.sdump('D_TRACE','sc_id = ' + sc_id + '  entry_id = ' + entry_id + '\n');
196         for (var i = 0; i < g.copies.length; i++) {
197                 var copy = g.copies[i];
198                 try {
199                         copy.ischanged('1');
200                         var temp = copy.stat_cat_entries();
201                         if (!temp) temp = [];
202                         temp = util.functional.filter_list(
203                                 temp,
204                                 function (obj) {
205                                         return (obj.stat_cat() != sc_id);
206                                 }
207                         );
208                         temp.push( 
209                                 util.functional.find_id_object_in_list( 
210                                         g.data.hash.asc[sc_id].entries(), 
211                                         entry_id
212                                 )
213                         );
214                         copy.stat_cat_entries( temp );
215
216                 } catch(E) {
217                         alert(E);
218                 }
219         }
220 }
221
222
223 /******************************************************************************************************/
224 /* These need data from the middle layer to render */
225
226 g.special_exception = {
227         'Call Number' : function(label,value) {
228                 if (value>0) { /* an existing call number */
229                         g.network.request(
230                                 api.FM_ACN_RETRIEVE.app,
231                                 api.FM_ACN_RETRIEVE.method,
232                                 [ value ],
233                                 function(req) {
234                                         var cn = '??? id = ' + value;
235                                         try {
236                                                 cn = req.getResultObject().label();
237                                         } catch(E) {
238                                                 g.error.sdump('D_ERROR','callnumber retrieve: ' + E);
239                                         }
240                                         label.setAttribute('value',cn);
241                                 }
242                         );
243                 } else { /* a yet to be created call number */
244                         if (g.callnumbers) {
245                                 label.setAttribute('value',g.callnumbers[value]);
246                         }
247                 }
248         },
249         'Creator' : function(label,value) {
250                 if (value == null || value == '' || value == 'null') return;
251                 g.network.simple_request(
252                         'FM_AU_RETRIEVE_VIA_ID',
253                         [ ses(), value ],
254                         function(req) {
255                                 var p = '??? id = ' + value;
256                                 try {
257                                         p = req.getResultObject();
258                                         p = p.usrname();
259
260                                 } catch(E) {
261                                         g.error.sdump('D_ERROR','patron retrieve: ' + E);
262                                 }
263                                 label.setAttribute('value',p);
264                         }
265                 );
266         },
267         'Last Editor' : function(label,value) {
268                 if (value == null || value == '' || value == 'null') return;
269                 g.network.simple_request(
270                         'FM_AU_RETRIEVE_VIA_ID',
271                         [ ses(), value ],
272                         function(req) {
273                                 var p = '??? id = ' + value;
274                                 try {
275                                         p = req.getResultObject();
276                                         p = p.usrname();
277
278                                 } catch(E) {
279                                         g.error.sdump('D_ERROR','patron retrieve: ' + E);
280                                 }
281                                 label.setAttribute('value',p);
282                         }
283                 );
284         }
285
286 }
287
288 /******************************************************************************************************/
289 g.readonly_stat_cat_names = [];
290 g.editable_stat_cat_names = [];
291
292 /******************************************************************************************************/
293 /* These get show in the left panel */
294
295 g.panes_and_field_names = {
296
297         'left_pane' :
298 [
299         [
300                 "Barcode",               
301                 {
302                         render: 'fm.barcode();',
303                 }
304         ], 
305         [
306                 "Creation Date",
307                 { 
308                         render: 'util.date.formatted_date( fm.create_date(), "%F");',
309                 }
310         ],
311         [
312                 "Creator",
313                 { 
314                         render: 'fm.creator();',
315                 }
316         ],
317         [
318                 "Last Edit Date",
319                 { 
320                         render: 'util.date.formatted_date( fm.edit_date(), "%F");',
321                 }
322         ],
323         [
324                 "Last Editor",
325                 {
326                         render: 'fm.editor();',
327                 }
328         ],
329
330 ],
331
332 'right_pane' :
333 [
334         [
335                 "Shelving Location",
336                 { 
337                         render: 'fm.location().name();', 
338                         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.data.list.acpl, function(obj) { return [ obj.name(), obj.id() ]; }).sort()); x.addEventListener("command",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
339
340                 }
341         ],
342         [
343                 "Circulation Library",          
344                 {       
345                         render: 'fm.circ_lib().shortname();',
346                         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("command",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
347                 } 
348         ],
349         [
350                 "Call Number",  
351                 {
352                         render: 'fm.call_number();',
353                 }
354         ],
355         [
356                 "Copy Number",
357                 { 
358                         render: 'fm.copy_number() == null ? "<Unset>" : fm.copy_number()',
359                         input: 'c = function(v){ g.apply("copy_number",v); if (typeof post_c == "function") post_c(v); }; x = document.createElement("textbox"); x.addEventListener("change",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
360                 }
361         ],
362
363
364 ],
365
366 'right_pane2' :
367 [
368         [
369                 "Circulate?",
370                 {       
371                         render: 'fm.circulate() == null ? "<Unset>" : ( fm.circulate() == 1 ? "Yes" : "No" )',
372                         input: 'c = function(v){ g.apply("circulate",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( [ [ "Yes", "1" ], [ "No", "0" ] ] ); x.addEventListener("command",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
373                 }
374         ],
375         [
376                 "Holdable?",
377                 { 
378                         render: 'fm.holdable() == null ? "<Unset>" : ( fm.holdable() == 1? "Yes" : "No" )', 
379                         input: 'c = function(v){ g.apply("holdable",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( [ [ "Yes", "1" ], [ "No", "0" ] ] ); x.addEventListener("command",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
380                 }
381         ],
382
383         [
384                 "Loan Duration",
385                 { 
386                         render: 'switch(fm.loan_duration()){ case 1: "Short"; break; case 2: "Normal"; break; case 3: "Long"; break; }',
387                         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("command",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
388
389                 }
390         ],
391         [
392                 "Fine Level",
393                 {
394                         render: 'switch(fm.fine_level()){ case 1: "Low"; break; case 2: "Normal"; break; case 3: "High"; break; }',
395                         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("command",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
396                 }
397         ],
398
399          [
400                 "Circulate as Type",    
401                 {       
402                         render: 'fm.circ_as_type() == null ? "<Unset>" : fm.circ_as_type()',
403                         input: 'c = function(v){ g.apply("circ_as_type",v); if (typeof post_c == "function") post_c(v); }; x = document.createElement("textbox"); x.addEventListener("change",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
404                 } 
405         ],
406         [
407                 "Circulation Modifier",
408                 {       
409                         render: 'fm.circ_modifier() == null ? "<Unset>" : fm.circ_modifier()',
410                         input: 'c = function(v){ g.apply("circ_modifier",v); if (typeof post_c == "function") post_c(v); }; x = document.createElement("textbox"); x.addEventListener("change",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
411                 }
412         ],
413 ],
414
415 'right_pane3' :
416 [       [
417                 "Alert Message",
418                 {
419                         render: 'fm.alert_message();',
420                         input: 'c = function(v){ g.apply("alert_message",v); if (typeof post_c == "function") post_c(v); }; x = document.createElement("textbox"); x.addEventListener("change",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
421                 }
422         ],
423
424         [
425                 "Deposit?",
426                 { 
427                         render: 'fm.deposit() == null ? "<Unset>" : ( fm.deposit() == 1 ? "Yes" : "No" )',
428                         input: 'c = function(v){ g.apply("deposit",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( [ [ "Yes", "1" ], [ "No", "0" ] ] ); x.addEventListener("command",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
429                 }
430         ],
431         [
432                 "Deposit Amount",
433                 { 
434                         render: 'util.money.sanitize( fm.deposit_amount() );',
435                         input: 'c = function(v){ g.apply("deposit_amount",v); if (typeof post_c == "function") post_c(v); }; x = document.createElement("textbox"); x.addEventListener("change",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
436                 }
437         ],
438         [
439                 "Price",
440                 { 
441                         render: 'util.money.sanitize( fm.price() );', 
442                         input: 'c = function(v){ g.apply("price",v); if (typeof post_c == "function") post_c(v); }; x = document.createElement("textbox"); x.addEventListener("change",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
443                 }
444         ],
445
446         [
447                 "OPAC Visible?",
448                 { 
449                         render: 'fm.opac_visible() == null ? "<Unset>" : ( fm.opac_visible() == 1 ? "Yes" : "No" )', 
450                         input: 'c = function(v){ g.apply("opac_visible",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( [ [ "Yes", "1" ], [ "No", "0" ] ] ); x.addEventListener("command",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
451                 }
452         ],
453         [
454                 "Reference?",
455                 { 
456                         render: 'fm.ref() == null ? "<Unset>" : ( fm.ref() == 1 ? "Yes" : "No" )', 
457                         input: 'c = function(v){ g.apply("ref",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( [ [ "Yes", "1" ], [ "No", "0" ] ] ); x.addEventListener("command",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
458                 }
459         ],
460 ],
461
462 'right_pane4' : 
463 [
464 ]
465
466 };
467
468 /******************************************************************************************************/
469 /* This loops through all our fieldnames and all the copies, tallying up counts for the different values */
470
471 g.summarize = function( copies ) {
472         /******************************************************************************************************/
473         /* Setup */
474
475         JSAN.use('util.date'); JSAN.use('util.money');
476         g.summary = {};
477         g.field_names = [];
478         for (var i in g.panes_and_field_names) {
479                 g.field_names = g.field_names.concat( g.panes_and_field_names[i] );
480         }
481         g.field_names = g.field_names.concat( g.editable_stat_cat_names );
482         g.field_names = g.field_names.concat( g.readonly_stat_cat_names );
483
484         /******************************************************************************************************/
485         /* Loop through the field names */
486
487         for (var i = 0; i < g.field_names.length; i++) {
488
489                 var field_name = g.field_names[i][0];
490                 var render = g.field_names[i][1].render;
491                 g.summary[ field_name ] = {};
492
493                 /******************************************************************************************************/
494                 /* Loop through the copies */
495
496                 for (var j = 0; j < copies.length; j++) {
497
498                         var fm = copies[j];
499                         var cmd = render || ('fm.' + field_name + '();');
500                         var value = '???';
501
502                         /**********************************************************************************************/
503                         /* Try to retrieve the value for this field for this copy */
504
505                         try { 
506                                 value = eval( cmd ); 
507                         } catch(E) { 
508                                 g.error.sdump('D_ERROR','Attempted ' + cmd + '\n' +  E + '\n'); 
509                         }
510                         if (typeof value == 'object' && value != null) {
511                                 alert('FIXME: field_name = ' + field_name + '  value = ' + js2JSON(value) + '\n');
512                         }
513
514                         /**********************************************************************************************/
515                         /* Tally the count */
516
517                         if (g.summary[ field_name ][ value ]) {
518                                 g.summary[ field_name ][ value ]++;
519                         } else {
520                                 g.summary[ field_name ][ value ] = 1;
521                         }
522                 }
523         }
524         g.error.sdump('D_TRACE','summary = ' + js2JSON(g.summary) + '\n');
525 }
526
527 /******************************************************************************************************/
528 /* Display the summarized data and inputs for editing */
529
530 g.render = function() {
531
532         /******************************************************************************************************/
533         /* Library setup and clear any existing interface */
534
535         JSAN.use('util.widgets'); JSAN.use('util.date'); JSAN.use('util.money'); JSAN.use('util.functional');
536
537         for (var i in g.panes_and_field_names) {
538                 var p = document.getElementById(i);
539                 if (p) util.widgets.remove_children(p);
540         }
541
542         /******************************************************************************************************/
543         /* Prepare the panes */
544
545         //if (g.single_edit) {
546         if (false) {
547                 
548                 /******************************************************************************************************/
549                 /* For a less dangerous batch edit, choose one field here */
550
551                 var gb = document.createElement('groupbox'); document.getElementById('input_placeholder').appendChild(gb);
552                 var c = document.createElement('caption'); gb.appendChild(c);
553                 c.setAttribute('label','Choose a field to edit');
554                 JSAN.use('util.widgets'); JSAN.use('util.functional');
555                 var ml = util.widgets.make_menulist(
556                         util.functional.map_list(
557                                 g.panes_and_field_names.right_pane,
558                                 function(o,i) { return [ o[0], i ]; }
559                         )
560                 );
561                 gb.appendChild(ml);
562                 ml.addEventListener(
563                         'command',
564                         function(ev) {
565                                 g.render_input(gb, g.panes_and_field_names.right_pane[ ev.target.value ][1]);
566                                 ml.disabled = true;
567                         }, 
568                         false
569                 );
570
571         }
572
573         /******************************************************************************************************/
574         /* multi-copy mode has a groupbox for each field */
575
576         var groupbox; var caption; var vbox; var grid; var rows;
577         
578         /******************************************************************************************************/
579         /* Loop through the field names */
580
581         for (h in g.panes_and_field_names) {
582                 if (!document.getElementById(h)) continue;
583                 for (var i = 0; i < g.panes_and_field_names[h].length; i++) {
584                         try {
585                                 var f = g.panes_and_field_names[h][i]; var fn = f[0];
586                                 groupbox = document.createElement('groupbox'); document.getElementById(h).appendChild(groupbox);
587                                 caption = document.createElement('caption'); groupbox.appendChild(caption);
588                                 caption.setAttribute('label',fn);
589                                 vbox = document.createElement('vbox'); groupbox.appendChild(vbox);
590                                 grid = util.widgets.make_grid( [ { 'flex' : 1 }, {}, {} ] ); vbox.appendChild(grid);
591                                 grid.setAttribute('flex','1');
592                                 rows = grid.lastChild;
593                                 var row;
594                                 
595                                 /**************************************************************************************/
596                                 /* Loop through each value for the field */
597
598                                 for (var j in g.summary[fn]) {
599                                         var value = j; var count = g.summary[fn][j];
600                                         row = document.createElement('row'); rows.appendChild(row);
601                                         var label1 = document.createElement('description'); row.appendChild(label1);
602                                         if (g.special_exception[ fn ]) {
603                                                 g.special_exception[ fn ]( label1, value );
604                                         } else {
605                                                 label1.appendChild( document.createTextNode(value) );
606                                         }
607                                         var label2 = document.createElement('description'); row.appendChild(label2);
608                                         var unit = count == 1 ? 'copy' : 'copies';
609                                         label2.appendChild( document.createTextNode(count + ' ' + unit) );
610                                 }
611                                 var hbox = document.createElement('hbox'); 
612                                 hbox.setAttribute('id',fn);
613                                 groupbox.appendChild(hbox);
614                                 var hbox2 = document.createElement('hbox');
615                                 groupbox.appendChild(hbox2);
616
617                                 /**************************************************************************************/
618                                 /* Render the input widget */
619
620                                 if (f[1].input && g.edit) {
621                                         g.render_input(hbox,f[1]);
622                                 }
623
624                         } catch(E) {
625                                 g.error.sdump('D_ERROR','copy editor: ' + E + '\n');
626                         }
627                 }
628         }
629 }
630
631 /******************************************************************************************************/
632 /* This actually draws the change button and input widget for a given field */
633 g.render_input = function(node,blob) {
634         try {
635                 // node = hbox ;    groupbox ->  hbox, hbox
636
637                 var groupbox = node.parentNode;
638                 var vbox = node.previousSibling;
639                 var hbox = node;
640                 var hbox2 = node.nextSibling;
641
642                 var input_cmd = blob.input;
643                 var render_cmd = blob.render;
644
645                 var block = false; var first = true;
646
647                 function on_mouseover(ev) {
648                         groupbox.setAttribute('style','background: white');
649                 }
650
651                 function on_mouseout(ev) {
652                         groupbox.setAttribute('style', groupbox.getAttribute('normal_style'));
653                 }
654
655                 vbox.addEventListener('mouseover',on_mouseover,false);
656                 vbox.addEventListener('mouseout',on_mouseout,false);
657                 groupbox.addEventListener('mouseover',on_mouseover,false);
658                 groupbox.addEventListener('mouseout',on_mouseout,false);
659                 groupbox.firstChild.addEventListener('mouseover',on_mouseover,false);
660                 groupbox.firstChild.addEventListener('mouseout',on_mouseout,false);
661
662                 function on_click(ev){
663                         try {
664                                 if (block) return; block = true;
665
666                                 function post_c(v) {
667                                         groupbox.setAttribute('normal_style','background: lightgreen');
668                                         groupbox.setAttribute('style',groupbox.getAttribute('normal_style'));
669                                 }
670                         /*
671                                 function post_c(v) {
672                                         var label = document.createElement('label');
673                                         var fm = {}; // kludgey
674                                         fm[ render_cmd.match(/fm\.(.+?)\(\)/)[1] ] = function() { return v; }
675                                         label.setAttribute('value','New Value: ' + eval(render_cmd) );
676                                         label.setAttribute('style','color: green');
677                                         groupbox.setAttribute('normal_style','background: lightgreen');
678                                         setTimeout(
679                                                 function() {
680                                                         util.widgets.remove_children(hbox);
681                                                         hbox.appendChild(label);
682                                                         if (first) { 
683                                                                 first = false;
684                                                         } else {
685                                                                 util.widgets.remove_children(hbox2);
686                                                                 first = true;
687                                                         }
688                                                         block = false;
689                                                         groupbox.setAttribute('style',groupbox.getAttribute('normal_style'));
690                                                 }, 0
691                                         );
692                                 }
693                         */
694                                 var x; var c; eval( input_cmd );
695                                 if (x) {
696                                         util.widgets.remove_children(vbox);
697                                         util.widgets.remove_children(hbox2);
698                                         hbox2.appendChild(x);
699                                         setTimeout( function() { x.focus(); }, 0 );
700                                 }
701                                 c(x.value);
702                         } catch(E) {
703                                 g.error.standard_unexpected_error_alert('render_input',E);
704                         }
705                 }
706                 vbox.addEventListener('click',on_click, false);
707                 hbox.addEventListener('click',on_click, false);
708                 groupbox.firstChild.addEventListener('click',on_click, false);
709
710         } catch(E) {
711                 g.error.sdump('D_ERROR',E + '\n');
712         }
713 }
714
715 /******************************************************************************************************/
716 /* store the copies in the global xpcom stash */
717
718 g.stash_and_close = function() {
719         if (g.handle_update) {
720                 try {
721                         var r = g.network.request(
722                                 api.FM_ACP_FLESHED_BATCH_UPDATE.app,
723                                 api.FM_ACP_FLESHED_BATCH_UPDATE.method,
724                                 [ ses(), g.copies ]
725                         );
726                         if (typeof r.ilsevent != 'undefined') {
727                                 g.error.standard_unexpected_error_alert('copy update',r);
728                         }
729                         /* FIXME -- revisit the return value here */
730                 } catch(E) {
731                         alert('copy update error: ' + js2JSON(E));
732                 }
733         }
734         g.data.temp_copies = js2JSON( g.copies );
735         g.data.stash('temp_copies');
736         g.error.sdump('D_CAT','in modal window, g.data.temp_copies = \n' + g.data.temp_copies + '\n');
737         window.close();
738 }
739
740 /******************************************************************************************************/
741 /* spawn copy notes interface */
742
743 g.copy_notes = function() {
744         JSAN.use('util.window'); var win = new util.window();
745         win.open(urls.XUL_COPY_NOTES + '?copy_id=' + window.escape(g.copies[0].id()),'Copy Notes','chrome,resizable,modal');
746 }
747