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