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