Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /***
3 MochiKit.DOM 1.4.2
5 See <http://mochikit.com/> for documentation, downloads, license, etc.
7 (c) 2005 Bob Ippolito. All rights Reserved.
9 ***/
11 MochiKit.Base._deps('DOM', ['Base']);
13 MochiKit.DOM.NAME = "MochiKit.DOM";
14 MochiKit.DOM.VERSION = "1.4.2";
15 MochiKit.DOM.__repr__ = function () {
16 return "[" + this.NAME + " " + this.VERSION + "]";
17 };
18 MochiKit.DOM.toString = function () {
19 return this.__repr__();
20 };
22 MochiKit.DOM.EXPORT = [
23 "removeEmptyTextNodes",
24 "formContents",
25 "currentWindow",
26 "currentDocument",
27 "withWindow",
28 "withDocument",
29 "registerDOMConverter",
30 "coerceToDOM",
31 "createDOM",
32 "createDOMFunc",
33 "isChildNode",
34 "getNodeAttribute",
35 "removeNodeAttribute",
36 "setNodeAttribute",
37 "updateNodeAttributes",
38 "appendChildNodes",
39 "insertSiblingNodesAfter",
40 "insertSiblingNodesBefore",
41 "replaceChildNodes",
42 "removeElement",
43 "swapDOM",
44 "BUTTON",
45 "TT",
46 "PRE",
47 "H1",
48 "H2",
49 "H3",
50 "H4",
51 "H5",
52 "H6",
53 "BR",
54 "CANVAS",
55 "HR",
56 "LABEL",
57 "TEXTAREA",
58 "FORM",
59 "STRONG",
60 "SELECT",
61 "OPTION",
62 "OPTGROUP",
63 "LEGEND",
64 "FIELDSET",
65 "P",
66 "UL",
67 "OL",
68 "LI",
69 "DL",
70 "DT",
71 "DD",
72 "TD",
73 "TR",
74 "THEAD",
75 "TBODY",
76 "TFOOT",
77 "TABLE",
78 "TH",
79 "INPUT",
80 "SPAN",
81 "A",
82 "DIV",
83 "IMG",
84 "getElement",
85 "$",
86 "getElementsByTagAndClassName",
87 "addToCallStack",
88 "addLoadEvent",
89 "focusOnLoad",
90 "setElementClass",
91 "toggleElementClass",
92 "addElementClass",
93 "removeElementClass",
94 "swapElementClass",
95 "hasElementClass",
96 "computedStyle", // deprecated in 1.4
97 "escapeHTML",
98 "toHTML",
99 "emitHTML",
100 "scrapeText",
101 "getFirstParentByTagAndClassName",
102 "getFirstElementByTagAndClassName"
103 ];
105 MochiKit.DOM.EXPORT_OK = [
106 "domConverters"
107 ];
109 MochiKit.DOM.DEPRECATED = [
110 /** @id MochiKit.DOM.computedStyle */
111 ['computedStyle', 'MochiKit.Style.getStyle', '1.4'],
112 /** @id MochiKit.DOM.elementDimensions */
113 ['elementDimensions', 'MochiKit.Style.getElementDimensions', '1.4'],
114 /** @id MochiKit.DOM.elementPosition */
115 ['elementPosition', 'MochiKit.Style.getElementPosition', '1.4'],
116 /** @id MochiKit.DOM.getViewportDimensions */
117 ['getViewportDimensions', 'MochiKit.Style.getViewportDimensions', '1.4'],
118 /** @id MochiKit.DOM.hideElement */
119 ['hideElement', 'MochiKit.Style.hideElement', '1.4'],
120 /** @id MochiKit.DOM.makeClipping */
121 ['makeClipping', 'MochiKit.Style.makeClipping', '1.4.1'],
122 /** @id MochiKit.DOM.makePositioned */
123 ['makePositioned', 'MochiKit.Style.makePositioned', '1.4.1'],
124 /** @id MochiKit.DOM.setElementDimensions */
125 ['setElementDimensions', 'MochiKit.Style.setElementDimensions', '1.4'],
126 /** @id MochiKit.DOM.setElementPosition */
127 ['setElementPosition', 'MochiKit.Style.setElementPosition', '1.4'],
128 /** @id MochiKit.DOM.setDisplayForElement */
129 ['setDisplayForElement', 'MochiKit.Style.setDisplayForElement', '1.4'],
130 /** @id MochiKit.DOM.setOpacity */
131 ['setOpacity', 'MochiKit.Style.setOpacity', '1.4'],
132 /** @id MochiKit.DOM.showElement */
133 ['showElement', 'MochiKit.Style.showElement', '1.4'],
134 /** @id MochiKit.DOM.undoClipping */
135 ['undoClipping', 'MochiKit.Style.undoClipping', '1.4.1'],
136 /** @id MochiKit.DOM.undoPositioned */
137 ['undoPositioned', 'MochiKit.Style.undoPositioned', '1.4.1'],
138 /** @id MochiKit.DOM.Coordinates */
139 ['Coordinates', 'MochiKit.Style.Coordinates', '1.4'], // FIXME: broken
140 /** @id MochiKit.DOM.Dimensions */
141 ['Dimensions', 'MochiKit.Style.Dimensions', '1.4'] // FIXME: broken
142 ];
144 MochiKit.Base.update(MochiKit.DOM, {
146 /** @id MochiKit.DOM.currentWindow */
147 currentWindow: function () {
148 return MochiKit.DOM._window;
149 },
151 /** @id MochiKit.DOM.currentDocument */
152 currentDocument: function () {
153 return MochiKit.DOM._document;
154 },
156 /** @id MochiKit.DOM.withWindow */
157 withWindow: function (win, func) {
158 var self = MochiKit.DOM;
159 var oldDoc = self._document;
160 var oldWin = self._window;
161 var rval;
162 try {
163 self._window = win;
164 self._document = win.document;
165 rval = func();
166 } catch (e) {
167 self._window = oldWin;
168 self._document = oldDoc;
169 throw e;
170 }
171 self._window = oldWin;
172 self._document = oldDoc;
173 return rval;
174 },
176 /** @id MochiKit.DOM.formContents */
177 formContents: function (elem/* = document.body */) {
178 var names = [];
179 var values = [];
180 var m = MochiKit.Base;
181 var self = MochiKit.DOM;
182 if (typeof(elem) == "undefined" || elem === null) {
183 elem = self._document.body;
184 } else {
185 elem = self.getElement(elem);
186 }
187 m.nodeWalk(elem, function (elem) {
188 var name = elem.name;
189 if (m.isNotEmpty(name)) {
190 var tagName = elem.tagName.toUpperCase();
191 if (tagName === "INPUT"
192 && (elem.type == "radio" || elem.type == "checkbox")
193 && !elem.checked
194 ) {
195 return null;
196 }
197 if (tagName === "SELECT") {
198 if (elem.type == "select-one") {
199 if (elem.selectedIndex >= 0) {
200 var opt = elem.options[elem.selectedIndex];
201 var v = opt.value;
202 if (!v) {
203 var h = opt.outerHTML;
204 // internet explorer sure does suck.
205 if (h && !h.match(/^[^>]+\svalue\s*=/i)) {
206 v = opt.text;
207 }
208 }
209 names.push(name);
210 values.push(v);
211 return null;
212 }
213 // no form elements?
214 names.push(name);
215 values.push("");
216 return null;
217 } else {
218 var opts = elem.options;
219 if (!opts.length) {
220 names.push(name);
221 values.push("");
222 return null;
223 }
224 for (var i = 0; i < opts.length; i++) {
225 var opt = opts[i];
226 if (!opt.selected) {
227 continue;
228 }
229 var v = opt.value;
230 if (!v) {
231 var h = opt.outerHTML;
232 // internet explorer sure does suck.
233 if (h && !h.match(/^[^>]+\svalue\s*=/i)) {
234 v = opt.text;
235 }
236 }
237 names.push(name);
238 values.push(v);
239 }
240 return null;
241 }
242 }
243 if (tagName === "FORM" || tagName === "P" || tagName === "SPAN"
244 || tagName === "DIV"
245 ) {
246 return elem.childNodes;
247 }
248 names.push(name);
249 values.push(elem.value || '');
250 return null;
251 }
252 return elem.childNodes;
253 });
254 return [names, values];
255 },
257 /** @id MochiKit.DOM.withDocument */
258 withDocument: function (doc, func) {
259 var self = MochiKit.DOM;
260 var oldDoc = self._document;
261 var rval;
262 try {
263 self._document = doc;
264 rval = func();
265 } catch (e) {
266 self._document = oldDoc;
267 throw e;
268 }
269 self._document = oldDoc;
270 return rval;
271 },
273 /** @id MochiKit.DOM.registerDOMConverter */
274 registerDOMConverter: function (name, check, wrap, /* optional */override) {
275 MochiKit.DOM.domConverters.register(name, check, wrap, override);
276 },
278 /** @id MochiKit.DOM.coerceToDOM */
279 coerceToDOM: function (node, ctx) {
280 var m = MochiKit.Base;
281 var im = MochiKit.Iter;
282 var self = MochiKit.DOM;
283 if (im) {
284 var iter = im.iter;
285 var repeat = im.repeat;
286 }
287 var map = m.map;
288 var domConverters = self.domConverters;
289 var coerceToDOM = arguments.callee;
290 var NotFound = m.NotFound;
291 while (true) {
292 if (typeof(node) == 'undefined' || node === null) {
293 return null;
294 }
295 // this is a safari childNodes object, avoiding crashes w/ attr
296 // lookup
297 if (typeof(node) == "function" &&
298 typeof(node.length) == "number" &&
299 !(node instanceof Function)) {
300 node = im ? im.list(node) : m.extend(null, node);
301 }
302 if (typeof(node.nodeType) != 'undefined' && node.nodeType > 0) {
303 return node;
304 }
305 if (typeof(node) == 'number' || typeof(node) == 'boolean') {
306 node = node.toString();
307 // FALL THROUGH
308 }
309 if (typeof(node) == 'string') {
310 return self._document.createTextNode(node);
311 }
312 if (typeof(node.__dom__) == 'function') {
313 node = node.__dom__(ctx);
314 continue;
315 }
316 if (typeof(node.dom) == 'function') {
317 node = node.dom(ctx);
318 continue;
319 }
320 if (typeof(node) == 'function') {
321 node = node.apply(ctx, [ctx]);
322 continue;
323 }
325 if (im) {
326 // iterable
327 var iterNodes = null;
328 try {
329 iterNodes = iter(node);
330 } catch (e) {
331 // pass
332 }
333 if (iterNodes) {
334 return map(coerceToDOM, iterNodes, repeat(ctx));
335 }
336 } else if (m.isArrayLike(node)) {
337 var func = function (n) { return coerceToDOM(n, ctx); };
338 return map(func, node);
339 }
341 // adapter
342 try {
343 node = domConverters.match(node, ctx);
344 continue;
345 } catch (e) {
346 if (e != NotFound) {
347 throw e;
348 }
349 }
351 // fallback
352 return self._document.createTextNode(node.toString());
353 }
354 // mozilla warnings aren't too bright
355 return undefined;
356 },
358 /** @id MochiKit.DOM.isChildNode */
359 isChildNode: function (node, maybeparent) {
360 var self = MochiKit.DOM;
361 if (typeof(node) == "string") {
362 node = self.getElement(node);
363 }
364 if (typeof(maybeparent) == "string") {
365 maybeparent = self.getElement(maybeparent);
366 }
367 if (typeof(node) == 'undefined' || node === null) {
368 return false;
369 }
370 while (node != null && node !== self._document) {
371 if (node === maybeparent) {
372 return true;
373 }
374 node = node.parentNode;
375 }
376 return false;
377 },
379 /** @id MochiKit.DOM.setNodeAttribute */
380 setNodeAttribute: function (node, attr, value) {
381 var o = {};
382 o[attr] = value;
383 try {
384 return MochiKit.DOM.updateNodeAttributes(node, o);
385 } catch (e) {
386 // pass
387 }
388 return null;
389 },
391 /** @id MochiKit.DOM.getNodeAttribute */
392 getNodeAttribute: function (node, attr) {
393 var self = MochiKit.DOM;
394 var rename = self.attributeArray.renames[attr];
395 var ignoreValue = self.attributeArray.ignoreAttr[attr];
396 node = self.getElement(node);
397 try {
398 if (rename) {
399 return node[rename];
400 }
401 var value = node.getAttribute(attr);
402 if (value != ignoreValue) {
403 return value;
404 }
405 } catch (e) {
406 // pass
407 }
408 return null;
409 },
411 /** @id MochiKit.DOM.removeNodeAttribute */
412 removeNodeAttribute: function (node, attr) {
413 var self = MochiKit.DOM;
414 var rename = self.attributeArray.renames[attr];
415 node = self.getElement(node);
416 try {
417 if (rename) {
418 return node[rename];
419 }
420 return node.removeAttribute(attr);
421 } catch (e) {
422 // pass
423 }
424 return null;
425 },
427 /** @id MochiKit.DOM.updateNodeAttributes */
428 updateNodeAttributes: function (node, attrs) {
429 var elem = node;
430 var self = MochiKit.DOM;
431 if (typeof(node) == 'string') {
432 elem = self.getElement(node);
433 }
434 if (attrs) {
435 var updatetree = MochiKit.Base.updatetree;
436 if (self.attributeArray.compliant) {
437 // not IE, good.
438 for (var k in attrs) {
439 var v = attrs[k];
440 if (typeof(v) == 'object' && typeof(elem[k]) == 'object') {
441 if (k == "style" && MochiKit.Style) {
442 MochiKit.Style.setStyle(elem, v);
443 } else {
444 updatetree(elem[k], v);
445 }
446 } else if (k.substring(0, 2) == "on") {
447 if (typeof(v) == "string") {
448 v = new Function(v);
449 }
450 elem[k] = v;
451 } else {
452 elem.setAttribute(k, v);
453 }
454 if (typeof(elem[k]) == "string" && elem[k] != v) {
455 // Also set property for weird attributes (see #302)
456 elem[k] = v;
457 }
458 }
459 } else {
460 // IE is insane in the membrane
461 var renames = self.attributeArray.renames;
462 for (var k in attrs) {
463 v = attrs[k];
464 var renamed = renames[k];
465 if (k == "style" && typeof(v) == "string") {
466 elem.style.cssText = v;
467 } else if (typeof(renamed) == "string") {
468 elem[renamed] = v;
469 } else if (typeof(elem[k]) == 'object'
470 && typeof(v) == 'object') {
471 if (k == "style" && MochiKit.Style) {
472 MochiKit.Style.setStyle(elem, v);
473 } else {
474 updatetree(elem[k], v);
475 }
476 } else if (k.substring(0, 2) == "on") {
477 if (typeof(v) == "string") {
478 v = new Function(v);
479 }
480 elem[k] = v;
481 } else {
482 elem.setAttribute(k, v);
483 }
484 if (typeof(elem[k]) == "string" && elem[k] != v) {
485 // Also set property for weird attributes (see #302)
486 elem[k] = v;
487 }
488 }
489 }
490 }
491 return elem;
492 },
494 /** @id MochiKit.DOM.appendChildNodes */
495 appendChildNodes: function (node/*, nodes...*/) {
496 var elem = node;
497 var self = MochiKit.DOM;
498 if (typeof(node) == 'string') {
499 elem = self.getElement(node);
500 }
501 var nodeStack = [
502 self.coerceToDOM(
503 MochiKit.Base.extend(null, arguments, 1),
504 elem
505 )
506 ];
507 var concat = MochiKit.Base.concat;
508 while (nodeStack.length) {
509 var n = nodeStack.shift();
510 if (typeof(n) == 'undefined' || n === null) {
511 // pass
512 } else if (typeof(n.nodeType) == 'number') {
513 elem.appendChild(n);
514 } else {
515 nodeStack = concat(n, nodeStack);
516 }
517 }
518 return elem;
519 },
522 /** @id MochiKit.DOM.insertSiblingNodesBefore */
523 insertSiblingNodesBefore: function (node/*, nodes...*/) {
524 var elem = node;
525 var self = MochiKit.DOM;
526 if (typeof(node) == 'string') {
527 elem = self.getElement(node);
528 }
529 var nodeStack = [
530 self.coerceToDOM(
531 MochiKit.Base.extend(null, arguments, 1),
532 elem
533 )
534 ];
535 var parentnode = elem.parentNode;
536 var concat = MochiKit.Base.concat;
537 while (nodeStack.length) {
538 var n = nodeStack.shift();
539 if (typeof(n) == 'undefined' || n === null) {
540 // pass
541 } else if (typeof(n.nodeType) == 'number') {
542 parentnode.insertBefore(n, elem);
543 } else {
544 nodeStack = concat(n, nodeStack);
545 }
546 }
547 return parentnode;
548 },
550 /** @id MochiKit.DOM.insertSiblingNodesAfter */
551 insertSiblingNodesAfter: function (node/*, nodes...*/) {
552 var elem = node;
553 var self = MochiKit.DOM;
555 if (typeof(node) == 'string') {
556 elem = self.getElement(node);
557 }
558 var nodeStack = [
559 self.coerceToDOM(
560 MochiKit.Base.extend(null, arguments, 1),
561 elem
562 )
563 ];
565 if (elem.nextSibling) {
566 return self.insertSiblingNodesBefore(elem.nextSibling, nodeStack);
567 }
568 else {
569 return self.appendChildNodes(elem.parentNode, nodeStack);
570 }
571 },
573 /** @id MochiKit.DOM.replaceChildNodes */
574 replaceChildNodes: function (node/*, nodes...*/) {
575 var elem = node;
576 var self = MochiKit.DOM;
577 if (typeof(node) == 'string') {
578 elem = self.getElement(node);
579 arguments[0] = elem;
580 }
581 var child;
582 while ((child = elem.firstChild)) {
583 elem.removeChild(child);
584 }
585 if (arguments.length < 2) {
586 return elem;
587 } else {
588 return self.appendChildNodes.apply(this, arguments);
589 }
590 },
592 /** @id MochiKit.DOM.createDOM */
593 createDOM: function (name, attrs/*, nodes... */) {
594 var elem;
595 var self = MochiKit.DOM;
596 var m = MochiKit.Base;
597 if (typeof(attrs) == "string" || typeof(attrs) == "number") {
598 var args = m.extend([name, null], arguments, 1);
599 return arguments.callee.apply(this, args);
600 }
601 if (typeof(name) == 'string') {
602 // Internet Explorer is dumb
603 var xhtml = self._xhtml;
604 if (attrs && !self.attributeArray.compliant) {
605 // http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/name_2.asp
606 var contents = "";
607 if ('name' in attrs) {
608 contents += ' name="' + self.escapeHTML(attrs.name) + '"';
609 }
610 if (name == 'input' && 'type' in attrs) {
611 contents += ' type="' + self.escapeHTML(attrs.type) + '"';
612 }
613 if (contents) {
614 name = "<" + name + contents + ">";
615 xhtml = false;
616 }
617 }
618 var d = self._document;
619 if (xhtml && d === document) {
620 elem = d.createElementNS("http://www.w3.org/1999/xhtml", name);
621 } else {
622 elem = d.createElement(name);
623 }
624 } else {
625 elem = name;
626 }
627 if (attrs) {
628 self.updateNodeAttributes(elem, attrs);
629 }
630 if (arguments.length <= 2) {
631 return elem;
632 } else {
633 var args = m.extend([elem], arguments, 2);
634 return self.appendChildNodes.apply(this, args);
635 }
636 },
638 /** @id MochiKit.DOM.createDOMFunc */
639 createDOMFunc: function (/* tag, attrs, *nodes */) {
640 var m = MochiKit.Base;
641 return m.partial.apply(
642 this,
643 m.extend([MochiKit.DOM.createDOM], arguments)
644 );
645 },
647 /** @id MochiKit.DOM.removeElement */
648 removeElement: function (elem) {
649 var self = MochiKit.DOM;
650 var e = self.coerceToDOM(self.getElement(elem));
651 e.parentNode.removeChild(e);
652 return e;
653 },
655 /** @id MochiKit.DOM.swapDOM */
656 swapDOM: function (dest, src) {
657 var self = MochiKit.DOM;
658 dest = self.getElement(dest);
659 var parent = dest.parentNode;
660 if (src) {
661 src = self.coerceToDOM(self.getElement(src), parent);
662 parent.replaceChild(src, dest);
663 } else {
664 parent.removeChild(dest);
665 }
666 return src;
667 },
669 /** @id MochiKit.DOM.getElement */
670 getElement: function (id) {
671 var self = MochiKit.DOM;
672 if (arguments.length == 1) {
673 return ((typeof(id) == "string") ?
674 self._document.getElementById(id) : id);
675 } else {
676 return MochiKit.Base.map(self.getElement, arguments);
677 }
678 },
680 /** @id MochiKit.DOM.getElementsByTagAndClassName */
681 getElementsByTagAndClassName: function (tagName, className,
682 /* optional */parent) {
683 var self = MochiKit.DOM;
684 if (typeof(tagName) == 'undefined' || tagName === null) {
685 tagName = '*';
686 }
687 if (typeof(parent) == 'undefined' || parent === null) {
688 parent = self._document;
689 }
690 parent = self.getElement(parent);
691 if (parent == null) {
692 return [];
693 }
694 var children = (parent.getElementsByTagName(tagName)
695 || self._document.all);
696 if (typeof(className) == 'undefined' || className === null) {
697 return MochiKit.Base.extend(null, children);
698 }
700 var elements = [];
701 for (var i = 0; i < children.length; i++) {
702 var child = children[i];
703 var cls = child.className;
704 if (typeof(cls) != "string") {
705 cls = child.getAttribute("class");
706 }
707 if (typeof(cls) == "string") {
708 var classNames = cls.split(' ');
709 for (var j = 0; j < classNames.length; j++) {
710 if (classNames[j] == className) {
711 elements.push(child);
712 break;
713 }
714 }
715 }
716 }
718 return elements;
719 },
721 _newCallStack: function (path, once) {
722 var rval = function () {
723 var callStack = arguments.callee.callStack;
724 for (var i = 0; i < callStack.length; i++) {
725 if (callStack[i].apply(this, arguments) === false) {
726 break;
727 }
728 }
729 if (once) {
730 try {
731 this[path] = null;
732 } catch (e) {
733 // pass
734 }
735 }
736 };
737 rval.callStack = [];
738 return rval;
739 },
741 /** @id MochiKit.DOM.addToCallStack */
742 addToCallStack: function (target, path, func, once) {
743 var self = MochiKit.DOM;
744 var existing = target[path];
745 var regfunc = existing;
746 if (!(typeof(existing) == 'function'
747 && typeof(existing.callStack) == "object"
748 && existing.callStack !== null)) {
749 regfunc = self._newCallStack(path, once);
750 if (typeof(existing) == 'function') {
751 regfunc.callStack.push(existing);
752 }
753 target[path] = regfunc;
754 }
755 regfunc.callStack.push(func);
756 },
758 /** @id MochiKit.DOM.addLoadEvent */
759 addLoadEvent: function (func) {
760 var self = MochiKit.DOM;
761 self.addToCallStack(self._window, "onload", func, true);
763 },
765 /** @id MochiKit.DOM.focusOnLoad */
766 focusOnLoad: function (element) {
767 var self = MochiKit.DOM;
768 self.addLoadEvent(function () {
769 element = self.getElement(element);
770 if (element) {
771 element.focus();
772 }
773 });
774 },
776 /** @id MochiKit.DOM.setElementClass */
777 setElementClass: function (element, className) {
778 var self = MochiKit.DOM;
779 var obj = self.getElement(element);
780 if (self.attributeArray.compliant) {
781 obj.setAttribute("class", className);
782 } else {
783 obj.setAttribute("className", className);
784 }
785 },
787 /** @id MochiKit.DOM.toggleElementClass */
788 toggleElementClass: function (className/*, element... */) {
789 var self = MochiKit.DOM;
790 for (var i = 1; i < arguments.length; i++) {
791 var obj = self.getElement(arguments[i]);
792 if (!self.addElementClass(obj, className)) {
793 self.removeElementClass(obj, className);
794 }
795 }
796 },
798 /** @id MochiKit.DOM.addElementClass */
799 addElementClass: function (element, className) {
800 var self = MochiKit.DOM;
801 var obj = self.getElement(element);
802 var cls = obj.className;
803 if (typeof(cls) != "string") {
804 cls = obj.getAttribute("class");
805 }
806 // trivial case, no className yet
807 if (typeof(cls) != "string" || cls.length === 0) {
808 self.setElementClass(obj, className);
809 return true;
810 }
811 // the other trivial case, already set as the only class
812 if (cls == className) {
813 return false;
814 }
815 var classes = cls.split(" ");
816 for (var i = 0; i < classes.length; i++) {
817 // already present
818 if (classes[i] == className) {
819 return false;
820 }
821 }
822 // append class
823 self.setElementClass(obj, cls + " " + className);
824 return true;
825 },
827 /** @id MochiKit.DOM.removeElementClass */
828 removeElementClass: function (element, className) {
829 var self = MochiKit.DOM;
830 var obj = self.getElement(element);
831 var cls = obj.className;
832 if (typeof(cls) != "string") {
833 cls = obj.getAttribute("class");
834 }
835 // trivial case, no className yet
836 if (typeof(cls) != "string" || cls.length === 0) {
837 return false;
838 }
839 // other trivial case, set only to className
840 if (cls == className) {
841 self.setElementClass(obj, "");
842 return true;
843 }
844 var classes = cls.split(" ");
845 for (var i = 0; i < classes.length; i++) {
846 // already present
847 if (classes[i] == className) {
848 // only check sane case where the class is used once
849 classes.splice(i, 1);
850 self.setElementClass(obj, classes.join(" "));
851 return true;
852 }
853 }
854 // not found
855 return false;
856 },
858 /** @id MochiKit.DOM.swapElementClass */
859 swapElementClass: function (element, fromClass, toClass) {
860 var obj = MochiKit.DOM.getElement(element);
861 var res = MochiKit.DOM.removeElementClass(obj, fromClass);
862 if (res) {
863 MochiKit.DOM.addElementClass(obj, toClass);
864 }
865 return res;
866 },
868 /** @id MochiKit.DOM.hasElementClass */
869 hasElementClass: function (element, className/*...*/) {
870 var obj = MochiKit.DOM.getElement(element);
871 if (obj == null) {
872 return false;
873 }
874 var cls = obj.className;
875 if (typeof(cls) != "string") {
876 cls = obj.getAttribute("class");
877 }
878 if (typeof(cls) != "string") {
879 return false;
880 }
881 var classes = cls.split(" ");
882 for (var i = 1; i < arguments.length; i++) {
883 var good = false;
884 for (var j = 0; j < classes.length; j++) {
885 if (classes[j] == arguments[i]) {
886 good = true;
887 break;
888 }
889 }
890 if (!good) {
891 return false;
892 }
893 }
894 return true;
895 },
897 /** @id MochiKit.DOM.escapeHTML */
898 escapeHTML: function (s) {
899 return s.replace(/&/g, "&"
900 ).replace(/"/g, """
901 ).replace(/</g, "<"
902 ).replace(/>/g, ">");
903 },
905 /** @id MochiKit.DOM.toHTML */
906 toHTML: function (dom) {
907 return MochiKit.DOM.emitHTML(dom).join("");
908 },
910 /** @id MochiKit.DOM.emitHTML */
911 emitHTML: function (dom, /* optional */lst) {
912 if (typeof(lst) == 'undefined' || lst === null) {
913 lst = [];
914 }
915 // queue is the call stack, we're doing this non-recursively
916 var queue = [dom];
917 var self = MochiKit.DOM;
918 var escapeHTML = self.escapeHTML;
919 var attributeArray = self.attributeArray;
920 while (queue.length) {
921 dom = queue.pop();
922 if (typeof(dom) == 'string') {
923 lst.push(dom);
924 } else if (dom.nodeType == 1) {
925 // we're not using higher order stuff here
926 // because safari has heisenbugs.. argh.
927 //
928 // I think it might have something to do with
929 // garbage collection and function calls.
930 lst.push('<' + dom.tagName.toLowerCase());
931 var attributes = [];
932 var domAttr = attributeArray(dom);
933 for (var i = 0; i < domAttr.length; i++) {
934 var a = domAttr[i];
935 attributes.push([
936 " ",
937 a.name,
938 '="',
939 escapeHTML(a.value),
940 '"'
941 ]);
942 }
943 attributes.sort();
944 for (i = 0; i < attributes.length; i++) {
945 var attrs = attributes[i];
946 for (var j = 0; j < attrs.length; j++) {
947 lst.push(attrs[j]);
948 }
949 }
950 if (dom.hasChildNodes()) {
951 lst.push(">");
952 // queue is the FILO call stack, so we put the close tag
953 // on first
954 queue.push("</" + dom.tagName.toLowerCase() + ">");
955 var cnodes = dom.childNodes;
956 for (i = cnodes.length - 1; i >= 0; i--) {
957 queue.push(cnodes[i]);
958 }
959 } else {
960 lst.push('/>');
961 }
962 } else if (dom.nodeType == 3) {
963 lst.push(escapeHTML(dom.nodeValue));
964 }
965 }
966 return lst;
967 },
969 /** @id MochiKit.DOM.scrapeText */
970 scrapeText: function (node, /* optional */asArray) {
971 var rval = [];
972 (function (node) {
973 var cn = node.childNodes;
974 if (cn) {
975 for (var i = 0; i < cn.length; i++) {
976 arguments.callee.call(this, cn[i]);
977 }
978 }
979 var nodeValue = node.nodeValue;
980 if (typeof(nodeValue) == 'string') {
981 rval.push(nodeValue);
982 }
983 })(MochiKit.DOM.getElement(node));
984 if (asArray) {
985 return rval;
986 } else {
987 return rval.join("");
988 }
989 },
991 /** @id MochiKit.DOM.removeEmptyTextNodes */
992 removeEmptyTextNodes: function (element) {
993 element = MochiKit.DOM.getElement(element);
994 for (var i = 0; i < element.childNodes.length; i++) {
995 var node = element.childNodes[i];
996 if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) {
997 node.parentNode.removeChild(node);
998 }
999 }
1000 },
1002 /** @id MochiKit.DOM.getFirstElementByTagAndClassName */
1003 getFirstElementByTagAndClassName: function (tagName, className,
1004 /* optional */parent) {
1005 var self = MochiKit.DOM;
1006 if (typeof(tagName) == 'undefined' || tagName === null) {
1007 tagName = '*';
1008 }
1009 if (typeof(parent) == 'undefined' || parent === null) {
1010 parent = self._document;
1011 }
1012 parent = self.getElement(parent);
1013 if (parent == null) {
1014 return null;
1015 }
1016 var children = (parent.getElementsByTagName(tagName)
1017 || self._document.all);
1018 if (children.length <= 0) {
1019 return null;
1020 } else if (typeof(className) == 'undefined' || className === null) {
1021 return children[0];
1022 }
1024 for (var i = 0; i < children.length; i++) {
1025 var child = children[i];
1026 var cls = child.className;
1027 if (typeof(cls) != "string") {
1028 cls = child.getAttribute("class");
1029 }
1030 if (typeof(cls) == "string") {
1031 var classNames = cls.split(' ');
1032 for (var j = 0; j < classNames.length; j++) {
1033 if (classNames[j] == className) {
1034 return child;
1035 }
1036 }
1037 }
1038 }
1039 return null;
1040 },
1042 /** @id MochiKit.DOM.getFirstParentByTagAndClassName */
1043 getFirstParentByTagAndClassName: function (elem, tagName, className) {
1044 var self = MochiKit.DOM;
1045 elem = self.getElement(elem);
1046 if (typeof(tagName) == 'undefined' || tagName === null) {
1047 tagName = '*';
1048 } else {
1049 tagName = tagName.toUpperCase();
1050 }
1051 if (typeof(className) == 'undefined' || className === null) {
1052 className = null;
1053 }
1054 if (elem) {
1055 elem = elem.parentNode;
1056 }
1057 while (elem && elem.tagName) {
1058 var curTagName = elem.tagName.toUpperCase();
1059 if ((tagName === '*' || tagName == curTagName) &&
1060 (className === null || self.hasElementClass(elem, className))) {
1061 return elem;
1062 }
1063 elem = elem.parentNode;
1064 }
1065 return null;
1066 },
1068 __new__: function (win) {
1070 var m = MochiKit.Base;
1071 if (typeof(document) != "undefined") {
1072 this._document = document;
1073 var kXULNSURI = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
1074 this._xhtml = (document.documentElement &&
1075 document.createElementNS &&
1076 document.documentElement.namespaceURI === kXULNSURI);
1077 } else if (MochiKit.MockDOM) {
1078 this._document = MochiKit.MockDOM.document;
1079 }
1080 this._window = win;
1082 this.domConverters = new m.AdapterRegistry();
1084 var __tmpElement = this._document.createElement("span");
1085 var attributeArray;
1086 if (__tmpElement && __tmpElement.attributes &&
1087 __tmpElement.attributes.length > 0) {
1088 // for braindead browsers (IE) that insert extra junk
1089 var filter = m.filter;
1090 attributeArray = function (node) {
1091 /***
1093 Return an array of attributes for a given node,
1094 filtering out attributes that don't belong for
1095 that are inserted by "Certain Browsers".
1097 ***/
1098 return filter(attributeArray.ignoreAttrFilter, node.attributes);
1099 };
1100 attributeArray.ignoreAttr = {};
1101 var attrs = __tmpElement.attributes;
1102 var ignoreAttr = attributeArray.ignoreAttr;
1103 for (var i = 0; i < attrs.length; i++) {
1104 var a = attrs[i];
1105 ignoreAttr[a.name] = a.value;
1106 }
1107 attributeArray.ignoreAttrFilter = function (a) {
1108 return (attributeArray.ignoreAttr[a.name] != a.value);
1109 };
1110 attributeArray.compliant = false;
1111 attributeArray.renames = {
1112 "class": "className",
1113 "checked": "defaultChecked",
1114 "usemap": "useMap",
1115 "for": "htmlFor",
1116 "readonly": "readOnly",
1117 "colspan": "colSpan",
1118 "bgcolor": "bgColor",
1119 "cellspacing": "cellSpacing",
1120 "cellpadding": "cellPadding"
1121 };
1122 } else {
1123 attributeArray = function (node) {
1124 return node.attributes;
1125 };
1126 attributeArray.compliant = true;
1127 attributeArray.ignoreAttr = {};
1128 attributeArray.renames = {};
1129 }
1130 this.attributeArray = attributeArray;
1132 // FIXME: this really belongs in Base, and could probably be cleaner
1133 var _deprecated = function(fromModule, arr) {
1134 var fromName = arr[0];
1135 var toName = arr[1];
1136 var toModule = toName.split('.')[1];
1137 var str = '';
1139 str += 'if (!MochiKit.' + toModule + ') { throw new Error("';
1140 str += 'This function has been deprecated and depends on MochiKit.';
1141 str += toModule + '.");}';
1142 str += 'return ' + toName + '.apply(this, arguments);';
1143 MochiKit[fromModule][fromName] = new Function(str);
1144 }
1145 for (var i = 0; i < MochiKit.DOM.DEPRECATED.length; i++) {
1146 _deprecated('DOM', MochiKit.DOM.DEPRECATED[i]);
1147 }
1149 // shorthand for createDOM syntax
1150 var createDOMFunc = this.createDOMFunc;
1151 /** @id MochiKit.DOM.UL */
1152 this.UL = createDOMFunc("ul");
1153 /** @id MochiKit.DOM.OL */
1154 this.OL = createDOMFunc("ol");
1155 /** @id MochiKit.DOM.LI */
1156 this.LI = createDOMFunc("li");
1157 /** @id MochiKit.DOM.DL */
1158 this.DL = createDOMFunc("dl");
1159 /** @id MochiKit.DOM.DT */
1160 this.DT = createDOMFunc("dt");
1161 /** @id MochiKit.DOM.DD */
1162 this.DD = createDOMFunc("dd");
1163 /** @id MochiKit.DOM.TD */
1164 this.TD = createDOMFunc("td");
1165 /** @id MochiKit.DOM.TR */
1166 this.TR = createDOMFunc("tr");
1167 /** @id MochiKit.DOM.TBODY */
1168 this.TBODY = createDOMFunc("tbody");
1169 /** @id MochiKit.DOM.THEAD */
1170 this.THEAD = createDOMFunc("thead");
1171 /** @id MochiKit.DOM.TFOOT */
1172 this.TFOOT = createDOMFunc("tfoot");
1173 /** @id MochiKit.DOM.TABLE */
1174 this.TABLE = createDOMFunc("table");
1175 /** @id MochiKit.DOM.TH */
1176 this.TH = createDOMFunc("th");
1177 /** @id MochiKit.DOM.INPUT */
1178 this.INPUT = createDOMFunc("input");
1179 /** @id MochiKit.DOM.SPAN */
1180 this.SPAN = createDOMFunc("span");
1181 /** @id MochiKit.DOM.A */
1182 this.A = createDOMFunc("a");
1183 /** @id MochiKit.DOM.DIV */
1184 this.DIV = createDOMFunc("div");
1185 /** @id MochiKit.DOM.IMG */
1186 this.IMG = createDOMFunc("img");
1187 /** @id MochiKit.DOM.BUTTON */
1188 this.BUTTON = createDOMFunc("button");
1189 /** @id MochiKit.DOM.TT */
1190 this.TT = createDOMFunc("tt");
1191 /** @id MochiKit.DOM.PRE */
1192 this.PRE = createDOMFunc("pre");
1193 /** @id MochiKit.DOM.H1 */
1194 this.H1 = createDOMFunc("h1");
1195 /** @id MochiKit.DOM.H2 */
1196 this.H2 = createDOMFunc("h2");
1197 /** @id MochiKit.DOM.H3 */
1198 this.H3 = createDOMFunc("h3");
1199 /** @id MochiKit.DOM.H4 */
1200 this.H4 = createDOMFunc("h4");
1201 /** @id MochiKit.DOM.H5 */
1202 this.H5 = createDOMFunc("h5");
1203 /** @id MochiKit.DOM.H6 */
1204 this.H6 = createDOMFunc("h6");
1205 /** @id MochiKit.DOM.BR */
1206 this.BR = createDOMFunc("br");
1207 /** @id MochiKit.DOM.HR */
1208 this.HR = createDOMFunc("hr");
1209 /** @id MochiKit.DOM.LABEL */
1210 this.LABEL = createDOMFunc("label");
1211 /** @id MochiKit.DOM.TEXTAREA */
1212 this.TEXTAREA = createDOMFunc("textarea");
1213 /** @id MochiKit.DOM.FORM */
1214 this.FORM = createDOMFunc("form");
1215 /** @id MochiKit.DOM.P */
1216 this.P = createDOMFunc("p");
1217 /** @id MochiKit.DOM.SELECT */
1218 this.SELECT = createDOMFunc("select");
1219 /** @id MochiKit.DOM.OPTION */
1220 this.OPTION = createDOMFunc("option");
1221 /** @id MochiKit.DOM.OPTGROUP */
1222 this.OPTGROUP = createDOMFunc("optgroup");
1223 /** @id MochiKit.DOM.LEGEND */
1224 this.LEGEND = createDOMFunc("legend");
1225 /** @id MochiKit.DOM.FIELDSET */
1226 this.FIELDSET = createDOMFunc("fieldset");
1227 /** @id MochiKit.DOM.STRONG */
1228 this.STRONG = createDOMFunc("strong");
1229 /** @id MochiKit.DOM.CANVAS */
1230 this.CANVAS = createDOMFunc("canvas");
1232 /** @id MochiKit.DOM.$ */
1233 this.$ = this.getElement;
1235 this.EXPORT_TAGS = {
1236 ":common": this.EXPORT,
1237 ":all": m.concat(this.EXPORT, this.EXPORT_OK)
1238 };
1240 m.nameFunctions(this);
1242 }
1243 });
1246 MochiKit.DOM.__new__(((typeof(window) == "undefined") ? this : window));
1248 //
1249 // XXX: Internet Explorer blows
1250 //
1251 if (MochiKit.__export__) {
1252 withWindow = MochiKit.DOM.withWindow;
1253 withDocument = MochiKit.DOM.withDocument;
1254 }
1256 MochiKit.Base._exportSymbols(this, MochiKit.DOM);