8 /******************************************************************************************************/
9 /* setup JSAN and some initial libraries */
11 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
12 if (typeof JSAN == 'undefined') { throw( "The JSAN library object is missing."); }
13 JSAN.errorLevel = "die"; // none, warn, or die
14 JSAN.addRepository('/xul/server/');
15 JSAN.use('util.error'); g.error = new util.error();
16 g.error.sdump('D_TRACE','my_init() for cat/copy_editor.xul');
18 JSAN.use('util.functional');
19 JSAN.use('OpenILS.data'); g.data = new OpenILS.data(); g.data.init({'via':'stash'});
20 JSAN.use('util.network'); g.network = new util.network();
22 g.docid = xul_param('docid',{'modal_xulG':true});
23 g.handle_update = xul_param('handle_update',{'modal_xulG':true});
25 /******************************************************************************************************/
26 /* Get the copy ids from various sources and flesh them */
28 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});
29 if (!copy_ids) copy_ids = [];
31 if (copy_ids.length > 0) g.copies = g.network.simple_request(
32 'FM_ACP_FLESHED_BATCH_RETRIEVE.authoritative',
36 /******************************************************************************************************/
37 /* And other fleshed copies if any */
39 if (!g.copies) g.copies = [];
40 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})
41 if (c) g.copies = g.copies.concat(c);
43 /******************************************************************************************************/
44 /* We try to retrieve callnumbers for existing copies, but for new copies, we rely on this */
46 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});
49 /******************************************************************************************************/
50 /* Quick fix, this was defined inline in the global scope but now needs g.error and g.copies from my_init */
54 /******************************************************************************************************/
55 /* Is the interface an editor or a viewer, single or multi copy, existing copies or new copies? */
57 if (xul_param('edit',{'modal_xulG':true}) == '1') {
59 // Editor desired, but let's check permissions
63 var check = g.network.simple_request(
64 'PERM_MULTI_ORG_CHECK',
67 g.data.list.au[0].id(),
68 util.functional.map_list(
72 var cn_id = o.call_number();
74 lib = o.circ_lib(); // base perms on circ_lib instead of owning_lib if pre-cat
76 if (! g.map_acn[ cn_id ]) {
77 var req = g.network.simple_request('FM_ACN_RETRIEVE.authoritative',[ cn_id ]);
78 if (typeof req.ilsevent == 'undefined') {
79 g.map_acn[ cn_id ] = req;
80 lib = g.map_acn[ cn_id ].owning_lib();
85 lib = g.map_acn[ cn_id ].owning_lib();
91 g.copies.length == 1 ? [ 'UPDATE_COPY' ] : [ 'UPDATE_COPY', 'UPDATE_BATCH_COPY' ]
94 g.edit = check.length == 0;
96 g.error.standard_unexpected_error_alert('batch permission check',E);
100 document.getElementById('caption').setAttribute('label','Copy Editor');
101 document.getElementById('save').setAttribute('hidden','false');
102 g.retrieve_templates();
104 $('top_nav').setAttribute('hidden','true');
107 $('top_nav').setAttribute('hidden','true');
110 if (g.copies.length > 0 && g.copies[0].id() < 0) {
111 document.getElementById('copy_notes').setAttribute('hidden','true');
112 g.apply("status",5 /* In Process */);
113 $('save').setAttribute('label','Create Copies');
115 g.panes_and_field_names.left_pane =
120 render: 'typeof fm.status() == "object" ? fm.status().name() : g.data.hash.ccs[ fm.status() ].name()',
121 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,
122 //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);',
125 ].concat(g.panes_and_field_names.left_pane);
128 if (g.copies.length != 1) {
129 document.getElementById('copy_notes').setAttribute('hidden','true');
132 /******************************************************************************************************/
133 /* Show the Record Details? */
136 document.getElementById('brief_display').setAttribute(
138 urls.XUL_BIB_BRIEF + '?docid=' + g.docid
141 document.getElementById('brief_display').setAttribute('hidden','true');
144 /******************************************************************************************************/
145 /* Add stat cats to the panes_and_field_names.right_pane4 */
147 g.populate_stat_cats();
149 /******************************************************************************************************/
150 /* Backup copies :) */
152 g.original_copies = js2JSON( g.copies );
154 /******************************************************************************************************/
157 g.summarize( g.copies );
161 var err_msg = "!! This software has encountered an error. Please tell your friendly " +
162 "system administrator or software developer the following:\ncat/copy_editor.xul\n" + E + '\n';
163 try { g.error.sdump('D_ERROR',err_msg); } catch(E) { dump(err_msg); dump(js2JSON(E)); }
168 /******************************************************************************************************/
169 /* Retrieve Templates */
171 g.retrieve_templates = function() {
173 JSAN.use('util.widgets'); JSAN.use('util.functional');
175 var robj = g.network.simple_request('FM_AUS_RETRIEVE',[ses(),g.data.list.au[0].id()]);
176 if (typeof robj['staff_client.copy_editor.templates'] != 'undefined') {
177 g.templates = robj['staff_client.copy_editor.templates'];
179 util.widgets.remove_children('template_placeholder');
180 var list = util.functional.map_object_to_list( g.templates, function(obj,i) { return [i, i]; } );
182 g.template_menu = util.widgets.make_menulist( list );
183 g.template_menu.setAttribute('id','template_menu');
184 $('template_placeholder').appendChild(g.template_menu);
185 g.template_menu.addEventListener(
187 function() { g.copy_editor_prefs[ 'template_menu' ] = { 'value' : g.template_menu.value }; g.save_attributes(); },
191 g.error.standard_unexpected_error_alert('Error retrieving templates',E);
195 /******************************************************************************************************/
198 g.apply_template = function() {
200 var name = g.template_menu.value;
201 if (g.templates[ name ] != 'undefined') {
202 var template = g.templates[ name ];
203 for (var i in template) {
204 g.changed[ i ] = template[ i ];
205 switch( template[i].type ) {
207 g.apply(template[i].field,template[i].value);
210 if (g.stat_cat_seen[ template[i].field ]) g.apply_stat_cat(template[i].field,template[i].value);
213 g.apply_owning_lib(template[i].value);
217 g.summarize( g.copies );
221 g.error.standard_unexpected_error_alert('Error applying template',E);
225 /******************************************************************************************************/
226 /* Save as Template */
228 g.save_template = function() {
230 var name = window.prompt('Enter template name:','','Save As Template');
232 g.templates[name] = g.changed;
233 var robj = g.network.simple_request(
234 'FM_AUS_UPDATE',[ses(),g.data.list.au[0].id(), { 'staff_client.copy_editor.templates' : g.templates }]
236 if (typeof robj.ilsevent != 'undefined') {
239 alert('Template "' + name + '" saved.');
243 g.retrieve_templates();
245 g.error.standard_unexpected_error_alert('Error saving template',E);
251 g.error.standard_unexpected_error_alert('Error saving template',E);
255 /******************************************************************************************************/
256 /* Delete Template */
258 g.delete_template = function() {
260 var name = g.template_menu.value;
262 if (! window.confirm('Delete template "' + name + '"?') ) return;
263 delete(g.templates[name]);
264 var robj = g.network.simple_request(
265 'FM_AUS_UPDATE',[ses(),g.data.list.au[0].id(), { 'staff_client.copy_editor.templates' : g.templates }]
267 if (typeof robj.ilsevent != 'undefined') {
270 alert('Template "' + name + '" deleted.');
274 g.retrieve_templates();
276 g.error.standard_unexpected_error_alert('Error deleting template',E);
282 g.error.standard_unexpected_error_alert('Error deleting template',E);
286 /******************************************************************************************************/
287 /* Export Templates */
289 g.export_templates = function() {
291 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
292 JSAN.use('util.file'); var f = new util.file('');
293 f.export_file( { 'title' : 'Save Templates File As', 'data' : g.templates } );
295 g.error.standard_unexpected_error_alert('Error exporting templates',E);
299 /******************************************************************************************************/
300 /* Import Templates */
302 g.import_templates = function() {
304 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
305 JSAN.use('util.file'); var f = new util.file('');
306 var temp = f.import_file( { 'title' : 'Import Templates File' } );
308 for (var i in temp) {
310 if (g.templates[i]) {
312 var r = g.error.yns_alert(
313 'Replace the existing template with the imported template?\n' + g.error.pretty_print( js2JSON( temp[i] ) ),
314 'Template ' + i + ' already exists.','Yes','No',null,'Click here'
317 if (r == 0 /* Yes */) g.templates[i] = temp[i];
321 g.templates[i] = temp[i];
327 var r = g.error.yns_alert(
328 'Save all of these imported templates permanently to this account?',
329 'Final Warning', 'Yes', 'No', null, 'Click here'
332 if (r == 0 /* Yes */) {
333 var robj = g.network.simple_request(
334 'FM_AUS_UPDATE',[ses(),g.data.list.au[0].id(), { 'staff_client.copy_editor.templates' : g.templates }]
336 if (typeof robj.ilsevent != 'undefined') {
339 alert('All templates saved.');
343 g.retrieve_templates();
345 g.error.standard_unexpected_error_alert('Error saving templates',E);
351 util.widgets.remove_children('template_placeholder');
352 var list = util.functional.map_object_to_list( g.templates, function(obj,i) { return [i, i]; } );
353 g.template_menu = util.widgets.make_menulist( list );
354 $('template_placeholder').appendChild(g.template_menu);
355 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.");
360 g.error.standard_unexpected_error_alert('Error importing templates',E);
365 /******************************************************************************************************/
366 /* Restore backup copies */
368 g.reset = function() {
370 g.copies = JSON2js( g.original_copies );
371 g.summarize( g.copies );
375 /******************************************************************************************************/
376 /* Apply a value to a specific field on all the copies being edited */
378 g.apply = function(field,value) {
379 g.error.sdump('D_TRACE','applying field = <' + field + '> value = <' + value + '>\n');
380 if (value == '<HACK:KLUDGE:NULL>') value = null;
381 if (field == 'alert_message') { value = value.replace(/^\W+$/g,''); }
382 if (field == 'price' || field == 'deposit_amount') {
383 if (value == '') { value = null; } else { JSAN.use('util.money'); value = util.money.sanitize( value ); }
385 for (var i = 0; i < g.copies.length; i++) {
386 var copy = g.copies[i];
388 copy[field]( value ); copy.ischanged('1');
395 /******************************************************************************************************/
396 /* Apply a stat cat entry to all the copies being edited. An entry_id of < 0 signifies the stat cat is being removed. */
398 g.apply_stat_cat = function(sc_id,entry_id) {
399 g.error.sdump('D_TRACE','sc_id = ' + sc_id + ' entry_id = ' + entry_id + '\n');
400 for (var i = 0; i < g.copies.length; i++) {
401 var copy = g.copies[i];
404 var temp = copy.stat_cat_entries();
405 if (!temp) temp = [];
406 temp = util.functional.filter_list(
409 return (obj.stat_cat() != sc_id);
412 if (entry_id > -1) temp.push(
413 util.functional.find_id_object_in_list(
414 g.data.hash.asc[sc_id].entries(),
418 copy.stat_cat_entries( temp );
421 g.error.standard_unexpected_error_alert('apply_stat_cat',E);
426 /******************************************************************************************************/
427 /* Apply an "owning lib" to all the copies being edited. That is, change and auto-vivicating volumes */
429 g.apply_owning_lib = function(ou_id) {
430 g.error.sdump('D_TRACE','ou_id = ' + ou_id + '\n');
431 for (var i = 0; i < g.copies.length; i++) {
432 var copy = g.copies[i];
434 if (!g.map_acn[copy.call_number()]) {
435 var volume = g.network.simple_request('FM_ACN_RETRIEVE.authoritative',[ copy.call_number() ]);
436 if (typeof volume.ilsevent != 'undefined') {
437 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);
440 g.map_acn[copy.call_number()] = volume;
442 var old_volume = g.map_acn[copy.call_number()];
443 var acn_id = g.network.simple_request(
444 'FM_ACN_FIND_OR_CREATE',
445 [ses(),old_volume.label(),old_volume.record(),ou_id]
447 if (typeof acn_id.ilsevent != 'undefined') {
448 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);
451 copy.call_number(acn_id);
454 g.error.standard_unexpected_error_alert('apply_stat_cat',E);
459 /******************************************************************************************************/
460 /* This returns true if none of the copies being edited are pre-cats */
462 g.safe_to_change_owning_lib = function() {
465 for (var i = 0; i < g.copies.length; i++) {
466 var cn = g.copies[i].call_number();
467 if (typeof cn == 'object') { cn = cn.id(); }
468 if (cn == -1) { safe = false; }
472 g.error.standard_unexpected_error_alert('safe_to_change_owning_lib?',E);
477 /******************************************************************************************************/
478 /* This returns true if none of the copies being edited have a magical status found in my_constants.magical_statuses */
480 g.safe_to_edit_copy_status = function() {
483 for (var i = 0; i < g.copies.length; i++) {
484 var status = g.copies[i].status(); if (typeof status == 'object') status = status.id();
485 if (typeof my_constants.magical_statuses[ status ] != 'undefined') safe = false;
489 g.error.standard_unexpected_error_alert('safe_to_edit_copy_status?',E);
494 /******************************************************************************************************/
495 /* This concats and uniques all the alert messages for use as the default value for a new alert message */
497 g.populate_alert_message_input = function(tb) {
499 var seen = {}; var s = '';
500 for (var i = 0; i < g.copies.length; i++) {
501 var msg = g.copies[i].alert_message();
503 if (typeof seen[msg] == 'undefined') {
509 tb.setAttribute('value',s);
511 g.error.standard_unexpected_error_alert('populate_alert_message_input',E);
515 /***************************************************************************************************************/
516 /* This returns a list of acpl's appropriate for the copies being edited (and caches them in the global stash) */
518 g.get_acpl_list_for_lib = function(lib_id,but_only_these) {
519 g.data.stash_retrieve();
520 var label = 'acpl_list_for_lib_'+lib_id;
521 if (typeof g.data[label] == 'undefined') {
522 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
523 if (typeof robj.ilsevent != 'undefined') throw(robj);
525 for (var j = 0; j < robj.length; j++) {
526 var my_acpl = robj[j];
527 if (typeof g.data.hash.acpl[ my_acpl.id() ] == 'undefined') {
528 g.data.hash.acpl[ my_acpl.id() ] = my_acpl;
529 g.data.list.acpl.push( my_acpl );
531 var only_this_lib = my_acpl.owning_lib(); if (!only_this_lib) continue;
532 if (typeof only_this_lib == 'object') only_this_lib = only_this_lib.id();
533 if (but_only_these.indexOf( String( only_this_lib ) ) != -1) { // This filters out some of the libraries (usually the descendants)
534 temp_list.push( my_acpl );
537 g.data[label] = temp_list; g.data.stash(label,'hash','list');
539 return g.data[label];
542 /******************************************************************************************************/
543 /* This returns a list of acpl's appropriate for the copies being edited */
545 g.get_acpl_list = function() {
548 JSAN.use('util.functional');
552 /**************************************/
553 /* get owning libs from call numbers */
555 var owning_libs = {};
556 for (var i = 0; i < g.copies.length; i++) {
557 var callnumber = g.copies[i].call_number();
558 if (!callnumber) continue;
559 var cn_id = typeof callnumber == 'object' ? callnumber.id() : callnumber;
561 if (! g.map_acn[ cn_id ]) {
562 var req = g.network.simple_request('FM_ACN_RETRIEVE.authoritative',[ cn_id ]);
563 if (typeof req.ilsevent == 'undefined') {
564 g.map_acn[ cn_id ] = req;
569 var consider_lib = g.map_acn[ cn_id ].owning_lib();
570 if (!consider_lib) continue;
571 owning_libs[ typeof consider_lib == 'object' ? consider_lib.id() : consider_lib ] = true;
575 for (var i in g.callnumbers) {
576 var consider_lib = g.callnumbers[i].owning_lib;
577 if (!consider_lib) continue;
578 owning_libs[ typeof consider_lib == 'object' ? consider_lib.id() : consider_lib ] = true;
582 /***************************************************************************************************/
583 /* now find the first ancestor they all have in common, get the acpl's for it and higher ancestors */
585 JSAN.use('util.fm_utils');
586 var libs = []; for (var i in owning_libs) libs.push(i);
587 if (libs.length > 0) {
588 var ancestor = util.fm_utils.find_common_aou_ancestor( libs );
589 if (typeof ancestor == 'object' && ancestor != null) ancestor = ancestor.id();
592 var ancestors = util.fm_utils.find_common_aou_ancestors( libs );
593 var acpl_list = g.get_acpl_list_for_lib(ancestor, ancestors);
594 if (acpl_list) for (var i = 0; i < acpl_list.length; i++) {
595 if (acpl_list[i] != null) {
596 my_acpls[ typeof acpl_list[i] == 'object' ? acpl_list[i].id() : acpl_list[i] ] = true;
607 for (var i = 0; i < g.copies.length; i++) {
608 var consider_lib = g.copies[i].circ_lib();
609 if (!consider_lib) continue;
610 circ_libs[ typeof consider_lib == 'object' ? consider_lib.id() : consider_lib ] = true;
613 /***************************************************************************************************/
614 /* now find the first ancestor they all have in common, get the acpl's for it and higher ancestors */
616 libs = []; for (var i in circ_libs) libs.push(i);
617 if (libs.length > 0) {
618 var ancestor = util.fm_utils.find_common_aou_ancestor( libs );
619 if (typeof ancestor == 'object' && ancestor != null) ancestor = ancestor.id();
622 var ancestors = util.fm_utils.find_common_aou_ancestors( libs );
623 var acpl_list = g.get_acpl_list_for_lib(ancestor, ancestors);
624 if (acpl_list) for (var i = 0; i < acpl_list.length; i++) {
625 if (acpl_list[i] != null) {
626 my_acpls[ typeof acpl_list[i] == 'object' ? acpl_list[i].id() : acpl_list[i] ] = true;
632 var acpl_list = []; for (var i in my_acpls) acpl_list.push( g.data.hash.acpl[ i ] );
633 return acpl_list.sort(
635 var label_a = g.data.hash.aou[ a.owning_lib() ].shortname() + ' : ' + a.name();
636 var label_b = g.data.hash.aou[ b.owning_lib() ].shortname() + ' : ' + b.name();
637 if (label_a < label_b) return -1;
638 if (label_a > label_b) return 1;
644 g.error.standard_unexpected_error_alert('get_acpl_list',E);
650 /******************************************************************************************************/
651 /* This keeps track of what fields have been edited for styling purposes */
655 /******************************************************************************************************/
656 /* These need data from the middle layer to render */
658 g.special_exception = {
659 'Owning Lib : Call Number' : function(label,value) {
660 JSAN.use('util.widgets');
661 if (value>0) { /* an existing call number */
662 g.network.simple_request(
663 'FM_ACN_RETRIEVE.authoritative',
666 var cn = '??? id = ' + value;
668 cn = req.getResultObject();
670 g.error.sdump('D_ERROR','callnumber retrieve: ' + E);
672 util.widgets.set_text(label,g.data.hash.aou[ cn.owning_lib() ].shortname() + ' : ' + cn.label());
675 } else { /* a yet to be created call number */
677 util.widgets.set_text(label,g.data.hash.aou[ g.callnumbers[value].owning_lib ].shortname() + ' : ' + g.callnumbers[value].label);
681 'Creator' : function(label,value) {
682 if (value == null || value == '' || value == 'null') return;
683 g.network.simple_request(
684 'FM_AU_RETRIEVE_VIA_ID',
687 var p = '??? id = ' + value;
689 p = req.getResultObject();
693 g.error.sdump('D_ERROR','patron retrieve: ' + E);
695 JSAN.use('util.widgets');
696 util.widgets.set_text(label,p);
700 'Last Editor' : function(label,value) {
701 if (value == null || value == '' || value == 'null') return;
702 g.network.simple_request(
703 'FM_AU_RETRIEVE_VIA_ID',
706 var p = '??? id = ' + value;
708 p = req.getResultObject();
712 g.error.sdump('D_ERROR','patron retrieve: ' + E);
714 util.widgets.set_text(label,p);
721 /******************************************************************************************************/
722 g.readonly_stat_cat_names = [];
723 g.editable_stat_cat_names = [];
725 /******************************************************************************************************/
726 /* These get show in the left panel */
728 function init_panes() {
729 g.panes_and_field_names = {
736 render: 'fm.barcode();',
742 render: 'util.date.formatted_date( fm.create_date(), "%F");',
748 render: 'fm.creator();',
754 render: 'util.date.formatted_date( fm.edit_date(), "%F");',
760 render: 'fm.editor();',
771 render: 'typeof fm.location() == "object" ? fm.location().name() : g.data.lookup("acpl",fm.location()).name()',
772 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);',
777 "Circulation Library",
779 render: 'typeof fm.circ_lib() == "object" ? fm.circ_lib().shortname() : g.data.hash.aou[ fm.circ_lib() ].shortname()',
780 //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);',
781 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);',
785 "Owning Lib : Call Number",
787 render: 'fm.call_number();',
788 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,
794 render: 'fm.copy_number() == null ? "<Unset>" : fm.copy_number()',
795 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);',
807 render: 'fm.circulate() == null ? "<Unset>" : ( get_bool( fm.circulate() ) ? "Yes" : "No" )',
808 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);',
814 render: 'fm.holdable() == null ? "<Unset>" : ( get_bool( fm.holdable() ) ? "Yes" : "No" )',
815 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);',
821 render: 'fm.age_protect() == null ? "<Unset>" : ( typeof fm.age_protect() == "object" ? fm.age_protect().name() : g.data.hash.crahp[ fm.age_protect() ].name() )',
822 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);',
829 render: 'switch(Number(fm.loan_duration())){ case 1: "Short"; break; case 2: "Normal"; break; case 3: "Long"; break; }',
830 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);',
837 render: 'switch(Number(fm.fine_level())){ case 1: "Low"; break; case 2: "Normal"; break; case 3: "High"; break; }',
838 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);',
845 render: 'fm.circ_as_type() == null ? "<Unset>" : g.data.hash.citm[ fm.circ_as_type() ].value()',
846 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);',
850 "Circulation Modifier",
852 render: 'fm.circ_modifier() == null ? "<Unset>" : fm.circ_modifier()',
853 /*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);',*/
854 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);',
863 render: 'fm.alert_message() == null ? "<Unset>" : fm.alert_message()',
864 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);',
871 render: 'fm.deposit() == null ? "<Unset>" : ( get_bool( fm.deposit() ) ? "Yes" : "No" )',
872 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);',
878 render: 'if (fm.deposit_amount() == null) { "<Unset>"; } else { util.money.sanitize( fm.deposit_amount() ); }',
879 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);',
885 render: 'if (fm.price() == null) { "<Unset>"; } else { util.money.sanitize( fm.price() ); }',
886 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);',
893 render: 'fm.opac_visible() == null ? "<Unset>" : ( get_bool( fm.opac_visible() ) ? "Yes" : "No" )',
894 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);',
900 render: 'fm.ref() == null ? "<Unset>" : ( get_bool( fm.ref() ) ? "Yes" : "No" )',
901 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);',
913 /******************************************************************************************************/
914 /* This loops through all our fieldnames and all the copies, tallying up counts for the different values */
916 g.summarize = function( copies ) {
917 /******************************************************************************************************/
920 JSAN.use('util.date'); JSAN.use('util.money');
923 for (var i in g.panes_and_field_names) {
924 g.field_names = g.field_names.concat( g.panes_and_field_names[i] );
926 g.field_names = g.field_names.concat( g.editable_stat_cat_names );
927 g.field_names = g.field_names.concat( g.readonly_stat_cat_names );
929 /******************************************************************************************************/
930 /* Loop through the field names */
932 for (var i = 0; i < g.field_names.length; i++) {
934 var field_name = g.field_names[i][0];
935 var render = g.field_names[i][1].render;
936 var attr = g.field_names[i][1].attr;
937 g.summary[ field_name ] = {};
939 /******************************************************************************************************/
940 /* Loop through the copies */
942 for (var j = 0; j < copies.length; j++) {
945 var cmd = render || ('fm.' + field_name + '();');
948 /**********************************************************************************************/
949 /* Try to retrieve the value for this field for this copy */
954 g.error.sdump('D_ERROR','Attempted ' + cmd + '\n' + E + '\n');
956 if (typeof value == 'object' && value != null) {
957 alert('FIXME: field_name = <' + field_name + '> value = <' + js2JSON(value) + '>\n');
960 /**********************************************************************************************/
961 /* Tally the count */
963 if (g.summary[ field_name ][ value ]) {
964 g.summary[ field_name ][ value ]++;
966 g.summary[ field_name ][ value ] = 1;
970 g.error.sdump('D_TRACE','summary = ' + js2JSON(g.summary) + '\n');
973 /******************************************************************************************************/
974 /* Display the summarized data and inputs for editing */
976 g.render = function() {
978 /******************************************************************************************************/
979 /* Library setup and clear any existing interface */
981 JSAN.use('util.widgets'); JSAN.use('util.date'); JSAN.use('util.money'); JSAN.use('util.functional');
983 for (var i in g.panes_and_field_names) {
984 var p = document.getElementById(i);
985 if (p) util.widgets.remove_children(p);
988 /******************************************************************************************************/
989 /* Populate the library filter menu for stat cats */
992 for (var i = 0; i < g.panes_and_field_names.right_pane4.length; i++) {
993 sc_libs[ g.panes_and_field_names.right_pane4[i][1].attr.sc_lib ] = true;
996 for (var i in sc_libs) { sc_libs2.push( [ g.data.hash.aou[ i ].shortname(), i ] ); }
998 var x = document.getElementById("stat_cat_lib_filter_menu").firstChild;
999 JSAN.use('util.widgets'); util.widgets.remove_children(x);
1000 for (var i = 0; i < sc_libs2.length; i++) {
1001 var menuitem = document.createElement('menuitem');
1002 menuitem.setAttribute('id','filter_'+sc_libs2[i][1]);
1003 menuitem.setAttribute('type','checkbox');
1004 menuitem.setAttribute('checked','true');
1005 menuitem.setAttribute('label',sc_libs2[i][0]);
1006 menuitem.setAttribute('value',sc_libs2[i][1]);
1007 menuitem.setAttribute('oncommand','try{g.toggle_stat_cat_display(this);}catch(E){alert(E);}');
1008 x.appendChild(menuitem);
1011 /******************************************************************************************************/
1012 /* Prepare the panes */
1014 var groupbox; var caption; var vbox; var grid; var rows;
1016 /******************************************************************************************************/
1017 /* Loop through the field names */
1019 for (h in g.panes_and_field_names) {
1020 if (!document.getElementById(h)) continue;
1021 for (var i = 0; i < g.panes_and_field_names[h].length; i++) {
1023 var f = g.panes_and_field_names[h][i]; var fn = f[0]; var attr = f[1].attr;
1024 groupbox = document.createElement('groupbox'); document.getElementById(h).appendChild(groupbox);
1026 for (var a in attr) {
1027 groupbox.setAttribute(a,attr[a]);
1030 if (typeof g.changed[fn] != 'undefined') groupbox.setAttribute('class','copy_editor_field_changed');
1031 caption = document.createElement('caption'); groupbox.appendChild(caption);
1032 caption.setAttribute('label',fn); caption.setAttribute('id','caption_'+fn);
1033 vbox = document.createElement('vbox'); groupbox.appendChild(vbox);
1034 grid = util.widgets.make_grid( [ { 'flex' : 1 }, {}, {} ] ); vbox.appendChild(grid);
1035 grid.setAttribute('flex','1');
1036 rows = grid.lastChild;
1039 /**************************************************************************************/
1040 /* Loop through each value for the field */
1042 for (var j in g.summary[fn]) {
1043 var value = j; var count = g.summary[fn][j];
1044 row = document.createElement('row'); rows.appendChild(row);
1045 var label1 = document.createElement('description'); row.appendChild(label1);
1046 if (g.special_exception[ fn ]) {
1047 g.special_exception[ fn ]( label1, value );
1049 label1.appendChild( document.createTextNode(value) );
1051 var label2 = document.createElement('description'); row.appendChild(label2);
1052 var unit = count == 1 ? 'copy' : 'copies';
1053 label2.appendChild( document.createTextNode(count + ' ' + unit) );
1055 var hbox = document.createElement('hbox');
1056 hbox.setAttribute('id',fn);
1057 groupbox.appendChild(hbox);
1058 var hbox2 = document.createElement('hbox');
1059 groupbox.appendChild(hbox2);
1061 /**************************************************************************************/
1062 /* Render the input widget */
1064 if (f[1].input && g.edit) {
1065 g.render_input(hbox,f[1]);
1069 g.error.sdump('D_ERROR','copy editor: ' + E + '\n');
1075 /******************************************************************************************************/
1076 /* Synchronize stat cat visibility with library filter menu, and default template selection */
1077 JSAN.use('util.file');
1078 var file = new util.file('copy_editor_prefs.'+g.data.server_unadorned);
1079 g.copy_editor_prefs = util.widgets.load_attributes(file);
1080 for (var i in g.copy_editor_prefs) {
1081 if (i.match(/filter_/) && g.copy_editor_prefs[i].checked == '') {
1083 g.toggle_stat_cat_display( document.getElementById(i) );
1084 } catch(E) { alert(E); }
1087 if (g.template_menu) g.template_menu.value = g.template_menu.getAttribute('value');
1091 /******************************************************************************************************/
1092 /* This actually draws the change button and input widget for a given field */
1093 g.render_input = function(node,blob) {
1095 // node = hbox ; groupbox -> hbox, hbox
1097 var groupbox = node.parentNode;
1098 var caption = groupbox.firstChild;
1099 var vbox = node.previousSibling;
1101 var hbox2 = node.nextSibling;
1103 var input_cmd = blob.input;
1104 var render_cmd = blob.render;
1105 var attr = blob.attr;
1107 var block = false; var first = true;
1109 function on_mouseover(ev) {
1110 groupbox.setAttribute('style','background: white');
1113 function on_mouseout(ev) {
1114 groupbox.setAttribute('style','');
1117 vbox.addEventListener('mouseover',on_mouseover,false);
1118 vbox.addEventListener('mouseout',on_mouseout,false);
1119 groupbox.addEventListener('mouseover',on_mouseover,false);
1120 groupbox.addEventListener('mouseout',on_mouseout,false);
1121 groupbox.firstChild.addEventListener('mouseover',on_mouseover,false);
1122 groupbox.firstChild.addEventListener('mouseout',on_mouseout,false);
1124 function on_click(ev){
1126 if (block) return; block = true;
1128 function post_c(v) {
1130 /* FIXME - kludgy */
1131 var t = input_cmd.match('apply_stat_cat') ? 'stat_cat' : ( input_cmd.match('apply_owning_lib') ? 'owning_lib' : 'attribute' );
1135 f = input_cmd.match(/apply\("(.+?)",/)[1];
1138 f = input_cmd.match(/apply_stat_cat\((.+?),/)[1];
1144 g.changed[ hbox.id ] = { 'type' : t, 'field' : f, 'value' : v };
1148 g.summarize( g.copies );
1150 document.getElementById(caption.id).focus();
1154 g.error.standard_unexpected_error_alert('post_c',E);
1157 var x; var c; eval( input_cmd );
1159 util.widgets.remove_children(vbox);
1160 util.widgets.remove_children(hbox);
1161 util.widgets.remove_children(hbox2);
1162 hbox.appendChild(x);
1163 var apply = document.createElement('button');
1164 apply.setAttribute('label','Apply');
1165 apply.setAttribute('accesskey','A');
1166 hbox2.appendChild(apply);
1167 apply.addEventListener('command',function() { c(x.value); },false);
1168 var cancel = document.createElement('button');
1169 cancel.setAttribute('label','Cancel');
1170 cancel.addEventListener('command',function() { setTimeout( function() { g.summarize( g.copies ); g.render(); document.getElementById(caption.id).focus(); }, 0); }, false);
1171 hbox2.appendChild(cancel);
1172 setTimeout( function() { x.focus(); }, 0 );
1175 g.error.standard_unexpected_error_alert('render_input',E);
1178 vbox.addEventListener('click',on_click, false);
1179 hbox.addEventListener('click',on_click, false);
1180 caption.addEventListener('click',on_click, false);
1181 caption.addEventListener('keypress',function(ev) {
1182 if (ev.keyCode == 13 /* enter */ || ev.keyCode == 77 /* mac enter */) on_click();
1184 caption.setAttribute('style','-moz-user-focus: normal');
1185 caption.setAttribute('onfocus','this.setAttribute("class","outline_me")');
1186 caption.setAttribute('onblur','this.setAttribute("class","")');
1189 g.error.sdump('D_ERROR',E + '\n');
1193 /******************************************************************************************************/
1194 /* store the copies in the global xpcom stash */
1196 g.stash_and_close = function() {
1198 if (g.handle_update) {
1200 var r = g.network.request(
1201 api.FM_ACP_FLESHED_BATCH_UPDATE.app,
1202 api.FM_ACP_FLESHED_BATCH_UPDATE.method,
1203 [ ses(), g.copies, true ]
1205 if (typeof r.ilsevent != 'undefined') {
1206 g.error.standard_unexpected_error_alert('copy update',r);
1208 alert('Items added/modified.');
1210 /* FIXME -- revisit the return value here */
1212 alert('copy update error: ' + js2JSON(E));
1215 //g.data.temp_copies = js2JSON( g.copies );
1216 //g.data.stash('temp_copies');
1217 xulG.copies = g.copies;
1218 update_modal_xulG(xulG);
1221 g.error.standard_unexpected_error_alert('stash and close',E);
1225 /******************************************************************************************************/
1226 /* spawn copy notes interface */
1228 g.copy_notes = function() {
1229 JSAN.use('util.window'); var win = new util.window();
1231 urls.XUL_COPY_NOTES,
1232 //+ '?copy_id=' + window.escape(g.copies[0].id()),
1233 'Copy Notes','chrome,resizable,modal',
1234 { 'copy_id' : g.copies[0].id() }
1238 /******************************************************************************************************/
1239 /* hides or unhides stat cats based on library stat cat filter menu */
1240 g.toggle_stat_cat_display = function(el) {
1242 var visible = el.getAttribute('checked');
1243 var nl = document.getElementsByAttribute('sc_lib',el.getAttribute('value'));
1244 for (var n = 0; n < nl.length; n++) {
1246 nl[n].setAttribute('hidden','false');
1248 nl[n].setAttribute('hidden','true');
1251 g.copy_editor_prefs[ el.getAttribute('id') ] = { 'checked' : visible };
1252 g.save_attributes();
1255 /******************************************************************************************************/
1256 /* This adds a stat cat definition to the stat cat pane for rendering */
1257 g.save_attributes = function() {
1258 JSAN.use('util.widgets'); JSAN.use('util.file'); var file = new util.file('copy_editor_prefs.'+g.data.server_unadorned);
1259 var what_to_save = {};
1260 for (var i in g.copy_editor_prefs) {
1261 what_to_save[i] = [];
1262 for (var j in g.copy_editor_prefs[i]) what_to_save[i].push(j);
1264 util.widgets.save_attributes(file, what_to_save );
1267 /******************************************************************************************************/
1268 /* This adds a stat cat definition to the stat cat pane for rendering */
1269 g.add_stat_cat = function(sc) {
1271 if (typeof g.data.hash.asc == 'undefined') { g.data.hash.asc = {}; g.data.stash('hash'); }
1275 if (typeof sc == 'object') {
1280 if (typeof g.stat_cat_seen[sc_id] != 'undefined') { return; }
1282 g.stat_cat_seen[ sc_id ] = 1;
1284 if (typeof sc != 'object') {
1286 sc = g.network.simple_request(
1287 'FM_ASC_BATCH_RETRIEVE',
1288 [ ses(), [ sc_id ] ]
1293 g.data.hash.asc[ sc.id() ] = sc; g.data.stash('hash');
1295 var label_name = g.data.hash.aou[ sc.owner() ].shortname() + " : " + sc.name();
1300 render: 'var l = util.functional.find_list( fm.stat_cat_entries(), function(e){ return e.stat_cat() == '
1301 + sc.id() + '; } ); l ? l.value() : "<Unset>";',
1302 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()
1303 + '].entries(), function(obj){ return [ obj.value(), obj.id() ]; } ) ).sort() ); '
1304 + 'x.addEventListener("apply",function(f){ return function(ev) { f(ev.target.value); } }(c),false);',
1311 g.panes_and_field_names.right_pane4.push( temp_array );
1313 g.error.standard_unexpected_error_alert('Error adding stat cat to display definition',E);
1317 /******************************************************************************************************/
1318 /* Add stat cats to the panes_and_field_names.right_pane4 */
1319 g.populate_stat_cats = function() {
1321 g.data.stash_retrieve();
1322 g.stat_cat_seen = {};
1324 function get(lib_id,only_these) {
1325 g.data.stash_retrieve();
1326 var label = 'asc_list_for_lib_'+lib_id;
1327 if (typeof g.data[label] == 'undefined') {
1328 var robj = g.network.simple_request('FM_ASC_RETRIEVE_VIA_AOU', [ ses(), lib_id ]);
1329 if (typeof robj.ilsevent != 'undefined') throw(robj);
1331 for (var j = 0; j < robj.length; j++) {
1332 var my_asc = robj[j];
1333 if (typeof g.data.hash.asc == 'undefined') { g.data.hash.asc = {}; }
1334 if (typeof g.data.hash.asc[ my_asc.id() ] == 'undefined') {
1335 g.data.hash.asc[ my_asc.id() ] = my_asc;
1337 var only_this_lib = my_asc.owner(); if (typeof only_this_lib == 'object') only_this_lib = only_this_lib.id();
1338 if (only_these.indexOf( String( only_this_lib ) ) != -1) {
1339 temp_list.push( my_asc );
1342 g.data[label] = temp_list; g.data.stash(label,'hash','list');
1344 return g.data[label];
1347 /* The stat cats for the pertinent library -- this is based on workstation ou */
1348 var label = 'asc_list_for_' + typeof g.data.ws_ou == 'object' ? g.data.ws_ou.id() : g.data.ws_ou;
1349 g.data[ label ] = g.data.list.my_asc; g.data.stash('label');
1350 for (var i = 0; i < g.data.list.my_asc.length; i++) {
1351 g.add_stat_cat( g.data.list.my_asc[i] );
1354 /* For the others, we want to consider the owning libs, circ libs, and any libs that have stat cats already on the copies,
1355 however, if batch editing, we only want to show the ones they have in common. So let's compile the libs */
1357 function add_common_ancestors(sc_libs) {
1358 JSAN.use('util.fm_utils');
1359 var libs = []; for (var i in sc_libs) libs.push(i);
1360 var ancestor = util.fm_utils.find_common_aou_ancestor( libs );
1361 if (typeof ancestor == 'object' && ancestor != null) ancestor = ancestor.id();
1363 var ancestors = util.fm_utils.find_common_aou_ancestors( libs );
1364 var asc_list = get(ancestor, ancestors);
1365 for (var i = 0; i < asc_list.length; i++) {
1366 g.add_stat_cat( asc_list[i] );
1371 /* stat cats based on stat cat entries present on these copies */
1373 for (var i = 0; i < g.copies.length; i++) {
1374 var entries = g.copies[i].stat_cat_entries();
1375 if (!entries) entries = [];
1376 for (var j = 0; j < entries.length; j++) {
1377 var lib = entries[j].owner(); if (typeof lib == 'object') lib = lib.id();
1378 sc_libs[ lib ] = true;
1381 add_common_ancestors(sc_libs); // CAVEAT - if a copy has no stat_cat_entries, it basically gets no vote here
1383 /* stat cats based on Circ Lib */
1385 for (var i = 0; i < g.copies.length; i++) {
1386 var circ_lib = g.copies[i].circ_lib(); if (typeof circ_lib == 'object') circ_lib = circ_lib.id();
1387 sc_libs[ circ_lib ] = true;
1389 add_common_ancestors(sc_libs);
1391 /* stat cats based on Owning Lib */
1393 for (var i = 0; i < g.copies.length; i++) {
1394 var cn_id = g.copies[i].call_number();
1396 if (! g.map_acn[ cn_id ]) {
1397 var req = g.network.simple_request('FM_ACN_RETRIEVE.authoritative',[ cn_id ]);
1398 if (typeof req.ilsevent == 'undefined') {
1399 g.map_acn[ cn_id ] = req;
1404 var owning_lib = g.map_acn[ cn_id ].owning_lib(); if (typeof owning_lib == 'object') owning_lib = owning_lib.id();
1405 sc_libs[ owning_lib ] = true;
1408 add_common_ancestors(sc_libs); // CAVEAT - if a copy is a pre-cat, it basically gets no vote here
1410 g.panes_and_field_names.right_pane4.sort();
1413 g.error.standard_unexpected_error_alert('Error populating stat cats for display',E);