wrapping load_lib() in try {} so these can (potentially) be used outside OpenILS
[Evergreen.git] / Open-ILS / src / javascript / backend / libs / jsDOM.js
1 try {
2         load_lib('jsOO.js')
3         load_lib('xpath.js')
4 } catch (e) {}
5
6 function DOMException  (c) { this.code = c }
7 DOMException.INDEX_SIZE_ERR = 1;
8 DOMException.DOMSTRING_SIZE_ERR = 2;
9 DOMException.HIERARCHY_REQUEST_ERR = 3;
10 DOMException.WRONG_DOCUMENT_ERR = 4;
11 DOMException.INVALID_CHARACTER_ERR = 5;
12 DOMException.NO_DATA_ALLOWED_ERR = 6;
13 DOMException.NO_MODIFICATION_ALLOWED_ERR = 7;
14 DOMException.NOT_FOUND_ERR = 8;
15 DOMException.NOT_SUPPORTED_ERR = 9;
16 DOMException.INUSE_ATTRIBUTE_ERR = 10;
17 DOMException.INVALID_STATE_ERR = 11;
18 DOMException.SYNTAX_ERR = 12;
19 DOMException.INVALID_MODIFICATION_ERR = 13;
20 DOMException.NAMESPACE_ERR = 14;
21 DOMException.INVALID_ACCESS_ERR = 15;
22
23 function DOMImplementation () {
24         this._features = {};
25         this._features['CORE'] = {};
26         this._features['CORE']['any'] = true;
27         this._features['CORE']['1.0'] = true;
28         this._features['CORE']['2.0'] = true;
29         this._features['XML'] = {};
30         this._features['XML']['any'] = true;
31         this._features['XML']['1.0'] = true;
32         this._features['XML']['2.0'] = true;
33 }
34
35 DOMImplementation.method('hasFeature', function (f, v) {
36         if (!v) v = 'any';
37         if (this._features[f] && this._features[f][v])
38                 return this._features[f][v];
39         return false;
40 });
41 DOMImplementation.method('createDocumentType', function (n, p, s) {
42         return null;
43 });
44 DOMImplementation.method('createDocument', function (ns,qn,dt) {
45         var d = new Document(dt);
46         d.documentElement = d.createElement(qn);
47         d.appendChild(d.documentElement);
48         if (ns)
49                 d.documentElement.namespaceURI = ns;
50
51         installDOM3XPathSupport(d,new XPathParser());
52         return d;
53 });
54
55 var __XMLDOC = {};
56 var __XMLDOCid = 0;
57 DOMImplementation.parseString = function (xml) {
58         __XMLDOC['id' + __XMLDOCid] = {};
59         try {
60                 _OILS_FUNC_xml_parse_string(xml, '__XMLDOC.id' + __XMLDOCid);
61         } catch (e) {
62                 alert("Sorry, no string parsing support");
63         }
64         var x = __XMLDOC['id' + __XMLDOCid];
65         __XMLDOCid++;
66         return x;
67 }
68
69
70 // NodeList interface
71 function NodeList () {
72         this.length = 0;
73         //perl_print(' --  NodeList constructor');
74 }
75
76 NodeList.method('item', function (idx) {
77         return this[idx];
78 });
79 NodeList.method('push', function (node) {
80         var idx = this.length;
81         this[idx] = node;
82         this.length++;
83         return this[idx];
84 });
85
86
87
88
89 // NamedNodeMap interface
90 function NamedNodeMap () {
91         this.length = 0;
92         this._nodes = {};
93         this._ns_nodes = {};
94         //perl_print(' --  NamedNodeMap constructor');
95 }
96
97 NamedNodeMap.method('item', function (idx) {
98         return this.getNamedItem(idx);
99 });
100
101 NamedNodeMap.method('removeNamedItemNS', function (ns, name) {
102         var x = this._ns_nodes[ns][name];
103         for (var i in this._nodes) {
104                 if (this._nodes[i] === x) {
105                         this._nodes[i] = null;
106                 }
107         }
108         this._ns_nodes[ns][name] = null;
109         return x;
110 });
111
112 NamedNodeMap.method('removeNamedItem', function (name) {
113         var x = this._nodes[name];
114         for (var i in this._nodes) {
115                 if (this._nodes[i] === x) {
116                         this._nodes[i] = null;
117                 }
118         }
119         return x;
120 });
121
122 NamedNodeMap.method('getNamedItem', function (name) {
123         return this._nodes[name];
124 });
125
126 NamedNodeMap.method('getNamedItemNS', function (ns,name) {
127         return this._ns_nodes[ns][name];
128 });
129
130 NamedNodeMap.method('setNamedItem', function (node) {
131         if (node.nodeName == 'length') return null;
132         this[node.nodeName] = node.value;
133         this[this.length] = node.value;
134         this._nodes[node.nodeName] = node;
135         this._nodes[this.length] = node;
136         this.length++;
137 });
138
139 NamedNodeMap.method('setNamedItemNS', function (node) {
140         if (node.nodeName == 'length') return null;
141         this[this.length] = node.value;
142         if (!this._ns_nodes[node.namespaceURI]) this._ns_nodes[node.namespaceURI] = {};
143         this._ns_nodes[node.namespaceURI][node.nodeName] = node;
144         this._nodes[this.length] = node;
145         this.length++;
146 });
147
148 // Node interface
149 function Node (name) {
150         this.nodeName = name;
151         this.nodeValue = null;
152         this.nodeType = null;
153         this.parentNode = null;
154         this.childNodes = new NodeList();
155         this.firstChild = null;
156         this.lastChild = null;
157         this.previousSibling = null;
158         this.nextSibling = null;
159         this.attributes = new NamedNodeMap();
160         this.ownerDocument = null;
161         this.namespaceURI = null;
162
163         if (name) {
164                 var p = name.indexOf(':');
165                 if (p != -1) {
166                         this.prefix = name.substring(0,p);
167                         this.localName = name.substring(p + 1);
168                 } else {
169                         this.localName = name;
170                 }
171         }
172
173         //perl_print(' --  Node constructor');
174 }
175 Node.ELEMENT_NODE = 1;
176 Node.ATTRIBUTE_NODE = 2;
177 Node.TEXT_NODE = 3;
178 Node.CDATA_SECTION_NODE = 4;
179 Node.ENTITY_REFERENCE_NODE = 5;
180 Node.ENTITY_NODE = 6;
181 Node.PROCESSING_INSTRUCTION_NODE = 7;
182 Node.COMMENT_NODE = 8;
183 Node.DOCUMENT_NODE = 9;
184 Node.DOCUMENT_TYPE_NODE = 10;
185 Node.DOCUMENT_FRAGMENT_NODE = 11;
186 Node.NOTATION_NODE = 12;
187 Node.NAMESPACE_DECL = 18;
188
189 Node.method('_childIndex', function (node) {
190         for (var i = 0; i < this.childNodes.length; i++)
191                 if (this.childNodes[i] === node) return i;
192 });
193 Node.method('insertBefore', function (node, target) {
194
195         if (node.nodeType == Node.DOCUMENT_FRAGMENT_NODE) {
196                 for (var i = 0; i < node.childNodes.length; i++)
197                         this.insertBefore(node.childNodes.item(i));
198                 return node;
199         }
200
201         node.parentNode = this;
202         node.ownerDocument = this.ownerDocument;
203         var i = this._childIndex(target);
204
205         for (var j = this.childNodes.length; j > i; j--)
206                 this.childNodes[j] = this.childNodes[j - 1];
207
208         this.childNodes[i] = node;
209
210         if (i == 0) {
211                 this.firstChild = node;
212         } else {
213                 this.childNodes[i - 1].nextSibling = node;
214                 node.previousSibling = this.childNodes[i + 1];
215         }
216
217         this.childNodes[i + 1].previousSibling = node;
218         node.nextSibling = this.childNodes[i + 1];
219         
220         node._index = this.ownerDocument._nodes.length;
221         this.ownerDocument._nodes[this.ownerDocument._nodes.length] = node;
222
223         this.childNodes.length++;
224         return node;
225 });
226
227 Node.method('removeChild', function (node) {
228         node.parentNode = this;
229         node.ownerDocument = this.ownerDocument;
230         var i = this._childIndex(node);
231
232         if (node === this.firstChild) {
233                 this.firstChild = node.nextSibling;
234         } else {
235                 node.previousSibling.nextSibling = node.nextSibling;
236                 for (var j = i; j < this.childNodes.length; j++)
237                         this.childNodes[j - 1] = this.childNodes[j];
238         }
239
240         if (node === this.lastChild) {
241                 this.lastChild = node.previousSibling;
242         } else {
243                 node.nextSibling.previousSibling = node.previousSibling;
244         }
245
246         this.ownerDocument._nodes[node._index] = null;
247         
248         this.childNodes.length--;
249         return node;
250 });
251
252 Node.method('appendChild', function (node) {
253
254         if (node.nodeType == Node.DOCUMENT_FRAGMENT_NODE) {
255                 for (var i = 0; i < node.childNodes.length; i++)
256                         this.appendChild(node.childNodes.item(i));
257                 return node;
258         }
259
260         node.parentNode = this;
261         this.childNodes.push( node );
262         this.lastChild = node;
263         if (this.childNodes.length == 1) {
264                 this.firstChild = node;
265         } else {
266                 this.lastChild.previousSibling = this.childNodes[this.childNodes.length - 2]
267                 this.lastChild.previousSibling.nextSibling = this.lastChild;
268         }
269
270         return node;
271 });
272
273 Node.method('hasChildNodes', function () {
274         if (this.childNodes.length) return true;
275         return false;
276 });
277
278 Node.method('hasAttributes', function () {
279         if (this.attributes.length) return true;
280         return false;
281 });
282
283 Node.method('cloneNode', function (deep) {
284         //perl_print(this.constructor);
285         var newNode = new this.constructor( this.nodeName );
286         newNode.ownerDocument = this.ownerDocument;
287         newNode.namespaceURI = this.namespaceURI;
288         newNode.prefix = this.prefix;
289
290         if (deep) {
291                 for (var i = 0; i < this.childNodes.length; i++)
292                         newNode.appendChild( this.childNodes.item(i).cloneNode(deep) );
293         }
294
295         for (var i = 0; i < this.attributes.length; i++)
296                 newNode.attributes.setNamedItem( this.attributes.item(i) );
297
298         return newNode;
299 });
300
301 function DocumentType (n,p,s) {
302         this.uber('constructor');
303         this.constructor = DocumentType;
304         this.nodeType = Node.DOCUMENT_TYPE_NODE;
305         this.name = n;
306         this.entities = new NamedNodeMap();
307         this.notations = new NamedNodeMap();
308         this.publicId = p;
309         this.systemId = s;
310         this.internalSubset = null;
311 }
312 DocumentType.inherits(Node);
313
314 function Notation (p, s) {
315         this.uber('constructor');
316         this.constructor = Notation;
317         this.nodeType = Node.NOTATION_NODE;
318         this.publicId = p;
319         this.systemId = s;
320 }
321 Notation.inherits(Node);
322
323 function ProcessingInstruction (target, data) {
324         this.uber('constructor');
325         this.constructor = ProcessingInstruction;
326         this.nodeType = Node.PROCESSING_INSTRUCTION_NODE;
327         this.target = target;
328         this.data = data;
329 }
330 ProcessingInstruction.inherits(Node);
331
332 function Entity (p, s, n) {
333         this.uber('constructor');
334         this.constructor = Entity;
335         this.nodeType = Node.ENTITY_NODE;
336         this.publicId = p;
337         this.systemId = s;
338         this.notationName = n;
339 }
340 Entity.inherits(Node);
341
342 function EntityReference () {
343         this.uber('constructor');
344         this.constructor = EntityReference;
345         this.nodeType = Node.ENTITY_REFERENCE_NODE;
346 }
347 EntityReference.inherits(Node);
348
349 // Document interface
350 function Document (dt) {
351         this.uber('constructor');
352         this.constructor = Document;
353         this.nodeType = Node.DOCUMENT_NODE;
354         this.doctype = dt;
355         this.documentElement = null;
356         this.implementation = new DOMImplementation();
357         this._nodes = [];
358         //perl_print(' --  Document constructor');
359 }
360
361 Document.inherits(Node);
362 Document.method('createAttribute', function (tagName) {
363         var node = new Attr(tagName);
364         node.ownerDocument = this;
365         return node;
366 });
367
368 Document.method('createAttributeNS', function (ns,tagName) {
369         var node = this.createAttribute(tagName);
370         node.namespaceURI = ns;
371         return node;
372 });
373
374 Document.method('createElement', function (tagName) {
375         var node = new Element(tagName);
376         node.ownerDocument = this;
377         node._index = this._nodes.length;
378         this._nodes[this._nodes.length] = node;
379         return node;
380 });
381
382 Document.method('createElementNS', function (ns,tagName) {
383         var node = this.createElement(tagName);
384         node.namespaceURI = ns;
385         return node;
386 });
387
388 Document.method('importNode', function (node, deep) {
389         var tmp = node.clone(deep);
390         tmp.ownerDocument = this;
391         var newNode = tmp.cloneNode(deep);
392         return newNode;
393 });
394
395 Document.method('createDocumentFragment', function () {
396         var x = new Node();
397         x.nodeType = Node.DOCUMENT_FRAGMENT_NODE;
398         x.ownerDocument = this;
399 });
400
401 Document.method('createTextNode', function (content) {
402         var node = new Text(content);
403         node.ownerDocument = this;
404         return node;
405 });
406
407 Document.method('createComment', function (content) {
408         var node = new Comment(content);
409         node.ownerDocument = this;
410         return node;
411 });
412
413 Document.method('createCDATASection', function (content) {
414         var node = new CDATASection(content);
415         node.ownerDocument = this;
416         return node;
417 });
418
419 Document.method('getElementById', function (id) {
420         for (var i in this._nodes) {
421                 //perl_print(' id = ' + this._nodes[i].attributes.id);
422                 if (this._nodes[i] && this._nodes[i].attributes.id == id)
423                         return this._nodes[i];
424         }
425         return null;
426 });
427
428 Document.method('getElementsByTagName', function (tname) {
429         var list = new NodeList();
430         this.documentElement.getElementsByTagName(tname, list);
431         return list;
432 });
433
434 Document.method('getElementsByTagNameNS', function (ns, tname) {
435         var list = new NodeList();
436         this.documentElement.getElementsByTagNameNS(ns, tname, list);
437         return list;
438 });
439
440 // Attr interface
441 function Attr ( name, value ) {
442         this.uber('constructor',name);
443         this.constructor = Attr;
444         this.nodeType = Node.ATTRIBUTE_NODE;
445         this.name = name;
446         this.value = this.nodeValue = value;
447         this.specified = (this.value ? true : false);
448         this.ownerElement = null;
449         //perl_print(' --  Attr constructor');
450 }
451 Attr.inherits(Node);
452
453
454 // Element interface
455 function Element ( name ) {
456         this.uber('constructor',name);
457         this.constructor = Element;
458         this.nodeType = Node.ELEMENT_NODE;
459         this.tagName = name;
460         //perl_print(' --  Element constructor')
461 }
462 Element.inherits(Node);
463
464 Element.method('getAttribute', function (aname) {
465         var x = this.attributes.getNamedItem(aname);
466         if (x) return x.value;
467         return null;
468 });
469
470 Element.method('setAttribute', function (aname,aval) {
471         var attr = new Attr(aname, aval);
472         attr.ownerElement = this;
473         return this.attributes.setNamedItem(attr);
474 });
475
476 Element.method('removeAttribute', function (aname) {
477         this.attributes.removeNamedItem(aname);
478         return null;
479 });
480
481 Element.method('getAttributeNode', function (aname) {
482         return this.attributes.getNamedItem(aname);
483 });
484
485 Element.method('setAttributeNode', function (attr) {
486         attr.ownerElement = this;
487         attr.namespaceURI = (attr.namespaceURI ? attr.namespaceURI : this.namespaceURI);
488         return this.attributes.setNamedItem(attr);
489 });
490
491 Element.method('removeAttributeNode', function (attr) {
492         if (attr.namespaceURI) {
493                 return this.attributes.removeNamedItemNS(attr.namespaceURI, attr.name);
494         } else {
495                 return this.attributes.removeNamedItem(attr.name);
496         }
497 });
498
499 Element.method('getAttributeNS', function (ns,aname) {
500         var x = this.attributes.getNamedItemNS(ns,aname);
501         if (x) return x.value;
502         return null;
503 });
504
505 Element.method('setAttributeNS', function (ns,aname,aval) {
506         var attr = new Attr(aname, aval);
507         attr.ownerElement = this;
508         attr.namespaceURI = ns;
509         return this.attributes.setNamedItem(ns,attr);
510 });
511
512 Element.method('removeAttributeNS', function (ns,aname) {
513         this.attributes.removeNamedItemNS(ns,aname);
514         return null;
515 });
516
517 Element.method('getAttributeNodeNS', function (ns, aname) {
518         return this.attributes.getNamedItemNS(ns,aname);
519 });
520
521 Element.method('setAttributeNodeNS', function (attr) {
522         attr.ownerElement = this;
523         attr.namespaceURI = (attr.namespaceURI ? attr.namespaceURI : this.namespaceURI);
524         return this.attributes.setNamedItemNS(attr);
525 });
526
527 Element.method('hasAttribute', function (name) {
528         return ( this.getAttribute(name) ? true : false );
529 });
530
531 Element.method('hasAttributeNS', function (ns, name) {
532         return ( this.getAttributeNS(ns, name) ? true : false );
533 });
534
535 Element.method('getElementsByTagName', function (tname, list) {
536         if (!list) list = new NodeList();
537         if (this.tagName == tname) list.push(this);
538         //perl_print(' --  ' + this.tagName + ' :: ' + this.childNodes.length);
539         for (var i = 0;  i < this.childNodes.length; i++) {
540                 if (this.childNodes.item(i).nodeType == 1)
541                         this.childNodes.item(i).getElementsByTagName(tname, list);
542         }
543         return list;
544 });
545
546 Element.method('getElementsByTagNameNS', function (ns, tname, list) {
547         if (!list) list = new NodeList();
548         if (this.localName == tname && this.namespaceURI == ns) list.push(this);
549         //perl_print(' --  {' + this.namespaceURI + '}:' + this.localName + ' :: ' + this.childNodes.length);
550         for (var i = 0;  i < this.childNodes.length; i++) {
551                 if (this.childNodes.item(i).nodeType == 1)
552                         this.childNodes.item(i).getElementsByTagNameNS(ns, tname, list);
553         }
554         return list;
555 });
556
557
558 // CharacterData interface
559 function CharacterData ( name, content ) {
560         this.uber('constructor', name);
561         this.constructor = CharacterData;
562         this.setData(content);
563         //perl_print(' --  CharacterData constructor');
564         //perl_print(' --  CharacterData length == ' + this.length + ' :: ' + this.data);
565 }
566 CharacterData.inherits(Node);
567
568 CharacterData.method('setData', function (content) {
569         this.data = this.nodeValue = content;
570         if (this.data)
571                 this.length = this.data.length;
572 });
573 CharacterData.method('substringData', function (offset,count) {
574         this.data.substring(offset,count);
575 });
576 CharacterData.method('appendData', function (txt) {
577         this.data = this.nodeValue = this.data + txt;
578         this.length = this.data.length;
579 });
580 CharacterData.method('insertData', function (offset,txt) {
581         var b = this.data.substring(0,offset);
582         var a = this.data.substring(offset);
583         this.data = this.nodeValue = b + txt + a;
584         this.length = this.data.length;
585 });
586 CharacterData.method('deleteData', function (offset,count) {
587         var b = this.data.substring(0,offset);
588         var a = this.data.substring(offset + count);
589         this.data = this.nodeValue = b + a;
590         this.length = this.data.length;
591 });
592 CharacterData.method('replaceData', function (offset,count,txt) {
593         var b = this.data.substring(0,offset);
594         var a = this.data.substring(offset + count);
595         this.data = this.nodeValue = b + txt +  a;
596         this.length = this.data.length;
597 });
598
599
600
601 // Text interface
602 function Text ( content ) {
603         this.superclass.constructor.call(this, '#text', content);
604         this.constructor = Text;
605         this.nodeType = Node.TEXT_NODE;
606         //perl_print(' --  Text constructor :: ' + this.data);
607 }
608 Text.inherits(CharacterData);
609
610
611 // CDATASection interface
612 function CDATASection ( content ) {
613         this.uber('constructor', '#cdata', content);
614         this.constructor = CDATASection;
615         this.nodeType = Node.COMMENT_NODE;
616         //perl_print(' --  Comment constructor');
617 }
618 CDATASection.inherits(Text);
619
620 // Comment interface
621 function Comment ( content ) {
622         this.uber('constructor', '#comment', content);
623         this.constructor = Comment;
624         this.nodeType = Node.COMMENT_NODE;
625         //perl_print(' --  Comment constructor');
626 }
627 Comment.inherits(Text);
628
629
630
631 //////////////////////// XPath stuff /////////////////////////
632
633 function XPathNamespaceResolver (data) {
634         this.data = data;
635 }
636 XPathNamespaceResolver.inherits(NamespaceResolver);
637
638 XPathNamespaceResolver.method('lookupNamespaceURI', function (prefix) {
639         return this.data[prefix];
640 });
641 XPathNamespaceResolver.method('setNamespaceURI', function (prefix, uri) {
642         this.data[prefix] = uri;
643 });
644