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