]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/xul/staff_client/server/cat/marcedit.js
Authority records get some fixed-field love in the MARC Editor
[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         AUT : { Type : /[z]{1}/,        BLvl : /.{1}/ },
675     MFHD : { Type : /[uvxy]{1}/,  BLvl : /.{1}/ }
676 };
677
678 var ff_pos = {
679     TrAr : {
680         _8 : {
681             SCO : {start : 33, len : 1, def : ' ' },
682             REC : {start : 33, len : 1, def : 'n' }
683         },
684         _6 : {
685             SCO : {start : 16, len : 1, def : ' ' },
686             REC : {start : 16, len : 1, def : 'n' }
687         }
688     },
689     TMat : {
690         _8 : {
691             VIS : {start : 33, len : 1, def : ' ' }
692         },
693         _6 : {
694             VIS : {start : 16, len : 1, def : ' ' }
695         }
696     },
697     Time : {
698         _8 : {
699             VIS : {start : 18, len : 3, def : ' ' }
700         },
701         _6 : {
702             VIS : {start : 1, len : 3, def : ' ' }
703         }
704     },
705     Tech : {
706         _8 : {
707             VIS : {start : 34, len : 1, def : 'n' }
708         },
709         _6 : {
710             VIS : {start : 17, len : 1, def : 'n' }
711         }
712     },
713     SrTp : {
714         _8 : {
715             SER : {start : 21, len : 1, def : ' ' }
716         },
717         _6 : {
718             SER : {start : 4, len : 1, def : ' ' }
719         }
720     },
721     Srce : {
722         _8 : {
723             BKS : {start : 39, len : 1, def : 'd' },
724             SER : {start : 39, len : 1, def : 'd' },
725             VIS : {start : 39, len : 1, def : 'd' },
726             MIX : {start : 39, len : 1, def : 'd' },
727             MAP : {start : 39, len : 1, def : 'd' },
728             SCO : {start : 39, len : 1, def : 'd' },
729             REC : {start : 39, len : 1, def : 'd' },
730             COM : {start : 39, len : 1, def : 'd' }
731         }
732     },
733     SpFm : {
734         _8 : {
735             MAP : {start : 33, len : 2, def : ' ' }
736         },
737         _6 : {
738             MAP : {start : 16, len : 2, def : ' ' }
739         }
740     },
741     Relf : {
742         _8 : {
743             MAP : {start : 18, len : 4, def : ' ' }
744         },
745         _6 : {
746             MAP : {start : 1, len : 4, def : ' ' }
747         }
748     },
749     Regl : {
750         _8 : {
751             SER : {start : 19, len : 1, def : ' ' }
752         },
753         _6 : {
754             SER : {start : 2, len : 1, def : ' ' }
755         }
756     },
757     Proj : {
758         _8 : {
759             MAP : {start : 22, len : 2, def : ' ' }
760         },
761         _6 : {
762             MAP : {start : 5, len : 2, def : ' ' }
763         }
764     },
765     Part : {
766         _8 : {
767             SCO : {start : 21, len : 1, def : ' ' },
768             REC : {start : 21, len : 1, def : 'n' }
769         },
770         _6 : {
771             SCO : {start : 4, len : 1, def : ' ' },
772             REC : {start : 4, len : 1, def : 'n' }
773         }
774     },
775     Orig : {
776         _8 : {
777             SER : {start : 22, len : 1, def : ' ' }
778         },
779         _6 : {
780             SER : {start : 5, len : 1, def : ' ' }
781         }
782     },
783     LTxt : {
784         _8 : {
785             SCO : {start : 30, len : 2, def : ' ' },
786             REC : {start : 30, len : 2, def : ' ' }
787         },
788         _6 : {
789             SCO : {start : 13, len : 2, def : ' ' },
790             REC : {start : 13, len : 2, def : ' ' }
791         }
792     },
793     Freq : {
794         _8 : {
795             SER : {start : 18, len : 1, def : ' ' }
796         },
797         _6 : {
798             SER : {start : 1, len : 1, def : ' ' }
799         }
800     },
801     FMus : {
802         _8 : {
803             SCO : {start : 20, len : 1, def : ' ' },
804             REC : {start : 20, len : 1, def : 'n' }
805         },
806         _6 : {
807             SCO : {start : 3, len : 1, def : ' ' },
808             REC : {start : 3, len : 1, def : 'n' }
809         }
810     },
811     File : {
812         _8 : {
813             COM : {start : 26, len : 1, def : 'u' }
814         },
815         _6 : {
816             COM : {start : 9, len : 1, def : 'u' }
817         }
818     },
819     EntW : {
820         _8 : {
821             SER : {start : 24, len : 1, def : ' ' }
822         },
823         _6 : {
824             SER : {start : 7, len : 1, def : ' ' }
825         }
826     },
827     AccM : {
828         _8 : {
829             SCO : {start : 24, len : 6, def : ' ' },
830             REC : {start : 24, len : 6, def : ' ' }
831         },
832         _6 : {
833             SCO : {start : 7, len : 6, def : ' ' },
834             REC : {start : 7, len : 6, def : ' ' }
835         }
836     },
837     Comp : {
838         _8 : {
839             SCO : {start : 18, len : 2, def : ' ' },
840             REC : {start : 18, len : 2, def : ' ' }
841         },
842         _6 : {
843             SCO : {start : 1, len : 2, def : ' ' },
844             REC : {start : 1, len : 2, def : ' ' }
845         }
846     },
847     CrTp : {
848         _8 : {
849             MAP : {start : 25, len : 1, def : ' ' }
850         },
851         _6 : {
852             MAP : {start : 8, len : 1, def : ' ' }
853         }
854     },
855     Ctry : {
856         _8 : {
857             BKS : {start : 15, len : 3, def : ' ' },
858             SER : {start : 15, len : 3, def : ' ' },
859             VIS : {start : 15, len : 3, def : ' ' },
860             MIX : {start : 15, len : 3, def : ' ' },
861             MAP : {start : 15, len : 3, def : ' ' },
862             SCO : {start : 15, len : 3, def : ' ' },
863             REC : {start : 15, len : 3, def : ' ' },
864             COM : {start : 15, len : 3, def : ' ' }
865         }
866     },
867     Lang : {
868         _8 : {
869             BKS : {start : 35, len : 3, def : ' ' },
870             SER : {start : 35, len : 3, def : ' ' },
871             VIS : {start : 35, len : 3, def : ' ' },
872             MIX : {start : 35, len : 3, def : ' ' },
873             MAP : {start : 35, len : 3, def : ' ' },
874             SCO : {start : 35, len : 3, def : ' ' },
875             REC : {start : 35, len : 3, def : ' ' },
876             COM : {start : 35, len : 3, def : ' ' }
877         }
878     },
879     MRec : {
880         _8 : {
881             BKS : {start : 38, len : 1, def : ' ' },
882             SER : {start : 38, len : 1, def : ' ' },
883             VIS : {start : 38, len : 1, def : ' ' },
884             MIX : {start : 38, len : 1, def : ' ' },
885             MAP : {start : 38, len : 1, def : ' ' },
886             SCO : {start : 38, len : 1, def : ' ' },
887             REC : {start : 38, len : 1, def : ' ' },
888             COM : {start : 38, len : 1, def : ' ' }
889         }
890     },
891     DtSt : {
892         _8 : {
893             BKS : {start : 6, len : 1, def : ' ' },
894             SER : {start : 6, len : 1, def : 'c' },
895             VIS : {start : 6, len : 1, def : ' ' },
896             MIX : {start : 6, len : 1, def : ' ' },
897             MAP : {start : 6, len : 1, def : ' ' },
898             SCO : {start : 6, len : 1, def : ' ' },
899             REC : {start : 6, len : 1, def : ' ' },
900             COM : {start : 6, len : 1, def : ' ' }
901         }
902     },
903     Type : {
904         ldr : {
905             BKS : {start : 6, len : 1, def : 'a' },
906             SER : {start : 6, len : 1, def : 'a' },
907             VIS : {start : 6, len : 1, def : 'g' },
908             MIX : {start : 6, len : 1, def : 'p' },
909             MAP : {start : 6, len : 1, def : 'e' },
910             SCO : {start : 6, len : 1, def : 'c' },
911             REC : {start : 6, len : 1, def : 'i' },
912             COM : {start : 6, len : 1, def : 'm' },
913             AUT : {start : 6, len : 1, def : 'z' },
914             MFHD : {start : 6, len : 1, def : 'y' }
915         }
916     },
917     Ctrl : {
918         ldr : {
919             BKS : {start : 8, len : 1, def : ' ' },
920             SER : {start : 8, len : 1, def : ' ' },
921             VIS : {start : 8, len : 1, def : ' ' },
922             MIX : {start : 8, len : 1, def : ' ' },
923             MAP : {start : 8, len : 1, def : ' ' },
924             SCO : {start : 8, len : 1, def : ' ' },
925             REC : {start : 8, len : 1, def : ' ' },
926             COM : {start : 8, len : 1, def : ' ' }
927         }
928     },
929     BLvl : {
930         ldr : {
931             BKS : {start : 7, len : 1, def : 'm' },
932             SER : {start : 7, len : 1, def : 's' },
933             VIS : {start : 7, len : 1, def : 'm' },
934             MIX : {start : 7, len : 1, def : 'c' },
935             MAP : {start : 7, len : 1, def : 'm' },
936             SCO : {start : 7, len : 1, def : 'm' },
937             REC : {start : 7, len : 1, def : 'm' },
938             COM : {start : 7, len : 1, def : 'm' }
939         }
940     },
941     Desc : {
942         ldr : {
943             BKS : {start : 18, len : 1, def : ' ' },
944             SER : {start : 18, len : 1, def : ' ' },
945             VIS : {start : 18, len : 1, def : ' ' },
946             MIX : {start : 18, len : 1, def : ' ' },
947             MAP : {start : 18, len : 1, def : ' ' },
948             SCO : {start : 18, len : 1, def : ' ' },
949             REC : {start : 18, len : 1, def : ' ' },
950             COM : {start : 18, len : 1, def : 'i' }
951         }
952         },
953     Item : {
954         ldr : {
955             MFHD : {start : 18, len : 1, def : 'i' }
956         }
957     },
958     ELvl : {
959         ldr : {
960             BKS : {start : 17, len : 1, def : ' ' },
961             SER : {start : 17, len : 1, def : ' ' },
962             VIS : {start : 17, len : 1, def : ' ' },
963             MIX : {start : 17, len : 1, def : ' ' },
964             MAP : {start : 17, len : 1, def : ' ' },
965             SCO : {start : 17, len : 1, def : ' ' },
966             REC : {start : 17, len : 1, def : ' ' },
967             COM : {start : 17, len : 1, def : ' ' },
968             AUT : {start : 17, len : 1, def : 'n' },
969             MFHD : {start : 17, len : 1, def : 'u' }
970         }
971     },
972     Indx : {
973         _8 : {
974             BKS : {start : 31, len : 1, def : '0' },
975             MAP : {start : 31, len : 1, def : '0' }
976         },
977         _6 : {
978             BKS : {start : 14, len : 1, def : '0' },
979             MAP : {start : 14, len : 1, def : '0' }
980         }
981     },
982     Date1 : {
983         _8 : {
984             BKS : {start : 7, len : 4, def : ' ' },
985             SER : {start : 7, len : 4, def : ' ' },
986             VIS : {start : 7, len : 4, def : ' ' },
987             MIX : {start : 7, len : 4, def : ' ' },
988             MAP : {start : 7, len : 4, def : ' ' },
989             SCO : {start : 7, len : 4, def : ' ' },
990             REC : {start : 7, len : 4, def : ' ' },
991             COM : {start : 7, len : 4, def : ' ' }
992         }
993     },
994     Date2 : {
995         _8 : {
996             BKS : {start : 11, len : 4, def : ' ' },
997             SER : {start : 11, len : 4, def : '9' },
998             VIS : {start : 11, len : 4, def : ' ' },
999             MIX : {start : 11, len : 4, def : ' ' },
1000             MAP : {start : 11, len : 4, def : ' ' },
1001             SCO : {start : 11, len : 4, def : ' ' },
1002             REC : {start : 11, len : 4, def : ' ' },
1003             COM : {start : 11, len : 4, def : ' ' }
1004         }
1005     },
1006     LitF : {
1007         _8 : {
1008             BKS : {start : 33, len : 1, def : '0' }
1009         },
1010         _6 : {
1011             BKS : {start : 16, len : 1, def : '0' }
1012         }
1013     },
1014     Biog : {
1015         _8 : {
1016             BKS : {start : 34, len : 1, def : ' ' }
1017         },
1018         _6 : {
1019             BKS : {start : 17, len : 1, def : ' ' }
1020         }
1021     },
1022     Ills : {
1023         _8 : {
1024             BKS : {start : 18, len : 4, def : ' ' }
1025         },
1026         _6 : {
1027             BKS : {start : 1, len : 4, def : ' ' }
1028         }
1029     },
1030     Fest : {
1031         _8 : {
1032             BKS : {start : 30, len : 1, def : '0' }
1033         },
1034         _6 : {
1035             BKS : {start : 13, len : 1, def : '0' }
1036         }
1037     },
1038     Conf : {
1039         _8 : {
1040             BKS : {start : 29, len : 1, def : '0' },
1041             SER : {start : 29, len : 1, def : '0' }
1042         },
1043         _6 : {
1044             BKS : {start : 12, len : 1, def : '0' },
1045             SER : {start : 12, len : 1, def : '0' }
1046         }
1047     },
1048     Cont : {
1049         _8 : {
1050             BKS : {start : 24, len : 4, def : ' ' },
1051             SER : {start : 25, len : 3, def : ' ' }
1052         },
1053         _6 : {
1054             BKS : {start : 7, len : 4, def : ' ' },
1055             SER : {start : 8, len : 3, def : ' ' }
1056         }
1057     },
1058     GPub : {
1059         _8 : {
1060             BKS : {start : 28, len : 1, def : ' ' },
1061             SER : {start : 28, len : 1, def : ' ' },
1062             VIS : {start : 28, len : 1, def : ' ' },
1063             MAP : {start : 28, len : 1, def : ' ' },
1064             COM : {start : 28, len : 1, def : ' ' }
1065         },
1066         _6 : {
1067             BKS : {start : 11, len : 1, def : ' ' },
1068             SER : {start : 11, len : 1, def : ' ' },
1069             VIS : {start : 11, len : 1, def : ' ' },
1070             MAP : {start : 11, len : 1, def : ' ' },
1071             COM : {start : 11, len : 1, def : ' ' }
1072         }
1073     },
1074     Audn : {
1075         _8 : {
1076             BKS : {start : 22, len : 1, def : ' ' },
1077             SER : {start : 22, len : 1, def : ' ' },
1078             VIS : {start : 22, len : 1, def : ' ' },
1079             SCO : {start : 22, len : 1, def : ' ' },
1080             REC : {start : 22, len : 1, def : ' ' },
1081             COM : {start : 22, len : 1, def : ' ' }
1082         },
1083         _6 : {
1084             BKS : {start : 5, len : 1, def : ' ' },
1085             SER : {start : 5, len : 1, def : ' ' },
1086             VIS : {start : 5, len : 1, def : ' ' },
1087             SCO : {start : 5, len : 1, def : ' ' },
1088             REC : {start : 5, len : 1, def : ' ' },
1089             COM : {start : 5, len : 1, def : ' ' }
1090         }
1091     },
1092     Form : {
1093         _8 : {
1094             BKS : {start : 23, len : 1, def : ' ' },
1095             SER : {start : 23, len : 1, def : ' ' },
1096             VIS : {start : 29, len : 1, def : ' ' },
1097             MIX : {start : 23, len : 1, def : ' ' },
1098             MAP : {start : 29, len : 1, def : ' ' },
1099             SCO : {start : 23, len : 1, def : ' ' },
1100             REC : {start : 23, len : 1, def : ' ' }
1101         },
1102         _6 : {
1103             BKS : {start : 6, len : 1, def : ' ' },
1104             SER : {start : 6, len : 1, def : ' ' },
1105             VIS : {start : 12, len : 1, def : ' ' },
1106             MIX : {start : 6, len : 1, def : ' ' },
1107             MAP : {start : 12, len : 1, def : ' ' },
1108             SCO : {start : 6, len : 1, def : ' ' },
1109             REC : {start : 6, len : 1, def : ' ' }
1110         }
1111     },
1112     'S/L' : {
1113         _8 : {
1114             SER : {start : 34, len : 1, def : '0' }
1115         },
1116         _6 : {
1117             SER : {start : 17, len : 1, def : '0' }
1118         }
1119     },
1120     'Alph' : {
1121         _8 : {
1122             SER : {start : 33, len : 1, def : ' ' }
1123         },
1124         _6 : {
1125             SER : {start : 16, len : 1, def : ' ' }
1126         }
1127     },
1128         "GeoDiv" : {
1129                 "_8" : {
1130                         "AUT" : {"start" : 6, "len" : 1, "def" : ' ' }
1131                 }
1132         },
1133         "Roman" : {
1134                 "_8" : {
1135                         "AUT" : {"start" : 7, "len" : 1, "def" : ' ' }
1136                 }
1137         },
1138         "CatLang" : {
1139                 "_8" : {
1140                         "AUT" : {"start" : 8, "len" : 1, "def" : ' ' }
1141                 }
1142         },
1143         "Kind" : {
1144                 "_8" : {
1145                         "AUT" : {"start" : 9, "len" : 1, "def" : ' ' }
1146                 }
1147         },
1148         "Rules" : {
1149                 "_8" : {
1150                         "AUT" : {"start" : 10, "len" : 1, "def" : ' ' }
1151                 }
1152         },
1153         "SHSys" : {
1154                 "_8" : {
1155                         "AUT" : {"start" : 11, "len" : 1, "def" : ' ' }
1156                 }
1157         },
1158         "SerType" : {
1159                 "_8" : {
1160                         "AUT" : {"start" : 12, "len" : 1, "def" : ' ' }
1161                 }
1162         },
1163         "SerNum" : {
1164                 "_8" : {
1165                         "AUT" : {"start" : 13, "len" : 1, "def" : ' ' }
1166                 }
1167         },
1168         "HeadMain" : {
1169                 "_8" : {
1170                         "AUT" : {"start" : 14, "len" : 1, "def" : ' ' }
1171                 }
1172         },
1173         "HeadSubj" : {
1174                 "_8" : {
1175                         "AUT" : {"start" : 15, "len" : 1, "def" : ' ' }
1176                 }
1177         },
1178         "HeadSer" : {
1179                 "_8" : {
1180                         "AUT" : {"start" : 16, "len" : 1, "def" : ' ' }
1181                 }
1182         },
1183         "TypeSubd" : {
1184                 "_8" : {
1185                         "AUT" : {"start" : 17, "len" : 1, "def" : ' ' }
1186                 }
1187         },
1188         "TypeGov" : {
1189                 "_8" : {
1190                         "AUT" : {"start" : 28, "len" : 1, "def" : ' ' }
1191                 }
1192         },
1193         "RefEval" : {
1194                 "_8" : {
1195                         "AUT" : {"start" : 29, "len" : 1, "def" : ' ' }
1196                 }
1197         },
1198         "RecUpd" : {
1199                 "_8" : {
1200                         "AUT" : {"start" : 31, "len" : 1, "def" : ' ' }
1201                 }
1202         },
1203         "NameDiff" : {
1204                 "_8" : {
1205                         "AUT" : {"start" : 32, "len" : 1, "def" : ' ' }
1206                 }
1207         },
1208         "Level" : {
1209                 "_8" : {
1210                         "AUT" : {"start" : 33, "len" : 1, "def" : ' ' }
1211                 }
1212         },
1213         "ModRec" : {
1214                 "_8" : {
1215                         "AUT" : {"start" : 38, "len" : 1, "def" : ' ' }
1216                 }
1217         },
1218         "CatSrc" : {
1219                 "_8" : {
1220                         "AUT" : {"start" : 39, "len" : 1, "def" : ' ' }
1221                 }
1222         }
1223 };
1224
1225 function recordType (rec) {
1226     try {
1227         var _l = rec.leader.toString();
1228
1229         var _t = _l.substr(ff_pos.Type.ldr.BKS.start, ff_pos.Type.ldr.BKS.len);
1230         var _b = _l.substr(ff_pos.BLvl.ldr.BKS.start, ff_pos.BLvl.ldr.BKS.len);
1231
1232         for (var t in rec_type) {
1233             if (_t.match(rec_type[t].Type) && _b.match(rec_type[t].BLvl)) {
1234                 document.getElementById('recordTypeLabel').value = t;
1235                 _record_type = t;
1236                 return t;
1237             }
1238         }
1239
1240         // in case we don't have a valid record type ...
1241         _record_type = 'BKS';
1242         return _record_type;
1243
1244     } catch(E) {
1245         alert('FIXME, MARC Editor, recordType: ' + E);
1246     }
1247 }
1248
1249 function toggleFFE () {
1250     var grid = document.getElementById('leaderGrid');
1251     if (grid.hidden) {
1252         grid.hidden = false;
1253     } else {
1254         grid.hidden = true;
1255     }
1256     return true;
1257 }
1258
1259 function changeFFEditor (type) {
1260     var grid = document.getElementById('leaderGrid');
1261     grid.setAttribute('type',type);
1262
1263     // Hide FFEditor rows that we don't need for our current type
1264     // If all of the labels for a given row do not include our
1265     // desired type in their set attribute, we can hide that row
1266     dojo.query('rows row', grid).forEach(function(node, index, arr) {
1267         if (dojo.query('label[set~=' + type + ']', node).length == 0) {
1268             node.hidden = true;
1269         }
1270     });
1271
1272 }
1273
1274 function fillFixedFields (rec) {
1275     try {
1276             var grid = document.getElementById('leaderGrid');
1277
1278             var rtype = _record_type;
1279
1280             var _l = rec.leader.toString();
1281             var _6 = rec.controlfield.(@tag=='006').toString();
1282             var _7 = rec.controlfield.(@tag=='007').toString();
1283             var _8 = rec.controlfield.(@tag=='008').toString();
1284
1285             var list = [];
1286             var pre_list = grid.getElementsByTagName('label');
1287             for (var i in pre_list) {
1288                 if ( pre_list[i].getAttribute && pre_list[i].getAttribute('set').indexOf(grid.getAttribute('type')) > -1 ) {
1289                     list.push( pre_list[i] );
1290                 }
1291             }
1292
1293             for (var i in list) {
1294                 var name = list[i].getAttribute('name');
1295
1296                 if (!ff_pos[name])
1297                     continue;
1298
1299                 var value = '';
1300                 if ( ff_pos[name].ldr && ff_pos[name].ldr[rtype] )
1301                     value = _l.substr(ff_pos[name].ldr[rtype].start, ff_pos[name].ldr[rtype].len);
1302
1303                 if ( ff_pos[name]._8 && ff_pos[name]._8[rtype] )
1304                     value = _8.substr(ff_pos[name]._8[rtype].start, ff_pos[name]._8[rtype].len);
1305
1306                 if ( !value && ff_pos[name]._6 && ff_pos[name]._6[rtype] )
1307                     value = _6.substr(ff_pos[name]._6[rtype].start, ff_pos[name]._6[rtype].len);
1308
1309                 if ( ff_pos[name]._7 && ff_pos[name]._7[rtype] )
1310                     value = _7.substr(ff_pos[name]._7[rtype].start, ff_pos[name]._7[rtype].len);
1311                 
1312                 if (!value) {
1313                     var d;
1314                     var p;
1315                     if (ff_pos[name].ldr && ff_pos[name].ldr[rtype]) {
1316                         d = ff_pos[name].ldr[rtype].def;
1317                         p = 'ldr';
1318                     }
1319
1320                     if (ff_pos[name]._8 && ff_pos[name]._8[rtype]) {
1321                         d = ff_pos[name]._8[rtype].def;
1322                         p = '_8';
1323                     }
1324
1325                     if (!value && ff_pos[name]._6 && ff_pos[name]._6[rtype]) {
1326                         d = ff_pos[name]._6[rtype].def;
1327                         p = '_6';
1328                     }
1329
1330                     if (ff_pos[name]._7 && ff_pos[name]._7[rtype]) {
1331                         d = ff_pos[name]._7[rtype].def;
1332                         p = '_7';
1333                     }
1334
1335                     if (p && !value) {
1336                         for (var j = 0; j < ff_pos[name][p][rtype].len; j++) {
1337                             value += d;
1338                         }
1339                     }
1340                 }
1341
1342                 list[i].nextSibling.value = value;
1343             }
1344
1345             return true;
1346     } catch(E) {
1347         alert('FIXME, MARC Editor, fillFixedFields: ' + E);
1348     }
1349 }
1350
1351 function updateFixedFields (element) {
1352     var grid = document.getElementById('leaderGrid');
1353     var recGrid = document.getElementById('recGrid');
1354
1355     var rtype = _record_type;
1356     var new_value = element.value;
1357
1358     var parts = {
1359         ldr : _record.leader,
1360         _6 : _record.controlfield.(@tag=='006'),
1361         _7 : _record.controlfield.(@tag=='007'),
1362         _8 : _record.controlfield.(@tag=='008')
1363     };
1364
1365     var name = element.getAttribute('name');
1366     for (var i in ff_pos[name]) {
1367
1368         if (!ff_pos[name][i][rtype]) continue;
1369         if (!parts[i]) {
1370             // we're missing the required field.  Add it now.
1371
1372             var newfield;
1373             if (i == '_6') newfield = '006';
1374             else if (i == '_7') newfield = '007';
1375             else if (i == '_8') newfield = '008';
1376             else continue;
1377
1378             createControlField(newfield,'                                        ');
1379             parts[i] = _record.controlfield.(@tag==newfield);
1380         }
1381
1382         var before = parts[i].substr(0, ff_pos[name][i][rtype].start);
1383         var after = parts[i].substr(ff_pos[name][i][rtype].start + ff_pos[name][i][rtype].len);
1384
1385         for (var j = 0; new_value.length < ff_pos[name][i][rtype].len; j++) {
1386             new_value += ff_pos[name][i][rtype].def;
1387         }
1388
1389         parts[i].setChildren( before + new_value + after );
1390         recGrid.getElementsByAttribute('tag',i)[0].lastChild.value = parts[i].toString();
1391     }
1392
1393     return true;
1394 }
1395
1396 function marcLeader (leader) {
1397     var row = createRow(
1398         { class : 'marcLeaderRow',
1399           tag : 'ldr' },
1400         createLabel(
1401             { value : 'LDR',
1402               class : 'marcTag',
1403               tooltiptext : $('catStrings').getString('staff.cat.marcedit.marcTag.LDR.label') } ),
1404         createLabel(
1405             { value : '',
1406               class : 'marcInd1' } ),
1407         createLabel(
1408             { value : '',
1409               class : 'marcInd2' } ),
1410         createLabel(
1411             { value : leader.text(),
1412               class : 'marcLeader' } )
1413     );
1414
1415     return row;
1416 }
1417
1418 function marcControlfield (field) {
1419     tagname = field.@tag.toString().substr(2);
1420     var row;
1421     if (tagname == '1' || tagname == '3' || tagname == '6' || tagname == '7' || tagname == '8') {
1422         row = createRow(
1423             { class : 'marcControlfieldRow',
1424               tag : '_' + tagname },
1425             createLabel(
1426                 { value : field.@tag,
1427                   class : 'marcTag',
1428                   context : 'tags_popup',
1429                   onmouseover : 'getTooltip(this, "tag");',
1430                   tooltipid : 'tag' + field.@tag } ),
1431             createLabel(
1432                 { value : field.@ind1,
1433                   class : 'marcInd1',
1434                   onmouseover : 'getTooltip(this, "ind1");',
1435                   tooltipid : 'tag' + field.@tag + 'ind1val' + field.@ind1 } ),
1436             createLabel(
1437                 { value : field.@ind2,
1438                   class : 'marcInd2',
1439                   onmouseover : 'getTooltip(this, "ind2");',
1440                   tooltipid : 'tag' + field.@tag + 'ind2val' + field.@ind2 } ),
1441             createMARCTextbox(
1442                 field,
1443                 { value : field.text(),
1444                   class : 'plain marcEditableControlfield',
1445                   name : 'CONTROL' + tagname,
1446                   context : 'clipboard',
1447                   size : 50,
1448                   maxlength : 50 } )
1449             );
1450     } else {
1451         row = createRow(
1452             { class : 'marcControlfieldRow',
1453               tag : '_' + tagname },
1454             createLabel(
1455                 { value : field.@tag,
1456                   class : 'marcTag',
1457                   onmouseover : 'getTooltip(this, "tag");',
1458                   tooltipid : 'tag' + field.@tag } ),
1459             createLabel(
1460                 { value : field.@ind1,
1461                   class : 'marcInd1',
1462                   onmouseover : 'getTooltip(this, "ind1");',
1463                   tooltipid : 'tag' + field.@tag + 'ind1val' + field.@ind1 } ),
1464             createLabel(
1465                 { value : field.@ind2,
1466                   class : 'marcInd2',
1467                   onmouseover : 'getTooltip(this, "ind2");',
1468                   tooltipid : 'tag' + field.@tag + 'ind2val' + field.@ind2 } ),
1469             createLabel(
1470                 { value : field.text(),
1471                   class : 'marcControlfield' } )
1472         );
1473     }
1474
1475     return row;
1476 }
1477
1478 function stackSubfields(checkbox) {
1479     var list = document.getElementsByAttribute('name','sf_box');
1480
1481     var o = 'vertical';
1482     if (!checkbox.checked) o = 'horizontal';
1483     
1484     for (var i = 0; i < list.length; i++) {
1485         if (list[i]) list[i].setAttribute('orient',o);
1486     }
1487 }
1488
1489 function fastItemAdd_toggle(checkbox) {
1490     var x = document.getElementById('fastItemAdd_textboxes');
1491     if (checkbox.checked) {
1492         x.hidden = false;
1493         document.getElementById('fastItemAdd_callnumber').focus();
1494         document.getElementById('fastItemAdd_callnumber').select();
1495     } else {
1496         x.hidden = true;
1497     }
1498 }
1499
1500 function fastItemAdd_attempt(doc_id) {
1501     try {
1502         if (typeof window.xulG.fast_add_item != 'function') { return; }
1503         if (!document.getElementById('fastItemAdd_checkbox').checked) { return; }
1504         if (!document.getElementById('fastItemAdd_callnumber').value) { return; }
1505         if (!document.getElementById('fastItemAdd_barcode').value) { return; }
1506         window.xulG.fast_add_item( doc_id, document.getElementById('fastItemAdd_callnumber').value, document.getElementById('fastItemAdd_barcode').value );
1507         document.getElementById('fastItemAdd_barcode').value = '';
1508     } catch(E) {
1509         alert('fastItemAdd_attempt: ' + E);
1510     }
1511 }
1512
1513 function save_attempt(xml_string) {
1514     try {
1515         var result = window.xulG.save.func( xml_string );   
1516         if (result) {
1517             if (result.id) fastItemAdd_attempt(result.id);
1518             if (typeof result.on_complete == 'function') result.on_complete();
1519         }
1520     } catch(E) {
1521         alert('save_attempt: ' + E);
1522     }
1523 }
1524
1525 function marcDatafield (field) {
1526     var row = createRow(
1527         { class : 'marcDatafieldRow' },
1528         createMARCTextbox(
1529             field.@tag,
1530             { value : field.@tag,
1531               class : 'plain marcTag',
1532               name : 'marcTag',
1533               context : 'tags_popup',
1534               oninput : 'if (this.value.length == 3) { this.nextSibling.focus(); }',
1535               size : 3,
1536               maxlength : 3,
1537               onmouseover : 'current_focus = this; getTooltip(this, "tag");' } ),
1538         createMARCTextbox(
1539             field.@ind1,
1540             { value : field.@ind1,
1541               class : 'plain marcInd1',
1542               name : 'marcInd1',
1543               oninput : 'if (this.value.length == 1) { this.nextSibling.focus(); }',
1544               size : 1,
1545               maxlength : 1,
1546               onmouseover : 'current_focus = this; getContextMenu(this, "ind1"); getTooltip(this, "ind1");',
1547               oncontextmenu : 'getContextMenu(this, "ind1");' } ),
1548         createMARCTextbox(
1549             field.@ind2,
1550             { value : field.@ind2,
1551               class : 'plain marcInd2',
1552               name : 'marcInd2',
1553               oninput : 'if (this.value.length == 1) { this.nextSibling.firstChild.firstChild.focus(); }',
1554               size : 1,
1555               maxlength : 1,
1556               onmouseover : 'current_focus = this; getContextMenu(this, "ind2"); getTooltip(this, "ind2");',
1557               oncontextmenu : 'getContextMenu(this, "ind2");' } ),
1558         createHbox({ name : 'sf_box' })
1559     );
1560
1561     if (!current_focus && field.@tag == '') current_focus = row.childNodes[0];
1562     if (!current_focus && field.@ind1 == '') current_focus = row.childNodes[1];
1563     if (!current_focus && field.@ind2 == '') current_focus = row.childNodes[2];
1564
1565     var sf_box = row.lastChild;
1566     if (document.getElementById('stackSubfields').checked)
1567         sf_box.setAttribute('orient','vertical');
1568
1569     sf_box.addEventListener(
1570         'click',
1571         function (e) {
1572             if (sf_box === e.target) {
1573                 sf_box.lastChild.lastChild.focus();
1574             } else if (e.target.parentNode === sf_box) {
1575                 e.target.lastChild.focus();
1576             }
1577         },
1578         false
1579     );
1580
1581
1582     for (var i in field.subfield) {
1583         var sf = field.subfield[i];
1584         sf_box.appendChild(
1585             marcSubfield(sf)
1586         );
1587
1588         dojo.query('.marcSubfield', sf_box).forEach(wrap_long_fields);
1589
1590         if (sf.@code == '' && (!current_focus || current_focus.className.match(/Ind/)))
1591             current_focus = sf_box.lastChild.childNodes[1];
1592     }
1593
1594     return row;
1595 }
1596
1597 function marcSubfield (sf) {            
1598     return createHbox(
1599         { class : 'marcSubfieldBox' },
1600         createLabel(
1601             { value : "\u2021",
1602               class : 'plain marcSubfieldDelimiter',
1603               onmouseover : 'getTooltip(this.nextSibling, "subfield");',
1604               oncontextmenu : 'getContextMenu(this.nextSibling, "subfield");',
1605                 //onclick : 'this.nextSibling.focus();',
1606                 onfocus : 'this.nextSibling.focus();',
1607               size : 2 } ),
1608         createMARCTextbox(
1609             sf.@code,
1610             { value : sf.@code,
1611               class : 'plain marcSubfieldCode',
1612               name : 'marcSubfieldCode',
1613               onmouseover : 'current_focus = this; getContextMenu(this, "subfield"); getTooltip(this, "subfield");',
1614               oncontextmenu : 'getContextMenu(this, "subfield");',
1615               oninput : 'if (this.value.length == 1) { this.nextSibling.focus(); }',
1616               size : 2,
1617               maxlength : 1 } ),
1618         createMARCTextbox(
1619             sf,
1620             { value : sf.text(),
1621               name : sf.parent().@tag + ':' + sf.@code,
1622               class : 'plain marcSubfield', 
1623               onmouseover : 'getTooltip(this, "subfield");',
1624               contextmenu : function (event) { getAuthorityContextMenu(event.target, sf) },
1625               size : new String(sf.text()).length + 2,
1626               oninput : "this.setAttribute('size', this.value.length + 2);"
1627             } )
1628     );
1629 }
1630
1631 function loadRecord(rec) {
1632     try {
1633             _record = rec;
1634             var grid_rows = document.getElementById('recGrid').lastChild;
1635
1636             while (grid_rows.firstChild) grid_rows.removeChild(grid_rows.firstChild);
1637
1638             grid_rows.appendChild( marcLeader( rec.leader ) );
1639
1640             for (var i in rec.controlfield) {
1641                 grid_rows.appendChild( marcControlfield( rec.controlfield[i] ) );
1642             }
1643
1644             for (var i in rec.datafield) {
1645                 grid_rows.appendChild( marcDatafield( rec.datafield[i] ) );
1646             }
1647
1648             grid_rows.getElementsByAttribute('class','marcDatafieldRow')[0].firstChild.focus();
1649             changeFFEditor(recordType(rec));
1650             fillFixedFields(rec);
1651     } catch(E) {
1652         alert('FIXME, MARC Editor, loadRecord: ' + E);
1653     }
1654 }
1655
1656
1657 function genToolTips () {
1658     for (var i in bib_data.field) {
1659         var f = bib_data.field[i];
1660     
1661         tag_menu.appendChild(
1662             createMenuitem(
1663                 { label : f.@tag,
1664                   oncommand : 
1665                       'current_focus.value = "' + f.@tag + '";' +
1666                     'var e = document.createEvent("MutationEvents");' +
1667                     'e.initMutationEvent("change",1,1,null,0,0,0,0);' +
1668                     'current_focus.inputField.dispatchEvent(e);',
1669                   disabled : f.@tag < '010' ? "true" : "false",
1670                   tooltiptext : f.description }
1671             )
1672         );
1673     
1674         var i1_popup = createPopup({position : 'after_start', id : 't' + f.@tag + 'i1' });
1675         context_menus.appendChild( i1_popup );
1676     
1677         var i2_popup = createPopup({position : 'after_start', id : 't' + f.@tag + 'i2' });
1678         context_menus.appendChild( i2_popup );
1679     
1680         var sf_popup = createPopup({position : 'after_start', id : 't' + f.@tag + 'sf' });
1681         context_menus.appendChild( sf_popup );
1682     
1683         tooltip_hash['tag' + f.@tag] = f.description;
1684         for (var j in f.indicator) {
1685             var ind = f.indicator[j];
1686             tooltip_hash['tag' + f.@tag + 'ind' + ind.@position + 'val' + ind.@value] = ind.description;
1687     
1688             if (ind.@position == 1) {
1689                 i1_popup.appendChild(
1690                     createMenuitem(
1691                         { label : ind.@value,
1692                           oncommand : 
1693                               'current_focus.value = "' + ind.@value + '";' +
1694                             'var e = document.createEvent("MutationEvents");' +
1695                             'e.initMutationEvent("change",1,1,null,0,0,0,0);' +
1696                             'current_focus.inputField.dispatchEvent(e);',
1697                           tooltiptext : ind.description }
1698                     )
1699                 );
1700             }
1701     
1702             if (ind.@position == 2) {
1703                 i2_popup.appendChild(
1704                     createMenuitem(
1705                         { label : ind.@value,
1706                           oncommand : 
1707                               'current_focus.value = "' + ind.@value + '";' +
1708                             'var e = document.createEvent("MutationEvents");' +
1709                             'e.initMutationEvent("change",1,1,null,0,0,0,0);' +
1710                             'current_focus.inputField.dispatchEvent(e);',
1711                           tooltiptext : ind.description }
1712                     )
1713                 );
1714             }
1715         }
1716     
1717         for (var j in f.subfield) {
1718             var sf = f.subfield[j];
1719             tooltip_hash['tag' + f.@tag + 'sf' + sf.@code] = sf.description;
1720     
1721             sf_popup.appendChild(
1722                 createMenuitem(
1723                     { label : sf.@code,
1724                       oncommand : 
1725                           'current_focus.value = "' + sf.@code + '";' +
1726                         'var e = document.createEvent("MutationEvents");' +
1727                         'e.initMutationEvent("change",1,1,null,0,0,0,0);' +
1728                         'current_focus.inputField.dispatchEvent(e);',
1729                       tooltiptext : sf.description
1730                     }
1731                 )
1732             );
1733         }
1734     }
1735 }
1736
1737 function getTooltip (target, type) {
1738
1739     var tt = '';
1740     if (type == 'subfield')
1741         tt = 'tag' + target.parentNode.parentNode.parentNode.firstChild.value + 'sf' + target.parentNode.childNodes[1].value;
1742
1743     if (type == 'ind1')
1744         tt = 'tag' + target.parentNode.firstChild.value + 'ind1val' + target.value;
1745
1746     if (type == 'ind2')
1747         tt = 'tag' + target.parentNode.firstChild.value + 'ind2val' + target.value;
1748
1749     if (type == 'tag')
1750         tt = 'tag' + target.parentNode.firstChild.value;
1751
1752     if (!document.getElementById( tt )) {
1753         p.appendChild(
1754             createTooltip(
1755                 { id : tt,
1756                   flex : "1",
1757                   orient : 'vertical',
1758                   onpopupshown : 'this.width = this.firstChild.boxObject.width + 10; this.height = this.firstChild.boxObject.height + 10;',
1759                   class : 'tooltip' },
1760                 createDescription({}, document.createTextNode( tooltip_hash[tt] ) )
1761             )
1762         );
1763     }
1764
1765     target.tooltip = tt;
1766     return true;
1767 }
1768
1769 function getContextMenu (target, type) {
1770
1771     var tt = '';
1772     if (type == 'subfield')
1773         tt = 't' + target.parentNode.parentNode.parentNode.firstChild.value + 'sf';
1774
1775     if (type == 'ind1')
1776         tt = 't' + target.parentNode.firstChild.value + 'i1';
1777
1778     if (type == 'ind2')
1779         tt = 't' + target.parentNode.firstChild.value + 'i2';
1780
1781     target.setAttribute('context', tt);
1782     return true;
1783 }
1784
1785 var authority_tag_map = {
1786     100 : ['[100,400,500,700]',100],
1787     400 : ['[100,400,500,700]',100],
1788     700 : ['[100,400,500,700]',100],
1789     800 : ['[100,400,500,700]',100],
1790     110 : ['[110,410,510,710]',110],
1791     410 : ['[110,410,510,710]',110],
1792     710 : ['[110,410,510,710]',110],
1793     810 : ['[110,410,510,710]',110],
1794     111 : ['[111,411,511,711]',111],
1795     411 : ['[111,411,511,711]',111],
1796     711 : ['[111,411,511,711]',111],
1797     811 : ['[111,411,511,711]',111],
1798     240 : ['[130,430,530,730]',130],
1799     440 : ['[130,430,530,730]',130],
1800     130 : ['[130,430,530,730]',130],
1801     730 : ['[130,430,530,730]',130],
1802     830 : ['[130,430,530,730]',130],
1803     600 : ['[100,400,480,481,482,485,500,580,581,582,585,700,780,781,782,785]',100],
1804     650 : ['[150,450,480,481,482,485,550,580,581,582,585,750,780,781,782,785]',150],
1805     651 : ['[151,451,480,481,482,485,551,580,581,582,585,751,780,781,782,785]',151],
1806     655 : ['[155,455,480,481,482,485,555,580,581,582,585,755,780,781,782,785]',155]
1807 };
1808
1809 function getAuthorityContextMenu (target, sf) {
1810     var menu_id = sf.parent().@tag + ':' + sf.@code + '-authority-context-' + sf;
1811
1812     var old = document.getElementById( menu_id );
1813     if (old) old.parentNode.removeChild(old);
1814
1815     var sf_popup = createPopup({ id : menu_id, flex : 1 });
1816     context_menus.appendChild( sf_popup );
1817
1818     if (!authority_tag_map[sf.parent().@tag]) {
1819         sf_popup.appendChild(createLabel( { value : $('catStrings').getString('staff.cat.marcedit.not_authority_field.label') } ) );
1820         target.setAttribute('context', 'clipboard');
1821         return false;
1822     }
1823
1824     var auth_data = searchAuthority( sf, authority_tag_map[sf.parent().@tag][0], sf.@code, 50);
1825
1826     var res = new XML( auth_data.responseText );
1827
1828     var rec_list = [];
1829
1830     var recs = res.gw::payload.gw::array.gw::string;
1831     for (var i in recs) {
1832         var x = recs[i];
1833         var xml = new XML(x.toString());
1834         var main = xml.datafield.(@tag.toString().match(/^1/)).subfield;
1835
1836         if (! (main[0].parent().@tag == authority_tag_map[sf.parent().@tag][1]) ) continue;
1837
1838         var main_text = '';
1839         for (var i in main) {
1840             if (main_text) main_text += ' / ';
1841             main_text += main[i];
1842         }
1843
1844         rec_list.push( [ main_text, xml ] );
1845     }
1846     
1847     for (var i in rec_list.sort( function (a, b) { if(a[0] > b[0]) return 1; return -1; } )) {
1848
1849         var main_text = rec_list[i][0];
1850         var xml = rec_list[i][1];
1851         var main = xml.datafield.(@tag.toString().match(/^1/)).subfield;
1852
1853         if (! (main[0].parent().@tag == authority_tag_map[sf.parent().@tag][1]) ) continue;
1854
1855         var grid = document.getElementsByAttribute('name','authority-marc-template')[0].cloneNode(true);
1856         grid.setAttribute('name','-none-');
1857         grid.setAttribute('style','overflow:scroll');
1858
1859
1860         var submenu = createMenu( { label : main_text } );
1861
1862         var popup = createMenuPopup({ flex : "1" });
1863         submenu.appendChild(popup);
1864
1865         var fields = xml.datafield;
1866         for (var j in fields) {
1867
1868             var row = createRow(
1869                 {},
1870                 createLabel( { value : fields[j].@tag } ),
1871                 createLabel( { value : fields[j].@ind1 } ),
1872                 createLabel( { value : fields[j].@ind2 } )
1873             );
1874
1875             var sf_box = createHbox();
1876
1877             var subfields = fields[j].subfield;
1878             for (var k in subfields) {
1879                 sf_box.appendChild(
1880                     createCheckbox(
1881                         { label    : '\u2021' + subfields[k].@code + ' ' + subfields[k],
1882                           subfield : subfields[k].@code,
1883                           tag      : subfields[k].parent().@tag,
1884                           value    : subfields[k]
1885                         }
1886                     )
1887                 );
1888                 row.appendChild(sf_box);
1889             }
1890
1891             grid.lastChild.appendChild(row);
1892         }
1893
1894         grid.hidden = false;
1895         popup.appendChild( grid );
1896
1897         popup.appendChild(
1898             createMenuitem(
1899                 { label : $('catStrings').getString('staff.cat.marcedit.apply_selected.label'),
1900                   command : function (event) {
1901                         applyAuthority(event.target.previousSibling, target, sf);
1902                         return true;
1903                   }
1904                 }
1905             )
1906         );
1907
1908         sf_popup.appendChild( submenu );
1909     }
1910
1911     if (sf_popup.childNodes.length == 0)
1912         sf_popup.appendChild(createLabel( { value : $('catStrings').getString('staff.cat.marcedit.no_authority_match.label') } ) );
1913
1914     target.setAttribute('context', menu_id);
1915     return true;
1916 }
1917
1918 function applyAuthority ( target, ui_sf, e4x_sf ) {
1919
1920     var new_vals = target.getElementsByAttribute('checked','true');
1921     var field = e4x_sf.parent();
1922
1923     for (var i = 0; i < new_vals.length; i++) {
1924
1925         var sf_list = field.subfield;
1926         for (var j in sf_list) {
1927
1928             if (sf_list[j].@code == new_vals[i].getAttribute('subfield')) {
1929                 sf_list[j] = new_vals[i].getAttribute('value');
1930                 new_vals[i].setAttribute('subfield','');
1931                 break;
1932             }
1933         }
1934     }
1935
1936     for (var i = 0; i < new_vals.length; i++) {
1937         if (!new_vals[i].getAttribute('subfield')) continue;
1938
1939         var val = new_vals[i].getAttribute('value');
1940
1941         var sf = <subfield code="" xmlns="http://www.loc.gov/MARC21/slim">{val}</subfield>;
1942         sf.@code = new_vals[i].getAttribute('subfield');
1943
1944         field.insertChildAfter(field.subfield[field.subfield.length() - 1], sf);
1945     }
1946
1947     var row = marcDatafield( field );
1948
1949     var node = ui_sf;
1950     while (node.nodeName != 'row') {
1951         node = node.parentNode;
1952     }
1953
1954     node.parentNode.replaceChild( row, node );
1955     return true;
1956 }
1957
1958 var control_map = {
1959     100 : {
1960         'a' : { 100 : 'a' },
1961         'd' : { 100 : 'd' },
1962         'e' : { 100 : 'e' },
1963         'q' : { 100 : 'q' }
1964     },
1965     110 : {
1966         'a' : { 110 : 'a' },
1967         'd' : { 110 : 'd' }
1968     },
1969     111 : {
1970         'a' : { 111 : 'a' },
1971         'd' : { 111 : 'd' }
1972     },
1973     130 : {
1974         'a' : { 130 : 'a' },
1975         'd' : { 130 : 'd' }
1976     },
1977     240 : {
1978         'a' : { 130 : 'a' },
1979         'd' : { 130 : 'd' }
1980     },
1981     400 : {
1982         'a' : { 100 : 'a' },
1983         'd' : { 100 : 'd' }
1984     },
1985     410 : {
1986         'a' : { 110 : 'a' },
1987         'd' : { 110 : 'd' }
1988     },
1989     411 : {
1990         'a' : { 111 : 'a' },
1991         'd' : { 111 : 'd' }
1992     },
1993     440 : {
1994         'a' : { 130 : 'a' },
1995         'n' : { 130 : 'n' },
1996         'p' : { 130 : 'p' }
1997     },
1998     700 : {
1999         'a' : { 100 : 'a' },
2000         'd' : { 100 : 'd' },
2001         'q' : { 100 : 'q' },
2002         't' : { 100 : 't' }
2003     },
2004     710 : {
2005         'a' : { 110 : 'a' },
2006         'd' : { 110 : 'd' }
2007     },
2008     711 : {
2009         'a' : { 111 : 'a' },
2010         'c' : { 111 : 'c' },
2011         'd' : { 111 : 'd' }
2012     },
2013     730 : {
2014         'a' : { 130 : 'a' },
2015         'd' : { 130 : 'd' }
2016     },
2017     800 : {
2018         'a' : { 100 : 'a' },
2019         'd' : { 100 : 'd' }
2020     },
2021     810 : {
2022         'a' : { 110 : 'a' },
2023         'd' : { 110 : 'd' }
2024     },
2025     811 : {
2026         'a' : { 111 : 'a' },
2027         'd' : { 111 : 'd' }
2028     },
2029     830 : {
2030         'a' : { 130 : 'a' },
2031         'd' : { 130 : 'd' }
2032     },
2033     600 : {
2034         'a' : { 100 : 'a' },
2035         'd' : { 100 : 'd' },
2036         'q' : { 100 : 'q' },
2037         't' : { 100 : 't' },
2038         'v' : { 180 : 'v',
2039             100 : 'v',
2040             181 : 'v',
2041             182 : 'v',
2042             185 : 'v'
2043         },
2044         'x' : { 180 : 'x',
2045             100 : 'x',
2046             181 : 'x',
2047             182 : 'x',
2048             185 : 'x'
2049         },
2050         'y' : { 180 : 'y',
2051             100 : 'y',
2052             181 : 'y',
2053             182 : 'y',
2054             185 : 'y'
2055         },
2056         'z' : { 180 : 'z',
2057             100 : 'z',
2058             181 : 'z',
2059             182 : 'z',
2060             185 : 'z'
2061         }
2062     },
2063     610 : {
2064         'a' : { 110 : 'a' },
2065         'd' : { 110 : 'd' },
2066         't' : { 110 : 't' },
2067         'v' : { 180 : 'v',
2068             110 : 'v',
2069             181 : 'v',
2070             182 : 'v',
2071             185 : 'v'
2072         },
2073         'x' : { 180 : 'x',
2074             110 : 'x',
2075             181 : 'x',
2076             182 : 'x',
2077             185 : 'x'
2078         },
2079         'y' : { 180 : 'y',
2080             110 : 'y',
2081             181 : 'y',
2082             182 : 'y',
2083             185 : 'y'
2084         },
2085         'z' : { 180 : 'z',
2086             110 : 'z',
2087             181 : 'z',
2088             182 : 'z',
2089             185 : 'z'
2090         }
2091     },
2092     611 : {
2093         'a' : { 111 : 'a' },
2094         'd' : { 111 : 'd' },
2095         't' : { 111 : 't' },
2096         'v' : { 180 : 'v',
2097             111 : 'v',
2098             181 : 'v',
2099             182 : 'v',
2100             185 : 'v'
2101         },
2102         'x' : { 180 : 'x',
2103             111 : 'x',
2104             181 : 'x',
2105             182 : 'x',
2106             185 : 'x'
2107         },
2108         'y' : { 180 : 'y',
2109             111 : 'y',
2110             181 : 'y',
2111             182 : 'y',
2112             185 : 'y'
2113         },
2114         'z' : { 180 : 'z',
2115             111 : 'z',
2116             181 : 'z',
2117             182 : 'z',
2118             185 : 'z'
2119         }
2120     },
2121     630 : {
2122         'a' : { 130 : 'a' },
2123         'd' : { 130 : 'd' }
2124     },
2125     650 : {
2126         'a' : { 150 : 'a' },
2127         'b' : { 150 : 'b' },
2128         'v' : { 180 : 'v',
2129             150 : 'v',
2130             181 : 'v',
2131             182 : 'v',
2132             185 : 'v'
2133         },
2134         'x' : { 180 : 'x',
2135             150 : 'x',
2136             181 : 'x',
2137             182 : 'x',
2138             185 : 'x'
2139         },
2140         'y' : { 180 : 'y',
2141             150 : 'y',
2142             181 : 'y',
2143             182 : 'y',
2144             185 : 'y'
2145         },
2146         'z' : { 180 : 'z',
2147             150 : 'z',
2148             181 : 'z',
2149             182 : 'z',
2150             185 : 'z'
2151         }
2152     },
2153     651 : {
2154         'a' : { 151 : 'a' },
2155         'v' : { 180 : 'v',
2156             151 : 'v',
2157             181 : 'v',
2158             182 : 'v',
2159             185 : 'v'
2160         },
2161         'x' : { 180 : 'x',
2162             151 : 'x',
2163             181 : 'x',
2164             182 : 'x',
2165             185 : 'x'
2166         },
2167         'y' : { 180 : 'y',
2168             151 : 'y',
2169             181 : 'y',
2170             182 : 'y',
2171             185 : 'y'
2172         },
2173         'z' : { 180 : 'z',
2174             151 : 'z',
2175             181 : 'z',
2176             182 : 'z',
2177             185 : 'z'
2178         }
2179     },
2180     655 : {
2181         'a' : { 155 : 'a' },
2182         'v' : { 180 : 'v',
2183             155 : 'v',
2184             181 : 'v',
2185             182 : 'v',
2186             185 : 'v'
2187         },
2188         'x' : { 180 : 'x',
2189             155 : 'x',
2190             181 : 'x',
2191             182 : 'x',
2192             185 : 'x'
2193         },
2194         'y' : { 180 : 'y',
2195             155 : 'y',
2196             181 : 'y',
2197             182 : 'y',
2198             185 : 'y'
2199         },
2200         'z' : { 180 : 'z',
2201             155 : 'z',
2202             181 : 'z',
2203             182 : 'z',
2204             185 : 'z'
2205         }
2206     }
2207 };
2208
2209 function validateAuthority (button) {
2210     var grid = document.getElementById('recGrid');
2211     var label = button.getAttribute('label');
2212
2213     //loop over rows
2214     var rows = grid.lastChild.childNodes;
2215     for (var i = 0; i < rows.length; i++) {
2216         var row = rows[i];
2217         var tag = row.firstChild;
2218
2219         if (!control_map[tag.value]) continue
2220         button.setAttribute('label', label + ' - ' + tag.value);
2221
2222         var ind1 = tag.nextSibling;
2223         var ind2 = ind1.nextSibling;
2224         var subfields = ind2.nextSibling.childNodes;
2225
2226         var tags = {};
2227
2228         for (var j = 0; j < subfields.length; j++) {
2229             var sf = subfields[j];
2230             var sf_code = sf.childNodes[1].value;
2231             var sf_value = sf.childNodes[2].value;
2232
2233             if (!control_map[tag.value][sf_code]) continue;
2234
2235             var found = 0;
2236             for (var a_tag in control_map[tag.value][sf_code]) {
2237                 if (!tags[a_tag]) tags[a_tag] = [];
2238                 tags[a_tag].push({ term : sf_value, subfield : sf_code });
2239             }
2240
2241         }
2242
2243         for (var val_tag in tags) {
2244             var auth_data = validateBibField( [val_tag], tags[val_tag]);
2245             var res = new XML( auth_data.responseText );
2246             found = parseInt(res.gw::payload.gw::string.toString());
2247             if (found) break;
2248         }
2249
2250         // XXX If adt, etc should be validated separately from vxz, etc then move this up into the above for loop
2251         for (var j = 0; j < subfields.length; j++) {
2252             var sf = subfields[j];
2253                if (!found) {
2254                 sf.childNodes[2].inputField.style.color = 'red';
2255             } else {
2256                 sf.childNodes[2].inputField.style.color = 'black';
2257             }
2258         }
2259     }
2260
2261     button.setAttribute('label', label);
2262
2263     return true;
2264 }
2265
2266
2267 function validateBibField (tags, searches) {
2268     var url = "/gateway?input_format=json&format=xml&service=open-ils.search&method=open-ils.search.authority.validate.tag";
2269     url += '&param="tags"&param=' + js2JSON(tags);
2270     url += '&param="searches"&param=' + js2JSON(searches);
2271
2272
2273     var req = new XMLHttpRequest();
2274     req.open('GET',url,false);
2275     req.send(null);
2276
2277     return req;
2278
2279 }
2280 function searchAuthority (term, tag, sf, limit) {
2281     var url = "/gateway?input_format=json&format=xml&service=open-ils.search&method=open-ils.search.authority.fts";
2282     url += '&param="term"&param="' + term + '"';
2283     url += '&param="limit"&param=' + limit;
2284     url += '&param="tag"&param=' + tag;
2285     url += '&param="subfield"&param="' + sf + '"';
2286
2287
2288     var req = new XMLHttpRequest();
2289     req.open('GET',url,false);
2290     req.send(null);
2291
2292     return req;
2293
2294 }
2295