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