Bug 435739 Poor performance of Firefox 3 with no X RENDER extension
[wine-gecko.git] / testing / mochitest / MochiKit / DOM.js
blobcaff07ec2adc4e4d945321d43896e8a415f1ef3a
1 /***
3 MochiKit.DOM 1.4
5 See <http://mochikit.com/> for documentation, downloads, license, etc.
7 (c) 2005 Bob Ippolito.  All rights Reserved.
9 ***/
11 if (typeof(dojo) != 'undefined') {
12     dojo.provide("MochiKit.DOM");
13     dojo.require("MochiKit.Base");
15 if (typeof(JSAN) != 'undefined') {
16     JSAN.use("MochiKit.Base", []);
19 try {
20     if (typeof(MochiKit.Base) == 'undefined') {
21         throw "";
22     }
23 } catch (e) {
24     throw "MochiKit.DOM depends on MochiKit.Base!";
27 if (typeof(MochiKit.DOM) == 'undefined') {
28     MochiKit.DOM = {};
31 MochiKit.DOM.NAME = "MochiKit.DOM";
32 MochiKit.DOM.VERSION = "1.4";
33 MochiKit.DOM.__repr__ = function () {
34     return "[" + this.NAME + " " + this.VERSION + "]";
36 MochiKit.DOM.toString = function () {
37     return this.__repr__();
40 MochiKit.DOM.EXPORT = [
41     "removeEmptyTextNodes",
42     "formContents",
43     "currentWindow",
44     "currentDocument",
45     "withWindow",
46     "withDocument",
47     "registerDOMConverter",
48     "coerceToDOM",
49     "createDOM",
50     "createDOMFunc",
51     "isChildNode",
52     "getNodeAttribute",
53     "setNodeAttribute",
54     "updateNodeAttributes",
55     "appendChildNodes",
56     "replaceChildNodes",
57     "removeElement",
58     "swapDOM",
59     "BUTTON",
60     "TT",
61     "PRE",
62     "H1",
63     "H2",
64     "H3",
65     "BR",
66     "CANVAS",
67     "HR",
68     "LABEL",
69     "TEXTAREA",
70     "FORM",
71     "STRONG",
72     "SELECT",
73     "OPTION",
74     "OPTGROUP",
75     "LEGEND",
76     "FIELDSET",
77     "P",
78     "UL",
79     "OL",
80     "LI",
81     "TD",
82     "TR",
83     "THEAD",
84     "TBODY",
85     "TFOOT",
86     "TABLE",
87     "TH",
88     "INPUT",
89     "SPAN",
90     "A",
91     "DIV",
92     "IMG",
93     "getElement",
94     "$",
95     "getElementsByTagAndClassName",
96     "addToCallStack",
97     "addLoadEvent",
98     "focusOnLoad",
99     "setElementClass",
100     "toggleElementClass",
101     "addElementClass",
102     "removeElementClass",
103     "swapElementClass",
104     "hasElementClass",
105     "escapeHTML",
106     "toHTML",
107     "emitHTML",
108     "scrapeText"
111 MochiKit.DOM.EXPORT_OK = [
112     "domConverters"
115 MochiKit.DOM.DEPRECATED = [
116     ['computedStyle', 'MochiKit.Style.computedStyle', '1.4'],
117     /** @id MochiKit.DOM.elementDimensions  */
118     ['elementDimensions', 'MochiKit.Style.getElementDimensions', '1.4'],
119     /** @id MochiKit.DOM.elementPosition  */
120     ['elementPosition', 'MochiKit.Style.getElementPosition', '1.4'],
121     ['hideElement', 'MochiKit.Style.hideElement', '1.4'],
122     /** @id MochiKit.DOM.setElementDimensions */
123     ['setElementDimensions', 'MochiKit.Style.setElementDimensions', '1.4'],
124     /** @id MochiKit.DOM.setElementPosition */
125     ['setElementPosition', 'MochiKit.Style.setElementPosition', '1.4'],
126     ['setDisplayForElement', 'MochiKit.Style.setDisplayForElement', '1.4'],
127     /** @id MochiKit.DOM.setOpacity */
128     ['setOpacity', 'MochiKit.Style.setOpacity', '1.4'],
129     ['showElement', 'MochiKit.Style.showElement', '1.4'],
130     /** @id MochiKit.DOM.Coordinates */
131     ['Coordinates', 'MochiKit.Style.Coordinates', '1.4'], // FIXME: broken
132     /** @id MochiKit.DOM.Dimensions */
133     ['Dimensions', 'MochiKit.Style.Dimensions', '1.4'] // FIXME: broken
136 /** @id MochiKit.DOM.getViewportDimensions */
137 MochiKit.DOM.getViewportDimensions = new Function('' + 
138     'if (!MochiKit["Style"]) {' + 
139     '    throw new Error("This function has been deprecated and depends on MochiKit.Style.");' + 
140     '}' + 
141     'return MochiKit.Style.getViewportDimensions.apply(this, arguments);');
143 MochiKit.Base.update(MochiKit.DOM, {
145     /** @id MochiKit.DOM.currentWindow */
146     currentWindow: function () {
147         return MochiKit.DOM._window;
148     },
150     /** @id MochiKit.DOM.currentDocument */
151     currentDocument: function () {
152         return MochiKit.DOM._document;
153     },
155     /** @id MochiKit.DOM.withWindow */
156     withWindow: function (win, func) {
157         var self = MochiKit.DOM;
158         var oldDoc = self._document;
159         var oldWin = self._win;
160         var rval;
161         try {
162             self._window = win;
163             self._document = win.document;
164             rval = func();
165         } catch (e) {
166             self._window = oldWin;
167             self._document = oldDoc;
168             throw e;
169         }
170         self._window = oldWin;
171         self._document = oldDoc;
172         return rval;
173     },
175     /** @id MochiKit.DOM.formContents  */
176     formContents: function (elem/* = document */) {
177         var names = [];
178         var values = [];
179         var m = MochiKit.Base;
180         var self = MochiKit.DOM;
181         if (typeof(elem) == "undefined" || elem === null) {
182             elem = self._document;
183         } else {
184             elem = self.getElement(elem);
185         }
186         m.nodeWalk(elem, function (elem) {
187             var name = elem.name;
188             if (m.isNotEmpty(name)) {
189                 var tagName = elem.tagName.toUpperCase();
190                 if (tagName === "INPUT"
191                     && (elem.type == "radio" || elem.type == "checkbox")
192                     && !elem.checked
193                 ) {
194                     return null;
195                 }
196                 if (tagName === "SELECT") {
197                     if (elem.type == "select-one") {
198                         if (elem.selectedIndex >= 0) {
199                             var opt = elem.options[elem.selectedIndex];
200                             names.push(name);
201                             values.push(opt.value);
202                             return null;
203                         }
204                         // no form elements?
205                         names.push(name);
206                         values.push("");
207                         return null;
208                     } else {
209                         var opts = elem.options; 
210                         if (!opts.length) {
211                             names.push(name);
212                             values.push("");
213                             return null;
214                         }
215                         for (var i = 0; i < opts.length; i++) { 
216                             var opt = opts[i];
217                             if (!opt.selected) { 
218                                 continue; 
219                             } 
220                             names.push(name); 
221                             values.push(opt.value); 
222                         }
223                         return null;
224                     }
225                 }
226                 if (tagName === "FORM" || tagName === "P" || tagName === "SPAN"
227                     || tagName === "DIV"
228                 ) {
229                     return elem.childNodes;
230                 }
231                 names.push(name);
232                 values.push(elem.value || '');
233                 return null;
234             }
235             return elem.childNodes;
236         });
237         return [names, values];
238     },
240     /** @id MochiKit.DOM.withDocument */
241     withDocument: function (doc, func) {
242         var self = MochiKit.DOM;
243         var oldDoc = self._document;
244         var rval;
245         try {
246             self._document = doc;
247             rval = func();
248         } catch (e) {
249             self._document = oldDoc;
250             throw e;
251         }
252         self._document = oldDoc;
253         return rval;
254     },
256     /** @id MochiKit.DOM.registerDOMConverter */
257     registerDOMConverter: function (name, check, wrap, /* optional */override) {
258         MochiKit.DOM.domConverters.register(name, check, wrap, override);
259     },
261     /** @id MochiKit.DOM.coerceToDOM */
262     coerceToDOM: function (node, ctx) {
263         var m = MochiKit.Base;
264         var im = MochiKit.Iter;
265         var self = MochiKit.DOM;
266         if (im) {
267             var iter = im.iter;
268             var repeat = im.repeat;
269             var map = m.map;
270         }
271         var domConverters = self.domConverters;
272         var coerceToDOM = arguments.callee;
273         var NotFound = m.NotFound;
274         while (true) {
275             if (typeof(node) == 'undefined' || node === null) {
276                 return null;
277             }
278             if (typeof(node.nodeType) != 'undefined' && node.nodeType > 0) {
279                 return node;
280             }
281             if (typeof(node) == 'number' || typeof(node) == 'boolean') {
282                 node = node.toString();
283                 // FALL THROUGH
284             }
285             if (typeof(node) == 'string') {
286                 return self._document.createTextNode(node);
287             }
288             if (typeof(node.__dom__) == 'function') {
289                 node = node.__dom__(ctx);
290                 continue;
291             }
292             if (typeof(node.dom) == 'function') {
293                 node = node.dom(ctx);
294                 continue;
295             }
296             if (typeof(node) == 'function') {
297                 node = node.apply(ctx, [ctx]);
298                 continue;
299             }
301             if (im) {
302                 // iterable
303                 var iterNodes = null;
304                 try {
305                     iterNodes = iter(node);
306                 } catch (e) {
307                     // pass
308                 }
309                 if (iterNodes) {
310                     return map(coerceToDOM, iterNodes, repeat(ctx));
311                 }
312             }
314             // adapter
315             try {
316                 node = domConverters.match(node, ctx);
317                 continue;
318             } catch (e) {
319                 if (e != NotFound) {
320                     throw e;
321                 }
322             }
324             // fallback
325             return self._document.createTextNode(node.toString());
326         }
327         // mozilla warnings aren't too bright
328         return undefined;
329     },
330         
331     /** @id MochiKit.DOM.isChildNode */
332     isChildNode: function (node, maybeparent) {
333         var self = MochiKit.DOM;
334         if (typeof(node) == "string") {
335             node = self.getElement(node);
336         }
337         if (typeof(maybeparent) == "string") {
338             maybeparent = self.getElement(maybeparent);
339         }
340         if (node === maybeparent) {
341             return true;
342         }
343         while (node && node.tagName.toUpperCase() != "BODY") {
344             node = node.parentNode;
345             if (node === maybeparent) {
346                 return true;
347             }
348         }
349         return false;
350     },
352     /** @id MochiKit.DOM.setNodeAttribute */
353     setNodeAttribute: function (node, attr, value) {
354         var o = {};
355         o[attr] = value;
356         try {
357             return MochiKit.DOM.updateNodeAttributes(node, o);
358         } catch (e) {
359             // pass
360         }
361         return null;
362     },
364     /** @id MochiKit.DOM.getNodeAttribute */
365     getNodeAttribute: function (node, attr) {
366         var self = MochiKit.DOM;
367         var rename = self.attributeArray.renames[attr];
368         node = self.getElement(node);
369         try {
370             if (rename) {
371                 return node[rename];
372             }
373             return node.getAttribute(attr);
374         } catch (e) {
375             // pass
376         }
377         return null;
378     },
380     /** @id MochiKit.DOM.updateNodeAttributes */
381     updateNodeAttributes: function (node, attrs) {
382         var elem = node;
383         var self = MochiKit.DOM;
384         if (typeof(node) == 'string') {
385             elem = self.getElement(node);
386         }
387         if (attrs) {
388             var updatetree = MochiKit.Base.updatetree;
389             if (self.attributeArray.compliant) {
390                 // not IE, good.
391                 for (var k in attrs) {
392                     var v = attrs[k];
393                     if (typeof(v) == 'object' && typeof(elem[k]) == 'object') {
394                         updatetree(elem[k], v);
395                     } else if (k.substring(0, 2) == "on") {
396                         if (typeof(v) == "string") {
397                             v = new Function(v);
398                         }
399                         elem[k] = v;
400                     } else {
401                         elem.setAttribute(k, v);
402                     }
403                 }
404             } else {
405                 // IE is insane in the membrane
406                 var renames = self.attributeArray.renames;
407                 for (k in attrs) {
408                     v = attrs[k];
409                     var renamed = renames[k];
410                     if (k == "style" && typeof(v) == "string") {
411                         elem.style.cssText = v;
412                     } else if (typeof(renamed) == "string") {
413                         elem[renamed] = v;
414                     } else if (typeof(elem[k]) == 'object'
415                             && typeof(v) == 'object') {
416                         updatetree(elem[k], v);
417                     } else if (k.substring(0, 2) == "on") {
418                         if (typeof(v) == "string") {
419                             v = new Function(v);
420                         }
421                         elem[k] = v;
422                     } else {
423                         elem.setAttribute(k, v);
424                     }
425                 }
426             }
427         }
428         return elem;
429     },
431     /** @id MochiKit.DOM.appendChildNodes */
432     appendChildNodes: function (node/*, nodes...*/) {
433         var elem = node;
434         var self = MochiKit.DOM;
435         if (typeof(node) == 'string') {
436             elem = self.getElement(node);
437         }
438         var nodeStack = [
439             self.coerceToDOM(
440                 MochiKit.Base.extend(null, arguments, 1),
441                 elem
442             )
443         ];
444         var concat = MochiKit.Base.concat;
445         while (nodeStack.length) {
446             var n = nodeStack.shift();
447             if (typeof(n) == 'undefined' || n === null) {
448                 // pass
449             } else if (typeof(n.nodeType) == 'number') {
450                 elem.appendChild(n);
451             } else {
452                 nodeStack = concat(n, nodeStack);
453             }
454         }
455         return elem;
456     },
458     /** @id MochiKit.DOM.replaceChildNodes */
459     replaceChildNodes: function (node/*, nodes...*/) {
460         var elem = node;
461         var self = MochiKit.DOM;
462         if (typeof(node) == 'string') {
463             elem = self.getElement(node);
464             arguments[0] = elem;
465         }
466         var child;
467         while ((child = elem.firstChild)) {
468             elem.removeChild(child);
469         }
470         if (arguments.length < 2) {
471             return elem;
472         } else {
473             return self.appendChildNodes.apply(this, arguments);
474         }
475     },
477     /** @id MochiKit.DOM.createDOM */
478     createDOM: function (name, attrs/*, nodes... */) {
479         var elem;
480         var self = MochiKit.DOM;
481         var m = MochiKit.Base;
482         if (typeof(attrs) == "string" || typeof(attrs) == "number") {
483             var args = m.extend([name, null], arguments, 1);
484             return arguments.callee.apply(this, args);
485         }
486         if (typeof(name) == 'string') {
487             // Internet Explorer is dumb
488             var xhtml = self._xhtml;
489             if (attrs && !self.attributeArray.compliant) {
490                 // http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/name_2.asp
491                 var contents = "";
492                 if ('name' in attrs) {
493                     contents += ' name="' + self.escapeHTML(attrs.name) + '"';
494                 }
495                 if (name == 'input' && 'type' in attrs) {
496                     contents += ' type="' + self.escapeHTML(attrs.type) + '"';
497                 }
498                 if (contents) {
499                     name = "<" + name + contents + ">";
500                     xhtml = false;
501                 }
502             }
503             var d = self._document;
504             if (xhtml && d === document) {
505                 elem = d.createElementNS("http://www.w3.org/1999/xhtml", name);
506             } else {
507                 elem = d.createElement(name);
508             }
509         } else {
510             elem = name;
511         }
512         if (attrs) {
513             self.updateNodeAttributes(elem, attrs);
514         }
515         if (arguments.length <= 2) {
516             return elem;
517         } else {
518             var args = m.extend([elem], arguments, 2);
519             return self.appendChildNodes.apply(this, args);
520         }
521     },
523     /** @id MochiKit.DOM.createDOMFunc */
524     createDOMFunc: function (/* tag, attrs, *nodes */) {
525         var m = MochiKit.Base;
526         return m.partial.apply(
527             this,
528             m.extend([MochiKit.DOM.createDOM], arguments)
529         );
530     },
532     /** @id MochiKit.DOM.removeElement */
533     removeElement: function (elem) {
534         var e = MochiKit.DOM.getElement(elem);
535         e.parentNode.removeChild(e);
536         return e;
537     },
539     /** @id MochiKit.DOM.swapDOM */
540     swapDOM: function (dest, src) {
541         var self = MochiKit.DOM;
542         dest = self.getElement(dest);
543         var parent = dest.parentNode;
544         if (src) {
545             src = self.getElement(src);
546             parent.replaceChild(src, dest);
547         } else {
548             parent.removeChild(dest);
549         }
550         return src;
551     },
553     /** @id MochiKit.DOM.getElement */
554     getElement: function (id) {
555         var self = MochiKit.DOM;
556         if (arguments.length == 1) {
557             return ((typeof(id) == "string") ?
558                 self._document.getElementById(id) : id);
559         } else {
560             return MochiKit.Base.map(self.getElement, arguments);
561         }
562     },
564     /** @id MochiKit.DOM.getElementsByTagAndClassName */
565     getElementsByTagAndClassName: function (tagName, className,
566             /* optional */parent) {
567         var self = MochiKit.DOM;
568         if (typeof(tagName) == 'undefined' || tagName === null) {
569             tagName = '*';
570         }
571         if (typeof(parent) == 'undefined' || parent === null) {
572             parent = self._document;
573         }
574         parent = self.getElement(parent);
575         var children = (parent.getElementsByTagName(tagName)
576             || self._document.all);
577         if (typeof(className) == 'undefined' || className === null) {
578             return MochiKit.Base.extend(null, children);
579         }
581         var elements = [];
582         for (var i = 0; i < children.length; i++) {
583             var child = children[i];
584             var cls = child.className;
585             if (!cls) {
586                 continue;
587             }
588             var classNames = cls.split(' ');
589             for (var j = 0; j < classNames.length; j++) {
590                 if (classNames[j] == className) {
591                     elements.push(child);
592                     break;
593                 }
594             }
595         }
597         return elements;
598     },
600     _newCallStack: function (path, once) {
601         var rval = function () {
602             var callStack = arguments.callee.callStack;
603             for (var i = 0; i < callStack.length; i++) {
604                 if (callStack[i].apply(this, arguments) === false) {
605                     break;
606                 }
607             }
608             if (once) {
609                 try {
610                     this[path] = null;
611                 } catch (e) {
612                     // pass
613                 }
614             }
615         };
616         rval.callStack = [];
617         return rval;
618     },
620     /** @id MochiKit.DOM.addToCallStack */
621     addToCallStack: function (target, path, func, once) {
622         var self = MochiKit.DOM;
623         var existing = target[path];
624         var regfunc = existing;
625         if (!(typeof(existing) == 'function'
626                 && typeof(existing.callStack) == "object"
627                 && existing.callStack !== null)) {
628             regfunc = self._newCallStack(path, once);
629             if (typeof(existing) == 'function') {
630                 regfunc.callStack.push(existing);
631             }
632             target[path] = regfunc;
633         }
634         regfunc.callStack.push(func);
635     },
637     /** @id MochiKit.DOM.addLoadEvent */
638     addLoadEvent: function (func) {
639         var self = MochiKit.DOM;
640         self.addToCallStack(self._window, "onload", func, true);
641         
642     },
644     /** @id MochiKit.DOM.focusOnLoad */
645     focusOnLoad: function (element) {
646         var self = MochiKit.DOM;
647         self.addLoadEvent(function () {
648             element = self.getElement(element);
649             if (element) {
650                 element.focus();
651             }
652         });
653     },
654             
655     /** @id MochiKit.DOM.setElementClass */
656     setElementClass: function (element, className) {
657         var self = MochiKit.DOM;
658         var obj = self.getElement(element);
659         if (self.attributeArray.compliant) {
660             obj.setAttribute("class", className);
661         } else {
662             obj.setAttribute("className", className);
663         }
664     },
665             
666     /** @id MochiKit.DOM.toggleElementClass */
667     toggleElementClass: function (className/*, element... */) {
668         var self = MochiKit.DOM;
669         for (var i = 1; i < arguments.length; i++) {
670             var obj = self.getElement(arguments[i]);
671             if (!self.addElementClass(obj, className)) {
672                 self.removeElementClass(obj, className);
673             }
674         }
675     },
677     /** @id MochiKit.DOM.addElementClass */
678     addElementClass: function (element, className) {
679         var self = MochiKit.DOM;
680         var obj = self.getElement(element);
681         var cls = obj.className;
682         // trivial case, no className yet
683         if (cls == undefined || cls.length === 0) {
684             self.setElementClass(obj, className);
685             return true;
686         }
687         // the other trivial case, already set as the only class
688         if (cls == className) {
689             return false;
690         }
691         var classes = cls.split(" ");
692         for (var i = 0; i < classes.length; i++) {
693             // already present
694             if (classes[i] == className) {
695                 return false;
696             }
697         }
698         // append class
699         self.setElementClass(obj, cls + " " + className);
700         return true;
701     },
703     /** @id MochiKit.DOM.removeElementClass */
704     removeElementClass: function (element, className) {
705         var self = MochiKit.DOM;
706         var obj = self.getElement(element);
707         var cls = obj.className;
708         // trivial case, no className yet
709         if (cls == undefined || cls.length === 0) {
710             return false;
711         }
712         // other trivial case, set only to className
713         if (cls == className) {
714             self.setElementClass(obj, "");
715             return true;
716         }
717         var classes = cls.split(" ");
718         for (var i = 0; i < classes.length; i++) {
719             // already present
720             if (classes[i] == className) {
721                 // only check sane case where the class is used once
722                 classes.splice(i, 1);
723                 self.setElementClass(obj, classes.join(" "));
724                 return true;
725             }
726         }
727         // not found
728         return false;
729     },
731     /** @id MochiKit.DOM.swapElementClass */
732     swapElementClass: function (element, fromClass, toClass) {
733         var obj = MochiKit.DOM.getElement(element);
734         var res = MochiKit.DOM.removeElementClass(obj, fromClass);
735         if (res) {
736             MochiKit.DOM.addElementClass(obj, toClass);
737         }
738         return res;
739     },
741     /** @id MochiKit.DOM.hasElementClass */
742     hasElementClass: function (element, className/*...*/) {
743         var obj = MochiKit.DOM.getElement(element);
744         var cls = obj.className;
745         if (!cls) {
746             return false;
747         }
748         var classes = cls.split(" ");
749         for (var i = 1; i < arguments.length; i++) {
750             var good = false;
751             for (var j = 0; j < classes.length; j++) {
752                 if (classes[j] == arguments[i]) {
753                     good = true;
754                     break;
755                 }
756             }
757             if (!good) {
758                 return false;
759             }
760         }
761         return true;
762     },
764     /** @id MochiKit.DOM.escapeHTML */
765     escapeHTML: function (s) {
766         return s.replace(/&/g, "&amp;"
767             ).replace(/"/g, "&quot;"
768             ).replace(/</g, "&lt;"
769             ).replace(/>/g, "&gt;");
770     },
772     /** @id MochiKit.DOM.toHTML */
773     toHTML: function (dom) {
774         return MochiKit.DOM.emitHTML(dom).join("");
775     },
777     /** @id MochiKit.DOM.emitHTML */
778     emitHTML: function (dom, /* optional */lst) {
779         if (typeof(lst) == 'undefined' || lst === null) {
780             lst = [];
781         }
782         // queue is the call stack, we're doing this non-recursively
783         var queue = [dom];
784         var self = MochiKit.DOM;
785         var escapeHTML = self.escapeHTML;
786         var attributeArray = self.attributeArray;
787         while (queue.length) {
788             dom = queue.pop();
789             if (typeof(dom) == 'string') {
790                 lst.push(dom);
791             } else if (dom.nodeType == 1) {
792                 // we're not using higher order stuff here
793                 // because safari has heisenbugs.. argh.
794                 //
795                 // I think it might have something to do with
796                 // garbage collection and function calls.
797                 lst.push('<' + dom.tagName.toLowerCase());
798                 var attributes = [];
799                 var domAttr = attributeArray(dom);
800                 for (var i = 0; i < domAttr.length; i++) {
801                     var a = domAttr[i];
802                     attributes.push([
803                         " ",
804                         a.name,
805                         '="',
806                         escapeHTML(a.value),
807                         '"'
808                     ]);
809                 }
810                 attributes.sort();
811                 for (i = 0; i < attributes.length; i++) {
812                     var attrs = attributes[i];
813                     for (var j = 0; j < attrs.length; j++) {
814                         lst.push(attrs[j]);
815                     }
816                 }
817                 if (dom.hasChildNodes()) {
818                     lst.push(">");
819                     // queue is the FILO call stack, so we put the close tag
820                     // on first
821                     queue.push("</" + dom.tagName.toLowerCase() + ">");
822                     var cnodes = dom.childNodes;
823                     for (i = cnodes.length - 1; i >= 0; i--) {
824                         queue.push(cnodes[i]);
825                     }
826                 } else {
827                     lst.push('/>');
828                 }
829             } else if (dom.nodeType == 3) {
830                 lst.push(escapeHTML(dom.nodeValue));
831             }
832         }
833         return lst;
834     },
836     /** @id MochiKit.DOM.scrapeText */
837     scrapeText: function (node, /* optional */asArray) {
838         var rval = [];
839         (function (node) {
840             var cn = node.childNodes;
841             if (cn) {
842                 for (var i = 0; i < cn.length; i++) {
843                     arguments.callee.call(this, cn[i]);
844                 }
845             }
846             var nodeValue = node.nodeValue;
847             if (typeof(nodeValue) == 'string') {
848                 rval.push(nodeValue);
849             }
850         })(MochiKit.DOM.getElement(node));
851         if (asArray) {
852             return rval;
853         } else {
854             return rval.join("");
855         }
856     },    
858     /** @id MochiKit.DOM.removeEmptyTextNodes */
859     removeEmptyTextNodes: function (element) {
860         element = MochiKit.DOM.getElement(element);
861         for (var i = 0; i < element.childNodes.length; i++) {
862             var node = element.childNodes[i];
863             if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) {
864                 node.parentNode.removeChild(node);
865             }
866         }
867     },
869     __new__: function (win) {
871         var m = MochiKit.Base;
872         if (typeof(document) != "undefined") {
873             this._document = document;
874             this._xhtml =
875                 document.createElementNS &&
876                 document.createElement("testname").localName == "testname";
877         } else if (MochiKit.MockDOM) {
878             this._document = MochiKit.MockDOM.document;
879         }
880         this._window = win;
882         this.domConverters = new m.AdapterRegistry(); 
883         
884         var __tmpElement = this._document.createElement("span");
885         var attributeArray;
886         if (__tmpElement && __tmpElement.attributes &&
887                 __tmpElement.attributes.length > 0) {
888             // for braindead browsers (IE) that insert extra junk
889             var filter = m.filter;
890             attributeArray = function (node) {
891                 return filter(attributeArray.ignoreAttrFilter, node.attributes);
892             };
893             attributeArray.ignoreAttr = {};
894             var attrs = __tmpElement.attributes;
895             var ignoreAttr = attributeArray.ignoreAttr;
896             for (var i = 0; i < attrs.length; i++) {
897                 var a = attrs[i];
898                 ignoreAttr[a.name] = a.value;
899             }
900             attributeArray.ignoreAttrFilter = function (a) {
901                 return (attributeArray.ignoreAttr[a.name] != a.value);
902             };
903             attributeArray.compliant = false;
904             attributeArray.renames = {
905                 "class": "className",
906                 "checked": "defaultChecked",
907                 "usemap": "useMap",
908                 "for": "htmlFor",
909                 "readonly": "readOnly",
910                 "colspan": "colSpan",
911                 "bgcolor": "bgColor"
912             };
913         } else {
914             attributeArray = function (node) {
915                 /***
916                     
917                     Return an array of attributes for a given node,
918                     filtering out attributes that don't belong for
919                     that are inserted by "Certain Browsers".
921                 ***/
922                 return node.attributes;
923             };
924             attributeArray.compliant = true;
925             attributeArray.renames = {};
926         }
927         this.attributeArray = attributeArray;
929         // FIXME: this really belongs in Base, and could probably be cleaner
930         var _deprecated = function(fromModule, arr) {
931             var modules = arr[1].split('.');
932             var str = '';
933             var obj = {};
934             
935             str += 'if (!MochiKit.' + modules[1] + ') { throw new Error("';
936             str += 'This function has been deprecated and depends on MochiKit.';
937             str += modules[1] + '.");}';
938             str += 'return MochiKit.' + modules[1] + '.' + arr[0];
939             str += '.apply(this, arguments);';
940             
941             obj[modules[2]] = new Function(str);
942             MochiKit.Base.update(MochiKit[fromModule], obj);
943         }
944         for (var i; i < MochiKit.DOM.DEPRECATED.length; i++) {
945             _deprecated('DOM', MochiKit.DOM.DEPRECATED[i]);
946         }
948         // shorthand for createDOM syntax
949         var createDOMFunc = this.createDOMFunc;
950         /** @id MochiKit.DOM.UL */
951         this.UL = createDOMFunc("ul");
952         /** @id MochiKit.DOM.OL */
953         this.OL = createDOMFunc("ol");
954         /** @id MochiKit.DOM.LI */
955         this.LI = createDOMFunc("li");
956         /** @id MochiKit.DOM.TD */
957         this.TD = createDOMFunc("td");
958         /** @id MochiKit.DOM.TR */
959         this.TR = createDOMFunc("tr");
960         /** @id MochiKit.DOM.TBODY */
961         this.TBODY = createDOMFunc("tbody");
962         /** @id MochiKit.DOM.THEAD */
963         this.THEAD = createDOMFunc("thead");
964         /** @id MochiKit.DOM.TFOOT */
965         this.TFOOT = createDOMFunc("tfoot");
966         /** @id MochiKit.DOM.TABLE */
967         this.TABLE = createDOMFunc("table");
968         /** @id MochiKit.DOM.TH */
969         this.TH = createDOMFunc("th");
970         /** @id MochiKit.DOM.INPUT */
971         this.INPUT = createDOMFunc("input");
972         /** @id MochiKit.DOM.SPAN */
973         this.SPAN = createDOMFunc("span");
974         /** @id MochiKit.DOM.A */
975         this.A = createDOMFunc("a");
976         /** @id MochiKit.DOM.DIV */
977         this.DIV = createDOMFunc("div");
978         /** @id MochiKit.DOM.IMG */
979         this.IMG = createDOMFunc("img");
980         /** @id MochiKit.DOM.BUTTON */
981         this.BUTTON = createDOMFunc("button");
982         /** @id MochiKit.DOM.TT */
983         this.TT = createDOMFunc("tt");
984         /** @id MochiKit.DOM.PRE */
985         this.PRE = createDOMFunc("pre");
986         /** @id MochiKit.DOM.H1 */
987         this.H1 = createDOMFunc("h1");
988         /** @id MochiKit.DOM.H2 */
989         this.H2 = createDOMFunc("h2");
990         /** @id MochiKit.DOM.H3 */
991         this.H3 = createDOMFunc("h3");
992         /** @id MochiKit.DOM.BR */
993         this.BR = createDOMFunc("br");
994         /** @id MochiKit.DOM.HR */
995         this.HR = createDOMFunc("hr");
996         /** @id MochiKit.DOM.LABEL */
997         this.LABEL = createDOMFunc("label");
998         /** @id MochiKit.DOM.TEXTAREA */
999         this.TEXTAREA = createDOMFunc("textarea");
1000         /** @id MochiKit.DOM.FORM */
1001         this.FORM = createDOMFunc("form");
1002         /** @id MochiKit.DOM.P */
1003         this.P = createDOMFunc("p");
1004         /** @id MochiKit.DOM.SELECT */
1005         this.SELECT = createDOMFunc("select");
1006         /** @id MochiKit.DOM.OPTION */
1007         this.OPTION = createDOMFunc("option");
1008         /** @id MochiKit.DOM.OPTGROUP */
1009         this.OPTGROUP = createDOMFunc("optgroup");
1010         /** @id MochiKit.DOM.LEGEND */
1011         this.LEGEND = createDOMFunc("legend");
1012         /** @id MochiKit.DOM.FIELDSET */
1013         this.FIELDSET = createDOMFunc("fieldset");
1014         /** @id MochiKit.DOM.STRONG */
1015         this.STRONG = createDOMFunc("strong");
1016         /** @id MochiKit.DOM.CANVAS */
1017         this.CANVAS = createDOMFunc("canvas");
1019         /** @id MochiKit.DOM.$ */
1020         this.$ = this.getElement;
1022         this.EXPORT_TAGS = {
1023             ":common": this.EXPORT,
1024             ":all": m.concat(this.EXPORT, this.EXPORT_OK)
1025         };
1027         m.nameFunctions(this);
1029     }
1033 MochiKit.DOM.__new__(((typeof(window) == "undefined") ? this : window));
1036 // XXX: Internet Explorer blows
1038 if (MochiKit.__export__) {
1039     withWindow = MochiKit.DOM.withWindow;
1040     withDocument = MochiKit.DOM.withDocument;
1043 MochiKit.Base._exportSymbols(this, MochiKit.DOM);