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 g.template_menu.setAttribute('id','template_menu');
160 $('template_placeholder').appendChild(g.template_menu);
161 g.template_menu.addEventListener(
163 function() { g.copy_editor_prefs[ 'template_menu' ] = { 'value' : g.template_menu.value }; g.save_attributes(); },
167 g.error.standard_unexpected_error_alert('Error retrieving templates',E);
171 /******************************************************************************************************/
174 g.apply_template = function() {
176 var name = g.template_menu.value;
177 if (g.templates[ name ] != 'undefined') {
178 var template = g.templates[ name ];
179 for (var i in template) {
180 g.changed[ i ] = template[ i ];
181 switch( template[i].type ) {
183 g.apply(template[i].field,template[i].value);
186 if (g.stat_cat_seen[ template[i].field ]) g.apply_stat_cat(template[i].field,template[i].value);
189 g.apply_owning_lib(template[i].value);
193 g.summarize( g.copies );
197 g.error.standard_unexpected_error_alert('Error applying template',E);
201 /******************************************************************************************************/
202 /* Save as Template */
204 g.save_template = function() {
206 var name = window.prompt('Enter template name:','','Save As Template');
208 g.templates[name] = g.changed;
209 var robj = g.network.simple_request(
210 'FM_AUS_UPDATE',[ses(),g.data.list.au[0].id(), { 'staff_client.copy_editor.templates' : g.templates }]
212 if (typeof robj.ilsevent != 'undefined') {
215 alert('Template "' + name + '" saved.');
219 g.retrieve_templates();
221 g.error.standard_unexpected_error_alert('Error saving template',E);
227 g.error.standard_unexpected_error_alert('Error saving template',E);
231 /******************************************************************************************************/
232 /* Delete Template */
234 g.delete_template = function() {
236 var name = g.template_menu.value;
238 if (! window.confirm('Delete template "' + name + '"?') ) return;
239 delete(g.templates[name]);
240 var robj = g.network.simple_request(
241 'FM_AUS_UPDATE',[ses(),g.data.list.au[0].id(), { 'staff_client.copy_editor.templates' : g.templates }]
243 if (typeof robj.ilsevent != 'undefined') {
246 alert('Template "' + name + '" deleted.');
250 g.retrieve_templates();
252 g.error.standard_unexpected_error_alert('Error deleting template',E);
258 g.error.standard_unexpected_error_alert('Error deleting template',E);
262 /******************************************************************************************************/
263 /* Export Templates */
265 g.export_templates = function() {
267 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
268 JSAN.use('util.file');
269 var f = pick_file('save');
272 var r = G.error.yns_alert(
273 'Would you like to overwrite the existing file ' + f.leafName + '?',
274 'Templates Export Warning',
278 'Check here to confirm this message'
280 if (r != 0) { file.close(); alert('Not overwriting file.'); return; }
282 var e_file = new util.file(''); e_file._file = f;
283 e_file.write_content( 'truncate', js2JSON( g.templates ) );
285 alert('Templates exported as file ' + f.leafName);
287 alert('File not chosen for export.');
291 g.error.standard_unexpected_error_alert('Error exporting templates',E);
295 /******************************************************************************************************/
296 /* Import Templates */
298 g.import_templates = function() {
300 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
301 JSAN.use('util.file');
302 var f = pick_file('open');
303 if (f && f.exists()) {
304 var i_file = new util.file(''); i_file._file = f;
305 var temp = JSON2js( i_file.get_content() );
307 for (var i in temp) {
309 if (g.templates[i]) {
311 var r = g.error.yns_alert(
312 'Replace the existing template with the imported template?\n' + g.error.pretty_print( js2JSON( temp[i] ) ),
313 'Template ' + i + ' already exists.','Yes','No',null,'Click here'
316 if (r == 0 /* Yes */) g.templates[i] = temp[i];
320 g.templates[i] = temp[i];
326 var r = g.error.yns_alert(
327 'Save all of these imported templates permanently to this account?',
328 'Final Warning', 'Yes', 'No', null, 'Click here'
331 if (r == 0 /* Yes */) {
332 var robj = g.network.simple_request(
333 'FM_AUS_UPDATE',[ses(),g.data.list.au[0].id(), { 'staff_client.copy_editor.templates' : g.templates }]
335 if (typeof robj.ilsevent != 'undefined') {
338 alert('All templates saved.');
342 g.retrieve_templates();
344 g.error.standard_unexpected_error_alert('Error saving templates',E);
350 util.widgets.remove_children('template_placeholder');
351 var list = util.functional.map_object_to_list( g.templates, function(obj,i) { return [i, i]; } );
352 g.template_menu = util.widgets.make_menulist( list );
353 $('template_placeholder').appendChild(g.template_menu);
354 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 disappear with the next invocation of the item attribute editor.");
358 alert('File not chosen for import.');
361 g.error.standard_unexpected_error_alert('Error importing templates',E);
366 /******************************************************************************************************/
367 /* Restore backup copies */
369 g.reset = function() {
371 g.copies = JSON2js( g.original_copies );
372 g.summarize( g.copies );
376 /******************************************************************************************************/
377 /* Apply a value to a specific field on all the copies being edited */
379 g.apply = function(field,value) {
380 g.error.sdump('D_TRACE','applying field = <' + field + '> value = <' + value + '>\n');
381 if (value == '<HACK:KLUDGE:NULL>') value = null;
382 if (field == 'alert_message') { value = value.replace(/^\W+$/g,''); }
383 if (field == 'price' || field == 'deposit_amount') {
384 if (value == '') { value = null; } else { JSAN.use('util.money'); value = util.money.sanitize( value ); }
386 for (var i = 0; i < g.copies.length; i++) {
387 var copy = g.copies[i];
389 copy[field]( value ); copy.ischanged('1');
396 /******************************************************************************************************/
397 /* Apply a stat cat entry to all the copies being edited. An entry_id of < 0 signifies the stat cat is being removed. */
399 g.apply_stat_cat = function(sc_id,entry_id) {
400 g.error.sdump('D_TRACE','sc_id = ' + sc_id + ' entry_id = ' + entry_id + '\n');
401 for (var i = 0; i < g.copies.length; i++) {
402 var copy = g.copies[i];
405 var temp = copy.stat_cat_entries();
406 if (!temp) temp = [];
407 temp = util.functional.filter_list(
410 return (obj.stat_cat() != sc_id);
413 if (entry_id > -1) temp.push(
414 util.functional.find_id_object_in_list(
415 g.data.hash.asc[sc_id].entries(),
419 copy.stat_cat_entries( temp );
422 g.error.standard_unexpected_error_alert('apply_stat_cat',E);
427 /******************************************************************************************************/
428 /* Apply an "owning lib" to all the copies being edited. That is, change and auto-vivicating volumes */
431 g.apply_owning_lib = function(ou_id) {
432 g.error.sdump('D_TRACE','ou_id = ' + ou_id + '\n');
433 for (var i = 0; i < g.copies.length; i++) {
434 var copy = g.copies[i];
436 if (!g.map_acn[copy.call_number()]) {
437 var volume = g.network.simple_request('FM_ACN_RETRIEVE',[ copy.call_number() ]);
438 if (typeof volume.ilsevent != 'undefined') {
439 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);
442 g.map_acn[copy.call_number()] = volume;
444 var old_volume = g.map_acn[copy.call_number()];
445 var acn_id = g.network.simple_request(
446 'FM_ACN_FIND_OR_CREATE',
447 [ses(),old_volume.label(),old_volume.record(),ou_id]
449 if (typeof acn_id.ilsevent != 'undefined') {
450 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);
453 copy.call_number(acn_id);
456 g.error.standard_unexpected_error_alert('apply_stat_cat',E);
461 /******************************************************************************************************/
462 /* This returns true if none of the copies being edited are pre-cats */
464 g.safe_to_change_owning_lib = function() {
467 for (var i = 0; i < g.copies.length; i++) {
468 var cn = g.copies[i].call_number();
469 if (typeof cn == 'object') { cn = cn.id(); }
470 if (cn == -1) { safe = false; }
474 g.error.standard_unexpected_error_alert('safe_to_change_owning_lib?',E);
479 /******************************************************************************************************/
480 /* This returns true if none of the copies being edited have a magical status found in my_constants.magical_statuses */
482 g.safe_to_edit_copy_status = function() {
485 for (var i = 0; i < g.copies.length; i++) {
486 var status = g.copies[i].status(); if (typeof status == 'object') status = status.id();
487 if (typeof my_constants.magical_statuses[ status ] != 'undefined') safe = false;
491 g.error.standard_unexpected_error_alert('safe_to_edit_copy_status?',E);
496 /******************************************************************************************************/
497 /* This concats and uniques all the alert messages for use as the default value for a new alert message */
499 g.populate_alert_message_input = function(tb) {
501 var seen = {}; var s = '';
502 for (var i = 0; i < g.copies.length; i++) {
503 var msg = g.copies[i].alert_message();
505 if (typeof seen[msg] == 'undefined') {
511 tb.setAttribute('value',s);
513 g.error.standard_unexpected_error_alert('populate_alert_message_input',E);
517 /******************************************************************************************************/
518 /* This returns a list of acpl's appropriate for the copies being edited */
520 g.get_acpl_list = function() {
523 JSAN.use('util.functional');
525 function get(lib_id,only_these) {
526 g.data.stash_retrieve();
527 var label = 'acpl_list_for_lib_'+lib_id;
528 if (typeof g.data[label] == 'undefined') {
529 var robj = g.network.simple_request('FM_ACPL_RETRIEVE', [ lib_id ]);
530 if (typeof robj.ilsevent != 'undefined') throw(robj);
532 for (var j = 0; j < robj.length; j++) {
533 var my_acpl = robj[j];
534 if (typeof g.data.hash.acpl[ my_acpl.id() ] == 'undefined') {
535 g.data.hash.acpl[ my_acpl.id() ] = my_acpl;
536 g.data.list.acpl.push( my_acpl );
538 var only_this_lib = my_acpl.owning_lib(); if (typeof only_this_lib == 'object') only_this_lib = only_this_lib.id();
539 if (only_these.indexOf( String( only_this_lib ) ) != -1) {
540 temp_list.push( my_acpl );
543 g.data[label] = temp_list; g.data.stash(label,'hash','list');
545 return g.data[label];
548 var temp_acpl_list = [];
550 /* find acpl's based on owning_lib */
553 for (var i = 0; i < g.copies.length; i++) {
554 var cn_id = g.copies[i].call_number();
556 if (! g.map_acn[ cn_id ]) {
557 g.map_acn[ cn_id ] = g.network.simple_request('FM_ACN_RETRIEVE',[ cn_id ]);
559 var consider_lib = g.map_acn[ cn_id ].owning_lib();
560 if ( libs.indexOf( String( consider_lib ) ) > -1 ) { /* already in list */ } else { libs.push( consider_lib ); }
564 for (var i in g.callnumbers) {
565 var consider_lib = g.callnumbers[i].owning_lib;
566 if (typeof consider_lib == 'object') consider_lib = consider_lib.id();
567 if ( libs.indexOf( String( consider_lib ) ) > -1 ) { /* already in list */ } else { libs.push( consider_lib ); }
570 JSAN.use('util.fm_utils');
571 var ancestor = util.fm_utils.find_common_aou_ancestor( libs );
572 if (typeof ancestor == 'object' && ancestor != null) ancestor = ancestor.id();
575 var ancestors = util.fm_utils.find_common_aou_ancestors( libs );
576 var acpl_list = get(ancestor, ancestors);
577 if (acpl_list) for (var i = 0; i < acpl_list.length; i++) {
578 if (acpl_list[i] != null) {
579 temp_acpl_list.push(acpl_list[i]);
584 /* find acpl's based on circ_lib */
588 for (var i = 0; i < g.copies.length; i++) {
589 var consider_lib = g.copies[i].circ_lib();
590 if (typeof consider_lib == 'object') consider_lib = consider_lib.id();
591 if ( circ_libs.indexOf( String( consider_lib ) ) > -1 ) { /* already in list */ } else { circ_libs.push( consider_lib ); }
594 if (circ_libs.length > 0) {
595 var circ_ancestor = util.fm_utils.find_common_aou_ancestor( circ_libs );
596 if (typeof circ_ancestor == 'object' && circ_ancestor != null) circ_ancestor = circ_ancestor.id();
599 var circ_ancestors = util.fm_utils.find_common_aou_ancestors( circ_libs );
600 var circ_acpl_list = get(circ_ancestor, circ_ancestors);
601 var flat_acpl_list = util.functional.map_list( temp_acpl_list, function(o){return o.id();} );
602 for (var i = 0; i < circ_acpl_list.length; i++) {
603 var consider_acpl = circ_acpl_list[i].id();
604 if ( flat_acpl_list.indexOf( String( consider_acpl ) ) > -1 ) {
605 /* already in list */
607 if (circ_acpl_list[i] != null) temp_acpl_list.push( circ_acpl_list[i] );
613 return temp_acpl_list;
616 g.error.standard_unexpected_error_alert('get_acpl_list',E);
622 /******************************************************************************************************/
623 /* This keeps track of what fields have been edited for styling purposes */
627 /******************************************************************************************************/
628 /* These need data from the middle layer to render */
630 g.special_exception = {
631 'Owning Lib : Call Number' : function(label,value) {
632 JSAN.use('util.widgets');
633 if (value>0) { /* an existing call number */
635 api.FM_ACN_RETRIEVE.app,
636 api.FM_ACN_RETRIEVE.method,
639 var cn = '??? id = ' + value;
641 cn = req.getResultObject();
643 g.error.sdump('D_ERROR','callnumber retrieve: ' + E);
645 util.widgets.set_text(label,g.data.hash.aou[ cn.owning_lib() ].shortname() + ' : ' + cn.label());
648 } else { /* a yet to be created call number */
650 util.widgets.set_text(label,g.data.hash.aou[ g.callnumbers[value].owning_lib ].shortname() + ' : ' + g.callnumbers[value].label);
654 'Creator' : function(label,value) {
655 if (value == null || value == '' || value == 'null') return;
656 g.network.simple_request(
657 'FM_AU_RETRIEVE_VIA_ID',
660 var p = '??? id = ' + value;
662 p = req.getResultObject();
666 g.error.sdump('D_ERROR','patron retrieve: ' + E);
668 JSAN.use('util.widgets');
669 util.widgets.set_text(label,p);
673 'Last Editor' : function(label,value) {
674 if (value == null || value == '' || value == 'null') return;
675 g.network.simple_request(
676 'FM_AU_RETRIEVE_VIA_ID',
679 var p = '??? id = ' + value;
681 p = req.getResultObject();
685 g.error.sdump('D_ERROR','patron retrieve: ' + E);
687 util.widgets.set_text(label,p);
694 /******************************************************************************************************/
695 g.readonly_stat_cat_names = [];
696 g.editable_stat_cat_names = [];
698 /******************************************************************************************************/
699 /* These get show in the left panel */
701 function init_panes() {
702 g.panes_and_field_names = {
709 render: 'fm.barcode();',
715 render: 'util.date.formatted_date( fm.create_date(), "%F");',
721 render: 'fm.creator();',
727 render: 'util.date.formatted_date( fm.edit_date(), "%F");',
733 render: 'fm.editor();',
744 render: 'typeof fm.location() == "object" ? fm.location().name() : g.data.lookup("acpl",fm.location()).name()',
745 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);',
750 "Circulation Library",
752 render: 'typeof fm.circ_lib() == "object" ? fm.circ_lib().shortname() : g.data.hash.aou[ fm.circ_lib() ].shortname()',
753 //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);',
754 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);',
758 "Owning Lib : Call Number",
760 render: 'fm.call_number();',
761 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,
767 render: 'fm.copy_number() == null ? "<Unset>" : fm.copy_number()',
768 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);',
780 render: 'fm.circulate() == null ? "<Unset>" : ( get_bool( fm.circulate() ) ? "Yes" : "No" )',
781 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);',
787 render: 'fm.holdable() == null ? "<Unset>" : ( get_bool( fm.holdable() ) ? "Yes" : "No" )',
788 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);',
794 render: 'fm.age_protect() == null ? "<Unset>" : ( typeof fm.age_protect() == "object" ? fm.age_protect().name() : g.data.hash.crahp[ fm.age_protect() ].name() )',
795 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);',
802 render: 'switch(fm.loan_duration()){ case 1: case "1": "Short"; break; case 2: case "2": "Normal"; break; case 3:case "3": "Long"; break; }',
803 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);',
810 render: 'switch(fm.fine_level()){ case 1: case "1": "Low"; break; case 2: case "2": "Normal"; break; case 3: case "3": "High"; break; }',
811 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);',
818 render: 'fm.circ_as_type() == null ? "<Unset>" : g.data.hash.citm[ fm.circ_as_type() ].value()',
819 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);',
823 "Circulation Modifier",
825 render: 'fm.circ_modifier() == null ? "<Unset>" : fm.circ_modifier()',
826 /*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);',*/
827 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);',
836 render: 'fm.alert_message() == null ? "<Unset>" : fm.alert_message()',
837 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);',
844 render: 'fm.deposit() == null ? "<Unset>" : ( get_bool( fm.deposit() ) ? "Yes" : "No" )',
845 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);',
851 render: 'if (fm.deposit_amount() == null) { "<Unset>"; } else { util.money.sanitize( fm.deposit_amount() ); }',
852 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);',
858 render: 'if (fm.price() == null) { "<Unset>"; } else { util.money.sanitize( fm.price() ); }',
859 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);',
866 render: 'fm.opac_visible() == null ? "<Unset>" : ( get_bool( fm.opac_visible() ) ? "Yes" : "No" )',
867 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);',
873 render: 'fm.ref() == null ? "<Unset>" : ( get_bool( fm.ref() ) ? "Yes" : "No" )',
874 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);',
886 /******************************************************************************************************/
887 /* This loops through all our fieldnames and all the copies, tallying up counts for the different values */
889 g.summarize = function( copies ) {
890 /******************************************************************************************************/
893 JSAN.use('util.date'); JSAN.use('util.money');
896 for (var i in g.panes_and_field_names) {
897 g.field_names = g.field_names.concat( g.panes_and_field_names[i] );
899 g.field_names = g.field_names.concat( g.editable_stat_cat_names );
900 g.field_names = g.field_names.concat( g.readonly_stat_cat_names );
902 /******************************************************************************************************/
903 /* Loop through the field names */
905 for (var i = 0; i < g.field_names.length; i++) {
907 var field_name = g.field_names[i][0];
908 var render = g.field_names[i][1].render;
909 var attr = g.field_names[i][1].attr;
910 g.summary[ field_name ] = {};
912 /******************************************************************************************************/
913 /* Loop through the copies */
915 for (var j = 0; j < copies.length; j++) {
918 var cmd = render || ('fm.' + field_name + '();');
921 /**********************************************************************************************/
922 /* Try to retrieve the value for this field for this copy */
927 g.error.sdump('D_ERROR','Attempted ' + cmd + '\n' + E + '\n');
929 if (typeof value == 'object' && value != null) {
930 alert('FIXME: field_name = <' + field_name + '> value = <' + js2JSON(value) + '>\n');
933 /**********************************************************************************************/
934 /* Tally the count */
936 if (g.summary[ field_name ][ value ]) {
937 g.summary[ field_name ][ value ]++;
939 g.summary[ field_name ][ value ] = 1;
943 g.error.sdump('D_TRACE','summary = ' + js2JSON(g.summary) + '\n');
946 /******************************************************************************************************/
947 /* Display the summarized data and inputs for editing */
949 g.render = function() {
951 /******************************************************************************************************/
952 /* Library setup and clear any existing interface */
954 JSAN.use('util.widgets'); JSAN.use('util.date'); JSAN.use('util.money'); JSAN.use('util.functional');
956 for (var i in g.panes_and_field_names) {
957 var p = document.getElementById(i);
958 if (p) util.widgets.remove_children(p);
961 /******************************************************************************************************/
962 /* Populate the library filter menu for stat cats */
965 for (var i = 0; i < g.panes_and_field_names.right_pane4.length; i++) {
966 sc_libs[ g.panes_and_field_names.right_pane4[i][1].attr.sc_lib ] = true;
969 for (var i in sc_libs) { sc_libs2.push( [ g.data.hash.aou[ i ].shortname(), i ] ); }
971 var x = document.getElementById("stat_cat_lib_filter_menu").firstChild;
972 JSAN.use('util.widgets'); util.widgets.remove_children(x);
973 for (var i = 0; i < sc_libs2.length; i++) {
974 var menuitem = document.createElement('menuitem');
975 menuitem.setAttribute('id','filter_'+sc_libs2[i][1]);
976 menuitem.setAttribute('type','checkbox');
977 menuitem.setAttribute('checked','true');
978 menuitem.setAttribute('label',sc_libs2[i][0]);
979 menuitem.setAttribute('value',sc_libs2[i][1]);
980 menuitem.setAttribute('oncommand','try{g.toggle_stat_cat_display(this);}catch(E){alert(E);}');
981 x.appendChild(menuitem);
984 /******************************************************************************************************/
985 /* Prepare the panes */
987 var groupbox; var caption; var vbox; var grid; var rows;
989 /******************************************************************************************************/
990 /* Loop through the field names */
992 for (h in g.panes_and_field_names) {
993 if (!document.getElementById(h)) continue;
994 for (var i = 0; i < g.panes_and_field_names[h].length; i++) {
996 var f = g.panes_and_field_names[h][i]; var fn = f[0]; var attr = f[1].attr;
997 groupbox = document.createElement('groupbox'); document.getElementById(h).appendChild(groupbox);
999 for (var a in attr) {
1000 groupbox.setAttribute(a,attr[a]);
1003 if (typeof g.changed[fn] != 'undefined') groupbox.setAttribute('class','copy_editor_field_changed');
1004 caption = document.createElement('caption'); groupbox.appendChild(caption);
1005 caption.setAttribute('label',fn); caption.setAttribute('id','caption_'+fn);
1006 vbox = document.createElement('vbox'); groupbox.appendChild(vbox);
1007 grid = util.widgets.make_grid( [ { 'flex' : 1 }, {}, {} ] ); vbox.appendChild(grid);
1008 grid.setAttribute('flex','1');
1009 rows = grid.lastChild;
1012 /**************************************************************************************/
1013 /* Loop through each value for the field */
1015 for (var j in g.summary[fn]) {
1016 var value = j; var count = g.summary[fn][j];
1017 row = document.createElement('row'); rows.appendChild(row);
1018 var label1 = document.createElement('description'); row.appendChild(label1);
1019 if (g.special_exception[ fn ]) {
1020 g.special_exception[ fn ]( label1, value );
1022 label1.appendChild( document.createTextNode(value) );
1024 var label2 = document.createElement('description'); row.appendChild(label2);
1025 var unit = count == 1 ? 'copy' : 'copies';
1026 label2.appendChild( document.createTextNode(count + ' ' + unit) );
1028 var hbox = document.createElement('hbox');
1029 hbox.setAttribute('id',fn);
1030 groupbox.appendChild(hbox);
1031 var hbox2 = document.createElement('hbox');
1032 groupbox.appendChild(hbox2);
1034 /**************************************************************************************/
1035 /* Render the input widget */
1037 if (f[1].input && g.edit) {
1038 g.render_input(hbox,f[1]);
1042 g.error.sdump('D_ERROR','copy editor: ' + E + '\n');
1048 /******************************************************************************************************/
1049 /* Synchronize stat cat visibility with library filter menu, and default template selection */
1050 JSAN.use('util.file');
1051 var file = new util.file('copy_editor_prefs.'+g.data.server_unadorned);
1052 g.copy_editor_prefs = util.widgets.load_attributes(file);
1053 for (var i in g.copy_editor_prefs) {
1054 if (i.match(/filter_/) && g.copy_editor_prefs[i].checked == '') {
1056 g.toggle_stat_cat_display( document.getElementById(i) );
1057 } catch(E) { alert(E); }
1060 g.template_menu.value = g.template_menu.getAttribute('value');
1064 /******************************************************************************************************/
1065 /* This actually draws the change button and input widget for a given field */
1066 g.render_input = function(node,blob) {
1068 // node = hbox ; groupbox -> hbox, hbox
1070 var groupbox = node.parentNode;
1071 var caption = groupbox.firstChild;
1072 var vbox = node.previousSibling;
1074 var hbox2 = node.nextSibling;
1076 var input_cmd = blob.input;
1077 var render_cmd = blob.render;
1078 var attr = blob.attr;
1080 var block = false; var first = true;
1082 function on_mouseover(ev) {
1083 groupbox.setAttribute('style','background: white');
1086 function on_mouseout(ev) {
1087 groupbox.setAttribute('style','');
1090 vbox.addEventListener('mouseover',on_mouseover,false);
1091 vbox.addEventListener('mouseout',on_mouseout,false);
1092 groupbox.addEventListener('mouseover',on_mouseover,false);
1093 groupbox.addEventListener('mouseout',on_mouseout,false);
1094 groupbox.firstChild.addEventListener('mouseover',on_mouseover,false);
1095 groupbox.firstChild.addEventListener('mouseout',on_mouseout,false);
1097 function on_click(ev){
1099 if (block) return; block = true;
1101 function post_c(v) {
1103 /* FIXME - kludgy */
1104 var t = input_cmd.match('apply_stat_cat') ? 'stat_cat' : ( input_cmd.match('apply_owning_lib') ? 'owning_lib' : 'attribute' );
1108 f = input_cmd.match(/apply\("(.+?)",/)[1];
1111 f = input_cmd.match(/apply_stat_cat\((.+?),/)[1];
1117 g.changed[ hbox.id ] = { 'type' : t, 'field' : f, 'value' : v };
1121 g.summarize( g.copies );
1123 document.getElementById(caption.id).focus();
1127 g.error.standard_unexpected_error_alert('post_c',E);
1130 var x; var c; eval( input_cmd );
1132 util.widgets.remove_children(vbox);
1133 util.widgets.remove_children(hbox);
1134 util.widgets.remove_children(hbox2);
1135 hbox.appendChild(x);
1136 var apply = document.createElement('button');
1137 apply.setAttribute('label','Apply');
1138 apply.setAttribute('accesskey','A');
1139 hbox2.appendChild(apply);
1140 apply.addEventListener('command',function() { c(x.value); },false);
1141 var cancel = document.createElement('button');
1142 cancel.setAttribute('label','Cancel');
1143 cancel.addEventListener('command',function() { setTimeout( function() { g.summarize( g.copies ); g.render(); document.getElementById(caption.id).focus(); }, 0); }, false);
1144 hbox2.appendChild(cancel);
1145 setTimeout( function() { x.focus(); }, 0 );
1148 g.error.standard_unexpected_error_alert('render_input',E);
1151 vbox.addEventListener('click',on_click, false);
1152 hbox.addEventListener('click',on_click, false);
1153 caption.addEventListener('click',on_click, false);
1154 caption.addEventListener('keypress',function(ev) {
1155 if (ev.keyCode == 13 /* enter */ || ev.keyCode == 77 /* mac enter */) on_click();
1157 caption.setAttribute('style','-moz-user-focus: normal');
1158 caption.setAttribute('onfocus','this.setAttribute("class","outline_me")');
1159 caption.setAttribute('onblur','this.setAttribute("class","")');
1162 g.error.sdump('D_ERROR',E + '\n');
1166 /******************************************************************************************************/
1167 /* store the copies in the global xpcom stash */
1169 g.stash_and_close = function() {
1171 if (g.handle_update) {
1173 var r = g.network.request(
1174 api.FM_ACP_FLESHED_BATCH_UPDATE.app,
1175 api.FM_ACP_FLESHED_BATCH_UPDATE.method,
1176 [ ses(), g.copies, true ]
1178 if (typeof r.ilsevent != 'undefined') {
1179 g.error.standard_unexpected_error_alert('copy update',r);
1181 alert('Items added/modified.');
1183 /* FIXME -- revisit the return value here */
1185 alert('copy update error: ' + js2JSON(E));
1188 //g.data.temp_copies = js2JSON( g.copies );
1189 //g.data.stash('temp_copies');
1190 xulG.copies = g.copies;
1191 update_modal_xulG(xulG);
1194 g.error.standard_unexpected_error_alert('stash and close',E);
1198 /******************************************************************************************************/
1199 /* spawn copy notes interface */
1201 g.copy_notes = function() {
1202 JSAN.use('util.window'); var win = new util.window();
1204 urls.XUL_COPY_NOTES,
1205 //+ '?copy_id=' + window.escape(g.copies[0].id()),
1206 'Copy Notes','chrome,resizable,modal',
1207 { 'copy_id' : g.copies[0].id() }
1211 /******************************************************************************************************/
1212 /* hides or unhides stat cats based on library stat cat filter menu */
1213 g.toggle_stat_cat_display = function(el) {
1214 var visible = el.getAttribute('checked');
1215 var nl = document.getElementsByAttribute('sc_lib',el.getAttribute('value'));
1216 for (var n = 0; n < nl.length; n++) {
1218 nl[n].setAttribute('hidden','false');
1220 nl[n].setAttribute('hidden','true');
1223 g.copy_editor_prefs[ el.getAttribute('id') ] = { 'checked' : visible };
1224 g.save_attributes();
1227 /******************************************************************************************************/
1228 /* This adds a stat cat definition to the stat cat pane for rendering */
1229 g.save_attributes = function() {
1230 JSAN.use('util.widgets'); JSAN.use('util.file'); var file = new util.file('copy_editor_prefs.'+g.data.server_unadorned);
1231 var what_to_save = {};
1232 for (var i in g.copy_editor_prefs) {
1233 what_to_save[i] = [];
1234 for (var j in g.copy_editor_prefs[i]) what_to_save[i].push(j);
1236 util.widgets.save_attributes(file, what_to_save );
1239 /******************************************************************************************************/
1240 /* This adds a stat cat definition to the stat cat pane for rendering */
1241 g.add_stat_cat = function(sc) {
1243 if (typeof g.data.hash.asc == 'undefined') { g.data.hash.asc = {}; g.data.stash('hash'); }
1247 if (typeof sc == 'object') {
1252 if (typeof g.stat_cat_seen[sc_id] != 'undefined') { return; }
1254 g.stat_cat_seen[ sc_id ] = 1;
1256 if (typeof sc != 'object') {
1258 sc = g.network.simple_request(
1259 'FM_ASC_BATCH_RETRIEVE',
1260 [ ses(), [ sc_id ] ]
1265 g.data.hash.asc[ sc.id() ] = sc; g.data.stash('hash');
1267 var label_name = g.data.hash.aou[ sc.owner() ].shortname() + " : " + sc.name();
1272 render: 'var l = util.functional.find_list( fm.stat_cat_entries(), function(e){ return e.stat_cat() == '
1273 + sc.id() + '; } ); l ? l.value() : "<Unset>";',
1274 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()
1275 + '].entries(), function(obj){ return [ obj.value(), obj.id() ]; } ) ).sort() ); '
1276 + 'x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c),false);',
1283 g.panes_and_field_names.right_pane4.push( temp_array );
1285 g.error.standard_unexpected_error_alert('Error adding stat cat to display definition',E);
1289 /******************************************************************************************************/
1290 /* Add stat cats to the panes_and_field_names.right_pane4 */
1291 g.populate_stat_cats = function() {
1293 g.data.stash_retrieve();
1294 g.stat_cat_seen = {};
1296 function get(lib_id,only_these) {
1297 g.data.stash_retrieve();
1298 var label = 'asc_list_for_lib_'+lib_id;
1299 if (typeof g.data[label] == 'undefined') {
1300 var robj = g.network.simple_request('FM_ASC_RETRIEVE_VIA_AOU', [ ses(), lib_id ]);
1301 if (typeof robj.ilsevent != 'undefined') throw(robj);
1303 for (var j = 0; j < robj.length; j++) {
1304 var my_asc = robj[j];
1305 if (typeof g.data.hash.asc == 'undefined') { g.data.hash.asc = {}; }
1306 if (typeof g.data.hash.asc[ my_asc.id() ] == 'undefined') {
1307 g.data.hash.asc[ my_asc.id() ] = my_asc;
1309 var only_this_lib = my_asc.owner(); if (typeof only_this_lib == 'object') only_this_lib = only_this_lib.id();
1310 if (only_these.indexOf( String( only_this_lib ) ) != -1) {
1311 temp_list.push( my_asc );
1314 g.data[label] = temp_list; g.data.stash(label,'hash','list');
1316 return g.data[label];
1319 /* The stat cats for the pertinent library -- this is based on workstation ou */
1320 var label = 'asc_list_for_' + typeof g.data.ws_ou == 'object' ? g.data.ws_ou.id() : g.data.ws_ou;
1321 g.data[ label ] = g.data.list.my_asc; g.data.stash('label');
1322 for (var i = 0; i < g.data.list.my_asc.length; i++) {
1323 g.add_stat_cat( g.data.list.my_asc[i] );
1326 /* For the others, we want to consider the owning libs, circ libs, and any libs that have stat cats already on the copies,
1327 however, if batch editing, we only want to show the ones they have in common. So let's compile the libs */
1329 function add_common_ancestors(sc_libs) {
1330 JSAN.use('util.fm_utils');
1331 var libs = []; for (var i in sc_libs) libs.push(i);
1332 var ancestor = util.fm_utils.find_common_aou_ancestor( libs );
1333 if (typeof ancestor == 'object' && ancestor != null) ancestor = ancestor.id();
1335 var ancestors = util.fm_utils.find_common_aou_ancestors( libs );
1336 var asc_list = get(ancestor, ancestors);
1337 for (var i = 0; i < asc_list.length; i++) {
1338 g.add_stat_cat( asc_list[i] );
1343 /* stat cats based on stat cat entries present on these copies */
1345 for (var i = 0; i < g.copies.length; i++) {
1346 var entries = g.copies[i].stat_cat_entries();
1347 if (!entries) entries = [];
1348 for (var j = 0; j < entries.length; j++) {
1349 var lib = entries[j].owner(); if (typeof lib == 'object') lib = lib.id();
1350 sc_libs[ lib ] = true;
1353 add_common_ancestors(sc_libs); // CAVEAT - if a copy has no stat_cat_entries, it basically gets no vote here
1355 /* stat cats based on Circ Lib */
1357 for (var i = 0; i < g.copies.length; i++) {
1358 var circ_lib = g.copies[i].circ_lib(); if (typeof circ_lib == 'object') circ_lib = circ_lib.id();
1359 sc_libs[ circ_lib ] = true;
1361 add_common_ancestors(sc_libs);
1363 /* stat cats based on Owning Lib */
1365 for (var i = 0; i < g.copies.length; i++) {
1366 var cn_id = g.copies[i].call_number();
1368 if (! g.map_acn[ cn_id ]) {
1369 g.map_acn[ cn_id ] = g.network.simple_request('FM_ACN_RETRIEVE',[ cn_id ]);
1371 var owning_lib = g.map_acn[ cn_id ].owning_lib(); if (typeof owning_lib == 'object') owning_lib = owning_lib.id();
1372 sc_libs[ owning_lib ] = true;
1375 add_common_ancestors(sc_libs); // CAVEAT - if a copy is a pre-cat, it basically gets no vote here
1377 g.panes_and_field_names.right_pane4.sort();
1380 g.error.standard_unexpected_error_alert('Error populating stat cats for display',E);