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