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 /* Retrieve Templates */
126 g.retrieve_templates = function() {
128 JSAN.use('util.widgets'); JSAN.use('util.functional');
130 var robj = g.network.simple_request('FM_AUS_RETRIEVE',[ses(),g.data.list.au[0].id()]);
131 if (typeof robj['staff_client.copy_editor.templates'] != 'undefined') {
132 g.templates = robj['staff_client.copy_editor.templates'];
134 util.widgets.remove_children('template_placeholder');
135 var list = util.functional.map_object_to_list( g.templates, function(obj,i) { return [i, i]; } );
137 g.template_menu = util.widgets.make_menulist( list );
138 g.template_menu.setAttribute('id','template_menu');
139 $('template_placeholder').appendChild(g.template_menu);
140 g.template_menu.addEventListener(
142 function() { g.copy_editor_prefs[ 'template_menu' ] = { 'value' : g.template_menu.value }; g.save_attributes(); },
146 g.error.standard_unexpected_error_alert('Error retrieving templates',E);
150 /******************************************************************************************************/
153 g.apply_template = function() {
155 var name = g.template_menu.value;
156 if (g.templates[ name ] != 'undefined') {
157 var template = g.templates[ name ];
158 for (var i in template) {
159 g.changed[ i ] = template[ i ];
160 switch( template[i].type ) {
162 g.apply(template[i].field,template[i].value);
165 if (g.stat_cat_seen[ template[i].field ]) g.apply_stat_cat(template[i].field,template[i].value);
168 g.apply_owning_lib(template[i].value);
172 g.summarize( g.copies );
176 g.error.standard_unexpected_error_alert('Error applying template',E);
180 /******************************************************************************************************/
181 /* Save as Template */
183 g.save_template = function() {
185 var name = window.prompt('Enter template name:','','Save As Template');
187 g.templates[name] = g.changed;
188 var robj = g.network.simple_request(
189 'FM_AUS_UPDATE',[ses(),g.data.list.au[0].id(), { 'staff_client.copy_editor.templates' : g.templates }]
191 if (typeof robj.ilsevent != 'undefined') {
194 alert('Template "' + name + '" saved.');
198 g.retrieve_templates();
200 g.error.standard_unexpected_error_alert('Error saving template',E);
206 g.error.standard_unexpected_error_alert('Error saving template',E);
210 /******************************************************************************************************/
211 /* Delete Template */
213 g.delete_template = function() {
215 var name = g.template_menu.value;
217 if (! window.confirm('Delete template "' + name + '"?') ) return;
218 delete(g.templates[name]);
219 var robj = g.network.simple_request(
220 'FM_AUS_UPDATE',[ses(),g.data.list.au[0].id(), { 'staff_client.copy_editor.templates' : g.templates }]
222 if (typeof robj.ilsevent != 'undefined') {
225 alert('Template "' + name + '" deleted.');
229 g.retrieve_templates();
231 g.error.standard_unexpected_error_alert('Error deleting template',E);
237 g.error.standard_unexpected_error_alert('Error deleting template',E);
241 /******************************************************************************************************/
242 /* Export Templates */
244 g.export_templates = function() {
246 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
247 JSAN.use('util.file'); var f = new util.file('');
248 f.export_file( { 'title' : 'Save Templates File As', 'data' : g.templates } );
250 g.error.standard_unexpected_error_alert('Error exporting templates',E);
254 /******************************************************************************************************/
255 /* Import Templates */
257 g.import_templates = function() {
259 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
260 JSAN.use('util.file'); var f = new util.file('');
261 var temp = f.import_file( { 'title' : 'Import Templates File' } );
263 for (var i in temp) {
265 if (g.templates[i]) {
267 var r = g.error.yns_alert(
268 'Replace the existing template with the imported template?\n' + g.error.pretty_print( js2JSON( temp[i] ) ),
269 'Template ' + i + ' already exists.','Yes','No',null,'Click here'
272 if (r == 0 /* Yes */) g.templates[i] = temp[i];
276 g.templates[i] = temp[i];
282 var r = g.error.yns_alert(
283 'Save all of these imported templates permanently to this account?',
284 'Final Warning', 'Yes', 'No', null, 'Click here'
287 if (r == 0 /* Yes */) {
288 var robj = g.network.simple_request(
289 'FM_AUS_UPDATE',[ses(),g.data.list.au[0].id(), { 'staff_client.copy_editor.templates' : g.templates }]
291 if (typeof robj.ilsevent != 'undefined') {
294 alert('All templates saved.');
298 g.retrieve_templates();
300 g.error.standard_unexpected_error_alert('Error saving templates',E);
306 util.widgets.remove_children('template_placeholder');
307 var list = util.functional.map_object_to_list( g.templates, function(obj,i) { return [i, i]; } );
308 g.template_menu = util.widgets.make_menulist( list );
309 $('template_placeholder').appendChild(g.template_menu);
310 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.");
315 g.error.standard_unexpected_error_alert('Error importing templates',E);
320 /******************************************************************************************************/
321 /* Restore backup copies */
323 g.reset = function() {
325 g.copies = JSON2js( g.original_copies );
326 g.summarize( g.copies );
330 /******************************************************************************************************/
331 /* Apply a value to a specific field on all the copies being edited */
333 g.apply = function(field,value) {
334 g.error.sdump('D_TRACE','applying field = <' + field + '> value = <' + value + '>\n');
335 if (value == '<HACK:KLUDGE:NULL>') value = null;
336 if (field == 'alert_message') { value = value.replace(/^\W+$/g,''); }
337 if (field == 'price' || field == 'deposit_amount') {
338 if (value == '') { value = null; } else { JSAN.use('util.money'); value = util.money.sanitize( value ); }
340 for (var i = 0; i < g.copies.length; i++) {
341 var copy = g.copies[i];
343 copy[field]( value ); copy.ischanged('1');
350 /******************************************************************************************************/
351 /* Apply a stat cat entry to all the copies being edited. An entry_id of < 0 signifies the stat cat is being removed. */
353 g.apply_stat_cat = function(sc_id,entry_id) {
354 g.error.sdump('D_TRACE','sc_id = ' + sc_id + ' entry_id = ' + entry_id + '\n');
355 for (var i = 0; i < g.copies.length; i++) {
356 var copy = g.copies[i];
359 var temp = copy.stat_cat_entries();
360 if (!temp) temp = [];
361 temp = util.functional.filter_list(
364 return (obj.stat_cat() != sc_id);
367 if (entry_id > -1) temp.push(
368 util.functional.find_id_object_in_list(
369 g.data.hash.asc[sc_id].entries(),
373 copy.stat_cat_entries( temp );
376 g.error.standard_unexpected_error_alert('apply_stat_cat',E);
381 /******************************************************************************************************/
382 /* Apply an "owning lib" to all the copies being edited. That is, change and auto-vivicating volumes */
385 g.apply_owning_lib = function(ou_id) {
386 g.error.sdump('D_TRACE','ou_id = ' + ou_id + '\n');
387 for (var i = 0; i < g.copies.length; i++) {
388 var copy = g.copies[i];
390 if (!g.map_acn[copy.call_number()]) {
391 var volume = g.network.simple_request('FM_ACN_RETRIEVE',[ copy.call_number() ]);
392 if (typeof volume.ilsevent != 'undefined') {
393 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);
396 g.map_acn[copy.call_number()] = volume;
398 var old_volume = g.map_acn[copy.call_number()];
399 var acn_id = g.network.simple_request(
400 'FM_ACN_FIND_OR_CREATE',
401 [ses(),old_volume.label(),old_volume.record(),ou_id]
403 if (typeof acn_id.ilsevent != 'undefined') {
404 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);
407 copy.call_number(acn_id);
410 g.error.standard_unexpected_error_alert('apply_stat_cat',E);
415 /******************************************************************************************************/
416 /* This returns true if none of the copies being edited are pre-cats */
418 g.safe_to_change_owning_lib = function() {
421 for (var i = 0; i < g.copies.length; i++) {
422 var cn = g.copies[i].call_number();
423 if (typeof cn == 'object') { cn = cn.id(); }
424 if (cn == -1) { safe = false; }
428 g.error.standard_unexpected_error_alert('safe_to_change_owning_lib?',E);
433 /******************************************************************************************************/
434 /* This returns true if none of the copies being edited have a magical status found in my_constants.magical_statuses */
436 g.safe_to_edit_copy_status = function() {
439 for (var i = 0; i < g.copies.length; i++) {
440 var status = g.copies[i].status(); if (typeof status == 'object') status = status.id();
441 if (typeof my_constants.magical_statuses[ status ] != 'undefined') safe = false;
445 g.error.standard_unexpected_error_alert('safe_to_edit_copy_status?',E);
450 /******************************************************************************************************/
451 /* This concats and uniques all the alert messages for use as the default value for a new alert message */
453 g.populate_alert_message_input = function(tb) {
455 var seen = {}; var s = '';
456 for (var i = 0; i < g.copies.length; i++) {
457 var msg = g.copies[i].alert_message();
459 if (typeof seen[msg] == 'undefined') {
465 tb.setAttribute('value',s);
467 g.error.standard_unexpected_error_alert('populate_alert_message_input',E);
471 /***************************************************************************************************************/
472 /* This returns a list of acpl's appropriate for the copies being edited (and caches them in the global stash) */
474 g.get_acpl_list_for_lib = function(lib_id,but_only_these) {
475 g.data.stash_retrieve();
476 var label = 'acpl_list_for_lib_'+lib_id;
477 if (typeof g.data[label] == 'undefined') {
478 var robj = g.network.simple_request('FM_ACPL_RETRIEVE', [ lib_id ]); // This returns acpl's for all ancestors and descendants as well as the lib
479 if (typeof robj.ilsevent != 'undefined') throw(robj);
481 for (var j = 0; j < robj.length; j++) {
482 var my_acpl = robj[j];
483 if (typeof g.data.hash.acpl[ my_acpl.id() ] == 'undefined') {
484 g.data.hash.acpl[ my_acpl.id() ] = my_acpl;
485 g.data.list.acpl.push( my_acpl );
487 var only_this_lib = my_acpl.owning_lib(); if (!only_this_lib) continue;
488 if (typeof only_this_lib == 'object') only_this_lib = only_this_lib.id();
489 if (but_only_these.indexOf( String( only_this_lib ) ) != -1) { // This filters out some of the libraries (usually the descendants)
490 temp_list.push( my_acpl );
493 g.data[label] = temp_list; g.data.stash(label,'hash','list');
495 return g.data[label];
498 /******************************************************************************************************/
499 /* This returns a list of acpl's appropriate for the copies being edited */
501 g.get_acpl_list = function() {
504 JSAN.use('util.functional');
508 /**************************************/
509 /* get owning libs from call numbers */
511 var owning_libs = {};
512 for (var i = 0; i < g.copies.length; i++) {
513 var callnumber = g.copies[i].call_number();
514 if (!callnumber) continue;
515 var cn_id = typeof callnumber == 'object' ? callnumber.id() : callnumber;
517 if (! g.map_acn[ cn_id ]) {
518 g.map_acn[ cn_id ] = g.network.simple_request('FM_ACN_RETRIEVE',[ cn_id ]);
520 var consider_lib = g.map_acn[ cn_id ].owning_lib();
521 if (!consider_lib) continue;
522 owning_libs[ typeof consider_lib == 'object' ? consider_lib.id() : consider_lib ] = true;
526 for (var i in g.callnumbers) {
527 var consider_lib = g.callnumbers[i].owning_lib;
528 if (!consider_lib) continue;
529 owning_libs[ typeof consider_lib == 'object' ? consider_lib.id() : consider_lib ] = true;
533 /***************************************************************************************************/
534 /* now find the first ancestor they all have in common, get the acpl's for it and higher ancestors */
536 JSAN.use('util.fm_utils');
537 var libs = []; for (var i in owning_libs) libs.push(i);
538 if (libs.length > 1) {
539 var ancestor = util.fm_utils.find_common_aou_ancestor( libs );
540 if (typeof ancestor == 'object' && ancestor != null) ancestor = ancestor.id();
543 var ancestors = util.fm_utils.find_common_aou_ancestors( libs );
544 var acpl_list = g.get_acpl_list_for_lib(ancestor, ancestors);
545 if (acpl_list) for (var i = 0; i < acpl_list.length; i++) {
546 if (acpl_list[i] != null) {
547 my_acpls[ typeof acpl_list[i] == 'object' ? acpl_list[i].id() : acpl_list[i] ] = true;
558 for (var i = 0; i < g.copies.length; i++) {
559 var consider_lib = g.copies[i].circ_lib();
560 if (!consider_lib) continue;
561 circ_libs[ typeof consider_lib == 'object' ? consider_lib.id() : consider_lib ] = true;
564 /***************************************************************************************************/
565 /* now find the first ancestor they all have in common, get the acpl's for it and higher ancestors */
567 libs = []; for (var i in circ_libs) libs.push(i);
568 if (libs.length > 0) {
569 var ancestor = util.fm_utils.find_common_aou_ancestor( libs );
570 if (typeof ancestor == 'object' && ancestor != null) ancestor = ancestor.id();
573 var ancestors = util.fm_utils.find_common_aou_ancestors( libs );
574 var acpl_list = g.get_acpl_list_for_lib(ancestor, ancestors);
575 if (acpl_list) for (var i = 0; i < acpl_list.length; i++) {
576 if (acpl_list[i] != null) {
577 my_acpls[ typeof acpl_list[i] == 'object' ? acpl_list[i].id() : acpl_list[i] ] = true;
583 var acpl_list = []; for (var i in my_acpls) acpl_list.push( g.data.hash.acpl[ i ] );
584 return acpl_list.sort(
586 var label_a = g.data.hash.aou[ a.owning_lib() ].shortname() + ' : ' + a.name();
587 var label_b = g.data.hash.aou[ b.owning_lib() ].shortname() + ' : ' + b.name();
588 if (label_a < label_b) return -1;
589 if (label_a > label_b) return 1;
595 g.error.standard_unexpected_error_alert('get_acpl_list',E);
601 /******************************************************************************************************/
602 /* This keeps track of what fields have been edited for styling purposes */
606 /******************************************************************************************************/
607 /* These need data from the middle layer to render */
609 g.special_exception = {
610 'Owning Lib : Call Number' : function(label,value) {
611 JSAN.use('util.widgets');
612 if (value>0) { /* an existing call number */
614 api.FM_ACN_RETRIEVE.app,
615 api.FM_ACN_RETRIEVE.method,
618 var cn = '??? id = ' + value;
620 cn = req.getResultObject();
622 g.error.sdump('D_ERROR','callnumber retrieve: ' + E);
624 util.widgets.set_text(label,g.data.hash.aou[ cn.owning_lib() ].shortname() + ' : ' + cn.label());
627 } else { /* a yet to be created call number */
629 util.widgets.set_text(label,g.data.hash.aou[ g.callnumbers[value].owning_lib ].shortname() + ' : ' + g.callnumbers[value].label);
633 'Creator' : function(label,value) {
634 if (value == null || value == '' || value == 'null') return;
635 g.network.simple_request(
636 'FM_AU_RETRIEVE_VIA_ID',
639 var p = '??? id = ' + value;
641 p = req.getResultObject();
645 g.error.sdump('D_ERROR','patron retrieve: ' + E);
647 JSAN.use('util.widgets');
648 util.widgets.set_text(label,p);
652 'Last Editor' : function(label,value) {
653 if (value == null || value == '' || value == 'null') return;
654 g.network.simple_request(
655 'FM_AU_RETRIEVE_VIA_ID',
658 var p = '??? id = ' + value;
660 p = req.getResultObject();
664 g.error.sdump('D_ERROR','patron retrieve: ' + E);
666 util.widgets.set_text(label,p);
673 /******************************************************************************************************/
674 g.readonly_stat_cat_names = [];
675 g.editable_stat_cat_names = [];
677 /******************************************************************************************************/
678 /* These get show in the left panel */
680 function init_panes() {
681 g.panes_and_field_names = {
688 render: 'fm.barcode();',
694 render: 'util.date.formatted_date( fm.create_date(), "%F");',
700 render: 'fm.creator();',
706 render: 'util.date.formatted_date( fm.edit_date(), "%F");',
712 render: 'fm.editor();',
723 render: 'typeof fm.location() == "object" ? fm.location().name() : g.data.lookup("acpl",fm.location()).name()',
724 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);',
729 "Circulation Library",
731 render: 'typeof fm.circ_lib() == "object" ? fm.circ_lib().shortname() : g.data.hash.aou[ fm.circ_lib() ].shortname()',
732 //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);',
733 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);',
737 "Owning Lib : Call Number",
739 render: 'fm.call_number();',
740 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,
746 render: 'fm.copy_number() == null ? "<Unset>" : fm.copy_number()',
747 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);',
759 render: 'fm.circulate() == null ? "<Unset>" : ( get_bool( fm.circulate() ) ? "Yes" : "No" )',
760 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);',
766 render: 'fm.holdable() == null ? "<Unset>" : ( get_bool( fm.holdable() ) ? "Yes" : "No" )',
767 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);',
773 render: 'fm.age_protect() == null ? "<Unset>" : ( typeof fm.age_protect() == "object" ? fm.age_protect().name() : g.data.hash.crahp[ fm.age_protect() ].name() )',
774 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);',
781 render: 'switch(fm.loan_duration()){ case 1: case "1": "Short"; break; case 2: case "2": "Normal"; break; case 3:case "3": "Long"; break; }',
782 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);',
789 render: 'switch(fm.fine_level()){ case 1: case "1": "Low"; break; case 2: case "2": "Normal"; break; case 3: case "3": "High"; break; }',
790 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);',
797 render: 'fm.circ_as_type() == null ? "<Unset>" : g.data.hash.citm[ fm.circ_as_type() ].value()',
798 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);',
802 "Circulation Modifier",
804 render: 'fm.circ_modifier() == null ? "<Unset>" : fm.circ_modifier()',
805 /*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);',*/
806 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);',
815 render: 'fm.alert_message() == null ? "<Unset>" : fm.alert_message()',
816 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);',
823 render: 'fm.deposit() == null ? "<Unset>" : ( get_bool( fm.deposit() ) ? "Yes" : "No" )',
824 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);',
830 render: 'if (fm.deposit_amount() == null) { "<Unset>"; } else { util.money.sanitize( fm.deposit_amount() ); }',
831 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);',
837 render: 'if (fm.price() == null) { "<Unset>"; } else { util.money.sanitize( fm.price() ); }',
838 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);',
845 render: 'fm.opac_visible() == null ? "<Unset>" : ( get_bool( fm.opac_visible() ) ? "Yes" : "No" )',
846 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);',
852 render: 'fm.ref() == null ? "<Unset>" : ( get_bool( fm.ref() ) ? "Yes" : "No" )',
853 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);',
865 /******************************************************************************************************/
866 /* This loops through all our fieldnames and all the copies, tallying up counts for the different values */
868 g.summarize = function( copies ) {
869 /******************************************************************************************************/
872 JSAN.use('util.date'); JSAN.use('util.money');
875 for (var i in g.panes_and_field_names) {
876 g.field_names = g.field_names.concat( g.panes_and_field_names[i] );
878 g.field_names = g.field_names.concat( g.editable_stat_cat_names );
879 g.field_names = g.field_names.concat( g.readonly_stat_cat_names );
881 /******************************************************************************************************/
882 /* Loop through the field names */
884 for (var i = 0; i < g.field_names.length; i++) {
886 var field_name = g.field_names[i][0];
887 var render = g.field_names[i][1].render;
888 var attr = g.field_names[i][1].attr;
889 g.summary[ field_name ] = {};
891 /******************************************************************************************************/
892 /* Loop through the copies */
894 for (var j = 0; j < copies.length; j++) {
897 var cmd = render || ('fm.' + field_name + '();');
900 /**********************************************************************************************/
901 /* Try to retrieve the value for this field for this copy */
906 g.error.sdump('D_ERROR','Attempted ' + cmd + '\n' + E + '\n');
908 if (typeof value == 'object' && value != null) {
909 alert('FIXME: field_name = <' + field_name + '> value = <' + js2JSON(value) + '>\n');
912 /**********************************************************************************************/
913 /* Tally the count */
915 if (g.summary[ field_name ][ value ]) {
916 g.summary[ field_name ][ value ]++;
918 g.summary[ field_name ][ value ] = 1;
922 g.error.sdump('D_TRACE','summary = ' + js2JSON(g.summary) + '\n');
925 /******************************************************************************************************/
926 /* Display the summarized data and inputs for editing */
928 g.render = function() {
930 /******************************************************************************************************/
931 /* Library setup and clear any existing interface */
933 JSAN.use('util.widgets'); JSAN.use('util.date'); JSAN.use('util.money'); JSAN.use('util.functional');
935 for (var i in g.panes_and_field_names) {
936 var p = document.getElementById(i);
937 if (p) util.widgets.remove_children(p);
940 /******************************************************************************************************/
941 /* Populate the library filter menu for stat cats */
944 for (var i = 0; i < g.panes_and_field_names.right_pane4.length; i++) {
945 sc_libs[ g.panes_and_field_names.right_pane4[i][1].attr.sc_lib ] = true;
948 for (var i in sc_libs) { sc_libs2.push( [ g.data.hash.aou[ i ].shortname(), i ] ); }
950 var x = document.getElementById("stat_cat_lib_filter_menu").firstChild;
951 JSAN.use('util.widgets'); util.widgets.remove_children(x);
952 for (var i = 0; i < sc_libs2.length; i++) {
953 var menuitem = document.createElement('menuitem');
954 menuitem.setAttribute('id','filter_'+sc_libs2[i][1]);
955 menuitem.setAttribute('type','checkbox');
956 menuitem.setAttribute('checked','true');
957 menuitem.setAttribute('label',sc_libs2[i][0]);
958 menuitem.setAttribute('value',sc_libs2[i][1]);
959 menuitem.setAttribute('oncommand','try{g.toggle_stat_cat_display(this);}catch(E){alert(E);}');
960 x.appendChild(menuitem);
963 /******************************************************************************************************/
964 /* Prepare the panes */
966 var groupbox; var caption; var vbox; var grid; var rows;
968 /******************************************************************************************************/
969 /* Loop through the field names */
971 for (h in g.panes_and_field_names) {
972 if (!document.getElementById(h)) continue;
973 for (var i = 0; i < g.panes_and_field_names[h].length; i++) {
975 var f = g.panes_and_field_names[h][i]; var fn = f[0]; var attr = f[1].attr;
976 groupbox = document.createElement('groupbox'); document.getElementById(h).appendChild(groupbox);
978 for (var a in attr) {
979 groupbox.setAttribute(a,attr[a]);
982 if (typeof g.changed[fn] != 'undefined') groupbox.setAttribute('class','copy_editor_field_changed');
983 caption = document.createElement('caption'); groupbox.appendChild(caption);
984 caption.setAttribute('label',fn); caption.setAttribute('id','caption_'+fn);
985 vbox = document.createElement('vbox'); groupbox.appendChild(vbox);
986 grid = util.widgets.make_grid( [ { 'flex' : 1 }, {}, {} ] ); vbox.appendChild(grid);
987 grid.setAttribute('flex','1');
988 rows = grid.lastChild;
991 /**************************************************************************************/
992 /* Loop through each value for the field */
994 for (var j in g.summary[fn]) {
995 var value = j; var count = g.summary[fn][j];
996 row = document.createElement('row'); rows.appendChild(row);
997 var label1 = document.createElement('description'); row.appendChild(label1);
998 if (g.special_exception[ fn ]) {
999 g.special_exception[ fn ]( label1, value );
1001 label1.appendChild( document.createTextNode(value) );
1003 var label2 = document.createElement('description'); row.appendChild(label2);
1004 var unit = count == 1 ? 'copy' : 'copies';
1005 label2.appendChild( document.createTextNode(count + ' ' + unit) );
1007 var hbox = document.createElement('hbox');
1008 hbox.setAttribute('id',fn);
1009 groupbox.appendChild(hbox);
1010 var hbox2 = document.createElement('hbox');
1011 groupbox.appendChild(hbox2);
1013 /**************************************************************************************/
1014 /* Render the input widget */
1016 if (f[1].input && g.edit) {
1017 g.render_input(hbox,f[1]);
1021 g.error.sdump('D_ERROR','copy editor: ' + E + '\n');
1027 /******************************************************************************************************/
1028 /* Synchronize stat cat visibility with library filter menu, and default template selection */
1029 JSAN.use('util.file');
1030 var file = new util.file('copy_editor_prefs.'+g.data.server_unadorned);
1031 g.copy_editor_prefs = util.widgets.load_attributes(file);
1032 for (var i in g.copy_editor_prefs) {
1033 if (i.match(/filter_/) && g.copy_editor_prefs[i].checked == '') {
1035 g.toggle_stat_cat_display( document.getElementById(i) );
1036 } catch(E) { alert(E); }
1039 if (g.template_menu) g.template_menu.value = g.template_menu.getAttribute('value');
1043 /******************************************************************************************************/
1044 /* This actually draws the change button and input widget for a given field */
1045 g.render_input = function(node,blob) {
1047 // node = hbox ; groupbox -> hbox, hbox
1049 var groupbox = node.parentNode;
1050 var caption = groupbox.firstChild;
1051 var vbox = node.previousSibling;
1053 var hbox2 = node.nextSibling;
1055 var input_cmd = blob.input;
1056 var render_cmd = blob.render;
1057 var attr = blob.attr;
1059 var block = false; var first = true;
1061 function on_mouseover(ev) {
1062 groupbox.setAttribute('style','background: white');
1065 function on_mouseout(ev) {
1066 groupbox.setAttribute('style','');
1069 vbox.addEventListener('mouseover',on_mouseover,false);
1070 vbox.addEventListener('mouseout',on_mouseout,false);
1071 groupbox.addEventListener('mouseover',on_mouseover,false);
1072 groupbox.addEventListener('mouseout',on_mouseout,false);
1073 groupbox.firstChild.addEventListener('mouseover',on_mouseover,false);
1074 groupbox.firstChild.addEventListener('mouseout',on_mouseout,false);
1076 function on_click(ev){
1078 if (block) return; block = true;
1080 function post_c(v) {
1082 /* FIXME - kludgy */
1083 var t = input_cmd.match('apply_stat_cat') ? 'stat_cat' : ( input_cmd.match('apply_owning_lib') ? 'owning_lib' : 'attribute' );
1087 f = input_cmd.match(/apply\("(.+?)",/)[1];
1090 f = input_cmd.match(/apply_stat_cat\((.+?),/)[1];
1096 g.changed[ hbox.id ] = { 'type' : t, 'field' : f, 'value' : v };
1100 g.summarize( g.copies );
1102 document.getElementById(caption.id).focus();
1106 g.error.standard_unexpected_error_alert('post_c',E);
1109 var x; var c; eval( input_cmd );
1111 util.widgets.remove_children(vbox);
1112 util.widgets.remove_children(hbox);
1113 util.widgets.remove_children(hbox2);
1114 hbox.appendChild(x);
1115 var apply = document.createElement('button');
1116 apply.setAttribute('label','Apply');
1117 apply.setAttribute('accesskey','A');
1118 hbox2.appendChild(apply);
1119 apply.addEventListener('command',function() { c(x.value); },false);
1120 var cancel = document.createElement('button');
1121 cancel.setAttribute('label','Cancel');
1122 cancel.addEventListener('command',function() { setTimeout( function() { g.summarize( g.copies ); g.render(); document.getElementById(caption.id).focus(); }, 0); }, false);
1123 hbox2.appendChild(cancel);
1124 setTimeout( function() { x.focus(); }, 0 );
1127 g.error.standard_unexpected_error_alert('render_input',E);
1130 vbox.addEventListener('click',on_click, false);
1131 hbox.addEventListener('click',on_click, false);
1132 caption.addEventListener('click',on_click, false);
1133 caption.addEventListener('keypress',function(ev) {
1134 if (ev.keyCode == 13 /* enter */ || ev.keyCode == 77 /* mac enter */) on_click();
1136 caption.setAttribute('style','-moz-user-focus: normal');
1137 caption.setAttribute('onfocus','this.setAttribute("class","outline_me")');
1138 caption.setAttribute('onblur','this.setAttribute("class","")');
1141 g.error.sdump('D_ERROR',E + '\n');
1145 /******************************************************************************************************/
1146 /* store the copies in the global xpcom stash */
1148 g.stash_and_close = function() {
1150 if (g.handle_update) {
1152 var r = g.network.request(
1153 api.FM_ACP_FLESHED_BATCH_UPDATE.app,
1154 api.FM_ACP_FLESHED_BATCH_UPDATE.method,
1155 [ ses(), g.copies, true ]
1157 if (typeof r.ilsevent != 'undefined') {
1158 g.error.standard_unexpected_error_alert('copy update',r);
1160 alert('Items added/modified.');
1162 /* FIXME -- revisit the return value here */
1164 alert('copy update error: ' + js2JSON(E));
1167 //g.data.temp_copies = js2JSON( g.copies );
1168 //g.data.stash('temp_copies');
1169 xulG.copies = g.copies;
1170 update_modal_xulG(xulG);
1173 g.error.standard_unexpected_error_alert('stash and close',E);
1177 /******************************************************************************************************/
1178 /* spawn copy notes interface */
1180 g.copy_notes = function() {
1181 JSAN.use('util.window'); var win = new util.window();
1183 urls.XUL_COPY_NOTES,
1184 //+ '?copy_id=' + window.escape(g.copies[0].id()),
1185 'Copy Notes','chrome,resizable,modal',
1186 { 'copy_id' : g.copies[0].id() }
1190 /******************************************************************************************************/
1191 /* hides or unhides stat cats based on library stat cat filter menu */
1192 g.toggle_stat_cat_display = function(el) {
1194 var visible = el.getAttribute('checked');
1195 var nl = document.getElementsByAttribute('sc_lib',el.getAttribute('value'));
1196 for (var n = 0; n < nl.length; n++) {
1198 nl[n].setAttribute('hidden','false');
1200 nl[n].setAttribute('hidden','true');
1203 g.copy_editor_prefs[ el.getAttribute('id') ] = { 'checked' : visible };
1204 g.save_attributes();
1207 /******************************************************************************************************/
1208 /* This adds a stat cat definition to the stat cat pane for rendering */
1209 g.save_attributes = function() {
1210 JSAN.use('util.widgets'); JSAN.use('util.file'); var file = new util.file('copy_editor_prefs.'+g.data.server_unadorned);
1211 var what_to_save = {};
1212 for (var i in g.copy_editor_prefs) {
1213 what_to_save[i] = [];
1214 for (var j in g.copy_editor_prefs[i]) what_to_save[i].push(j);
1216 util.widgets.save_attributes(file, what_to_save );
1219 /******************************************************************************************************/
1220 /* This adds a stat cat definition to the stat cat pane for rendering */
1221 g.add_stat_cat = function(sc) {
1223 if (typeof g.data.hash.asc == 'undefined') { g.data.hash.asc = {}; g.data.stash('hash'); }
1227 if (typeof sc == 'object') {
1232 if (typeof g.stat_cat_seen[sc_id] != 'undefined') { return; }
1234 g.stat_cat_seen[ sc_id ] = 1;
1236 if (typeof sc != 'object') {
1238 sc = g.network.simple_request(
1239 'FM_ASC_BATCH_RETRIEVE',
1240 [ ses(), [ sc_id ] ]
1245 g.data.hash.asc[ sc.id() ] = sc; g.data.stash('hash');
1247 var label_name = g.data.hash.aou[ sc.owner() ].shortname() + " : " + sc.name();
1252 render: 'var l = util.functional.find_list( fm.stat_cat_entries(), function(e){ return e.stat_cat() == '
1253 + sc.id() + '; } ); l ? l.value() : "<Unset>";',
1254 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()
1255 + '].entries(), function(obj){ return [ obj.value(), obj.id() ]; } ) ).sort() ); '
1256 + 'x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c),false);',
1263 g.panes_and_field_names.right_pane4.push( temp_array );
1265 g.error.standard_unexpected_error_alert('Error adding stat cat to display definition',E);
1269 /******************************************************************************************************/
1270 /* Add stat cats to the panes_and_field_names.right_pane4 */
1271 g.populate_stat_cats = function() {
1273 g.data.stash_retrieve();
1274 g.stat_cat_seen = {};
1276 function get(lib_id,only_these) {
1277 g.data.stash_retrieve();
1278 var label = 'asc_list_for_lib_'+lib_id;
1279 if (typeof g.data[label] == 'undefined') {
1280 var robj = g.network.simple_request('FM_ASC_RETRIEVE_VIA_AOU', [ ses(), lib_id ]);
1281 if (typeof robj.ilsevent != 'undefined') throw(robj);
1283 for (var j = 0; j < robj.length; j++) {
1284 var my_asc = robj[j];
1285 if (typeof g.data.hash.asc == 'undefined') { g.data.hash.asc = {}; }
1286 if (typeof g.data.hash.asc[ my_asc.id() ] == 'undefined') {
1287 g.data.hash.asc[ my_asc.id() ] = my_asc;
1289 var only_this_lib = my_asc.owner(); if (typeof only_this_lib == 'object') only_this_lib = only_this_lib.id();
1290 if (only_these.indexOf( String( only_this_lib ) ) != -1) {
1291 temp_list.push( my_asc );
1294 g.data[label] = temp_list; g.data.stash(label,'hash','list');
1296 return g.data[label];
1299 /* The stat cats for the pertinent library -- this is based on workstation ou */
1300 var label = 'asc_list_for_' + typeof g.data.ws_ou == 'object' ? g.data.ws_ou.id() : g.data.ws_ou;
1301 g.data[ label ] = g.data.list.my_asc; g.data.stash('label');
1302 for (var i = 0; i < g.data.list.my_asc.length; i++) {
1303 g.add_stat_cat( g.data.list.my_asc[i] );
1306 /* For the others, we want to consider the owning libs, circ libs, and any libs that have stat cats already on the copies,
1307 however, if batch editing, we only want to show the ones they have in common. So let's compile the libs */
1309 function add_common_ancestors(sc_libs) {
1310 JSAN.use('util.fm_utils');
1311 var libs = []; for (var i in sc_libs) libs.push(i);
1312 var ancestor = util.fm_utils.find_common_aou_ancestor( libs );
1313 if (typeof ancestor == 'object' && ancestor != null) ancestor = ancestor.id();
1315 var ancestors = util.fm_utils.find_common_aou_ancestors( libs );
1316 var asc_list = get(ancestor, ancestors);
1317 for (var i = 0; i < asc_list.length; i++) {
1318 g.add_stat_cat( asc_list[i] );
1323 /* stat cats based on stat cat entries present on these copies */
1325 for (var i = 0; i < g.copies.length; i++) {
1326 var entries = g.copies[i].stat_cat_entries();
1327 if (!entries) entries = [];
1328 for (var j = 0; j < entries.length; j++) {
1329 var lib = entries[j].owner(); if (typeof lib == 'object') lib = lib.id();
1330 sc_libs[ lib ] = true;
1333 add_common_ancestors(sc_libs); // CAVEAT - if a copy has no stat_cat_entries, it basically gets no vote here
1335 /* stat cats based on Circ Lib */
1337 for (var i = 0; i < g.copies.length; i++) {
1338 var circ_lib = g.copies[i].circ_lib(); if (typeof circ_lib == 'object') circ_lib = circ_lib.id();
1339 sc_libs[ circ_lib ] = true;
1341 add_common_ancestors(sc_libs);
1343 /* stat cats based on Owning Lib */
1345 for (var i = 0; i < g.copies.length; i++) {
1346 var cn_id = g.copies[i].call_number();
1348 if (! g.map_acn[ cn_id ]) {
1349 g.map_acn[ cn_id ] = g.network.simple_request('FM_ACN_RETRIEVE',[ cn_id ]);
1351 var owning_lib = g.map_acn[ cn_id ].owning_lib(); if (typeof owning_lib == 'object') owning_lib = owning_lib.id();
1352 sc_libs[ owning_lib ] = true;
1355 add_common_ancestors(sc_libs); // CAVEAT - if a copy is a pre-cat, it basically gets no vote here
1357 g.panes_and_field_names.right_pane4.sort();
1360 g.error.standard_unexpected_error_alert('Error populating stat cats for display',E);