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