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('id','filter_'+sc_libs2[i][1]);
970 menuitem.setAttribute('type','checkbox');
971 menuitem.setAttribute('checked','true');
972 menuitem.setAttribute('label',sc_libs2[i][0]);
973 menuitem.setAttribute('value',sc_libs2[i][1]);
974 menuitem.setAttribute('oncommand','try{g.toggle_stat_cat_display(this);}catch(E){alert(E);}');
975 x.appendChild(menuitem);
978 JSAN.use('util.file');
979 var file = new util.file('copy_editor_prefs.'+g.data.server_unadorned);
980 g.copy_editor_prefs = util.widgets.load_attributes(file);
981 for (var i in g.copy_editor_prefs) {
982 if (i.match(/filter_/) && g.copy_editor_prefs[i].checked == '') {
984 g.toggle_stat_cat_display( document.getElementById(i) );
985 } catch(E) { alert(E); }
989 /******************************************************************************************************/
990 /* Prepare the panes */
992 var groupbox; var caption; var vbox; var grid; var rows;
994 /******************************************************************************************************/
995 /* Loop through the field names */
997 for (h in g.panes_and_field_names) {
998 if (!document.getElementById(h)) continue;
999 for (var i = 0; i < g.panes_and_field_names[h].length; i++) {
1001 var f = g.panes_and_field_names[h][i]; var fn = f[0]; var attr = f[1].attr;
1002 groupbox = document.createElement('groupbox'); document.getElementById(h).appendChild(groupbox);
1004 for (var a in attr) {
1005 groupbox.setAttribute(a,attr[a]);
1008 if (typeof g.changed[fn] != 'undefined') groupbox.setAttribute('class','copy_editor_field_changed');
1009 caption = document.createElement('caption'); groupbox.appendChild(caption);
1010 caption.setAttribute('label',fn); caption.setAttribute('id','caption_'+fn);
1011 vbox = document.createElement('vbox'); groupbox.appendChild(vbox);
1012 grid = util.widgets.make_grid( [ { 'flex' : 1 }, {}, {} ] ); vbox.appendChild(grid);
1013 grid.setAttribute('flex','1');
1014 rows = grid.lastChild;
1017 /**************************************************************************************/
1018 /* Loop through each value for the field */
1020 for (var j in g.summary[fn]) {
1021 var value = j; var count = g.summary[fn][j];
1022 row = document.createElement('row'); rows.appendChild(row);
1023 var label1 = document.createElement('description'); row.appendChild(label1);
1024 if (g.special_exception[ fn ]) {
1025 g.special_exception[ fn ]( label1, value );
1027 label1.appendChild( document.createTextNode(value) );
1029 var label2 = document.createElement('description'); row.appendChild(label2);
1030 var unit = count == 1 ? 'copy' : 'copies';
1031 label2.appendChild( document.createTextNode(count + ' ' + unit) );
1033 var hbox = document.createElement('hbox');
1034 hbox.setAttribute('id',fn);
1035 groupbox.appendChild(hbox);
1036 var hbox2 = document.createElement('hbox');
1037 groupbox.appendChild(hbox2);
1039 /**************************************************************************************/
1040 /* Render the input widget */
1042 if (f[1].input && g.edit) {
1043 g.render_input(hbox,f[1]);
1047 g.error.sdump('D_ERROR','copy editor: ' + E + '\n');
1053 /******************************************************************************************************/
1054 /* This actually draws the change button and input widget for a given field */
1055 g.render_input = function(node,blob) {
1057 // node = hbox ; groupbox -> hbox, hbox
1059 var groupbox = node.parentNode;
1060 var caption = groupbox.firstChild;
1061 var vbox = node.previousSibling;
1063 var hbox2 = node.nextSibling;
1065 var input_cmd = blob.input;
1066 var render_cmd = blob.render;
1067 var attr = blob.attr;
1069 var block = false; var first = true;
1071 function on_mouseover(ev) {
1072 groupbox.setAttribute('style','background: white');
1075 function on_mouseout(ev) {
1076 groupbox.setAttribute('style','');
1079 vbox.addEventListener('mouseover',on_mouseover,false);
1080 vbox.addEventListener('mouseout',on_mouseout,false);
1081 groupbox.addEventListener('mouseover',on_mouseover,false);
1082 groupbox.addEventListener('mouseout',on_mouseout,false);
1083 groupbox.firstChild.addEventListener('mouseover',on_mouseover,false);
1084 groupbox.firstChild.addEventListener('mouseout',on_mouseout,false);
1086 function on_click(ev){
1088 if (block) return; block = true;
1090 function post_c(v) {
1092 /* FIXME - kludgy */
1093 var t = input_cmd.match('apply_stat_cat') ? 'stat_cat' : ( input_cmd.match('apply_owning_lib') ? 'owning_lib' : 'attribute' );
1097 f = input_cmd.match(/apply\("(.+?)",/)[1];
1100 f = input_cmd.match(/apply_stat_cat\((.+?),/)[1];
1106 g.changed[ hbox.id ] = { 'type' : t, 'field' : f, 'value' : v };
1110 g.summarize( g.copies );
1112 document.getElementById(caption.id).focus();
1116 g.error.standard_unexpected_error_alert('post_c',E);
1119 var x; var c; eval( input_cmd );
1121 util.widgets.remove_children(vbox);
1122 util.widgets.remove_children(hbox);
1123 util.widgets.remove_children(hbox2);
1124 hbox.appendChild(x);
1125 var apply = document.createElement('button');
1126 apply.setAttribute('label','Apply');
1127 apply.setAttribute('accesskey','A');
1128 hbox2.appendChild(apply);
1129 apply.addEventListener('command',function() { c(x.value); },false);
1130 var cancel = document.createElement('button');
1131 cancel.setAttribute('label','Cancel');
1132 cancel.addEventListener('command',function() { setTimeout( function() { g.summarize( g.copies ); g.render(); document.getElementById(caption.id).focus(); }, 0); }, false);
1133 hbox2.appendChild(cancel);
1134 setTimeout( function() { x.focus(); }, 0 );
1137 g.error.standard_unexpected_error_alert('render_input',E);
1140 vbox.addEventListener('click',on_click, false);
1141 hbox.addEventListener('click',on_click, false);
1142 caption.addEventListener('click',on_click, false);
1143 caption.addEventListener('keypress',function(ev) {
1144 if (ev.keyCode == 13 /* enter */ || ev.keyCode == 77 /* mac enter */) on_click();
1146 caption.setAttribute('style','-moz-user-focus: normal');
1147 caption.setAttribute('onfocus','this.setAttribute("class","outline_me")');
1148 caption.setAttribute('onblur','this.setAttribute("class","")');
1151 g.error.sdump('D_ERROR',E + '\n');
1155 /******************************************************************************************************/
1156 /* store the copies in the global xpcom stash */
1158 g.stash_and_close = function() {
1160 if (g.handle_update) {
1162 var r = g.network.request(
1163 api.FM_ACP_FLESHED_BATCH_UPDATE.app,
1164 api.FM_ACP_FLESHED_BATCH_UPDATE.method,
1165 [ ses(), g.copies, true ]
1167 if (typeof r.ilsevent != 'undefined') {
1168 g.error.standard_unexpected_error_alert('copy update',r);
1170 alert('Items added/modified.');
1172 /* FIXME -- revisit the return value here */
1174 alert('copy update error: ' + js2JSON(E));
1177 //g.data.temp_copies = js2JSON( g.copies );
1178 //g.data.stash('temp_copies');
1179 xulG.copies = g.copies;
1180 update_modal_xulG(xulG);
1183 g.error.standard_unexpected_error_alert('stash and close',E);
1187 /******************************************************************************************************/
1188 /* spawn copy notes interface */
1190 g.copy_notes = function() {
1191 JSAN.use('util.window'); var win = new util.window();
1193 urls.XUL_COPY_NOTES,
1194 //+ '?copy_id=' + window.escape(g.copies[0].id()),
1195 'Copy Notes','chrome,resizable,modal',
1196 { 'copy_id' : g.copies[0].id() }
1200 /******************************************************************************************************/
1201 /* hides or unhides stat cats based on library stat cat filter menu */
1202 g.toggle_stat_cat_display = function(el) {
1203 var visible = el.getAttribute('checked');
1204 var nl = document.getElementsByAttribute('sc_lib',el.getAttribute('value'));
1205 for (var n = 0; n < nl.length; n++) {
1207 nl[n].setAttribute('hidden','false');
1209 nl[n].setAttribute('hidden','true');
1212 g.copy_editor_prefs[ el.getAttribute('id') ] = { 'checked' : visible };
1213 JSAN.use('util.widgets'); JSAN.use('util.file'); var file = new util.file('copy_editor_prefs.'+g.data.server_unadorned);
1214 var what_to_save = {};
1215 for (var i in g.copy_editor_prefs) {
1216 what_to_save[i] = [];
1217 for (var j in g.copy_editor_prefs[i]) what_to_save[i].push(j);
1219 util.widgets.save_attributes(file, what_to_save );
1222 /******************************************************************************************************/
1223 /* This adds a stat cat definition to the stat cat pane for rendering */
1224 g.add_stat_cat = function(sc) {
1226 if (typeof g.data.hash.asc == 'undefined') { g.data.hash.asc = {}; g.data.stash('hash'); }
1230 if (typeof sc == 'object') {
1235 if (typeof g.stat_cat_seen[sc_id] != 'undefined') { return; }
1237 g.stat_cat_seen[ sc_id ] = 1;
1239 if (typeof sc != 'object') {
1241 sc = g.network.simple_request(
1242 'FM_ASC_BATCH_RETRIEVE',
1243 [ ses(), [ sc_id ] ]
1248 g.data.hash.asc[ sc.id() ] = sc; g.data.stash('hash');
1250 var label_name = g.data.hash.aou[ sc.owner() ].shortname() + " : " + sc.name();
1255 render: 'var l = util.functional.find_list( fm.stat_cat_entries(), function(e){ return e.stat_cat() == '
1256 + sc.id() + '; } ); l ? l.value() : "<Unset>";',
1257 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()
1258 + '].entries(), function(obj){ return [ obj.value(), obj.id() ]; } ) ).sort() ); '
1259 + 'x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c),false);',
1266 g.panes_and_field_names.right_pane4.push( temp_array );
1268 g.error.standard_unexpected_error_alert('Error adding stat cat to display definition',E);
1272 /******************************************************************************************************/
1273 /* Add stat cats to the panes_and_field_names.right_pane4 */
1274 g.populate_stat_cats = function() {
1276 g.data.stash_retrieve();
1277 g.stat_cat_seen = {};
1279 function get(lib_id,only_these) {
1280 g.data.stash_retrieve();
1281 var label = 'asc_list_for_lib_'+lib_id;
1282 if (typeof g.data[label] == 'undefined') {
1283 var robj = g.network.simple_request('FM_ASC_RETRIEVE_VIA_AOU', [ ses(), lib_id ]);
1284 if (typeof robj.ilsevent != 'undefined') throw(robj);
1286 for (var j = 0; j < robj.length; j++) {
1287 var my_asc = robj[j];
1288 if (typeof g.data.hash.asc == 'undefined') { g.data.hash.asc = {}; }
1289 if (typeof g.data.hash.asc[ my_asc.id() ] == 'undefined') {
1290 g.data.hash.asc[ my_asc.id() ] = my_asc;
1292 var only_this_lib = my_asc.owner(); if (typeof only_this_lib == 'object') only_this_lib = only_this_lib.id();
1293 if (only_these.indexOf( String( only_this_lib ) ) != -1) {
1294 temp_list.push( my_asc );
1297 g.data[label] = temp_list; g.data.stash(label,'hash','list');
1299 return g.data[label];
1302 /* The stat cats for the pertinent library -- this is based on workstation ou */
1303 var label = 'asc_list_for_' + typeof g.data.ws_ou == 'object' ? g.data.ws_ou.id() : g.data.ws_ou;
1304 g.data[ label ] = g.data.list.my_asc; g.data.stash('label');
1305 for (var i = 0; i < g.data.list.my_asc.length; i++) {
1306 g.add_stat_cat( g.data.list.my_asc[i] );
1309 /* For the others, we want to consider the owning libs, circ libs, and any libs that have stat cats already on the copies,
1310 however, if batch editing, we only want to show the ones they have in common. So let's compile the libs */
1312 function add_common_ancestors(sc_libs) {
1313 JSAN.use('util.fm_utils');
1314 var libs = []; for (var i in sc_libs) libs.push(i);
1315 var ancestor = util.fm_utils.find_common_aou_ancestor( libs );
1316 if (typeof ancestor == 'object' && ancestor != null) ancestor = ancestor.id();
1318 var ancestors = util.fm_utils.find_common_aou_ancestors( libs );
1319 var asc_list = get(ancestor, ancestors);
1320 for (var i = 0; i < asc_list.length; i++) {
1321 g.add_stat_cat( asc_list[i] );
1326 /* stat cats based on stat cat entries present on these copies */
1328 for (var i = 0; i < g.copies.length; i++) {
1329 var entries = g.copies[i].stat_cat_entries();
1330 if (!entries) entries = [];
1331 for (var j = 0; j < entries.length; j++) {
1332 var lib = entries[j].owner(); if (typeof lib == 'object') lib = lib.id();
1333 sc_libs[ lib ] = true;
1336 add_common_ancestors(sc_libs); // CAVEAT - if a copy has no stat_cat_entries, it basically gets no vote here
1338 /* stat cats based on Circ Lib */
1340 for (var i = 0; i < g.copies.length; i++) {
1341 var circ_lib = g.copies[i].circ_lib(); if (typeof circ_lib == 'object') circ_lib = circ_lib.id();
1342 sc_libs[ circ_lib ] = true;
1344 add_common_ancestors(sc_libs);
1346 /* stat cats based on Owning Lib */
1348 for (var i = 0; i < g.copies.length; i++) {
1349 var cn_id = g.copies[i].call_number();
1351 if (! g.map_acn[ cn_id ]) {
1352 g.map_acn[ cn_id ] = g.network.simple_request('FM_ACN_RETRIEVE',[ cn_id ]);
1354 var owning_lib = g.map_acn[ cn_id ].owning_lib(); if (typeof owning_lib == 'object') owning_lib = owning_lib.id();
1355 sc_libs[ owning_lib ] = true;
1358 add_common_ancestors(sc_libs); // CAVEAT - if a copy is a pre-cat, it basically gets no vote here
1360 g.panes_and_field_names.right_pane4.sort();
1363 g.error.standard_unexpected_error_alert('Error populating stat cats for display',E);