7 /******************************************************************************************************/
8 /* setup JSAN and some initial libraries */
10 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
11 if (typeof JSAN == 'undefined') { throw( "The JSAN library object is missing."); }
12 JSAN.errorLevel = "die"; // none, warn, or die
13 JSAN.addRepository('/xul/server/');
14 JSAN.use('util.error'); g.error = new util.error();
15 g.error.sdump('D_TRACE','my_init() for cat/copy_editor.xul');
17 JSAN.use('util.functional');
18 JSAN.use('OpenILS.data'); g.data = new OpenILS.data(); g.data.init({'via':'stash'});
19 JSAN.use('util.network'); g.network = new util.network();
21 g.docid = xul_param('docid',{'modal_xulG':true});
22 g.handle_update = xul_param('handle_update',{'modal_xulG':true});
24 /******************************************************************************************************/
25 /* Get the copy ids from various sources and flesh them */
27 var copy_ids = xul_param('copy_ids',{'concat':true,'JSON2js_if_cgi':true,'JSON2js_if_xulG':true,'JSON2js_if_xpcom':true,'stash_name':'temp_copy_ids','clear_xpcom':true,'modal_xulG':true});
28 if (!copy_ids) copy_ids = [];
30 if (copy_ids.length > 0) g.copies = g.network.simple_request(
31 'FM_ACP_FLESHED_BATCH_RETRIEVE',
35 /******************************************************************************************************/
36 /* And other fleshed copies if any */
38 if (!g.copies) g.copies = [];
39 var c = xul_param('copies',{'concat':true,'JSON2js_if_cgi':true,'JSON2js_if_xpcom':true,'stash_name':'temp_copies','clear_xpcom':true,'modal_xulG':true})
40 if (c) g.copies = g.copies.concat(c);
42 /******************************************************************************************************/
43 /* We try to retrieve callnumbers for existing copies, but for new copies, we rely on this */
45 g.callnumbers = xul_param('callnumbers',{'concat':true,'JSON2js_if_cgi':true,'JSON2js_if_xpcom':true,'stash_name':'temp_callnumbers','clear_xpcom':true,'modal_xulG':true});
47 /******************************************************************************************************/
48 /* Is the interface an editor or a viewer, single or multi copy, existing copies or new copies? */
50 if (xul_param('edit',{'modal_xulG':true}) == '1') {
52 document.getElementById('caption').setAttribute('label','Copy Editor');
53 document.getElementById('save').setAttribute('hidden','false');
54 g.retrieve_templates();
56 $('top_nav').setAttribute('hidden','true');
59 if (g.copies.length > 0 && g.copies[0].id() < 0) {
60 document.getElementById('copy_notes').setAttribute('hidden','true');
61 g.apply("status",5 /* In Process */);
62 $('save').setAttribute('label','Create Copies');
64 g.panes_and_field_names.left_pane =
69 render: 'typeof fm.status() == "object" ? fm.status().name() : g.data.hash.ccs[ fm.status() ].name()',
70 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,
71 //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);',
74 ].concat(g.panes_and_field_names.left_pane);
77 if (g.copies.length != 1) {
78 document.getElementById('copy_notes').setAttribute('hidden','true');
81 /******************************************************************************************************/
82 /* Show the Record Details? */
85 document.getElementById('brief_display').setAttribute(
87 urls.XUL_BIB_BRIEF + '?docid=' + g.docid
90 document.getElementById('brief_display').setAttribute('hidden','true');
93 /******************************************************************************************************/
94 /* Add stat cats to the panes_and_field_names.right_pane4 */
98 function add_stat_cat(sc) {
100 if (typeof g.data.hash.asc == 'undefined') { g.data.hash.asc = {}; g.data.stash('hash'); }
104 if (typeof sc == 'object') {
109 if (typeof g.stat_cat_seen[sc_id] != 'undefined') { return; }
111 g.stat_cat_seen[ sc_id ] = 1;
113 if (typeof sc != 'object') {
115 sc = g.network.simple_request(
116 'FM_ASC_BATCH_RETRIEVE',
122 g.data.hash.asc[ sc.id() ] = sc; g.data.stash('hash');
124 var label_name = g.data.hash.aou[ sc.owner() ].shortname() + " : " + sc.name();
129 render: 'var l = util.functional.find_list( fm.stat_cat_entries(), function(e){ return e.stat_cat() == '
130 + sc.id() + '; } ); l ? l.value() : "<Unset>";',
131 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()
132 + '].entries(), function(obj){ return [ obj.value(), obj.id() ]; } ) ).sort() ); '
133 //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()
134 // + '].entries(), function(obj){ return [ obj.value(), obj.id() ]; } ).sort() ) ); '
135 + 'x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c),false);',
139 dump('temp_array = ' + js2JSON(temp_array) + '\n');
141 g.panes_and_field_names.right_pane4.push( temp_array );
144 /* The stat cats for the pertinent library */
145 for (var i = 0; i < g.data.list.my_asc.length; i++) {
146 add_stat_cat( g.data.list.my_asc[i] );
149 /* Other stat cats present on these copies */
150 for (var i = 0; i < g.copies.length; i++) {
151 var entries = g.copies[i].stat_cat_entries();
152 if (!entries) entries = [];
153 for (var j = 0; j < entries.length; j++) {
154 var sc_id = entries[j].stat_cat();
155 add_stat_cat( sc_id );
159 /******************************************************************************************************/
160 /* Backup copies :) */
162 g.original_copies = js2JSON( g.copies );
164 /******************************************************************************************************/
167 g.summarize( g.copies );
171 var err_msg = "!! This software has encountered an error. Please tell your friendly " +
172 "system administrator or software developer the following:\ncat/copy_editor.xul\n" + E + '\n';
173 try { g.error.sdump('D_ERROR',err_msg); } catch(E) { dump(err_msg); dump(js2JSON(E)); }
178 /******************************************************************************************************/
179 /* File picker for template export/import */
181 function pick_file(mode) {
182 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
183 var nsIFilePicker = Components.interfaces.nsIFilePicker;
184 var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance( nsIFilePicker );
187 mode == 'open' ? "Import Templates File" : "Save Templates File As",
188 mode == 'open' ? nsIFilePicker.modeOpen : nsIFilePicker.modeSave
190 fp.appendFilters( nsIFilePicker.filterAll );
191 if ( fp.show( ) == nsIFilePicker.returnOK && fp.file ) {
198 /******************************************************************************************************/
199 /* Retrieve Templates */
201 g.retrieve_templates = function() {
203 JSAN.use('util.widgets'); JSAN.use('util.functional');
205 var robj = g.network.simple_request('FM_AUS_RETRIEVE',[ses(),g.data.list.au[0].id()]);
206 if (typeof robj['staff_client.copy_editor.templates'] != 'undefined') {
207 g.templates = robj['staff_client.copy_editor.templates'];
209 util.widgets.remove_children('template_placeholder');
210 var list = util.functional.map_object_to_list( g.templates, function(obj,i) { return [i, i]; } );
212 g.template_menu = util.widgets.make_menulist( list );
213 $('template_placeholder').appendChild(g.template_menu);
215 g.error.standard_unexpected_error_alert('Error retrieving templates',E);
219 /******************************************************************************************************/
222 g.apply_template = function() {
224 var name = g.template_menu.value;
225 if (g.templates[ name ] != 'undefined') {
226 var template = g.templates[ name ];
227 for (var i in template) {
228 g.changed[ i ] = template[ i ];
229 switch( template[i].type ) {
231 g.apply(template[i].field,template[i].value);
234 if (g.stat_cat_seen[ template[i].field ]) g.apply_stat_cat(template[i].field,template[i].value);
237 g.apply_owning_lib(template[i].value);
241 g.summarize( g.copies );
245 g.error.standard_unexpected_error_alert('Error applying template',E);
249 /******************************************************************************************************/
250 /* Save as Template */
252 g.save_template = function() {
254 var name = window.prompt('Enter template name:','','Save As Template');
256 g.templates[name] = g.changed;
257 var robj = g.network.simple_request(
258 'FM_AUS_UPDATE',[ses(),g.data.list.au[0].id(), { 'staff_client.copy_editor.templates' : g.templates }]
260 if (typeof robj.ilsevent != 'undefined') {
263 alert('Template "' + name + '" saved.');
267 g.retrieve_templates();
269 g.error.standard_unexpected_error_alert('Error saving template',E);
275 g.error.standard_unexpected_error_alert('Error saving template',E);
279 /******************************************************************************************************/
280 /* Delete Template */
282 g.delete_template = function() {
284 var name = g.template_menu.value;
286 if (! window.confirm('Delete template "' + name + '"?') ) return;
287 delete(g.templates[name]);
288 var robj = g.network.simple_request(
289 'FM_AUS_UPDATE',[ses(),g.data.list.au[0].id(), { 'staff_client.copy_editor.templates' : g.templates }]
291 if (typeof robj.ilsevent != 'undefined') {
294 alert('Template "' + name + '" deleted.');
298 g.retrieve_templates();
300 g.error.standard_unexpected_error_alert('Error deleting template',E);
306 g.error.standard_unexpected_error_alert('Error deleting template',E);
310 /******************************************************************************************************/
311 /* Export Templates */
313 g.export_templates = function() {
315 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
316 JSAN.use('util.file');
317 var f = pick_file('save');
320 var r = G.error.yns_alert(
321 'Would you like to overwrite the existing file ' + f.leafName + '?',
322 'Templates Export Warning',
326 'Check here to confirm this message'
328 if (r != 0) { file.close(); alert('Not overwriting file.'); return; }
330 var e_file = new util.file(''); e_file._file = f;
331 e_file.write_content( 'truncate', js2JSON( g.templates ) );
333 alert('Templates exported as file ' + f.leafName);
335 alert('File not chosen for export.');
339 g.error.standard_unexpected_error_alert('Error exporting templates',E);
343 /******************************************************************************************************/
344 /* Import Templates */
346 g.import_templates = function() {
348 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
349 JSAN.use('util.file');
350 var f = pick_file('open');
351 if (f && f.exists()) {
352 var i_file = new util.file(''); i_file._file = f;
353 var temp = JSON2js( i_file.get_content() );
355 for (var i in temp) {
357 if (g.templates[i]) {
359 var r = g.error.yns_alert(
360 'Replace the existing template with the imported template?\n' + g.error.pretty_print( js2JSON( temp[i] ) ),
361 'Template ' + i + ' already exists.','Yes','No',null,'Click here'
364 if (r == 0 /* Yes */) g.templates[i] = temp[i];
368 g.templates[i] = temp[i];
374 var r = g.error.yns_alert(
375 'Save all of these imported templates permanently to this account?',
376 'Final Warning', 'Yes', 'No', null, 'Click here'
379 if (r == 0 /* Yes */) {
380 var robj = g.network.simple_request(
381 'FM_AUS_UPDATE',[ses(),g.data.list.au[0].id(), { 'staff_client.copy_editor.templates' : g.templates }]
383 if (typeof robj.ilsevent != 'undefined') {
386 alert('All templates saved.');
390 g.retrieve_templates();
392 g.error.standard_unexpected_error_alert('Error saving templates',E);
398 util.widgets.remove_children('template_placeholder');
399 var list = util.functional.map_object_to_list( g.templates, function(obj,i) { return [i, i]; } );
400 g.template_menu = util.widgets.make_menulist( list );
401 $('template_placeholder').appendChild(g.template_menu);
402 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.");
406 alert('File not chosen for import.');
409 g.error.standard_unexpected_error_alert('Error importing templates',E);
414 /******************************************************************************************************/
415 /* Restore backup copies */
417 g.reset = function() {
419 g.copies = JSON2js( g.original_copies );
420 g.summarize( g.copies );
424 /******************************************************************************************************/
425 /* Apply a value to a specific field on all the copies being edited */
427 g.apply = function(field,value) {
428 g.error.sdump('D_TRACE','applying field = <' + field + '> value = <' + value + '>\n');
429 if (value == '<HACK:KLUDGE:NULL>') value = null;
430 if (field == 'alert_message') { value = value.replace(/^\W+$/g,''); }
431 if (field == 'price' || field == 'deposit_amount') {
432 if (value == '') { value = null; } else { JSAN.use('util.money'); value = util.money.sanitize( value ); }
434 for (var i = 0; i < g.copies.length; i++) {
435 var copy = g.copies[i];
437 copy[field]( value ); copy.ischanged('1');
444 /******************************************************************************************************/
445 /* Apply a stat cat entry to all the copies being edited. An entry_id of < 0 signifies the stat cat is being removed. */
447 g.apply_stat_cat = function(sc_id,entry_id) {
448 g.error.sdump('D_TRACE','sc_id = ' + sc_id + ' entry_id = ' + entry_id + '\n');
449 for (var i = 0; i < g.copies.length; i++) {
450 var copy = g.copies[i];
453 var temp = copy.stat_cat_entries();
454 if (!temp) temp = [];
455 temp = util.functional.filter_list(
458 return (obj.stat_cat() != sc_id);
461 if (entry_id > -1) temp.push(
462 util.functional.find_id_object_in_list(
463 g.data.hash.asc[sc_id].entries(),
467 copy.stat_cat_entries( temp );
470 g.error.standard_unexpected_error_alert('apply_stat_cat',E);
475 /******************************************************************************************************/
476 /* Apply an "owning lib" to all the copies being edited. That is, change and auto-vivicating volumes */
478 g.apply_owning_lib = function(ou_id) {
479 g.error.sdump('D_TRACE','ou_id = ' + ou_id + '\n');
481 for (var i = 0; i < g.copies.length; i++) {
482 var copy = g.copies[i];
484 if (!map_acn[copy.call_number()]) {
485 var volume = g.network.simple_request('FM_ACN_RETRIEVE',[ copy.call_number() ]);
486 if (typeof volume.ilsevent != 'undefined') {
487 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);
490 map_acn[copy.call_number()] = volume;
492 var old_volume = map_acn[copy.call_number()];
493 var acn_id = g.network.simple_request(
494 'FM_ACN_FIND_OR_CREATE',
495 [ses(),old_volume.label(),old_volume.record(),ou_id]
497 if (typeof acn_id.ilsevent != 'undefined') {
498 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);
501 copy.call_number(acn_id);
504 g.error.standard_unexpected_error_alert('apply_stat_cat',E);
510 /******************************************************************************************************/
511 /* This returns true if none of the copies being edited have a magical status found in my_constants.magical_statuses */
513 g.safe_to_edit_copy_status = function() {
516 for (var i = 0; i < g.copies.length; i++) {
517 var status = g.copies[i].status(); if (typeof status == 'object') status = status.id();
518 if (typeof my_constants.magical_statuses[ status ] != 'undefined') safe = false;
522 g.error.standard_unexpected_error_alert('safe_to_edit_copy_status?',E);
527 /******************************************************************************************************/
528 /* This concats and uniques all the alert messages for use as the default value for a new alert message */
530 g.populate_alert_message_input = function(tb) {
532 var seen = {}; var s = '';
533 for (var i = 0; i < g.copies.length; i++) {
534 var msg = g.copies[i].alert_message();
536 if (typeof seen[msg] == 'undefined') {
542 tb.setAttribute('value',s);
544 g.error.standard_unexpected_error_alert('populate_alert_message_input',E);
548 /******************************************************************************************************/
549 /* This returns a list of acpl's appropriate for the copies being edited */
551 g.get_acpl_list = function() {
554 JSAN.use('util.functional');
556 function get(lib_id,only_these) {
557 g.data.stash_retrieve();
558 var label = 'acpl_list_for_lib_'+lib_id;
559 if (typeof g.data[label] == 'undefined') {
560 var robj = g.network.simple_request('FM_ACPL_RETRIEVE', [ lib_id ]);
561 if (typeof robj.ilsevent != 'undefined') throw(robj);
563 for (var j = 0; j < robj.length; j++) {
564 var my_acpl = robj[j];
565 if (typeof g.data.hash.acpl[ my_acpl.id() ] == 'undefined') {
566 g.data.hash.acpl[ my_acpl.id() ] = my_acpl;
567 g.data.list.acpl.push( my_acpl );
569 if (only_these.indexOf( String( my_acpl.owning_lib() ) ) != -1) {
570 temp_list.push( my_acpl );
573 g.data[label] = temp_list; g.data.stash(label,'hash','list');
575 return g.data[label];
578 var libs = []; var map_acn = {};
579 for (var i = 0; i < g.copies.length; i++) {
580 var cn_id = g.copies[i].call_number();
582 if (! map_acn[ cn_id ]) {
583 map_acn[ cn_id ] = g.network.simple_request('FM_ACN_RETRIEVE',[ cn_id ]);
584 libs.push( map_acn[ cn_id ].owning_lib() );
589 for (var i in g.callnumbers) {
590 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 ); }
593 JSAN.use('util.fm_utils');
594 var ancestor = util.fm_utils.find_common_aou_ancestor( libs );
595 if (typeof ancestor == 'object' && ancestor != null) ancestor = ancestor.id();
597 var ancestors = util.fm_utils.find_common_aou_ancestors( libs );
600 return get(ancestor, ancestors);
606 g.error.standard_unexpected_error_alert('get_acpl_list',E);
612 /******************************************************************************************************/
613 /* This keeps track of what fields have been edited for styling purposes */
617 /******************************************************************************************************/
618 /* These need data from the middle layer to render */
620 g.special_exception = {
621 'Owning Lib : Call Number' : function(label,value) {
622 JSAN.use('util.widgets');
623 if (value>0) { /* an existing call number */
625 api.FM_ACN_RETRIEVE.app,
626 api.FM_ACN_RETRIEVE.method,
629 var cn = '??? id = ' + value;
631 cn = req.getResultObject();
633 g.error.sdump('D_ERROR','callnumber retrieve: ' + E);
635 util.widgets.set_text(label,g.data.hash.aou[ cn.owning_lib() ].shortname() + ' : ' + cn.label());
638 } else { /* a yet to be created call number */
640 util.widgets.set_text(label,g.data.hash.aou[ g.callnumbers[value].owning_lib ].shortname() + ' : ' + g.callnumbers[value].label);
644 'Creator' : function(label,value) {
645 if (value == null || value == '' || value == 'null') return;
646 g.network.simple_request(
647 'FM_AU_RETRIEVE_VIA_ID',
650 var p = '??? id = ' + value;
652 p = req.getResultObject();
656 g.error.sdump('D_ERROR','patron retrieve: ' + E);
658 JSAN.use('util.widgets');
659 util.widgets.set_text(label,p);
663 'Last Editor' : function(label,value) {
664 if (value == null || value == '' || value == 'null') return;
665 g.network.simple_request(
666 'FM_AU_RETRIEVE_VIA_ID',
669 var p = '??? id = ' + value;
671 p = req.getResultObject();
675 g.error.sdump('D_ERROR','patron retrieve: ' + E);
677 util.widgets.set_text(label,p);
684 /******************************************************************************************************/
685 g.readonly_stat_cat_names = [];
686 g.editable_stat_cat_names = [];
688 /******************************************************************************************************/
689 /* These get show in the left panel */
691 g.panes_and_field_names = {
698 render: 'fm.barcode();',
704 render: 'util.date.formatted_date( fm.create_date(), "%F");',
710 render: 'fm.creator();',
716 render: 'util.date.formatted_date( fm.edit_date(), "%F");',
722 render: 'fm.editor();',
733 render: 'typeof fm.location() == "object" ? fm.location().name() : g.data.lookup("acpl",fm.location()).name()',
734 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);',
739 "Circulation Library",
741 render: 'typeof fm.circ_lib() == "object" ? fm.circ_lib().shortname() : g.data.hash.aou[ fm.circ_lib() ].shortname()',
742 //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);',
743 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);',
747 "Owning Lib : Call Number",
749 render: 'fm.call_number();',
750 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);',
756 render: 'fm.copy_number() == null ? "<Unset>" : fm.copy_number()',
757 input: 'c = function(v){ g.apply("copy_number",v); if (typeof post_c == "function") post_c(v); }; x = document.createElement("textbox"); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
769 render: 'fm.circulate() == null ? "<Unset>" : ( get_bool( fm.circulate() ) ? "Yes" : "No" )',
770 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);',
776 render: 'fm.holdable() == null ? "<Unset>" : ( get_bool( fm.holdable() ) ? "Yes" : "No" )',
777 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);',
783 render: 'fm.age_protect() == null ? "<Unset>" : ( typeof fm.age_protect() == "object" ? fm.age_protect().name() : g.data.hash.crahp[ fm.age_protect() ].name() )',
784 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);',
791 render: 'switch(fm.loan_duration()){ case 1: case "1": "Short"; break; case 2: case "2": "Normal"; break; case 3:case "3": "Long"; break; }',
792 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);',
799 render: 'switch(fm.fine_level()){ case 1: case "1": "Low"; break; case 2: case "2": "Normal"; break; case 3: case "3": "High"; break; }',
800 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);',
807 render: 'fm.circ_as_type() == null ? "<Unset>" : g.data.hash.citm[ fm.circ_as_type() ].value()',
808 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);',
812 "Circulation Modifier",
814 render: 'fm.circ_modifier() == null ? "<Unset>" : fm.circ_modifier()',
815 /*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);',*/
816 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 render: 'fm.alert_message() == null ? "<Unset>" : fm.alert_message()',
826 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);',
833 render: 'fm.deposit() == null ? "<Unset>" : ( get_bool( fm.deposit() ) ? "Yes" : "No" )',
834 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);',
840 render: 'if (fm.deposit_amount() == null) { "<Unset>"; } else { util.money.sanitize( fm.deposit_amount() ); }',
841 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);',
847 render: 'if (fm.price() == null) { "<Unset>"; } else { util.money.sanitize( fm.price() ); }',
848 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);',
855 render: 'fm.opac_visible() == null ? "<Unset>" : ( get_bool( fm.opac_visible() ) ? "Yes" : "No" )',
856 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);',
862 render: 'fm.ref() == null ? "<Unset>" : ( get_bool( fm.ref() ) ? "Yes" : "No" )',
863 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);',
874 /******************************************************************************************************/
875 /* This loops through all our fieldnames and all the copies, tallying up counts for the different values */
877 g.summarize = function( copies ) {
878 /******************************************************************************************************/
881 JSAN.use('util.date'); JSAN.use('util.money');
884 for (var i in g.panes_and_field_names) {
885 g.field_names = g.field_names.concat( g.panes_and_field_names[i] );
887 g.field_names = g.field_names.concat( g.editable_stat_cat_names );
888 g.field_names = g.field_names.concat( g.readonly_stat_cat_names );
890 /******************************************************************************************************/
891 /* Loop through the field names */
893 for (var i = 0; i < g.field_names.length; i++) {
895 var field_name = g.field_names[i][0];
896 var render = g.field_names[i][1].render;
897 g.summary[ field_name ] = {};
899 /******************************************************************************************************/
900 /* Loop through the copies */
902 for (var j = 0; j < copies.length; j++) {
905 var cmd = render || ('fm.' + field_name + '();');
908 /**********************************************************************************************/
909 /* Try to retrieve the value for this field for this copy */
914 g.error.sdump('D_ERROR','Attempted ' + cmd + '\n' + E + '\n');
916 if (typeof value == 'object' && value != null) {
917 alert('FIXME: field_name = <' + field_name + '> value = <' + js2JSON(value) + '>\n');
920 /**********************************************************************************************/
921 /* Tally the count */
923 if (g.summary[ field_name ][ value ]) {
924 g.summary[ field_name ][ value ]++;
926 g.summary[ field_name ][ value ] = 1;
930 g.error.sdump('D_TRACE','summary = ' + js2JSON(g.summary) + '\n');
933 /******************************************************************************************************/
934 /* Display the summarized data and inputs for editing */
936 g.render = function() {
938 /******************************************************************************************************/
939 /* Library setup and clear any existing interface */
941 JSAN.use('util.widgets'); JSAN.use('util.date'); JSAN.use('util.money'); JSAN.use('util.functional');
943 for (var i in g.panes_and_field_names) {
944 var p = document.getElementById(i);
945 if (p) util.widgets.remove_children(p);
948 /******************************************************************************************************/
949 /* Prepare the panes */
951 var groupbox; var caption; var vbox; var grid; var rows;
953 /******************************************************************************************************/
954 /* Loop through the field names */
956 for (h in g.panes_and_field_names) {
957 if (!document.getElementById(h)) continue;
958 for (var i = 0; i < g.panes_and_field_names[h].length; i++) {
960 var f = g.panes_and_field_names[h][i]; var fn = f[0];
961 groupbox = document.createElement('groupbox'); document.getElementById(h).appendChild(groupbox);
962 if (typeof g.changed[fn] != 'undefined') groupbox.setAttribute('class','copy_editor_field_changed');
963 caption = document.createElement('caption'); groupbox.appendChild(caption);
964 caption.setAttribute('label',fn); caption.setAttribute('id','caption_'+fn);
965 vbox = document.createElement('vbox'); groupbox.appendChild(vbox);
966 grid = util.widgets.make_grid( [ { 'flex' : 1 }, {}, {} ] ); vbox.appendChild(grid);
967 grid.setAttribute('flex','1');
968 rows = grid.lastChild;
971 /**************************************************************************************/
972 /* Loop through each value for the field */
974 for (var j in g.summary[fn]) {
975 var value = j; var count = g.summary[fn][j];
976 row = document.createElement('row'); rows.appendChild(row);
977 var label1 = document.createElement('description'); row.appendChild(label1);
978 if (g.special_exception[ fn ]) {
979 g.special_exception[ fn ]( label1, value );
981 label1.appendChild( document.createTextNode(value) );
983 var label2 = document.createElement('description'); row.appendChild(label2);
984 var unit = count == 1 ? 'copy' : 'copies';
985 label2.appendChild( document.createTextNode(count + ' ' + unit) );
987 var hbox = document.createElement('hbox');
988 hbox.setAttribute('id',fn);
989 groupbox.appendChild(hbox);
990 var hbox2 = document.createElement('hbox');
991 groupbox.appendChild(hbox2);
993 /**************************************************************************************/
994 /* Render the input widget */
996 if (f[1].input && g.edit) {
997 g.render_input(hbox,f[1]);
1001 g.error.sdump('D_ERROR','copy editor: ' + E + '\n');
1007 /******************************************************************************************************/
1008 /* This actually draws the change button and input widget for a given field */
1009 g.render_input = function(node,blob) {
1011 // node = hbox ; groupbox -> hbox, hbox
1013 var groupbox = node.parentNode;
1014 var caption = groupbox.firstChild;
1015 var vbox = node.previousSibling;
1017 var hbox2 = node.nextSibling;
1019 var input_cmd = blob.input;
1020 var render_cmd = blob.render;
1022 var block = false; var first = true;
1024 function on_mouseover(ev) {
1025 groupbox.setAttribute('style','background: white');
1028 function on_mouseout(ev) {
1029 groupbox.setAttribute('style','');
1032 vbox.addEventListener('mouseover',on_mouseover,false);
1033 vbox.addEventListener('mouseout',on_mouseout,false);
1034 groupbox.addEventListener('mouseover',on_mouseover,false);
1035 groupbox.addEventListener('mouseout',on_mouseout,false);
1036 groupbox.firstChild.addEventListener('mouseover',on_mouseover,false);
1037 groupbox.firstChild.addEventListener('mouseout',on_mouseout,false);
1039 function on_click(ev){
1041 if (block) return; block = true;
1043 function post_c(v) {
1045 /* FIXME - kludgy */
1046 var t = input_cmd.match('apply_stat_cat') ? 'stat_cat' : ( input_cmd.match('apply_owning_lib') ? 'owning_lib' : 'attribute' );
1050 f = input_cmd.match(/apply\("(.+?)",/)[1];
1053 f = input_cmd.match(/apply_stat_cat\((.+?),/)[1];
1059 g.changed[ hbox.id ] = { 'type' : t, 'field' : f, 'value' : v };
1063 g.summarize( g.copies );
1065 document.getElementById(caption.id).focus();
1069 g.error.standard_unexpected_error_alert('post_c',E);
1072 var x; var c; eval( input_cmd );
1074 util.widgets.remove_children(vbox);
1075 util.widgets.remove_children(hbox);
1076 util.widgets.remove_children(hbox2);
1077 hbox.appendChild(x);
1078 var apply = document.createElement('button');
1079 apply.setAttribute('label','Apply');
1080 apply.setAttribute('accesskey','A');
1081 hbox2.appendChild(apply);
1082 apply.addEventListener('command',function() { c(x.value); },false);
1083 var cancel = document.createElement('button');
1084 cancel.setAttribute('label','Cancel');
1085 cancel.addEventListener('command',function() { setTimeout( function() { g.summarize( g.copies ); g.render(); document.getElementById(caption.id).focus(); }, 0); }, false);
1086 hbox2.appendChild(cancel);
1087 setTimeout( function() { x.focus(); }, 0 );
1090 g.error.standard_unexpected_error_alert('render_input',E);
1093 vbox.addEventListener('click',on_click, false);
1094 hbox.addEventListener('click',on_click, false);
1095 caption.addEventListener('click',on_click, false);
1096 caption.addEventListener('keypress',function(ev) {
1097 if (ev.keyCode == 13 /* enter */ || ev.keyCode == 77 /* mac enter */) on_click();
1099 caption.setAttribute('style','-moz-user-focus: normal');
1100 caption.setAttribute('onfocus','this.setAttribute("class","outline_me")');
1101 caption.setAttribute('onblur','this.setAttribute("class","")');
1104 g.error.sdump('D_ERROR',E + '\n');
1108 /******************************************************************************************************/
1109 /* store the copies in the global xpcom stash */
1111 g.stash_and_close = function() {
1113 if (g.handle_update) {
1115 var r = g.network.request(
1116 api.FM_ACP_FLESHED_BATCH_UPDATE.app,
1117 api.FM_ACP_FLESHED_BATCH_UPDATE.method,
1118 [ ses(), g.copies, true ]
1120 if (typeof r.ilsevent != 'undefined') {
1121 g.error.standard_unexpected_error_alert('copy update',r);
1123 alert('Items added/modified.');
1125 /* FIXME -- revisit the return value here */
1127 alert('copy update error: ' + js2JSON(E));
1130 //g.data.temp_copies = js2JSON( g.copies );
1131 //g.data.stash('temp_copies');
1132 xulG.copies = g.copies;
1133 update_modal_xulG(xulG);
1136 g.error.standard_unexpected_error_alert('stash and close',E);
1140 /******************************************************************************************************/
1141 /* spawn copy notes interface */
1143 g.copy_notes = function() {
1144 JSAN.use('util.window'); var win = new util.window();
1146 urls.XUL_COPY_NOTES,
1147 //+ '?copy_id=' + window.escape(g.copies[0].id()),
1148 'Copy Notes','chrome,resizable,modal',
1149 { 'copy_id' : g.copies[0].id() }