Add 100$e (relator) and 711$c (Location of meeting) to controlled field map
[working/Evergreen.git] / Open-ILS / xul / staff_client / server / cat / marcedit.js
1 // vim: noet:sw=4:ts=4:
2 var xmlDeclaration = /^<\?xml version[^>]+?>/;
3
4 var serializer = new XMLSerializer();
5 var marcns = new Namespace("http://www.loc.gov/MARC21/slim");
6 var gw = new Namespace("http://opensrf.org/-/namespaces/gateway/v1");
7 var xulns = new Namespace("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
8 default xml namespace = marcns;
9
10 var tooltip_hash = {};
11 var current_focus;
12 var _record;
13 var _record_type;
14 var bib_data;
15
16 var xml_record;
17
18 var context_menus;
19 var tag_menu;
20 var p;
21
22 function $(id) { return document.getElementById(id); }
23
24 function mangle_005() {
25     var now = new Date();
26     var y = now.getUTCFullYear();
27
28     var m = now.getUTCMonth() + 1;
29     if (m < 10) m = '0' + m;
30     
31     var d = now.getUTCDate();
32     if (d < 10) d = '0' + d;
33     
34     var H = now.getUTCHours();
35     if (H < 10) H = '0' + H;
36     
37     var M = now.getUTCMinutes();
38     if (M < 10) M = '0' + M;
39     
40     var S = now.getUTCSeconds();
41     if (S < 10) S = '0' + S;
42     
43
44     var stamp = '' + y + m + d + H + M + S + '.0';
45     createControlField('005',stamp);
46
47 }
48
49 function createControlField (tag,data) {
50     // first, remove the old field, if any;
51     for (var i in xml_record.controlfield.(@tag == tag)) delete xml_record.controlfield.(@tag == tag)[i];
52
53     var cf = <controlfield tag="" xmlns="http://www.loc.gov/MARC21/slim">{ data }</controlfield>;
54     cf.@tag = tag;
55
56     // then, find the right position and insert it
57     var done = 0;
58     var cfields = xml_record.controlfield;
59     var base = Number(tag.substring(2));
60     for (var i in cfields) {
61         var t = Number(cfields[i].@tag.toString().substring(2));
62         if (t > base) {
63             xml_record.insertChildBefore( cfields[i], cf );
64             done = 1
65             break;
66         }
67     }
68
69     if (!done) xml_record.insertChildBefore( xml_record.datafield[0], cf );
70
71     return cf;
72 }
73
74 function xml_escape_unicode ( str ) {
75     return str.replace(
76         /([\u0080-\ufffe])/g,
77         function (r,s) { return "&#x" + s.charCodeAt(0).toString(16) + ";"; }
78     );
79 }
80
81 function wrap_long_fields (node) {
82     var text_size = dojo.attr(node, 'size');
83     var hard_width = 100; 
84     if (text_size > hard_width) {
85         dojo.attr(node, 'multiline', 'true');
86         dojo.attr(node, 'cols', hard_width);
87         var text_rows = (text_size / hard_width) + 1;
88         dojo.attr(node, 'rows', text_rows);
89     }
90 }
91
92 function swap_editors () {
93
94     dojo.require('MARC.Record');
95
96     var xe = $('xul-editor');
97     var te = $('text-editor');
98
99     te.hidden = te.hidden ? false : true;
100     xe.hidden = xe.hidden ? false : true;
101
102     if (te.hidden) {
103         // get the marcxml from the text box
104         var xml_string = new MARC.Record({
105             marcbreaker : $('text-editor-box').value,
106             delimiter : '$'
107         }).toXmlString();
108
109         // reset the xml record and rerender it
110         xml_record = new XML( xml_string );
111         loadRecord(xml_record);
112     } else {
113         var xml_string = xml_record.toXMLString();
114
115         // push the xml record into the textbox
116         var rec = new MARC.Record ({ delimiter : '$', marcxml : xml_string });
117         $('text-editor-box').value = rec.toBreaker();
118     }
119 }
120
121 function my_init() {
122     try {
123
124         netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
125         if (typeof JSAN == 'undefined') { throw( $("commonStrings").getString('common.jsan.missing') ); }
126         JSAN.errorLevel = "die"; // none, warn, or die
127         JSAN.addRepository('/xul/server/');
128
129         // Fake xulG for standalone...
130         try {
131             window.xulG.record;
132         } catch (e) {
133             window.xulG = {};
134             window.xulG.record = {};
135             window.xulG.save = {};
136
137             window.xulG.save.label = $('catStrings').getString('staff.cat.marcedit.save.label');
138             window.xulG.save.func = function (r) { alert(r); }
139
140             var cgi = new CGI();
141             var _rid = cgi.param('record');
142             if (_rid) {
143                 window.xulG.record.url = '/opac/extras/supercat/retrieve/marcxml/record/' + _rid;
144             }
145         }
146         // End faking part...
147
148         document.getElementById('save-button').setAttribute('label', window.xulG.save.label);
149         document.getElementById('save-button').setAttribute('oncommand',
150             'if ($("xul-editor").hidden) swap_editors(); ' +
151             'mangle_005(); ' + 
152             'var xml_string = xml_escape_unicode( xml_record.toXMLString() ); ' + 
153             'save_attempt( xml_string ); ' +
154             'loadRecord(xml_record);'
155         );
156
157         if (window.xulG.record.url) {
158             var req =  new XMLHttpRequest();
159             req.open('POST',window.xulG.record.url,false);
160             req.send(null);
161             window.xulG.record.marc = req.responseText.replace(xmlDeclaration, '');
162         }
163
164         xml_record = new XML( window.xulG.record.marc );
165         if (xml_record..record[0]) xml_record = xml_record..record[0];
166
167         // Get the tooltip xml all async like
168         req =  new XMLHttpRequest();
169
170         // Set a default locale in case preferences fail us
171         var locale = "en-US";
172
173         // Try to get the locale from our preferences
174         netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
175         try {
176             const Cc = Components.classes;
177             const Ci = Components.interfaces;
178             locale = Cc["@mozilla.org/preferences-service;1"].
179                 getService(Ci.nsIPrefBranch).
180                 getCharPref("general.useragent.locale");
181         }
182         catch (e) { }
183
184         // TODO: We should send a HEAD request to check for the existence of the desired file
185         // then fall back to the default locale if preferred locale is not necessary;
186         // however, for now we have a simplistic check:
187         //
188         // we currently have translations for only two locales; in the absence of a
189         // valid locale, default to the almighty en-US
190         if (locale != 'en-US' && locale != 'fr-CA') {
191             locale = 'en-US';
192         }
193
194         // Get the locale-specific tooltips
195         req.open('GET','/xul/server/locale/' + locale + '/marcedit-tooltips.xml',true);
196
197         context_menus = createComplexXULElement('popupset');
198         document.documentElement.appendChild( context_menus );
199
200         tag_menu = createPopup({position : 'after_start', id : 'tags_popup'});
201         context_menus.appendChild( tag_menu );
202
203         tag_menu.appendChild(
204             createMenuitem(
205                 { label : $('catStrings').getString('staff.cat.marcedit.add_row.label'),
206                   oncommand : 
207                     'var e = document.createEvent("KeyEvents");' +
208                     'e.initKeyEvent("keypress",1,1,null,1,0,0,0,13,0);' +
209                     'current_focus.inputField.dispatchEvent(e);'
210                  }
211             )
212         );
213
214         tag_menu.appendChild(
215             createMenuitem(
216                 { label : $('catStrings').getString('staff.cat.marcedit.insert_row.label'),
217                   oncommand : 
218                     'var e = document.createEvent("KeyEvents");' +
219                     'e.initKeyEvent("keypress",1,1,null,1,0,1,0,13,0);' +
220                     'current_focus.inputField.dispatchEvent(e);'
221                  }
222             )
223         );
224
225         tag_menu.appendChild(
226             createMenuitem(
227                 { label : $('catStrings').getString('staff.cat.marcedit.remove_row.label'),
228                   oncommand : 
229                     'var e = document.createEvent("KeyEvents");' +
230                     'e.initKeyEvent("keypress",1,1,null,1,0,0,0,46,0);' +
231                     'current_focus.inputField.dispatchEvent(e);'
232                 }
233             )
234         );
235
236         tag_menu.appendChild( createComplexXULElement( 'separator' ) );
237
238         tag_menu.appendChild(
239             createMenuitem(
240                 { label : $('catStrings').getString('staff.cat.marcedit.replace_006.label'),
241                   oncommand : 
242                     'var e = document.createEvent("KeyEvents");' +
243                     'e.initKeyEvent("keypress",1,1,null,1,0,0,0,64,0);' +
244                     'current_focus.inputField.dispatchEvent(e);'
245                  }
246             )
247         );
248
249         tag_menu.appendChild(
250             createMenuitem(
251                 { label : $('catStrings').getString('staff.cat.marcedit.replace_007.label'),
252                   oncommand : 
253                     'var e = document.createEvent("KeyEvents");' +
254                     'e.initKeyEvent("keypress",1,1,null,1,0,0,0,65,0);' +
255                     'current_focus.inputField.dispatchEvent(e);'
256                 }
257             )
258         );
259
260         tag_menu.appendChild(
261             createMenuitem(
262                 { label : $('catStrings').getString('staff.cat.marcedit.replace_008.label'),
263                   oncommand : 
264                     'var e = document.createEvent("KeyEvents");' +
265                     'e.initKeyEvent("keypress",1,1,null,1,0,0,0,66,0);' +
266                     'current_focus.inputField.dispatchEvent(e);'
267                 }
268             )
269         );
270
271         tag_menu.appendChild( createComplexXULElement( 'separator' ) );
272
273         p = createComplexXULElement('popupset');
274         document.documentElement.appendChild( p );
275
276         req.onreadystatechange = function () {
277             if (req.readyState == 4) {
278                 bib_data = new XML( req.responseText.replace(xmlDeclaration, '') );
279                 genToolTips();
280             }
281         }
282         req.send(null);
283
284         loadRecord(xml_record);
285
286         if (! xulG.fast_add_item) {
287             document.getElementById('fastItemAdd_checkbox').hidden = true;
288         }
289         document.getElementById('fastItemAdd_textboxes').hidden = document.getElementById('fastItemAdd_checkbox').hidden || !document.getElementById('fastItemAdd_checkbox').checked;
290
291     } catch(E) {
292         alert('FIXME, MARC Editor, my_init: ' + E);
293     }
294 }
295
296
297 function createComplexHTMLElement (e, attrs, objects, text) {
298     var l = document.createElementNS('http://www.w3.org/1999/xhtml',e);
299
300     if (attrs) {
301         for (var i in attrs) l.setAttribute(i,attrs[i]);
302     }
303
304     if (objects) {
305         for ( var i in objects ) l.appendChild( objects[i] );
306     }
307
308     if (text) {
309         l.appendChild( document.createTextNode(text) )
310     }
311
312     return l;
313 }
314
315 function createComplexXULElement (e, attrs, objects) {
316     var l = document.createElementNS('http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul',e);
317
318     if (attrs) {
319         for (var i in attrs) {
320             if (typeof attrs[i] == 'function') {
321                 l.addEventListener( i, attrs[i], true );
322             } else {
323                 l.setAttribute(i,attrs[i]);
324             }
325         }
326     } 
327
328     if (objects) {
329         for ( var i in objects ) l.appendChild( objects[i] );
330     }
331
332     return l;
333 }
334
335 function createDescription (attrs) {
336     return createComplexXULElement('description', attrs, Array.prototype.slice.apply(arguments, [1]) );
337 }
338
339 function createTooltip (attrs) {
340     return createComplexXULElement('tooltip', attrs, Array.prototype.slice.apply(arguments, [1]) );
341 }
342
343 function createLabel (attrs) {
344     return createComplexXULElement('label', attrs, Array.prototype.slice.apply(arguments, [1]) );
345 }
346
347 function createVbox (attrs) {
348     return createComplexXULElement('vbox', attrs, Array.prototype.slice.apply(arguments, [1]) );
349 }
350
351 function createHbox (attrs) {
352     return createComplexXULElement('hbox', attrs, Array.prototype.slice.apply(arguments, [1]) );
353 }
354
355 function createRow (attrs) {
356     return createComplexXULElement('row', attrs, Array.prototype.slice.apply(arguments, [1]) );
357 }
358
359 function createTextbox (attrs) {
360     return createComplexXULElement('textbox', attrs, Array.prototype.slice.apply(arguments, [1]) );
361 }
362
363 function createMenu (attrs) {
364     return createComplexXULElement('menu', attrs, Array.prototype.slice.apply(arguments, [1]) );
365 }
366
367 function createMenuPopup (attrs) {
368     return createComplexXULElement('menupopup', attrs, Array.prototype.slice.apply(arguments, [1]) );
369 }
370
371 function createPopup (attrs) {
372     return createComplexXULElement('popup', attrs, Array.prototype.slice.apply(arguments, [1]) );
373 }
374
375 function createMenuitem (attrs) {
376     return createComplexXULElement('menuitem', attrs, Array.prototype.slice.apply(arguments, [1]) );
377 }
378
379 function createCheckbox (attrs) {
380     return createComplexXULElement('checkbox', attrs, Array.prototype.slice.apply(arguments, [1]) );
381 }
382
383 // Find the next textbox that we can use for a focus point
384 // For control fields, use the first editable text box
385 // For data fields, focus on the first subfield text box
386 function setFocusToNextTag (row, direction) {
387     var keep_looking = true;
388     while (keep_looking && (direction == 'up' ? row = row.previousSibling : row = row.nextSibling)) {
389         // Is it a datafield?
390         dojo.query('hbox hbox textbox', row).forEach(function(node, index, arr) {
391             node.focus();
392             keep_looking = false;
393         });
394
395         // No, it's a control field; use the first textbox
396         if (keep_looking) {
397             dojo.query('textbox', row).forEach(function(node, index, arr) {
398                 node.focus();
399                 keep_looking = false;
400             });
401         }
402     }
403
404     return true;
405 }
406
407
408 function createMARCTextbox (element,attrs) {
409
410     var box = createComplexXULElement('textbox', attrs, Array.prototype.slice.apply(arguments, [2]) );
411     box.onkeypress = function (event) {
412         var root_node;
413         var node = element;
414         while(node = node.parent()) {
415             root_node = node;
416         }
417
418         var row = event.target;
419         while (row.tagName != 'row') row = row.parentNode;
420
421         if (element.nodeKind() == 'attribute') element[0]=box.value;
422         else element.setChildren( box.value );
423
424         if (element.localName() != 'controlfield') {
425             if ((event.charCode == 100 || event.charCode == 105) && event.ctrlKey) { // ctrl+d or ctrl+i
426
427                 var index_sf, target, move_data;
428                 if (element.localName() == 'subfield') {
429                     index_sf = element;
430                     target = event.target.parentNode;
431
432                     var start = event.target.selectionStart;
433                     var end = event.target.selectionEnd - event.target.selectionStart ?
434                             event.target.selectionEnd :
435                             event.target.value.length;
436
437                     move_data = event.target.value.substring(start,end);
438                     event.target.value = event.target.value.substring(0,start) + event.target.value.substring(end);
439                     event.target.setAttribute('size', event.target.value.length + 2);
440     
441                     element.setChildren( event.target.value );
442
443                 } else if (element.localName() == 'code') {
444                     index_sf = element.parent();
445                     target = event.target.parentNode;
446                 } else if (element.localName() == 'tag' || element.localName() == 'ind1' || element.localName() == 'ind2') {
447                     index_sf = element.parent().children()[element.parent().children().length() - 1];
448                     target = event.target.parentNode.lastChild.lastChild;
449                 }
450
451                 var sf = <subfield code="" xmlns="http://www.loc.gov/MARC21/slim">{ move_data }</subfield>;
452
453                 index_sf.parent().insertChildAfter( index_sf, sf );
454
455                 var new_sf = marcSubfield(sf);
456
457                 if (target === target.parentNode.lastChild) {
458                     target.parentNode.appendChild( new_sf );
459                 } else {
460                     target.parentNode.insertBefore( new_sf, target.nextSibling );
461                 }
462
463                 new_sf.firstChild.nextSibling.focus();
464
465                 event.preventDefault();
466                 return false;
467
468             } else if (event.keyCode == 13 || event.keyCode == 77) {
469                 if (event.ctrlKey) { // ctrl+enter
470
471                     var index;
472                     if (element.localName() == 'subfield') index = element.parent();
473                     if (element.localName() == 'code') index = element.parent().parent();
474                     if (element.localName() == 'tag') index = element.parent();
475                     if (element.localName() == 'ind1') index = element.parent();
476                     if (element.localName() == 'ind2') index = element.parent();
477
478                     var df = <datafield tag="" ind1="" ind2="" xmlns="http://www.loc.gov/MARC21/slim"><subfield code="" /></datafield>;
479
480                     if (event.shiftKey) { // ctrl+shift+enter
481                         index.parent().insertChildBefore( index, df );
482                     } else {
483                         index.parent().insertChildAfter( index, df );
484                     }
485
486                     var new_df = marcDatafield(df);
487
488                     if (row.parentNode.lastChild === row) {
489                         row.parentNode.appendChild( new_df );
490                     } else {
491                         if (event.shiftKey) { // ctrl+shift+enter
492                             row.parentNode.insertBefore( new_df, row );
493                         } else {
494                             row.parentNode.insertBefore( new_df, row.nextSibling );
495                         }
496                     }
497
498                     new_df.firstChild.focus();
499
500                     event.preventDefault();
501                     return false;
502
503                 } else if (event.shiftKey) {
504                     if (row.previousSibling.className.match('marcDatafieldRow'))
505                         row.previousSibling.firstChild.focus();
506                 } else {
507                     row.nextSibling.firstChild.focus();
508                 }
509
510             } else if (event.keyCode == 38 || event.keyCode == 40) { // up-arrow or down-arrow
511                 if (event.ctrlKey) { // CTRL key: copy the field
512                     var index;
513                     if (element.localName() == 'subfield') index = element.parent();
514                     if (element.localName() == 'code') index = element.parent().parent();
515                     if (element.localName() == 'tag') index = element.parent();
516                     if (element.localName() == 'ind1') index = element.parent();
517                     if (element.localName() == 'ind2') index = element.parent();
518
519                     var copyField = index.copy();
520
521                     if (event.keyCode == 38) { // ctrl+up-arrow
522                         index.parent().insertChildBefore( index, copyField );
523                     } else {
524                         index.parent().insertChildAfter( index, copyField );
525                     }
526
527                     var new_df = marcDatafield(copyField);
528
529                     if (row.parentNode.lastChild === row) {
530                         row.parentNode.appendChild( new_df );
531                     } else {
532                         if (event.keyCode == 38) { // ctrl+up-arrow
533                             row.parentNode.insertBefore( new_df, row );
534                         } else { // ctrl+down-arrow
535                             row.parentNode.insertBefore( new_df, row.nextSibling );
536                         }
537                     }
538
539                     new_df.firstChild.focus();
540
541                     event.preventDefault();
542
543                     return false;
544                 } else {
545                     if (event.keyCode == 38) {
546                         return setFocusToNextTag(row, 'up');
547                     }
548                     if (event.keyCode == 40) {
549                         return setFocusToNextTag(row, 'down');
550                     }
551                     return false;
552                 }
553
554             } else if (event.keyCode == 46 && event.ctrlKey) { // ctrl+del
555
556                 var index;
557                 if (element.localName() == 'subfield') index = element.parent();
558                 if (element.localName() == 'code') index = element.parent().parent();
559                 if (element.localName() == 'tag') index = element.parent();
560                 if (element.localName() == 'ind1') index = element.parent();
561                 if (element.localName() == 'ind2') index = element.parent();
562
563                 for (var i in index.parent().children()) {
564                     if (index === index.parent().children()[i]) {
565                         delete index.parent().children()[i];
566                         break;
567                     }
568                 }
569
570                 row.previousSibling.firstChild.focus();
571                 row.parentNode.removeChild(row);
572
573                 event.preventDefault();
574                 return false;
575
576             } else if (event.keyCode == 46 && event.shiftKey) { // shift+del
577
578                 var index;
579                 if (element.localName() == 'subfield') index = element;
580                 if (element.localName() == 'code') index = element.parent();
581
582                 if (index) {
583                     for (var i in index.parent().children()) {
584                         if (index === index.parent().children()[i]) {
585                             delete index.parent().children()[i];
586                             break;
587                         }
588                     }
589
590                     if (event.target.parentNode === event.target.parentNode.parentNode.lastChild) {
591                         event.target.parentNode.previousSibling.lastChild.focus();
592                     } else {
593                         event.target.parentNode.nextSibling.firstChild.nextSibling.focus();
594                     }
595
596                     event.target.parentNode.parentNode.removeChild(event.target.parentNode);
597
598                     event.preventDefault();
599                     return false;
600                 }
601             } else if (event.keyCode == 64 && event.ctrlKey) { // ctrl + F6
602                 createControlField('006','                                        ');
603                 loadRecord(xml_record);
604             } else if (event.keyCode == 65 && event.ctrlKey) { // ctrl + F7
605                 createControlField('007','                                        ');
606                 loadRecord(xml_record);
607             } else if (event.keyCode == 66 && event.ctrlKey) { // ctrl + F8
608                 createControlField('008','                                        ');
609                 loadRecord(xml_record);
610             }
611
612             return true;
613
614         } else { // event on a control field
615             if (event.keyCode == 38) { 
616                 return setFocusToNextTag(row, 'up'); 
617             } else if (event.keyCode == 40) { 
618                 return setFocusToNextTag(row, 'down');
619             }
620         }
621     };
622
623     box.addEventListener(
624         'keypress', 
625         function () {
626             if (element.nodeKind() == 'attribute') element[0]=box.value;
627             else element.setChildren( box.value );
628             return true;
629         },
630         false
631     );
632
633     box.addEventListener(
634         'change', 
635         function () {
636             if (element.nodeKind() == 'attribute') element[0]=box.value;
637             else element.setChildren( box.value );
638             return true;
639         },
640         false
641     );
642
643     box.addEventListener(
644         'keypress', 
645         function () {
646             if (element.nodeKind() == 'attribute') element[0]=box.value;
647             else element.setChildren( box.value );
648             return true;
649         },
650         true
651     );
652
653     box.addEventListener(
654         'keyup', 
655         function () {
656             if (element.localName() == 'controlfield')
657                 eval('fillFixedFields(xml_record);');
658         },
659         true
660     );
661
662     return box;
663 }
664
665 var rec_type = {
666     BKS : { Type : /[at]{1}/,    BLvl : /[acdm]{1}/ },
667     SER : { Type : /[a]{1}/,    BLvl : /[bs]{1}/ },
668     VIS : { Type : /[gkro]{1}/,    BLvl : /[abcdms]{1}/ },
669     MIX : { Type : /[p]{1}/,    BLvl : /[cd]{1}/ },
670     MAP : { Type : /[ef]{1}/,    BLvl : /[abcdms]{1}/ },
671     SCO : { Type : /[cd]{1}/,    BLvl : /[abcdms]{1}/ },
672     REC : { Type : /[ij]{1}/,    BLvl : /[abcdms]{1}/ },
673     COM : { Type : /[m]{1}/,    BLvl : /[abcdms]{1}/ }
674 };
675
676 var ff_pos = {
677     TrAr : {
678         _8 : {
679             SCO : {start : 33, len : 1, def : ' ' },
680             REC : {start : 33, len : 1, def : 'n' }
681         },
682         _6 : {
683             SCO : {start : 16, len : 1, def : ' ' },
684             REC : {start : 16, len : 1, def : 'n' }
685         }
686     },
687     TMat : {
688         _8 : {
689             VIS : {start : 33, len : 1, def : ' ' }
690         },
691         _6 : {
692             VIS : {start : 16, len : 1, def : ' ' }
693         }
694     },
695     Time : {
696         _8 : {
697             VIS : {start : 18, len : 3, def : ' ' }
698         },
699         _6 : {
700             VIS : {start : 1, len : 3, def : ' ' }
701         }
702     },
703     Tech : {
704         _8 : {
705             VIS : {start : 34, len : 1, def : 'n' }
706         },
707         _6 : {
708             VIS : {start : 17, len : 1, def : 'n' }
709         }
710     },
711     SrTp : {
712         _8 : {
713             SER : {start : 21, len : 1, def : ' ' }
714         },
715         _6 : {
716             SER : {start : 4, len : 1, def : ' ' }
717         }
718     },
719     Srce : {
720         _8 : {
721             BKS : {start : 39, len : 1, def : 'd' },
722             SER : {start : 39, len : 1, def : 'd' },
723             VIS : {start : 39, len : 1, def : 'd' },
724             MIX : {start : 39, len : 1, def : 'd' },
725             MAP : {start : 39, len : 1, def : 'd' },
726             SCO : {start : 39, len : 1, def : 'd' },
727             REC : {start : 39, len : 1, def : 'd' },
728             COM : {start : 39, len : 1, def : 'd' }
729         }
730     },
731     SpFm : {
732         _8 : {
733             MAP : {start : 33, len : 2, def : ' ' }
734         },
735         _6 : {
736             MAP : {start : 16, len : 2, def : ' ' }
737         }
738     },
739     Relf : {
740         _8 : {
741             MAP : {start : 18, len : 4, def : ' ' }
742         },
743         _6 : {
744             MAP : {start : 1, len : 4, def : ' ' }
745         }
746     },
747     Regl : {
748         _8 : {
749             SER : {start : 19, len : 1, def : ' ' }
750         },
751         _6 : {
752             SER : {start : 2, len : 1, def : ' ' }
753         }
754     },
755     Proj : {
756         _8 : {
757             MAP : {start : 22, len : 2, def : ' ' }
758         },
759         _6 : {
760             MAP : {start : 5, len : 2, def : ' ' }
761         }
762     },
763     Part : {
764         _8 : {
765             SCO : {start : 21, len : 1, def : ' ' },
766             REC : {start : 21, len : 1, def : 'n' }
767         },
768         _6 : {
769             SCO : {start : 4, len : 1, def : ' ' },
770             REC : {start : 4, len : 1, def : 'n' }
771         }
772     },
773     Orig : {
774         _8 : {
775             SER : {start : 22, len : 1, def : ' ' }
776         },
777         _6 : {
778             SER : {start : 5, len : 1, def : ' ' }
779         }
780     },
781     LTxt : {
782         _8 : {
783             SCO : {start : 30, len : 2, def : ' ' },
784             REC : {start : 30, len : 2, def : ' ' }
785         },
786         _6 : {
787             SCO : {start : 13, len : 2, def : ' ' },
788             REC : {start : 13, len : 2, def : ' ' }
789         }
790     },
791     Freq : {
792         _8 : {
793             SER : {start : 18, len : 1, def : ' ' }
794         },
795         _6 : {
796             SER : {start : 1, len : 1, def : ' ' }
797         }
798     },
799     FMus : {
800         _8 : {
801             SCO : {start : 20, len : 1, def : ' ' },
802             REC : {start : 20, len : 1, def : 'n' }
803         },
804         _6 : {
805             SCO : {start : 3, len : 1, def : ' ' },
806             REC : {start : 3, len : 1, def : 'n' }
807         }
808     },
809     File : {
810         _8 : {
811             COM : {start : 26, len : 1, def : 'u' }
812         },
813         _6 : {
814             COM : {start : 9, len : 1, def : 'u' }
815         }
816     },
817     EntW : {
818         _8 : {
819             SER : {start : 24, len : 1, def : ' ' }
820         },
821         _6 : {
822             SER : {start : 7, len : 1, def : ' ' }
823         }
824     },
825     AccM : {
826         _8 : {
827             SCO : {start : 24, len : 6, def : ' ' },
828             REC : {start : 24, len : 6, def : ' ' }
829         },
830         _6 : {
831             SCO : {start : 7, len : 6, def : ' ' },
832             REC : {start : 7, len : 6, def : ' ' }
833         }
834     },
835     Comp : {
836         _8 : {
837             SCO : {start : 18, len : 2, def : ' ' },
838             REC : {start : 18, len : 2, def : ' ' }
839         },
840         _6 : {
841             SCO : {start : 1, len : 2, def : ' ' },
842             REC : {start : 1, len : 2, def : ' ' }
843         }
844     },
845     CrTp : {
846         _8 : {
847             MAP : {start : 25, len : 1, def : ' ' }
848         },
849         _6 : {
850             MAP : {start : 8, len : 1, def : ' ' }
851         }
852     },
853     Ctry : {
854         _8 : {
855             BKS : {start : 15, len : 3, def : ' ' },
856             SER : {start : 15, len : 3, def : ' ' },
857             VIS : {start : 15, len : 3, def : ' ' },
858             MIX : {start : 15, len : 3, def : ' ' },
859             MAP : {start : 15, len : 3, def : ' ' },
860             SCO : {start : 15, len : 3, def : ' ' },
861             REC : {start : 15, len : 3, def : ' ' },
862             COM : {start : 15, len : 3, def : ' ' }
863         }
864     },
865     Lang : {
866         _8 : {
867             BKS : {start : 35, len : 3, def : ' ' },
868             SER : {start : 35, len : 3, def : ' ' },
869             VIS : {start : 35, len : 3, def : ' ' },
870             MIX : {start : 35, len : 3, def : ' ' },
871             MAP : {start : 35, len : 3, def : ' ' },
872             SCO : {start : 35, len : 3, def : ' ' },
873             REC : {start : 35, len : 3, def : ' ' },
874             COM : {start : 35, len : 3, def : ' ' }
875         }
876     },
877     MRec : {
878         _8 : {
879             BKS : {start : 38, len : 1, def : ' ' },
880             SER : {start : 38, len : 1, def : ' ' },
881             VIS : {start : 38, len : 1, def : ' ' },
882             MIX : {start : 38, len : 1, def : ' ' },
883             MAP : {start : 38, len : 1, def : ' ' },
884             SCO : {start : 38, len : 1, def : ' ' },
885             REC : {start : 38, len : 1, def : ' ' },
886             COM : {start : 38, len : 1, def : ' ' }
887         }
888     },
889     DtSt : {
890         _8 : {
891             BKS : {start : 6, len : 1, def : ' ' },
892             SER : {start : 6, len : 1, def : 'c' },
893             VIS : {start : 6, len : 1, def : ' ' },
894             MIX : {start : 6, len : 1, def : ' ' },
895             MAP : {start : 6, len : 1, def : ' ' },
896             SCO : {start : 6, len : 1, def : ' ' },
897             REC : {start : 6, len : 1, def : ' ' },
898             COM : {start : 6, len : 1, def : ' ' }
899         }
900     },
901     Type : {
902         ldr : {
903             BKS : {start : 6, len : 1, def : 'a' },
904             SER : {start : 6, len : 1, def : 'a' },
905             VIS : {start : 6, len : 1, def : 'g' },
906             MIX : {start : 6, len : 1, def : 'p' },
907             MAP : {start : 6, len : 1, def : 'e' },
908             SCO : {start : 6, len : 1, def : 'c' },
909             REC : {start : 6, len : 1, def : 'i' },
910             COM : {start : 6, len : 1, def : 'm' }
911         }
912     },
913     Ctrl : {
914         ldr : {
915             BKS : {start : 8, len : 1, def : ' ' },
916             SER : {start : 8, len : 1, def : ' ' },
917             VIS : {start : 8, len : 1, def : ' ' },
918             MIX : {start : 8, len : 1, def : ' ' },
919             MAP : {start : 8, len : 1, def : ' ' },
920             SCO : {start : 8, len : 1, def : ' ' },
921             REC : {start : 8, len : 1, def : ' ' },
922             COM : {start : 8, len : 1, def : ' ' }
923         }
924     },
925     BLvl : {
926         ldr : {
927             BKS : {start : 7, len : 1, def : 'm' },
928             SER : {start : 7, len : 1, def : 's' },
929             VIS : {start : 7, len : 1, def : 'm' },
930             MIX : {start : 7, len : 1, def : 'c' },
931             MAP : {start : 7, len : 1, def : 'm' },
932             SCO : {start : 7, len : 1, def : 'm' },
933             REC : {start : 7, len : 1, def : 'm' },
934             COM : {start : 7, len : 1, def : 'm' }
935         }
936     },
937     Desc : {
938         ldr : {
939             BKS : {start : 18, len : 1, def : ' ' },
940             SER : {start : 18, len : 1, def : ' ' },
941             VIS : {start : 18, len : 1, def : ' ' },
942             MIX : {start : 18, len : 1, def : ' ' },
943             MAP : {start : 18, len : 1, def : ' ' },
944             SCO : {start : 18, len : 1, def : ' ' },
945             REC : {start : 18, len : 1, def : ' ' },
946             COM : {start : 18, len : 1, def : ' ' }
947         }
948     },
949     ELvl : {
950         ldr : {
951             BKS : {start : 17, len : 1, def : ' ' },
952             SER : {start : 17, len : 1, def : ' ' },
953             VIS : {start : 17, len : 1, def : ' ' },
954             MIX : {start : 17, len : 1, def : ' ' },
955             MAP : {start : 17, len : 1, def : ' ' },
956             SCO : {start : 17, len : 1, def : ' ' },
957             REC : {start : 17, len : 1, def : ' ' },
958             COM : {start : 17, len : 1, def : ' ' }
959         }
960     },
961     Indx : {
962         _8 : {
963             BKS : {start : 31, len : 1, def : '0' },
964             MAP : {start : 31, len : 1, def : '0' }
965         },
966         _6 : {
967             BKS : {start : 14, len : 1, def : '0' },
968             MAP : {start : 14, len : 1, def : '0' }
969         }
970     },
971     Date1 : {
972         _8 : {
973             BKS : {start : 7, len : 4, def : ' ' },
974             SER : {start : 7, len : 4, def : ' ' },
975             VIS : {start : 7, len : 4, def : ' ' },
976             MIX : {start : 7, len : 4, def : ' ' },
977             MAP : {start : 7, len : 4, def : ' ' },
978             SCO : {start : 7, len : 4, def : ' ' },
979             REC : {start : 7, len : 4, def : ' ' },
980             COM : {start : 7, len : 4, def : ' ' }
981         }
982     },
983     Date2 : {
984         _8 : {
985             BKS : {start : 11, len : 4, def : ' ' },
986             SER : {start : 11, len : 4, def : '9' },
987             VIS : {start : 11, len : 4, def : ' ' },
988             MIX : {start : 11, len : 4, def : ' ' },
989             MAP : {start : 11, len : 4, def : ' ' },
990             SCO : {start : 11, len : 4, def : ' ' },
991             REC : {start : 11, len : 4, def : ' ' },
992             COM : {start : 11, len : 4, def : ' ' }
993         }
994     },
995     LitF : {
996         _8 : {
997             BKS : {start : 33, len : 1, def : '0' }
998         },
999         _6 : {
1000             BKS : {start : 16, len : 1, def : '0' }
1001         }
1002     },
1003     Biog : {
1004         _8 : {
1005             BKS : {start : 34, len : 1, def : ' ' }
1006         },
1007         _6 : {
1008             BKS : {start : 17, len : 1, def : ' ' }
1009         }
1010     },
1011     Ills : {
1012         _8 : {
1013             BKS : {start : 18, len : 4, def : ' ' }
1014         },
1015         _6 : {
1016             BKS : {start : 1, len : 4, def : ' ' }
1017         }
1018     },
1019     Fest : {
1020         _8 : {
1021             BKS : {start : 30, len : 1, def : '0' }
1022         },
1023         _6 : {
1024             BKS : {start : 13, len : 1, def : '0' }
1025         }
1026     },
1027     Conf : {
1028         _8 : {
1029             BKS : {start : 29, len : 1, def : '0' },
1030             SER : {start : 29, len : 1, def : '0' }
1031         },
1032         _6 : {
1033             BKS : {start : 12, len : 1, def : '0' },
1034             SER : {start : 12, len : 1, def : '0' }
1035         }
1036     },
1037     Cont : {
1038         _8 : {
1039             BKS : {start : 24, len : 4, def : ' ' },
1040             SER : {start : 25, len : 3, def : ' ' }
1041         },
1042         _6 : {
1043             BKS : {start : 7, len : 4, def : ' ' },
1044             SER : {start : 8, len : 3, def : ' ' }
1045         }
1046     },
1047     GPub : {
1048         _8 : {
1049             BKS : {start : 28, len : 1, def : ' ' },
1050             SER : {start : 28, len : 1, def : ' ' },
1051             VIS : {start : 28, len : 1, def : ' ' },
1052             MAP : {start : 28, len : 1, def : ' ' },
1053             COM : {start : 28, len : 1, def : ' ' }
1054         },
1055         _6 : {
1056             BKS : {start : 11, len : 1, def : ' ' },
1057             SER : {start : 11, len : 1, def : ' ' },
1058             VIS : {start : 11, len : 1, def : ' ' },
1059             MAP : {start : 11, len : 1, def : ' ' },
1060             COM : {start : 11, len : 1, def : ' ' }
1061         }
1062     },
1063     Audn : {
1064         _8 : {
1065             BKS : {start : 22, len : 1, def : ' ' },
1066             SER : {start : 22, len : 1, def : ' ' },
1067             VIS : {start : 22, len : 1, def : ' ' },
1068             SCO : {start : 22, len : 1, def : ' ' },
1069             REC : {start : 22, len : 1, def : ' ' },
1070             COM : {start : 22, len : 1, def : ' ' }
1071         },
1072         _6 : {
1073             BKS : {start : 5, len : 1, def : ' ' },
1074             SER : {start : 5, len : 1, def : ' ' },
1075             VIS : {start : 5, len : 1, def : ' ' },
1076             SCO : {start : 5, len : 1, def : ' ' },
1077             REC : {start : 5, len : 1, def : ' ' },
1078             COM : {start : 5, len : 1, def : ' ' }
1079         }
1080     },
1081     Form : {
1082         _8 : {
1083             BKS : {start : 23, len : 1, def : ' ' },
1084             SER : {start : 23, len : 1, def : ' ' },
1085             VIS : {start : 29, len : 1, def : ' ' },
1086             MIX : {start : 23, len : 1, def : ' ' },
1087             MAP : {start : 29, len : 1, def : ' ' },
1088             SCO : {start : 23, len : 1, def : ' ' },
1089             REC : {start : 23, len : 1, def : ' ' }
1090         },
1091         _6 : {
1092             BKS : {start : 6, len : 1, def : ' ' },
1093             SER : {start : 6, len : 1, def : ' ' },
1094             VIS : {start : 12, len : 1, def : ' ' },
1095             MIX : {start : 6, len : 1, def : ' ' },
1096             MAP : {start : 12, len : 1, def : ' ' },
1097             SCO : {start : 6, len : 1, def : ' ' },
1098             REC : {start : 6, len : 1, def : ' ' }
1099         }
1100     },
1101     'S/L' : {
1102         _8 : {
1103             SER : {start : 34, len : 1, def : '0' }
1104         },
1105         _6 : {
1106             SER : {start : 17, len : 1, def : '0' }
1107         }
1108     },
1109     'Alph' : {
1110         _8 : {
1111             SER : {start : 33, len : 1, def : ' ' }
1112         },
1113         _6 : {
1114             SER : {start : 16, len : 1, def : ' ' }
1115         }
1116     }
1117 };
1118
1119 function recordType (rec) {
1120     try {
1121         var _l = rec.leader.toString();
1122
1123         var _t = _l.substr(ff_pos.Type.ldr.BKS.start, ff_pos.Type.ldr.BKS.len);
1124         var _b = _l.substr(ff_pos.BLvl.ldr.BKS.start, ff_pos.BLvl.ldr.BKS.len);
1125
1126         for (var t in rec_type) {
1127             if (_t.match(rec_type[t].Type) && _b.match(rec_type[t].BLvl)) {
1128                 document.getElementById('recordTypeLabel').value = t;
1129                 _record_type = t;
1130                 return t;
1131             }
1132         }
1133
1134         // in case we don't have a valid record type ...
1135         _record_type = 'BKS';
1136         return _record_type;
1137
1138     } catch(E) {
1139         alert('FIXME, MARC Editor, recordType: ' + E);
1140     }
1141 }
1142
1143 function toggleFFE () {
1144     var grid = document.getElementById('leaderGrid');
1145     if (grid.hidden) {
1146         grid.hidden = false;
1147     } else {
1148         grid.hidden = true;
1149     }
1150     return true;
1151 }
1152
1153 function changeFFEditor (type) {
1154     var grid = document.getElementById('leaderGrid');
1155     grid.setAttribute('type',type);
1156
1157     // Hide FFEditor rows that we don't need for our current type
1158     // If all of the labels for a given row do not include our
1159     // desired type in their set attribute, we can hide that row
1160     dojo.query('rows row', grid).forEach(function(node, index, arr) {
1161         if (dojo.query('label[set~=' + type + ']', node).length == 0) {
1162             node.hidden = true;
1163         }
1164     });
1165
1166 }
1167
1168 function fillFixedFields (rec) {
1169     try {
1170             var grid = document.getElementById('leaderGrid');
1171
1172             var rtype = _record_type;
1173
1174             var _l = rec.leader.toString();
1175             var _6 = rec.controlfield.(@tag=='006').toString();
1176             var _7 = rec.controlfield.(@tag=='007').toString();
1177             var _8 = rec.controlfield.(@tag=='008').toString();
1178
1179             var list = [];
1180             var pre_list = grid.getElementsByTagName('label');
1181             for (var i in pre_list) {
1182                 if ( pre_list[i].getAttribute && pre_list[i].getAttribute('set').indexOf(grid.getAttribute('type')) > -1 ) {
1183                     list.push( pre_list[i] );
1184                 }
1185             }
1186
1187             for (var i in list) {
1188                 var name = list[i].getAttribute('name');
1189
1190                 if (!ff_pos[name])
1191                     continue;
1192
1193                 var value = '';
1194                 if ( ff_pos[name].ldr && ff_pos[name].ldr[rtype] )
1195                     value = _l.substr(ff_pos[name].ldr[rtype].start, ff_pos[name].ldr[rtype].len);
1196
1197                 if ( ff_pos[name]._8 && ff_pos[name]._8[rtype] )
1198                     value = _8.substr(ff_pos[name]._8[rtype].start, ff_pos[name]._8[rtype].len);
1199
1200                 if ( !value && ff_pos[name]._6 && ff_pos[name]._6[rtype] )
1201                     value = _6.substr(ff_pos[name]._6[rtype].start, ff_pos[name]._6[rtype].len);
1202
1203                 if ( ff_pos[name]._7 && ff_pos[name]._7[rtype] )
1204                     value = _7.substr(ff_pos[name]._7[rtype].start, ff_pos[name]._7[rtype].len);
1205                 
1206                 if (!value) {
1207                     var d;
1208                     var p;
1209                     if (ff_pos[name].ldr && ff_pos[name].ldr[rtype]) {
1210                         d = ff_pos[name].ldr[rtype].def;
1211                         p = 'ldr';
1212                     }
1213
1214                     if (ff_pos[name]._8 && ff_pos[name]._8[rtype]) {
1215                         d = ff_pos[name]._8[rtype].def;
1216                         p = '_8';
1217                     }
1218
1219                     if (!value && ff_pos[name]._6 && ff_pos[name]._6[rtype]) {
1220                         d = ff_pos[name]._6[rtype].def;
1221                         p = '_6';
1222                     }
1223
1224                     if (ff_pos[name]._7 && ff_pos[name]._7[rtype]) {
1225                         d = ff_pos[name]._7[rtype].def;
1226                         p = '_7';
1227                     }
1228
1229                     if (!value) {
1230                         for (var j = 0; j < ff_pos[name][p][rtype].len; j++) {
1231                             value += d;
1232                         }
1233                     }
1234                 }
1235
1236                 list[i].nextSibling.value = value;
1237             }
1238
1239             return true;
1240     } catch(E) {
1241         alert('FIXME, MARC Editor, fillFixedFields: ' + E);
1242     }
1243 }
1244
1245 function updateFixedFields (element) {
1246     var grid = document.getElementById('leaderGrid');
1247     var recGrid = document.getElementById('recGrid');
1248
1249     var rtype = _record_type;
1250     var new_value = element.value;
1251
1252     var parts = {
1253         ldr : _record.leader,
1254         _6 : _record.controlfield.(@tag=='006'),
1255         _7 : _record.controlfield.(@tag=='007'),
1256         _8 : _record.controlfield.(@tag=='008')
1257     };
1258
1259     var name = element.getAttribute('name');
1260     for (var i in ff_pos[name]) {
1261
1262         if (!ff_pos[name][i][rtype]) continue;
1263         if (!parts[i]) {
1264             // we're missing the required field.  Add it now.
1265
1266             var newfield;
1267             if (i == '_6') newfield = '006';
1268             else if (i == '_7') newfield = '007';
1269             else if (i == '_8') newfield = '008';
1270             else continue;
1271
1272             createControlField(newfield,'                                        ');
1273             parts[i] = _record.controlfield.(@tag==newfield);
1274         }
1275
1276         var before = parts[i].substr(0, ff_pos[name][i][rtype].start);
1277         var after = parts[i].substr(ff_pos[name][i][rtype].start + ff_pos[name][i][rtype].len);
1278
1279         for (var j = 0; new_value.length < ff_pos[name][i][rtype].len; j++) {
1280             new_value += ff_pos[name][i][rtype].def;
1281         }
1282
1283         parts[i].setChildren( before + new_value + after );
1284         recGrid.getElementsByAttribute('tag',i)[0].lastChild.value = parts[i].toString();
1285     }
1286
1287     return true;
1288 }
1289
1290 function marcLeader (leader) {
1291     var row = createRow(
1292         { class : 'marcLeaderRow',
1293           tag : 'ldr' },
1294         createLabel(
1295             { value : 'LDR',
1296               class : 'marcTag',
1297               tooltiptext : $('catStrings').getString('staff.cat.marcedit.marcTag.LDR.label') } ),
1298         createLabel(
1299             { value : '',
1300               class : 'marcInd1' } ),
1301         createLabel(
1302             { value : '',
1303               class : 'marcInd2' } ),
1304         createLabel(
1305             { value : leader.text(),
1306               class : 'marcLeader' } )
1307     );
1308
1309     return row;
1310 }
1311
1312 function marcControlfield (field) {
1313     tagname = field.@tag.toString().substr(2);
1314     var row;
1315     if (tagname == '1' || tagname == '3' || tagname == '6' || tagname == '7' || tagname == '8') {
1316         row = createRow(
1317             { class : 'marcControlfieldRow',
1318               tag : '_' + tagname },
1319             createLabel(
1320                 { value : field.@tag,
1321                   class : 'marcTag',
1322                   context : 'tags_popup',
1323                   onmouseover : 'getTooltip(this, "tag");',
1324                   tooltipid : 'tag' + field.@tag } ),
1325             createLabel(
1326                 { value : field.@ind1,
1327                   class : 'marcInd1',
1328                   onmouseover : 'getTooltip(this, "ind1");',
1329                   tooltipid : 'tag' + field.@tag + 'ind1val' + field.@ind1 } ),
1330             createLabel(
1331                 { value : field.@ind2,
1332                   class : 'marcInd2',
1333                   onmouseover : 'getTooltip(this, "ind2");',
1334                   tooltipid : 'tag' + field.@tag + 'ind2val' + field.@ind2 } ),
1335             createMARCTextbox(
1336                 field,
1337                 { value : field.text(),
1338                   class : 'plain marcEditableControlfield',
1339                   name : 'CONTROL' + tagname,
1340                   context : 'clipboard',
1341                   size : 50,
1342                   maxlength : 50 } )
1343             );
1344     } else {
1345         row = createRow(
1346             { class : 'marcControlfieldRow',
1347               tag : '_' + tagname },
1348             createLabel(
1349                 { value : field.@tag,
1350                   class : 'marcTag',
1351                   onmouseover : 'getTooltip(this, "tag");',
1352                   tooltipid : 'tag' + field.@tag } ),
1353             createLabel(
1354                 { value : field.@ind1,
1355                   class : 'marcInd1',
1356                   onmouseover : 'getTooltip(this, "ind1");',
1357                   tooltipid : 'tag' + field.@tag + 'ind1val' + field.@ind1 } ),
1358             createLabel(
1359                 { value : field.@ind2,
1360                   class : 'marcInd2',
1361                   onmouseover : 'getTooltip(this, "ind2");',
1362                   tooltipid : 'tag' + field.@tag + 'ind2val' + field.@ind2 } ),
1363             createLabel(
1364                 { value : field.text(),
1365                   class : 'marcControlfield' } )
1366         );
1367     }
1368
1369     return row;
1370 }
1371
1372 function stackSubfields(checkbox) {
1373     var list = document.getElementsByAttribute('name','sf_box');
1374
1375     var o = 'vertical';
1376     if (!checkbox.checked) o = 'horizontal';
1377     
1378     for (var i = 0; i < list.length; i++) {
1379         if (list[i]) list[i].setAttribute('orient',o);
1380     }
1381 }
1382
1383 function fastItemAdd_toggle(checkbox) {
1384     var x = document.getElementById('fastItemAdd_textboxes');
1385     if (checkbox.checked) {
1386         x.hidden = false;
1387         document.getElementById('fastItemAdd_callnumber').focus();
1388         document.getElementById('fastItemAdd_callnumber').select();
1389     } else {
1390         x.hidden = true;
1391     }
1392 }
1393
1394 function fastItemAdd_attempt(doc_id) {
1395     try {
1396         if (typeof window.xulG.fast_add_item != 'function') { return; }
1397         if (!document.getElementById('fastItemAdd_checkbox').checked) { return; }
1398         if (!document.getElementById('fastItemAdd_callnumber').value) { return; }
1399         if (!document.getElementById('fastItemAdd_barcode').value) { return; }
1400         window.xulG.fast_add_item( doc_id, document.getElementById('fastItemAdd_callnumber').value, document.getElementById('fastItemAdd_barcode').value );
1401         document.getElementById('fastItemAdd_barcode').value = '';
1402     } catch(E) {
1403         alert('fastItemAdd_attempt: ' + E);
1404     }
1405 }
1406
1407 function save_attempt(xml_string) {
1408     try {
1409         var result = window.xulG.save.func( xml_string );   
1410         if (result) {
1411             if (result.id) fastItemAdd_attempt(result.id);
1412             if (typeof result.on_complete == 'function') result.on_complete();
1413         }
1414     } catch(E) {
1415         alert('save_attempt: ' + E);
1416     }
1417 }
1418
1419 function marcDatafield (field) {
1420     var row = createRow(
1421         { class : 'marcDatafieldRow' },
1422         createMARCTextbox(
1423             field.@tag,
1424             { value : field.@tag,
1425               class : 'plain marcTag',
1426               name : 'marcTag',
1427               context : 'tags_popup',
1428               oninput : 'if (this.value.length == 3) { this.nextSibling.focus(); }',
1429               size : 3,
1430               maxlength : 3,
1431               onmouseover : 'current_focus = this; getTooltip(this, "tag");' } ),
1432         createMARCTextbox(
1433             field.@ind1,
1434             { value : field.@ind1,
1435               class : 'plain marcInd1',
1436               name : 'marcInd1',
1437               oninput : 'if (this.value.length == 1) { this.nextSibling.focus(); }',
1438               size : 1,
1439               maxlength : 1,
1440               onmouseover : 'current_focus = this; getContextMenu(this, "ind1"); getTooltip(this, "ind1");',
1441               oncontextmenu : 'getContextMenu(this, "ind1");' } ),
1442         createMARCTextbox(
1443             field.@ind2,
1444             { value : field.@ind2,
1445               class : 'plain marcInd2',
1446               name : 'marcInd2',
1447               oninput : 'if (this.value.length == 1) { this.nextSibling.firstChild.firstChild.focus(); }',
1448               size : 1,
1449               maxlength : 1,
1450               onmouseover : 'current_focus = this; getContextMenu(this, "ind2"); getTooltip(this, "ind2");',
1451               oncontextmenu : 'getContextMenu(this, "ind2");' } ),
1452         createHbox({ name : 'sf_box' })
1453     );
1454
1455     if (!current_focus && field.@tag == '') current_focus = row.childNodes[0];
1456     if (!current_focus && field.@ind1 == '') current_focus = row.childNodes[1];
1457     if (!current_focus && field.@ind2 == '') current_focus = row.childNodes[2];
1458
1459     var sf_box = row.lastChild;
1460     if (document.getElementById('stackSubfields').checked)
1461         sf_box.setAttribute('orient','vertical');
1462
1463     sf_box.addEventListener(
1464         'click',
1465         function (e) {
1466             if (sf_box === e.target) {
1467                 sf_box.lastChild.lastChild.focus();
1468             } else if (e.target.parentNode === sf_box) {
1469                 e.target.lastChild.focus();
1470             }
1471         },
1472         false
1473     );
1474
1475
1476     for (var i in field.subfield) {
1477         var sf = field.subfield[i];
1478         sf_box.appendChild(
1479             marcSubfield(sf)
1480         );
1481
1482         dojo.query('.marcSubfield', sf_box).forEach(wrap_long_fields);
1483
1484         if (sf.@code == '' && (!current_focus || current_focus.className.match(/Ind/)))
1485             current_focus = sf_box.lastChild.childNodes[1];
1486     }
1487
1488     return row;
1489 }
1490
1491 function marcSubfield (sf) {            
1492     return createHbox(
1493         { class : 'marcSubfieldBox' },
1494         createLabel(
1495             { value : "\u2021",
1496               class : 'plain marcSubfieldDelimiter',
1497               onmouseover : 'getTooltip(this.nextSibling, "subfield");',
1498               oncontextmenu : 'getContextMenu(this.nextSibling, "subfield");',
1499                 //onclick : 'this.nextSibling.focus();',
1500                 onfocus : 'this.nextSibling.focus();',
1501               size : 2 } ),
1502         createMARCTextbox(
1503             sf.@code,
1504             { value : sf.@code,
1505               class : 'plain marcSubfieldCode',
1506               name : 'marcSubfieldCode',
1507               onmouseover : 'current_focus = this; getContextMenu(this, "subfield"); getTooltip(this, "subfield");',
1508               oncontextmenu : 'getContextMenu(this, "subfield");',
1509               oninput : 'if (this.value.length == 1) { this.nextSibling.focus(); }',
1510               size : 2,
1511               maxlength : 1 } ),
1512         createMARCTextbox(
1513             sf,
1514             { value : sf.text(),
1515               name : sf.parent().@tag + ':' + sf.@code,
1516               class : 'plain marcSubfield', 
1517               onmouseover : 'getTooltip(this, "subfield");',
1518               contextmenu : function (event) { getAuthorityContextMenu(event.target, sf) },
1519               size : new String(sf.text()).length + 2,
1520               oninput : "this.setAttribute('size', this.value.length + 2);"
1521             } )
1522     );
1523 }
1524
1525 function loadRecord(rec) {
1526     try {
1527             _record = rec;
1528             var grid_rows = document.getElementById('recGrid').lastChild;
1529
1530             while (grid_rows.firstChild) grid_rows.removeChild(grid_rows.firstChild);
1531
1532             grid_rows.appendChild( marcLeader( rec.leader ) );
1533
1534             for (var i in rec.controlfield) {
1535                 grid_rows.appendChild( marcControlfield( rec.controlfield[i] ) );
1536             }
1537
1538             for (var i in rec.datafield) {
1539                 grid_rows.appendChild( marcDatafield( rec.datafield[i] ) );
1540             }
1541
1542             grid_rows.getElementsByAttribute('class','marcDatafieldRow')[0].firstChild.focus();
1543             changeFFEditor(recordType(rec));
1544             fillFixedFields(rec);
1545     } catch(E) {
1546         alert('FIXME, MARC Editor, loadRecord: ' + E);
1547     }
1548 }
1549
1550
1551 function genToolTips () {
1552     for (var i in bib_data.field) {
1553         var f = bib_data.field[i];
1554     
1555         tag_menu.appendChild(
1556             createMenuitem(
1557                 { label : f.@tag,
1558                   oncommand : 
1559                       'current_focus.value = "' + f.@tag + '";' +
1560                     'var e = document.createEvent("MutationEvents");' +
1561                     'e.initMutationEvent("change",1,1,null,0,0,0,0);' +
1562                     'current_focus.inputField.dispatchEvent(e);',
1563                   disabled : f.@tag < '010' ? "true" : "false",
1564                   tooltiptext : f.description }
1565             )
1566         );
1567     
1568         var i1_popup = createPopup({position : 'after_start', id : 't' + f.@tag + 'i1' });
1569         context_menus.appendChild( i1_popup );
1570     
1571         var i2_popup = createPopup({position : 'after_start', id : 't' + f.@tag + 'i2' });
1572         context_menus.appendChild( i2_popup );
1573     
1574         var sf_popup = createPopup({position : 'after_start', id : 't' + f.@tag + 'sf' });
1575         context_menus.appendChild( sf_popup );
1576     
1577         tooltip_hash['tag' + f.@tag] = f.description;
1578         for (var j in f.indicator) {
1579             var ind = f.indicator[j];
1580             tooltip_hash['tag' + f.@tag + 'ind' + ind.@position + 'val' + ind.@value] = ind.description;
1581     
1582             if (ind.@position == 1) {
1583                 i1_popup.appendChild(
1584                     createMenuitem(
1585                         { label : ind.@value,
1586                           oncommand : 
1587                               'current_focus.value = "' + ind.@value + '";' +
1588                             'var e = document.createEvent("MutationEvents");' +
1589                             'e.initMutationEvent("change",1,1,null,0,0,0,0);' +
1590                             'current_focus.inputField.dispatchEvent(e);',
1591                           tooltiptext : ind.description }
1592                     )
1593                 );
1594             }
1595     
1596             if (ind.@position == 2) {
1597                 i2_popup.appendChild(
1598                     createMenuitem(
1599                         { label : ind.@value,
1600                           oncommand : 
1601                               'current_focus.value = "' + ind.@value + '";' +
1602                             'var e = document.createEvent("MutationEvents");' +
1603                             'e.initMutationEvent("change",1,1,null,0,0,0,0);' +
1604                             'current_focus.inputField.dispatchEvent(e);',
1605                           tooltiptext : ind.description }
1606                     )
1607                 );
1608             }
1609         }
1610     
1611         for (var j in f.subfield) {
1612             var sf = f.subfield[j];
1613             tooltip_hash['tag' + f.@tag + 'sf' + sf.@code] = sf.description;
1614     
1615             sf_popup.appendChild(
1616                 createMenuitem(
1617                     { label : sf.@code,
1618                       oncommand : 
1619                           'current_focus.value = "' + sf.@code + '";' +
1620                         'var e = document.createEvent("MutationEvents");' +
1621                         'e.initMutationEvent("change",1,1,null,0,0,0,0);' +
1622                         'current_focus.inputField.dispatchEvent(e);',
1623                       tooltiptext : sf.description
1624                     }
1625                 )
1626             );
1627         }
1628     }
1629 }
1630
1631 function getTooltip (target, type) {
1632
1633     var tt = '';
1634     if (type == 'subfield')
1635         tt = 'tag' + target.parentNode.parentNode.parentNode.firstChild.value + 'sf' + target.parentNode.childNodes[1].value;
1636
1637     if (type == 'ind1')
1638         tt = 'tag' + target.parentNode.firstChild.value + 'ind1val' + target.value;
1639
1640     if (type == 'ind2')
1641         tt = 'tag' + target.parentNode.firstChild.value + 'ind2val' + target.value;
1642
1643     if (type == 'tag')
1644         tt = 'tag' + target.parentNode.firstChild.value;
1645
1646     if (!document.getElementById( tt )) {
1647         p.appendChild(
1648             createTooltip(
1649                 { id : tt,
1650                   flex : "1",
1651                   orient : 'vertical',
1652                   onpopupshown : 'this.width = this.firstChild.boxObject.width + 10; this.height = this.firstChild.boxObject.height + 10;',
1653                   class : 'tooltip' },
1654                 createDescription({}, document.createTextNode( tooltip_hash[tt] ) )
1655             )
1656         );
1657     }
1658
1659     target.tooltip = tt;
1660     return true;
1661 }
1662
1663 function getContextMenu (target, type) {
1664
1665     var tt = '';
1666     if (type == 'subfield')
1667         tt = 't' + target.parentNode.parentNode.parentNode.firstChild.value + 'sf';
1668
1669     if (type == 'ind1')
1670         tt = 't' + target.parentNode.firstChild.value + 'i1';
1671
1672     if (type == 'ind2')
1673         tt = 't' + target.parentNode.firstChild.value + 'i2';
1674
1675     target.setAttribute('context', tt);
1676     return true;
1677 }
1678
1679 var authority_tag_map = {
1680     100 : ['[100,400,500,700]',100],
1681     400 : ['[100,400,500,700]',100],
1682     700 : ['[100,400,500,700]',100],
1683     800 : ['[100,400,500,700]',100],
1684     110 : ['[110,410,510,710]',110],
1685     410 : ['[110,410,510,710]',110],
1686     710 : ['[110,410,510,710]',110],
1687     810 : ['[110,410,510,710]',110],
1688     111 : ['[111,411,511,711]',111],
1689     411 : ['[111,411,511,711]',111],
1690     711 : ['[111,411,511,711]',111],
1691     811 : ['[111,411,511,711]',111],
1692     240 : ['[130,430,530,730]',130],
1693     440 : ['[130,430,530,730]',130],
1694     130 : ['[130,430,530,730]',130],
1695     730 : ['[130,430,530,730]',130],
1696     830 : ['[130,430,530,730]',130],
1697     600 : ['[100,400,480,481,482,485,500,580,581,582,585,700,780,781,782,785]',100],
1698     650 : ['[150,450,480,481,482,485,550,580,581,582,585,750,780,781,782,785]',150],
1699     651 : ['[151,451,480,481,482,485,551,580,581,582,585,751,780,781,782,785]',151],
1700     655 : ['[155,455,480,481,482,485,555,580,581,582,585,755,780,781,782,785]',155]
1701 };
1702
1703 function getAuthorityContextMenu (target, sf) {
1704     var menu_id = sf.parent().@tag + ':' + sf.@code + '-authority-context-' + sf;
1705
1706     var old = document.getElementById( menu_id );
1707     if (old) old.parentNode.removeChild(old);
1708
1709     var sf_popup = createPopup({ id : menu_id, flex : 1 });
1710     context_menus.appendChild( sf_popup );
1711
1712     if (!authority_tag_map[sf.parent().@tag]) {
1713         sf_popup.appendChild(createLabel( { value : $('catStrings').getString('staff.cat.marcedit.not_authority_field.label') } ) );
1714         target.setAttribute('context', 'clipboard');
1715         return false;
1716     }
1717
1718     var auth_data = searchAuthority( sf, authority_tag_map[sf.parent().@tag][0], sf.@code, 50);
1719
1720     var res = new XML( auth_data.responseText );
1721
1722     var rec_list = [];
1723
1724     var recs = res.gw::payload.gw::array.gw::string;
1725     for (var i in recs) {
1726         var x = recs[i];
1727         var xml = new XML(x.toString());
1728         var main = xml.datafield.(@tag.toString().match(/^1/)).subfield;
1729
1730         if (! (main[0].parent().@tag == authority_tag_map[sf.parent().@tag][1]) ) continue;
1731
1732         var main_text = '';
1733         for (var i in main) {
1734             if (main_text) main_text += ' / ';
1735             main_text += main[i];
1736         }
1737
1738         rec_list.push( [ main_text, xml ] );
1739     }
1740     
1741     for (var i in rec_list.sort( function (a, b) { if(a[0] > b[0]) return 1; return -1; } )) {
1742
1743         var main_text = rec_list[i][0];
1744         var xml = rec_list[i][1];
1745         var main = xml.datafield.(@tag.toString().match(/^1/)).subfield;
1746
1747         if (! (main[0].parent().@tag == authority_tag_map[sf.parent().@tag][1]) ) continue;
1748
1749         var grid = document.getElementsByAttribute('name','authority-marc-template')[0].cloneNode(true);
1750         grid.setAttribute('name','-none-');
1751         grid.setAttribute('style','overflow:scroll');
1752
1753
1754         var submenu = createMenu( { label : main_text } );
1755
1756         var popup = createMenuPopup({ flex : "1" });
1757         submenu.appendChild(popup);
1758
1759         var fields = xml.datafield;
1760         for (var j in fields) {
1761
1762             var row = createRow(
1763                 {},
1764                 createLabel( { value : fields[j].@tag } ),
1765                 createLabel( { value : fields[j].@ind1 } ),
1766                 createLabel( { value : fields[j].@ind2 } )
1767             );
1768
1769             var sf_box = createHbox();
1770
1771             var subfields = fields[j].subfield;
1772             for (var k in subfields) {
1773                 sf_box.appendChild(
1774                     createCheckbox(
1775                         { label    : '\u2021' + subfields[k].@code + ' ' + subfields[k],
1776                           subfield : subfields[k].@code,
1777                           tag      : subfields[k].parent().@tag,
1778                           value    : subfields[k]
1779                         }
1780                     )
1781                 );
1782                 row.appendChild(sf_box);
1783             }
1784
1785             grid.lastChild.appendChild(row);
1786         }
1787
1788         grid.hidden = false;
1789         popup.appendChild( grid );
1790
1791         popup.appendChild(
1792             createMenuitem(
1793                 { label : $('catStrings').getString('staff.cat.marcedit.apply_selected.label'),
1794                   command : function (event) {
1795                         applyAuthority(event.target.previousSibling, target, sf);
1796                         return true;
1797                   }
1798                 }
1799             )
1800         );
1801
1802         sf_popup.appendChild( submenu );
1803     }
1804
1805     if (sf_popup.childNodes.length == 0)
1806         sf_popup.appendChild(createLabel( { value : $('catStrings').getString('staff.cat.marcedit.no_authority_match.label') } ) );
1807
1808     target.setAttribute('context', menu_id);
1809     return true;
1810 }
1811
1812 function applyAuthority ( target, ui_sf, e4x_sf ) {
1813
1814     var new_vals = target.getElementsByAttribute('checked','true');
1815     var field = e4x_sf.parent();
1816
1817     for (var i = 0; i < new_vals.length; i++) {
1818
1819         var sf_list = field.subfield;
1820         for (var j in sf_list) {
1821
1822             if (sf_list[j].@code == new_vals[i].getAttribute('subfield')) {
1823                 sf_list[j] = new_vals[i].getAttribute('value');
1824                 new_vals[i].setAttribute('subfield','');
1825                 break;
1826             }
1827         }
1828     }
1829
1830     for (var i = 0; i < new_vals.length; i++) {
1831         if (!new_vals[i].getAttribute('subfield')) continue;
1832
1833         var val = new_vals[i].getAttribute('value');
1834
1835         var sf = <subfield code="" xmlns="http://www.loc.gov/MARC21/slim">{val}</subfield>;
1836         sf.@code = new_vals[i].getAttribute('subfield');
1837
1838         field.insertChildAfter(field.subfield[field.subfield.length() - 1], sf);
1839     }
1840
1841     var row = marcDatafield( field );
1842
1843     var node = ui_sf;
1844     while (node.nodeName != 'row') {
1845         node = node.parentNode;
1846     }
1847
1848     node.parentNode.replaceChild( row, node );
1849     return true;
1850 }
1851
1852 var control_map = {
1853     100 : {
1854         'a' : { 100 : 'a' },
1855         'd' : { 100 : 'd' },
1856         'e' : { 100 : 'e' },
1857         'q' : { 100 : 'q' }
1858     },
1859     110 : {
1860         'a' : { 110 : 'a' },
1861         'd' : { 110 : 'd' }
1862     },
1863     111 : {
1864         'a' : { 111 : 'a' },
1865         'd' : { 111 : 'd' }
1866     },
1867     130 : {
1868         'a' : { 130 : 'a' },
1869         'd' : { 130 : 'd' }
1870     },
1871     240 : {
1872         'a' : { 130 : 'a' },
1873         'd' : { 130 : 'd' }
1874     },
1875     400 : {
1876         'a' : { 100 : 'a' },
1877         'd' : { 100 : 'd' }
1878     },
1879     410 : {
1880         'a' : { 110 : 'a' },
1881         'd' : { 110 : 'd' }
1882     },
1883     411 : {
1884         'a' : { 111 : 'a' },
1885         'd' : { 111 : 'd' }
1886     },
1887     440 : {
1888         'a' : { 130 : 'a' },
1889         'n' : { 130 : 'n' },
1890         'p' : { 130 : 'p' }
1891     },
1892     700 : {
1893         'a' : { 100 : 'a' },
1894         'd' : { 100 : 'd' },
1895         'q' : { 100 : 'q' },
1896         't' : { 100 : 't' }
1897     },
1898     710 : {
1899         'a' : { 110 : 'a' },
1900         'd' : { 110 : 'd' }
1901     },
1902     711 : {
1903         'a' : { 111 : 'a' },
1904         'c' : { 111 : 'c' },
1905         'd' : { 111 : 'd' }
1906     },
1907     730 : {
1908         'a' : { 130 : 'a' },
1909         'd' : { 130 : 'd' }
1910     },
1911     800 : {
1912         'a' : { 100 : 'a' },
1913         'd' : { 100 : 'd' }
1914     },
1915     810 : {
1916         'a' : { 110 : 'a' },
1917         'd' : { 110 : 'd' }
1918     },
1919     811 : {
1920         'a' : { 111 : 'a' },
1921         'd' : { 111 : 'd' }
1922     },
1923     830 : {
1924         'a' : { 130 : 'a' },
1925         'd' : { 130 : 'd' }
1926     },
1927     600 : {
1928         'a' : { 100 : 'a' },
1929         'd' : { 100 : 'd' },
1930         'q' : { 100 : 'q' },
1931         't' : { 100 : 't' },
1932         'v' : { 180 : 'v',
1933             100 : 'v',
1934             181 : 'v',
1935             182 : 'v',
1936             185 : 'v'
1937         },
1938         'x' : { 180 : 'x',
1939             100 : 'x',
1940             181 : 'x',
1941             182 : 'x',
1942             185 : 'x'
1943         },
1944         'y' : { 180 : 'y',
1945             100 : 'y',
1946             181 : 'y',
1947             182 : 'y',
1948             185 : 'y'
1949         },
1950         'z' : { 180 : 'z',
1951             100 : 'z',
1952             181 : 'z',
1953             182 : 'z',
1954             185 : 'z'
1955         }
1956     },
1957     610 : {
1958         'a' : { 110 : 'a' },
1959         'd' : { 110 : 'd' },
1960         't' : { 110 : 't' },
1961         'v' : { 180 : 'v',
1962             110 : 'v',
1963             181 : 'v',
1964             182 : 'v',
1965             185 : 'v'
1966         },
1967         'x' : { 180 : 'x',
1968             110 : 'x',
1969             181 : 'x',
1970             182 : 'x',
1971             185 : 'x'
1972         },
1973         'y' : { 180 : 'y',
1974             110 : 'y',
1975             181 : 'y',
1976             182 : 'y',
1977             185 : 'y'
1978         },
1979         'z' : { 180 : 'z',
1980             110 : 'z',
1981             181 : 'z',
1982             182 : 'z',
1983             185 : 'z'
1984         }
1985     },
1986     611 : {
1987         'a' : { 111 : 'a' },
1988         'd' : { 111 : 'd' },
1989         't' : { 111 : 't' },
1990         'v' : { 180 : 'v',
1991             111 : 'v',
1992             181 : 'v',
1993             182 : 'v',
1994             185 : 'v'
1995         },
1996         'x' : { 180 : 'x',
1997             111 : 'x',
1998             181 : 'x',
1999             182 : 'x',
2000             185 : 'x'
2001         },
2002         'y' : { 180 : 'y',
2003             111 : 'y',
2004             181 : 'y',
2005             182 : 'y',
2006             185 : 'y'
2007         },
2008         'z' : { 180 : 'z',
2009             111 : 'z',
2010             181 : 'z',
2011             182 : 'z',
2012             185 : 'z'
2013         }
2014     },
2015     630 : {
2016         'a' : { 130 : 'a' },
2017         'd' : { 130 : 'd' }
2018     },
2019     650 : {
2020         'a' : { 150 : 'a' },
2021         'b' : { 150 : 'b' },
2022         'v' : { 180 : 'v',
2023             150 : 'v',
2024             181 : 'v',
2025             182 : 'v',
2026             185 : 'v'
2027         },
2028         'x' : { 180 : 'x',
2029             150 : 'x',
2030             181 : 'x',
2031             182 : 'x',
2032             185 : 'x'
2033         },
2034         'y' : { 180 : 'y',
2035             150 : 'y',
2036             181 : 'y',
2037             182 : 'y',
2038             185 : 'y'
2039         },
2040         'z' : { 180 : 'z',
2041             150 : 'z',
2042             181 : 'z',
2043             182 : 'z',
2044             185 : 'z'
2045         }
2046     },
2047     651 : {
2048         'a' : { 151 : 'a' },
2049         'v' : { 180 : 'v',
2050             151 : 'v',
2051             181 : 'v',
2052             182 : 'v',
2053             185 : 'v'
2054         },
2055         'x' : { 180 : 'x',
2056             151 : 'x',
2057             181 : 'x',
2058             182 : 'x',
2059             185 : 'x'
2060         },
2061         'y' : { 180 : 'y',
2062             151 : 'y',
2063             181 : 'y',
2064             182 : 'y',
2065             185 : 'y'
2066         },
2067         'z' : { 180 : 'z',
2068             151 : 'z',
2069             181 : 'z',
2070             182 : 'z',
2071             185 : 'z'
2072         }
2073     },
2074     655 : {
2075         'a' : { 155 : 'a' },
2076         'v' : { 180 : 'v',
2077             155 : 'v',
2078             181 : 'v',
2079             182 : 'v',
2080             185 : 'v'
2081         },
2082         'x' : { 180 : 'x',
2083             155 : 'x',
2084             181 : 'x',
2085             182 : 'x',
2086             185 : 'x'
2087         },
2088         'y' : { 180 : 'y',
2089             155 : 'y',
2090             181 : 'y',
2091             182 : 'y',
2092             185 : 'y'
2093         },
2094         'z' : { 180 : 'z',
2095             155 : 'z',
2096             181 : 'z',
2097             182 : 'z',
2098             185 : 'z'
2099         }
2100     }
2101 };
2102
2103 function validateAuthority (button) {
2104     var grid = document.getElementById('recGrid');
2105     var label = button.getAttribute('label');
2106
2107     //loop over rows
2108     var rows = grid.lastChild.childNodes;
2109     for (var i = 0; i < rows.length; i++) {
2110         var row = rows[i];
2111         var tag = row.firstChild;
2112
2113         if (!control_map[tag.value]) continue
2114         button.setAttribute('label', label + ' - ' + tag.value);
2115
2116         var ind1 = tag.nextSibling;
2117         var ind2 = ind1.nextSibling;
2118         var subfields = ind2.nextSibling.childNodes;
2119
2120         var tags = {};
2121
2122         for (var j = 0; j < subfields.length; j++) {
2123             var sf = subfields[j];
2124             var sf_code = sf.childNodes[1].value;
2125             var sf_value = sf.childNodes[2].value;
2126
2127             if (!control_map[tag.value][sf_code]) continue;
2128
2129             var found = 0;
2130             for (var a_tag in control_map[tag.value][sf_code]) {
2131                 if (!tags[a_tag]) tags[a_tag] = [];
2132                 tags[a_tag].push({ term : sf_value, subfield : sf_code });
2133             }
2134
2135         }
2136
2137         for (var val_tag in tags) {
2138             var auth_data = validateBibField( [val_tag], tags[val_tag]);
2139             var res = new XML( auth_data.responseText );
2140             found = parseInt(res.gw::payload.gw::string.toString());
2141             if (found) break;
2142         }
2143
2144         // XXX If adt, etc should be validated separately from vxz, etc then move this up into the above for loop
2145         for (var j = 0; j < subfields.length; j++) {
2146             var sf = subfields[j];
2147                if (!found) {
2148                 sf.childNodes[2].inputField.style.color = 'red';
2149             } else {
2150                 sf.childNodes[2].inputField.style.color = 'black';
2151             }
2152         }
2153     }
2154
2155     button.setAttribute('label', label);
2156
2157     return true;
2158 }
2159
2160
2161 function validateBibField (tags, searches) {
2162     var url = "/gateway?input_format=json&format=xml&service=open-ils.search&method=open-ils.search.authority.validate.tag";
2163     url += '&param="tags"&param=' + js2JSON(tags);
2164     url += '&param="searches"&param=' + js2JSON(searches);
2165
2166
2167     var req = new XMLHttpRequest();
2168     req.open('GET',url,false);
2169     req.send(null);
2170
2171     return req;
2172
2173 }
2174 function searchAuthority (term, tag, sf, limit) {
2175     var url = "/gateway?input_format=json&format=xml&service=open-ils.search&method=open-ils.search.authority.fts";
2176     url += '&param="term"&param="' + term + '"';
2177     url += '&param="limit"&param=' + limit;
2178     url += '&param="tag"&param=' + tag;
2179     url += '&param="subfield"&param="' + sf + '"';
2180
2181
2182     var req = new XMLHttpRequest();
2183     req.open('GET',url,false);
2184     req.send(null);
2185
2186     return req;
2187
2188 }
2189