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});
48 /******************************************************************************************************/
49 /* Quick fix, this was defined inline in the global scope but now needs g.error and g.copies from my_init */
53 /******************************************************************************************************/
54 /* Is the interface an editor or a viewer, single or multi copy, existing copies or new copies? */
56 if (xul_param('edit',{'modal_xulG':true}) == '1') {
58 document.getElementById('caption').setAttribute('label','Copy Editor');
59 document.getElementById('save').setAttribute('hidden','false');
60 g.retrieve_templates();
62 $('top_nav').setAttribute('hidden','true');
65 if (g.copies.length > 0 && g.copies[0].id() < 0) {
66 document.getElementById('copy_notes').setAttribute('hidden','true');
67 g.apply("status",5 /* In Process */);
68 $('save').setAttribute('label','Create Copies');
70 g.panes_and_field_names.left_pane =
75 render: 'typeof fm.status() == "object" ? fm.status().name() : g.data.hash.ccs[ fm.status() ].name()',
76 input: g.safe_to_edit_copy_status() ? 'c = function(v){ g.apply("status",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( util.functional.map_list( g.data.list.ccs, function(obj) { return [ obj.name(), obj.id(), typeof my_constants.magical_statuses[obj.id()] != "undefined" ? true : false ]; } ).sort() ); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);' : undefined,
77 //input: 'c = function(v){ g.apply("status",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( util.functional.map_list( util.functional.filter_list( g.data.list.ccs, function(obj) { return typeof my_constants.magical_statuses[obj.id()] == "undefined"; } ), function(obj) { return [ obj.name(), obj.id() ]; } ).sort() ); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
80 ].concat(g.panes_and_field_names.left_pane);
83 if (g.copies.length != 1) {
84 document.getElementById('copy_notes').setAttribute('hidden','true');
87 /******************************************************************************************************/
88 /* Show the Record Details? */
91 document.getElementById('brief_display').setAttribute(
93 urls.XUL_BIB_BRIEF + '?docid=' + g.docid
96 document.getElementById('brief_display').setAttribute('hidden','true');
99 /******************************************************************************************************/
100 /* Add stat cats to the panes_and_field_names.right_pane4 */
102 g.populate_stat_cats();
104 /******************************************************************************************************/
105 /* Backup copies :) */
107 g.original_copies = js2JSON( g.copies );
109 /******************************************************************************************************/
112 g.summarize( g.copies );
116 var err_msg = "!! This software has encountered an error. Please tell your friendly " +
117 "system administrator or software developer the following:\ncat/copy_editor.xul\n" + E + '\n';
118 try { g.error.sdump('D_ERROR',err_msg); } catch(E) { dump(err_msg); dump(js2JSON(E)); }
123 /******************************************************************************************************/
124 /* File picker for template export/import */
126 function pick_file(mode) {
127 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
128 var nsIFilePicker = Components.interfaces.nsIFilePicker;
129 var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance( nsIFilePicker );
132 mode == 'open' ? "Import Templates File" : "Save Templates File As",
133 mode == 'open' ? nsIFilePicker.modeOpen : nsIFilePicker.modeSave
135 fp.appendFilters( nsIFilePicker.filterAll );
136 var fp_result = fp.show();
137 if ( ( fp_result == nsIFilePicker.returnOK || fp_result == nsIFilePicker.returnReplace ) && fp.file ) {
144 /******************************************************************************************************/
145 /* Retrieve Templates */
147 g.retrieve_templates = function() {
149 JSAN.use('util.widgets'); JSAN.use('util.functional');
151 var robj = g.network.simple_request('FM_AUS_RETRIEVE',[ses(),g.data.list.au[0].id()]);
152 if (typeof robj['staff_client.copy_editor.templates'] != 'undefined') {
153 g.templates = robj['staff_client.copy_editor.templates'];
155 util.widgets.remove_children('template_placeholder');
156 var list = util.functional.map_object_to_list( g.templates, function(obj,i) { return [i, i]; } );
158 g.template_menu = util.widgets.make_menulist( list );
159 $('template_placeholder').appendChild(g.template_menu);
161 g.error.standard_unexpected_error_alert('Error retrieving templates',E);
165 /******************************************************************************************************/
168 g.apply_template = function() {
170 var name = g.template_menu.value;
171 if (g.templates[ name ] != 'undefined') {
172 var template = g.templates[ name ];
173 for (var i in template) {
174 g.changed[ i ] = template[ i ];
175 switch( template[i].type ) {
177 g.apply(template[i].field,template[i].value);
180 if (g.stat_cat_seen[ template[i].field ]) g.apply_stat_cat(template[i].field,template[i].value);
183 g.apply_owning_lib(template[i].value);
187 g.summarize( g.copies );
191 g.error.standard_unexpected_error_alert('Error applying template',E);
195 /******************************************************************************************************/
196 /* Save as Template */
198 g.save_template = function() {
200 var name = window.prompt('Enter template name:','','Save As Template');
202 g.templates[name] = g.changed;
203 var robj = g.network.simple_request(
204 'FM_AUS_UPDATE',[ses(),g.data.list.au[0].id(), { 'staff_client.copy_editor.templates' : g.templates }]
206 if (typeof robj.ilsevent != 'undefined') {
209 alert('Template "' + name + '" saved.');
213 g.retrieve_templates();
215 g.error.standard_unexpected_error_alert('Error saving template',E);
221 g.error.standard_unexpected_error_alert('Error saving template',E);
225 /******************************************************************************************************/
226 /* Delete Template */
228 g.delete_template = function() {
230 var name = g.template_menu.value;
232 if (! window.confirm('Delete template "' + name + '"?') ) return;
233 delete(g.templates[name]);
234 var robj = g.network.simple_request(
235 'FM_AUS_UPDATE',[ses(),g.data.list.au[0].id(), { 'staff_client.copy_editor.templates' : g.templates }]
237 if (typeof robj.ilsevent != 'undefined') {
240 alert('Template "' + name + '" deleted.');
244 g.retrieve_templates();
246 g.error.standard_unexpected_error_alert('Error deleting template',E);
252 g.error.standard_unexpected_error_alert('Error deleting template',E);
256 /******************************************************************************************************/
257 /* Export Templates */
259 g.export_templates = function() {
261 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
262 JSAN.use('util.file');
263 var f = pick_file('save');
266 var r = G.error.yns_alert(
267 'Would you like to overwrite the existing file ' + f.leafName + '?',
268 'Templates Export Warning',
272 'Check here to confirm this message'
274 if (r != 0) { file.close(); alert('Not overwriting file.'); return; }
276 var e_file = new util.file(''); e_file._file = f;
277 e_file.write_content( 'truncate', js2JSON( g.templates ) );
279 alert('Templates exported as file ' + f.leafName);
281 alert('File not chosen for export.');
285 g.error.standard_unexpected_error_alert('Error exporting templates',E);
289 /******************************************************************************************************/
290 /* Import Templates */
292 g.import_templates = function() {
294 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
295 JSAN.use('util.file');
296 var f = pick_file('open');
297 if (f && f.exists()) {
298 var i_file = new util.file(''); i_file._file = f;
299 var temp = JSON2js( i_file.get_content() );
301 for (var i in temp) {
303 if (g.templates[i]) {
305 var r = g.error.yns_alert(
306 'Replace the existing template with the imported template?\n' + g.error.pretty_print( js2JSON( temp[i] ) ),
307 'Template ' + i + ' already exists.','Yes','No',null,'Click here'
310 if (r == 0 /* Yes */) g.templates[i] = temp[i];
314 g.templates[i] = temp[i];
320 var r = g.error.yns_alert(
321 'Save all of these imported templates permanently to this account?',
322 'Final Warning', 'Yes', 'No', null, 'Click here'
325 if (r == 0 /* Yes */) {
326 var robj = g.network.simple_request(
327 'FM_AUS_UPDATE',[ses(),g.data.list.au[0].id(), { 'staff_client.copy_editor.templates' : g.templates }]
329 if (typeof robj.ilsevent != 'undefined') {
332 alert('All templates saved.');
336 g.retrieve_templates();
338 g.error.standard_unexpected_error_alert('Error saving templates',E);
344 util.widgets.remove_children('template_placeholder');
345 var list = util.functional.map_object_to_list( g.templates, function(obj,i) { return [i, i]; } );
346 g.template_menu = util.widgets.make_menulist( list );
347 $('template_placeholder').appendChild(g.template_menu);
348 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.");
352 alert('File not chosen for import.');
355 g.error.standard_unexpected_error_alert('Error importing templates',E);
360 /******************************************************************************************************/
361 /* Restore backup copies */
363 g.reset = function() {
365 g.copies = JSON2js( g.original_copies );
366 g.summarize( g.copies );
370 /******************************************************************************************************/
371 /* Apply a value to a specific field on all the copies being edited */
373 g.apply = function(field,value) {
374 g.error.sdump('D_TRACE','applying field = <' + field + '> value = <' + value + '>\n');
375 if (value == '<HACK:KLUDGE:NULL>') value = null;
376 if (field == 'alert_message') { value = value.replace(/^\W+$/g,''); }
377 if (field == 'price' || field == 'deposit_amount') {
378 if (value == '') { value = null; } else { JSAN.use('util.money'); value = util.money.sanitize( value ); }
380 for (var i = 0; i < g.copies.length; i++) {
381 var copy = g.copies[i];
383 copy[field]( value ); copy.ischanged('1');
390 /******************************************************************************************************/
391 /* Apply a stat cat entry to all the copies being edited. An entry_id of < 0 signifies the stat cat is being removed. */
393 g.apply_stat_cat = function(sc_id,entry_id) {
394 g.error.sdump('D_TRACE','sc_id = ' + sc_id + ' entry_id = ' + entry_id + '\n');
395 for (var i = 0; i < g.copies.length; i++) {
396 var copy = g.copies[i];
399 var temp = copy.stat_cat_entries();
400 if (!temp) temp = [];
401 temp = util.functional.filter_list(
404 return (obj.stat_cat() != sc_id);
407 if (entry_id > -1) temp.push(
408 util.functional.find_id_object_in_list(
409 g.data.hash.asc[sc_id].entries(),
413 copy.stat_cat_entries( temp );
416 g.error.standard_unexpected_error_alert('apply_stat_cat',E);
421 /******************************************************************************************************/
422 /* Apply an "owning lib" to all the copies being edited. That is, change and auto-vivicating volumes */
425 g.apply_owning_lib = function(ou_id) {
426 g.error.sdump('D_TRACE','ou_id = ' + ou_id + '\n');
427 for (var i = 0; i < g.copies.length; i++) {
428 var copy = g.copies[i];
430 if (!g.map_acn[copy.call_number()]) {
431 var volume = g.network.simple_request('FM_ACN_RETRIEVE',[ copy.call_number() ]);
432 if (typeof volume.ilsevent != 'undefined') {
433 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);
436 g.map_acn[copy.call_number()] = volume;
438 var old_volume = g.map_acn[copy.call_number()];
439 var acn_id = g.network.simple_request(
440 'FM_ACN_FIND_OR_CREATE',
441 [ses(),old_volume.label(),old_volume.record(),ou_id]
443 if (typeof acn_id.ilsevent != 'undefined') {
444 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);
447 copy.call_number(acn_id);
450 g.error.standard_unexpected_error_alert('apply_stat_cat',E);
455 /******************************************************************************************************/
456 /* This returns true if none of the copies being edited are pre-cats */
458 g.safe_to_change_owning_lib = function() {
461 for (var i = 0; i < g.copies.length; i++) {
462 var cn = g.copies[i].call_number();
463 if (typeof cn == 'object') { cn = cn.id(); }
464 if (cn == -1) { safe = false; }
468 g.error.standard_unexpected_error_alert('safe_to_change_owning_lib?',E);
473 /******************************************************************************************************/
474 /* This returns true if none of the copies being edited have a magical status found in my_constants.magical_statuses */
476 g.safe_to_edit_copy_status = function() {
479 for (var i = 0; i < g.copies.length; i++) {
480 var status = g.copies[i].status(); if (typeof status == 'object') status = status.id();
481 if (typeof my_constants.magical_statuses[ status ] != 'undefined') safe = false;
485 g.error.standard_unexpected_error_alert('safe_to_edit_copy_status?',E);
490 /******************************************************************************************************/
491 /* This concats and uniques all the alert messages for use as the default value for a new alert message */
493 g.populate_alert_message_input = function(tb) {
495 var seen = {}; var s = '';
496 for (var i = 0; i < g.copies.length; i++) {
497 var msg = g.copies[i].alert_message();
499 if (typeof seen[msg] == 'undefined') {
505 tb.setAttribute('value',s);
507 g.error.standard_unexpected_error_alert('populate_alert_message_input',E);
511 /******************************************************************************************************/
512 /* This returns a list of acpl's appropriate for the copies being edited */
514 g.get_acpl_list = function() {
517 JSAN.use('util.functional');
519 function get(lib_id,only_these) {
520 g.data.stash_retrieve();
521 var label = 'acpl_list_for_lib_'+lib_id;
522 if (typeof g.data[label] == 'undefined') {
523 var robj = g.network.simple_request('FM_ACPL_RETRIEVE', [ lib_id ]);
524 if (typeof robj.ilsevent != 'undefined') throw(robj);
526 for (var j = 0; j < robj.length; j++) {
527 var my_acpl = robj[j];
528 if (typeof g.data.hash.acpl[ my_acpl.id() ] == 'undefined') {
529 g.data.hash.acpl[ my_acpl.id() ] = my_acpl;
530 g.data.list.acpl.push( my_acpl );
532 var only_this_lib = my_acpl.owning_lib(); if (typeof only_this_lib == 'object') only_this_lib = only_this_lib.id();
533 if (only_these.indexOf( String( only_this_lib ) ) != -1) {
534 temp_list.push( my_acpl );
537 g.data[label] = temp_list; g.data.stash(label,'hash','list');
539 return g.data[label];
542 var temp_acpl_list = [];
544 /* find acpl's based on owning_lib */
547 for (var i = 0; i < g.copies.length; i++) {
548 var cn_id = g.copies[i].call_number();
550 if (! g.map_acn[ cn_id ]) {
551 g.map_acn[ cn_id ] = g.network.simple_request('FM_ACN_RETRIEVE',[ cn_id ]);
553 var consider_lib = g.map_acn[ cn_id ].owning_lib();
554 if ( libs.indexOf( String( consider_lib ) ) > -1 ) { /* already in list */ } else { libs.push( consider_lib ); }
558 for (var i in g.callnumbers) {
559 var consider_lib = g.callnumbers[i].owning_lib;
560 if (typeof consider_lib == 'object') consider_lib = consider_lib.id();
561 if ( libs.indexOf( String( consider_lib ) ) > -1 ) { /* already in list */ } else { libs.push( consider_lib ); }
564 JSAN.use('util.fm_utils');
565 var ancestor = util.fm_utils.find_common_aou_ancestor( libs );
566 if (typeof ancestor == 'object' && ancestor != null) ancestor = ancestor.id();
569 var ancestors = util.fm_utils.find_common_aou_ancestors( libs );
570 var acpl_list = get(ancestor, ancestors);
571 if (acpl_list) for (var i = 0; i < acpl_list.length; i++) {
572 if (acpl_list[i] != null) {
573 temp_acpl_list.push(acpl_list[i]);
578 /* find acpl's based on circ_lib */
582 for (var i = 0; i < g.copies.length; i++) {
583 var consider_lib = g.copies[i].circ_lib();
584 if (typeof consider_lib == 'object') consider_lib = consider_lib.id();
585 if ( circ_libs.indexOf( String( consider_lib ) ) > -1 ) { /* already in list */ } else { circ_libs.push( consider_lib ); }
588 if (circ_libs.length > 0) {
589 var circ_ancestor = util.fm_utils.find_common_aou_ancestor( circ_libs );
590 if (typeof circ_ancestor == 'object' && circ_ancestor != null) circ_ancestor = circ_ancestor.id();
593 var circ_ancestors = util.fm_utils.find_common_aou_ancestors( circ_libs );
594 var circ_acpl_list = get(circ_ancestor, circ_ancestors);
595 var flat_acpl_list = util.functional.map_list( temp_acpl_list, function(o){return o.id();} );
596 for (var i = 0; i < circ_acpl_list.length; i++) {
597 var consider_acpl = circ_acpl_list[i].id();
598 if ( flat_acpl_list.indexOf( String( consider_acpl ) ) > -1 ) {
599 /* already in list */
601 if (circ_acpl_list[i] != null) temp_acpl_list.push( circ_acpl_list[i] );
607 return temp_acpl_list;
610 g.error.standard_unexpected_error_alert('get_acpl_list',E);
616 /******************************************************************************************************/
617 /* This keeps track of what fields have been edited for styling purposes */
621 /******************************************************************************************************/
622 /* These need data from the middle layer to render */
624 g.special_exception = {
625 'Owning Lib : Call Number' : function(label,value) {
626 JSAN.use('util.widgets');
627 if (value>0) { /* an existing call number */
629 api.FM_ACN_RETRIEVE.app,
630 api.FM_ACN_RETRIEVE.method,
633 var cn = '??? id = ' + value;
635 cn = req.getResultObject();
637 g.error.sdump('D_ERROR','callnumber retrieve: ' + E);
639 util.widgets.set_text(label,g.data.hash.aou[ cn.owning_lib() ].shortname() + ' : ' + cn.label());
642 } else { /* a yet to be created call number */
644 util.widgets.set_text(label,g.data.hash.aou[ g.callnumbers[value].owning_lib ].shortname() + ' : ' + g.callnumbers[value].label);
648 'Creator' : function(label,value) {
649 if (value == null || value == '' || value == 'null') return;
650 g.network.simple_request(
651 'FM_AU_RETRIEVE_VIA_ID',
654 var p = '??? id = ' + value;
656 p = req.getResultObject();
660 g.error.sdump('D_ERROR','patron retrieve: ' + E);
662 JSAN.use('util.widgets');
663 util.widgets.set_text(label,p);
667 'Last Editor' : function(label,value) {
668 if (value == null || value == '' || value == 'null') return;
669 g.network.simple_request(
670 'FM_AU_RETRIEVE_VIA_ID',
673 var p = '??? id = ' + value;
675 p = req.getResultObject();
679 g.error.sdump('D_ERROR','patron retrieve: ' + E);
681 util.widgets.set_text(label,p);
688 /******************************************************************************************************/
689 g.readonly_stat_cat_names = [];
690 g.editable_stat_cat_names = [];
692 /******************************************************************************************************/
693 /* These get show in the left panel */
695 function init_panes() {
696 g.panes_and_field_names = {
703 render: 'fm.barcode();',
709 render: 'util.date.formatted_date( fm.create_date(), "%F");',
715 render: 'fm.creator();',
721 render: 'util.date.formatted_date( fm.edit_date(), "%F");',
727 render: 'fm.editor();',
738 render: 'typeof fm.location() == "object" ? fm.location().name() : g.data.lookup("acpl",fm.location()).name()',
739 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);',
744 "Circulation Library",
746 render: 'typeof fm.circ_lib() == "object" ? fm.circ_lib().shortname() : g.data.hash.aou[ fm.circ_lib() ].shortname()',
747 //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);',
748 input: 'c = function(v){ g.apply("circ_lib",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( util.functional.map_list( g.data.list.aou, function(obj) { var sname = obj.shortname(); for (i = sname.length; i < 20; i++) sname += " "; return [ obj.name() ? sname + " " + obj.name() : obj.shortname(), obj.id(), ( ! get_bool( g.data.hash.aout[ obj.ou_type() ].can_have_vols() ) ), ( g.data.hash.aout[ obj.ou_type() ].depth() * 2), ]; }), g.data.list.au[0].ws_ou()); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
752 "Owning Lib : Call Number",
754 render: 'fm.call_number();',
755 input: g.safe_to_change_owning_lib() ? 'c = function(v){ g.apply_owning_lib(v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( util.functional.map_list( g.data.list.aou, function(obj) { var sname = obj.shortname(); for (i = sname.length; i < 20; i++) sname += " "; return [ obj.name() ? sname + " " + obj.name() : obj.shortname(), obj.id(), ( ! get_bool( g.data.hash.aout[ obj.ou_type() ].can_have_vols() ) ), ( g.data.hash.aout[ obj.ou_type() ].depth() * 2), ]; }), g.data.list.au[0].ws_ou()); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);' : undefined,
761 render: 'fm.copy_number() == null ? "<Unset>" : fm.copy_number()',
762 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);',
774 render: 'fm.circulate() == null ? "<Unset>" : ( get_bool( fm.circulate() ) ? "Yes" : "No" )',
775 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);',
781 render: 'fm.holdable() == null ? "<Unset>" : ( get_bool( fm.holdable() ) ? "Yes" : "No" )',
782 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);',
788 render: 'fm.age_protect() == null ? "<Unset>" : ( typeof fm.age_protect() == "object" ? fm.age_protect().name() : g.data.hash.crahp[ fm.age_protect() ].name() )',
789 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);',
796 render: 'switch(fm.loan_duration()){ case 1: case "1": "Short"; break; case 2: case "2": "Normal"; break; case 3:case "3": "Long"; break; }',
797 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);',
804 render: 'switch(fm.fine_level()){ case 1: case "1": "Low"; break; case 2: case "2": "Normal"; break; case 3: case "3": "High"; break; }',
805 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);',
812 render: 'fm.circ_as_type() == null ? "<Unset>" : g.data.hash.citm[ fm.circ_as_type() ].value()',
813 input: 'c = function(v){ g.apply("circ_as_type",v); if (typeof post_c == "function") post_c(v); }; x = util.widgets.make_menulist( util.functional.map_list( g.data.list.citm, function(n){return [ n.code() + " - " + n.value(), n.code()];} ).sort() ); x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c), false);',
817 "Circulation Modifier",
819 render: 'fm.circ_modifier() == null ? "<Unset>" : fm.circ_modifier()',
820 /*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);',*/
821 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);',
830 render: 'fm.alert_message() == null ? "<Unset>" : fm.alert_message()',
831 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);',
838 render: 'fm.deposit() == null ? "<Unset>" : ( get_bool( fm.deposit() ) ? "Yes" : "No" )',
839 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);',
845 render: 'if (fm.deposit_amount() == null) { "<Unset>"; } else { util.money.sanitize( fm.deposit_amount() ); }',
846 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);',
852 render: 'if (fm.price() == null) { "<Unset>"; } else { util.money.sanitize( fm.price() ); }',
853 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);',
860 render: 'fm.opac_visible() == null ? "<Unset>" : ( get_bool( fm.opac_visible() ) ? "Yes" : "No" )',
861 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);',
867 render: 'fm.ref() == null ? "<Unset>" : ( get_bool( fm.ref() ) ? "Yes" : "No" )',
868 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);',
880 /******************************************************************************************************/
881 /* This loops through all our fieldnames and all the copies, tallying up counts for the different values */
883 g.summarize = function( copies ) {
884 /******************************************************************************************************/
887 JSAN.use('util.date'); JSAN.use('util.money');
890 for (var i in g.panes_and_field_names) {
891 g.field_names = g.field_names.concat( g.panes_and_field_names[i] );
893 g.field_names = g.field_names.concat( g.editable_stat_cat_names );
894 g.field_names = g.field_names.concat( g.readonly_stat_cat_names );
896 /******************************************************************************************************/
897 /* Loop through the field names */
899 for (var i = 0; i < g.field_names.length; i++) {
901 var field_name = g.field_names[i][0];
902 var render = g.field_names[i][1].render;
903 var attr = g.field_names[i][1].attr;
904 g.summary[ field_name ] = {};
906 /******************************************************************************************************/
907 /* Loop through the copies */
909 for (var j = 0; j < copies.length; j++) {
912 var cmd = render || ('fm.' + field_name + '();');
915 /**********************************************************************************************/
916 /* Try to retrieve the value for this field for this copy */
921 g.error.sdump('D_ERROR','Attempted ' + cmd + '\n' + E + '\n');
923 if (typeof value == 'object' && value != null) {
924 alert('FIXME: field_name = <' + field_name + '> value = <' + js2JSON(value) + '>\n');
927 /**********************************************************************************************/
928 /* Tally the count */
930 if (g.summary[ field_name ][ value ]) {
931 g.summary[ field_name ][ value ]++;
933 g.summary[ field_name ][ value ] = 1;
937 g.error.sdump('D_TRACE','summary = ' + js2JSON(g.summary) + '\n');
940 /******************************************************************************************************/
941 /* Display the summarized data and inputs for editing */
943 g.render = function() {
945 /******************************************************************************************************/
946 /* Library setup and clear any existing interface */
948 JSAN.use('util.widgets'); JSAN.use('util.date'); JSAN.use('util.money'); JSAN.use('util.functional');
950 for (var i in g.panes_and_field_names) {
951 var p = document.getElementById(i);
952 if (p) util.widgets.remove_children(p);
955 /******************************************************************************************************/
956 /* Populate the library filter menu for stat cats */
959 for (var i = 0; i < g.panes_and_field_names.right_pane4.length; i++) {
960 sc_libs[ g.panes_and_field_names.right_pane4[i][1].attr.sc_lib ] = true;
963 for (var i in sc_libs) { sc_libs2.push( [ g.data.hash.aou[ i ].shortname(), i ] ); }
965 var x = document.getElementById("stat_cat_lib_filter_menu").firstChild;
966 JSAN.use('util.widgets'); util.widgets.remove_children(x);
967 for (var i = 0; i < sc_libs2.length; i++) {
968 var menuitem = document.createElement('menuitem');
969 menuitem.setAttribute('type','checkbox');
970 menuitem.setAttribute('checked','true');
971 menuitem.setAttribute('label',sc_libs2[i][0]);
972 menuitem.setAttribute('value',sc_libs2[i][1]);
973 menuitem.setAttribute('oncommand','try{g.toggle_stat_cat_display(this);}catch(E){alert(E);}');
974 x.appendChild(menuitem);
977 /******************************************************************************************************/
978 /* Prepare the panes */
980 var groupbox; var caption; var vbox; var grid; var rows;
982 /******************************************************************************************************/
983 /* Loop through the field names */
985 for (h in g.panes_and_field_names) {
986 if (!document.getElementById(h)) continue;
987 for (var i = 0; i < g.panes_and_field_names[h].length; i++) {
989 var f = g.panes_and_field_names[h][i]; var fn = f[0]; var attr = f[1].attr;
990 groupbox = document.createElement('groupbox'); document.getElementById(h).appendChild(groupbox);
992 for (var a in attr) {
993 groupbox.setAttribute(a,attr[a]);
996 if (typeof g.changed[fn] != 'undefined') groupbox.setAttribute('class','copy_editor_field_changed');
997 caption = document.createElement('caption'); groupbox.appendChild(caption);
998 caption.setAttribute('label',fn); caption.setAttribute('id','caption_'+fn);
999 vbox = document.createElement('vbox'); groupbox.appendChild(vbox);
1000 grid = util.widgets.make_grid( [ { 'flex' : 1 }, {}, {} ] ); vbox.appendChild(grid);
1001 grid.setAttribute('flex','1');
1002 rows = grid.lastChild;
1005 /**************************************************************************************/
1006 /* Loop through each value for the field */
1008 for (var j in g.summary[fn]) {
1009 var value = j; var count = g.summary[fn][j];
1010 row = document.createElement('row'); rows.appendChild(row);
1011 var label1 = document.createElement('description'); row.appendChild(label1);
1012 if (g.special_exception[ fn ]) {
1013 g.special_exception[ fn ]( label1, value );
1015 label1.appendChild( document.createTextNode(value) );
1017 var label2 = document.createElement('description'); row.appendChild(label2);
1018 var unit = count == 1 ? 'copy' : 'copies';
1019 label2.appendChild( document.createTextNode(count + ' ' + unit) );
1021 var hbox = document.createElement('hbox');
1022 hbox.setAttribute('id',fn);
1023 groupbox.appendChild(hbox);
1024 var hbox2 = document.createElement('hbox');
1025 groupbox.appendChild(hbox2);
1027 /**************************************************************************************/
1028 /* Render the input widget */
1030 if (f[1].input && g.edit) {
1031 g.render_input(hbox,f[1]);
1035 g.error.sdump('D_ERROR','copy editor: ' + E + '\n');
1041 /******************************************************************************************************/
1042 /* This actually draws the change button and input widget for a given field */
1043 g.render_input = function(node,blob) {
1045 // node = hbox ; groupbox -> hbox, hbox
1047 var groupbox = node.parentNode;
1048 var caption = groupbox.firstChild;
1049 var vbox = node.previousSibling;
1051 var hbox2 = node.nextSibling;
1053 var input_cmd = blob.input;
1054 var render_cmd = blob.render;
1055 var attr = blob.attr;
1057 var block = false; var first = true;
1059 function on_mouseover(ev) {
1060 groupbox.setAttribute('style','background: white');
1063 function on_mouseout(ev) {
1064 groupbox.setAttribute('style','');
1067 vbox.addEventListener('mouseover',on_mouseover,false);
1068 vbox.addEventListener('mouseout',on_mouseout,false);
1069 groupbox.addEventListener('mouseover',on_mouseover,false);
1070 groupbox.addEventListener('mouseout',on_mouseout,false);
1071 groupbox.firstChild.addEventListener('mouseover',on_mouseover,false);
1072 groupbox.firstChild.addEventListener('mouseout',on_mouseout,false);
1074 function on_click(ev){
1076 if (block) return; block = true;
1078 function post_c(v) {
1080 /* FIXME - kludgy */
1081 var t = input_cmd.match('apply_stat_cat') ? 'stat_cat' : ( input_cmd.match('apply_owning_lib') ? 'owning_lib' : 'attribute' );
1085 f = input_cmd.match(/apply\("(.+?)",/)[1];
1088 f = input_cmd.match(/apply_stat_cat\((.+?),/)[1];
1094 g.changed[ hbox.id ] = { 'type' : t, 'field' : f, 'value' : v };
1098 g.summarize( g.copies );
1100 document.getElementById(caption.id).focus();
1104 g.error.standard_unexpected_error_alert('post_c',E);
1107 var x; var c; eval( input_cmd );
1109 util.widgets.remove_children(vbox);
1110 util.widgets.remove_children(hbox);
1111 util.widgets.remove_children(hbox2);
1112 hbox.appendChild(x);
1113 var apply = document.createElement('button');
1114 apply.setAttribute('label','Apply');
1115 apply.setAttribute('accesskey','A');
1116 hbox2.appendChild(apply);
1117 apply.addEventListener('command',function() { c(x.value); },false);
1118 var cancel = document.createElement('button');
1119 cancel.setAttribute('label','Cancel');
1120 cancel.addEventListener('command',function() { setTimeout( function() { g.summarize( g.copies ); g.render(); document.getElementById(caption.id).focus(); }, 0); }, false);
1121 hbox2.appendChild(cancel);
1122 setTimeout( function() { x.focus(); }, 0 );
1125 g.error.standard_unexpected_error_alert('render_input',E);
1128 vbox.addEventListener('click',on_click, false);
1129 hbox.addEventListener('click',on_click, false);
1130 caption.addEventListener('click',on_click, false);
1131 caption.addEventListener('keypress',function(ev) {
1132 if (ev.keyCode == 13 /* enter */ || ev.keyCode == 77 /* mac enter */) on_click();
1134 caption.setAttribute('style','-moz-user-focus: normal');
1135 caption.setAttribute('onfocus','this.setAttribute("class","outline_me")');
1136 caption.setAttribute('onblur','this.setAttribute("class","")');
1139 g.error.sdump('D_ERROR',E + '\n');
1143 /******************************************************************************************************/
1144 /* store the copies in the global xpcom stash */
1146 g.stash_and_close = function() {
1148 if (g.handle_update) {
1150 var r = g.network.request(
1151 api.FM_ACP_FLESHED_BATCH_UPDATE.app,
1152 api.FM_ACP_FLESHED_BATCH_UPDATE.method,
1153 [ ses(), g.copies, true ]
1155 if (typeof r.ilsevent != 'undefined') {
1156 g.error.standard_unexpected_error_alert('copy update',r);
1158 alert('Items added/modified.');
1160 /* FIXME -- revisit the return value here */
1162 alert('copy update error: ' + js2JSON(E));
1165 //g.data.temp_copies = js2JSON( g.copies );
1166 //g.data.stash('temp_copies');
1167 xulG.copies = g.copies;
1168 update_modal_xulG(xulG);
1171 g.error.standard_unexpected_error_alert('stash and close',E);
1175 /******************************************************************************************************/
1176 /* spawn copy notes interface */
1178 g.copy_notes = function() {
1179 JSAN.use('util.window'); var win = new util.window();
1181 urls.XUL_COPY_NOTES,
1182 //+ '?copy_id=' + window.escape(g.copies[0].id()),
1183 'Copy Notes','chrome,resizable,modal',
1184 { 'copy_id' : g.copies[0].id() }
1188 /******************************************************************************************************/
1189 /* hides or unhides stat cats based on library stat cat filter menu */
1190 g.toggle_stat_cat_display = function(el) {
1191 var visible = el.getAttribute('checked');
1192 var nl = document.getElementsByAttribute('sc_lib',el.getAttribute('value'));
1193 for (var n = 0; n < nl.length; n++) {
1195 nl[n].setAttribute('hidden','false');
1197 nl[n].setAttribute('hidden','true');
1202 /******************************************************************************************************/
1203 /* This adds a stat cat definition to the stat cat pane for rendering */
1204 g.add_stat_cat = function(sc) {
1206 if (typeof g.data.hash.asc == 'undefined') { g.data.hash.asc = {}; g.data.stash('hash'); }
1210 if (typeof sc == 'object') {
1215 if (typeof g.stat_cat_seen[sc_id] != 'undefined') { return; }
1217 g.stat_cat_seen[ sc_id ] = 1;
1219 if (typeof sc != 'object') {
1221 sc = g.network.simple_request(
1222 'FM_ASC_BATCH_RETRIEVE',
1223 [ ses(), [ sc_id ] ]
1228 g.data.hash.asc[ sc.id() ] = sc; g.data.stash('hash');
1230 var label_name = g.data.hash.aou[ sc.owner() ].shortname() + " : " + sc.name();
1235 render: 'var l = util.functional.find_list( fm.stat_cat_entries(), function(e){ return e.stat_cat() == '
1236 + sc.id() + '; } ); l ? l.value() : "<Unset>";',
1237 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()
1238 + '].entries(), function(obj){ return [ obj.value(), obj.id() ]; } ) ).sort() ); '
1239 + 'x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c),false);',
1246 g.panes_and_field_names.right_pane4.push( temp_array );
1248 g.error.standard_unexpected_error_alert('Error adding stat cat to display definition',E);
1252 /******************************************************************************************************/
1253 /* Add stat cats to the panes_and_field_names.right_pane4 */
1254 g.populate_stat_cats = function() {
1256 g.data.stash_retrieve();
1257 g.stat_cat_seen = {};
1259 function get(lib_id,only_these) {
1260 g.data.stash_retrieve();
1261 var label = 'asc_list_for_lib_'+lib_id;
1262 if (typeof g.data[label] == 'undefined') {
1263 var robj = g.network.simple_request('FM_ASC_RETRIEVE_VIA_AOU', [ ses(), lib_id ]);
1264 if (typeof robj.ilsevent != 'undefined') throw(robj);
1266 for (var j = 0; j < robj.length; j++) {
1267 var my_asc = robj[j];
1268 if (typeof g.data.hash.asc == 'undefined') { g.data.hash.asc = {}; }
1269 if (typeof g.data.hash.asc[ my_asc.id() ] == 'undefined') {
1270 g.data.hash.asc[ my_asc.id() ] = my_asc;
1272 var only_this_lib = my_asc.owner(); if (typeof only_this_lib == 'object') only_this_lib = only_this_lib.id();
1273 if (only_these.indexOf( String( only_this_lib ) ) != -1) {
1274 temp_list.push( my_asc );
1277 g.data[label] = temp_list; g.data.stash(label,'hash','list');
1279 return g.data[label];
1282 /* The stat cats for the pertinent library -- this is based on workstation ou */
1283 var label = 'asc_list_for_' + typeof g.data.ws_ou == 'object' ? g.data.ws_ou.id() : g.data.ws_ou;
1284 g.data[ label ] = g.data.list.my_asc; g.data.stash('label');
1285 for (var i = 0; i < g.data.list.my_asc.length; i++) {
1286 g.add_stat_cat( g.data.list.my_asc[i] );
1289 /* For the others, we want to consider the owning libs, circ libs, and any libs that have stat cats already on the copies,
1290 however, if batch editing, we only want to show the ones they have in common. So let's compile the libs */
1292 function add_common_ancestors(sc_libs) {
1293 JSAN.use('util.fm_utils');
1294 var libs = []; for (var i in sc_libs) libs.push(i);
1295 var ancestor = util.fm_utils.find_common_aou_ancestor( libs );
1296 if (typeof ancestor == 'object' && ancestor != null) ancestor = ancestor.id();
1298 var ancestors = util.fm_utils.find_common_aou_ancestors( libs );
1299 var asc_list = get(ancestor, ancestors);
1300 for (var i = 0; i < asc_list.length; i++) {
1301 g.add_stat_cat( asc_list[i] );
1306 /* stat cats based on stat cat entries present on these copies */
1308 for (var i = 0; i < g.copies.length; i++) {
1309 var entries = g.copies[i].stat_cat_entries();
1310 if (!entries) entries = [];
1311 for (var j = 0; j < entries.length; j++) {
1312 var lib = entries[j].owner(); if (typeof lib == 'object') lib = lib.id();
1313 sc_libs[ lib ] = true;
1316 add_common_ancestors(sc_libs); // CAVEAT - if a copy has no stat_cat_entries, it basically gets no vote here
1318 /* stat cats based on Circ Lib */
1320 for (var i = 0; i < g.copies.length; i++) {
1321 var circ_lib = g.copies[i].circ_lib(); if (typeof circ_lib == 'object') circ_lib = circ_lib.id();
1322 sc_libs[ circ_lib ] = true;
1324 add_common_ancestors(sc_libs);
1326 /* stat cats based on Owning Lib */
1328 for (var i = 0; i < g.copies.length; i++) {
1329 var cn_id = g.copies[i].call_number();
1331 if (! g.map_acn[ cn_id ]) {
1332 g.map_acn[ cn_id ] = g.network.simple_request('FM_ACN_RETRIEVE',[ cn_id ]);
1334 var owning_lib = g.map_acn[ cn_id ].owning_lib(); if (typeof owning_lib == 'object') owning_lib = owning_lib.id();
1335 sc_libs[ owning_lib ] = true;
1338 add_common_ancestors(sc_libs); // CAVEAT - if a copy is a pre-cat, it basically gets no vote here
1340 g.panes_and_field_names.right_pane4.sort();
1343 g.error.standard_unexpected_error_alert('Error populating stat cats for display',E);