1 /* See license.txt for terms of usage */
  2 
  3 define([
  4     "firebug/lib/trace",
  5     "firebug/lib/deprecated",
  6     "firebug/lib/css",
  7     "firebug/lib/array",
  8     "firebug/lib/xml",
  9     "firebug/lib/wrapper",
 10 ],
 11 function(FBTrace, Deprecated, Css, Arr, Xml, Wrapper) {
 12 "use strict";
 13 
 14 // ********************************************************************************************* //
 15 // Constants
 16 
 17 var Ci = Components.interfaces;
 18 var Cc = Components.classes;
 19 
 20 /**
 21  * @name Dom
 22  * @lib Utility for Nodes
 23  */
 24 var Dom = {};
 25 
 26 var domMemberCache = null;
 27 var domMemberMap = {};
 28 var domMappedData = new WeakMap();
 29 
 30 Dom.domUtils = Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
 31 
 32 // ********************************************************************************************* //
 33 // DOM APIs
 34 
 35 // xxxFlorent: [SELECTOR_API2-FIND]; node.find() or document.querySelector + ":scope" pseudo-class
 36 // could make this method deprecated soon.
 37 // see also: 
 38 // - http://dev.w3.org/2006/webapi/selectors-api2/#findelements-relative
 39 // - http://www.w3.org/TR/selectors-api2/#the-scope-pseudo-class
 40 
 41 /**
 42  * Selects the first child element which matches with the first classname,
 43  * then the first child of it which matches with the second classname, and so on...
 44  *
 45  * @param {Element} elt The initial parent element
 46  * @param {String} ...classnames the classnames
 47  *
 48  * @return {Element} the element matching with the last classname or null
 49  */
 50 Dom.getChildByClass = function(elt/*, ...classnames*/)
 51 {
 52     if (!elt)
 53     {
 54         FBTrace.sysout("dom.getChildByClass; ERROR, no parent element!");
 55         return null;
 56     }
 57 
 58     for (var i = 1; i < arguments.length && elt; ++i)
 59     {
 60         var className = arguments[i];
 61         var child = elt.firstChild;
 62         elt = null;
 63         for (; child; child = child.nextSibling)
 64         {
 65             if (Css.hasClass(child, className))
 66             {
 67                 elt = child;
 68                 break;
 69             }
 70         }
 71     }
 72 
 73     return elt;
 74 };
 75 
 76 /**
 77  * Gets the ancestor of a node with a specific class name
 78  * @param {Node} node Child node, for which to search the ancestor
 79  * @param {String} className Class name of ancestor node
 80  * @returns {Node} Ancestor node
 81  */
 82 Dom.getAncestorByClass = function(node, className)
 83 {
 84     for (var parent = node; parent; parent = parent.parentNode)
 85     {
 86         if (Css.hasClass(parent, className))
 87             return parent;
 88     }
 89 
 90     return null;
 91 };
 92 
 93 /**
 94  * Gets the ancestor of a node with a specific tag name
 95  * @param {Node} node Child node, for which to search the ancestor
 96  * @param {String} tagName Tag name of the ancestor node
 97  * @returns {Node} Ancestor node
 98  */
 99 Dom.getAncestorByTagName = function(node, tagName)
100 {
101     for (var parent = node; parent; parent = parent.parentNode)
102     {
103         if (parent.localName && parent.tagName.toLowerCase() == tagName)
104             return parent;
105     }
106 
107     return null;
108 };
109 
110 /**
111  * @deprecated Use native Firefox node.getElementsByClassName(names).item(0)
112  */
113 Dom.getElementByClass = Deprecated.deprecated("Use node.getElementsByClassName(names)"+
114 ".item(0) or node.querySelector('.class') instead",
115 function(node, className)  // className, className, ...
116 {
117     return Dom.getElementsByClass.apply(this,arguments).item(0);
118 });
119 
120 /**
121  * @deprecated Use native Firefox node.getElementsByClassName(names)
122  */
123 Dom.getElementsByClass = Deprecated.deprecated("Use node.getElementsByClassName(names)",
124 function(node, className)  // className, className, ...
125 {
126     return node.getElementsByClassName(Array.prototype.slice.call(arguments, 1).join(" "));
127 });
128 
129 /**
130  * @deprecated Use native Firefox node.getElementsByClassName("[attrName=attrValue]")
131  */
132 Dom.getElementsByAttribute = Deprecated.deprecated("Use node.querySelectorAll(\"[attrName=attrValue]\") instead",
133 function(node, attrName, attrValue)
134 {
135     function iteratorHelper(node, attrName, attrValue, result)
136     {
137         for (var child = node.firstElementChild; child; child = child.nextElementSibling)
138         {
139             if (child.getAttribute(attrName) == attrValue)
140                 result.push(child);
141 
142             if (child.hasChildNodes())
143                 iteratorHelper(child, attrName, attrValue, result);
144         }
145     }
146 
147     var result = [];
148     iteratorHelper(node, attrName, attrValue, result);
149     return result;
150 });
151 
152 /**
153  * Checks whether a node is an ancestor of another node
154  * @param {Node} node Child node, for which to check the ancestor
155  * @param {Node} potentialAncestor Node to check
156  * @returns {Boolean} True if 'potentialAncestor' is an ancestor of 'node', otherwise false
157  */
158 Dom.isAncestor = function(node, potentialAncestor)
159 {
160     for (var parent = node; parent; parent = parent.parentNode)
161     {
162         if (parent == potentialAncestor)
163             return true;
164     }
165 
166     return false;
167 };
168 
169 /**
170  * Gets the next element node
171  * @param {Node} node Node, for which to get the next element node
172  * @returns {Node} Next element node
173  */
174 Dom.getNextElement = function(node)
175 {
176     while (node && node.nodeType != Node.ELEMENT_NODE)
177         node = node.nextSibling;
178 
179     return node;
180 };
181 
182 /**
183  * Gets the previous element node
184  * @param {Node} node Node, for which to get the previous element node
185  * @returns {Node} Previous element node
186  */
187 Dom.getPreviousElement = function(node)
188 {
189     while (node && node.nodeType != Node.ELEMENT_NODE)
190         node = node.previousSibling;
191 
192     return node;
193 };
194 
195 /**
196  * Gets the body element of an HTML document or the document element for non-HTML documents
197  * @param {Document} doc Document, for which to get the body element or document element
198  * @returns {Node} Body element or document element
199  */
200 Dom.getBody = function(doc)
201 {
202     if (doc.body)
203         return doc.body;
204 
205     var body = doc.getElementsByTagName("body")[0];
206     if (body)
207         return body;
208 
209     return doc.documentElement;  // For non-HTML docs
210 };
211 
212 // ********************************************************************************************* //
213 // DOM Modification
214 
215 /**
216  * Insert the new node after the reference node.
217  *
218  * @param {Node} newNode The node to insert
219  * @param {Node} referenceNode The node after which we insert the new node
220  *
221  * @return {Node} the new node if the insertion succeeded
222  */
223 Dom.insertAfter = function(newNode, referenceNode)
224 {
225     if (!referenceNode.parentNode)
226         return;
227 
228     if (referenceNode.nextSibling)
229         return referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
230     else
231         return referenceNode.parentNode.appendChild(newNode);
232 }
233 
234 /**
235  * Insert a script element in the document
236  *
237  * @param {DocumentElement} doc The document
238  * @param {String} id The id of the script to insert
239  * @param {String} content The content of the script (evaluated once the script is inserted)
240  *
241  * @return {Element} the inserted script
242  */
243 Dom.addScript = function(doc, id, src)
244 {
245     var element = doc.createElementNS("http://www.w3.org/1999/xhtml", "html:script");
246     element.setAttribute("type", "text/javascript");
247     element.setAttribute("id", id);
248 
249     if (!FBTrace.DBG_CONSOLE)
250         Firebug.setIgnored(element);
251 
252     element.textContent = src;
253 
254     if (doc.documentElement)
255     {
256         doc.documentElement.appendChild(element);
257     }
258     else
259     {
260         // See issue 1079, the svg test case gives this error
261         if (FBTrace.DBG_ERRORS)
262             FBTrace.sysout("lib.addScript doc has no documentElement (" +
263                 doc.readyState + ") " + doc.location, doc);
264         return;
265     }
266     return element;
267 }
268 
269 /**
270  * Set the outerHTML of kind of element
271  *
272  * @deprecated since Firefox 20, we can use outerHTML instead, even for non-HTML elements
273  */
274 Dom.setOuterHTML = Deprecated.deprecated("Since Firefox 20, use outerHTML instead, "+
275 "even with non-HTML elements", function(element, html)
276 {
277     try
278     {
279         var fragment = Dom.markupToDocFragment(html, element);
280 
281         var first = fragment.firstChild;
282         var last = fragment.lastChild;
283         element.parentNode.replaceChild(fragment, element);
284         return [first, last];
285     }
286     catch (e)
287     {
288         return [element, element];
289     }
290 });
291 
292 /**
293  * Converts a chunk of HTML code into DOM elements (stored in a document fragment)
294  *
295  * @param {String} markup The HTML code
296  * @param {Element} the Reference element (often the element which will receive the fragment)
297  *
298  * @return {DocumentFragment} the document fragment having the generated elements
299  */
300 Dom.markupToDocFragment = function(markup, referenceElement)
301 {
302     var doc = referenceElement.ownerDocument;
303     var range = doc.createRange();
304     range.selectNode(referenceElement || doc.documentElement);
305 
306     return range.createContextualFragment(markup);
307 };
308 
309 Dom.appendInnerHTML = Deprecated.deprecated("Since Firefox 20, use "+
310 "insertAdjacentHTML(\"beforeEnd\", html) instead, even with non-HTML elements",
311 function(element, html, referenceElement)
312 {
313     var firstGeneratedChild = null;
314     // using insertAdjacentHTML is safer for HTML elements:
315     if (element instanceof HTMLElement)
316     {
317         var lastChild = element.lastChild;
318         element.insertAdjacentHTML("beforeEnd", html);
319         firstGeneratedChild = (lastChild ? lastChild.nextSibling : element.firstChild);
320     }
321     else
322     {
323         var fragment = Dom.markupToDocFragment(html, referenceElement);
324         firstGeneratedChild = fragment.firstChild;
325         element.insertBefore(fragment, referenceElement);
326     }
327     return firstGeneratedChild;
328 });
329 
330 /**
331  * TODO...
332  */
333 Dom.insertTextIntoElement = function(element, text)
334 {
335     // xxxFlorent: could this be replaced with the following code? :
336     //      var textNode = element.ownerDocument.createTextNode(text);
337     //      element.appendChild(text);
338     var command = "cmd_insertText";
339 
340     var controller = element.controllers.getControllerForCommand(command);
341     if (!controller || !controller.isCommandEnabled(command))
342         return;
343 
344     var params = Cc["@mozilla.org/embedcomp/command-params;1"].createInstance(Ci.nsICommandParams);
345     params.setStringValue("state_data", text);
346 
347     if (controller instanceof Ci.nsICommandController)
348         controller.doCommandWithParams(command, params);
349 };
350 
351 // ********************************************************************************************* //
352 
353 /**
354  * @deprecated
355  * xxxFlorent: hide XUL elements?? (TODO)
356  */
357 Dom.collapse = function(elt, collapsed)
358 {
359     if (!elt)
360     {
361         FBTrace.sysout("Dom.collapse; ERROR null element.");
362         return;
363     }
364 
365     elt.setAttribute("collapsed", collapsed ? "true" : "false");
366 };
367 
368 /**
369  * @deprecated
370  * TODO
371  */
372 Dom.isCollapsed = function(elt)
373 {
374     return elt.getAttribute("collapsed") === "true";
375 };
376 
377 /**
378  * Hide or display an element
379  *
380  * @param {Element} elt The element
381  * @param {Boolean} hidden If set to true, hide the element, otherwise display it
382  *
383  * @deprecated set elt.style.visibility instead
384  */
385 Dom.hide = Deprecated.deprecated("set elt.style.visibility instead", function(elt, hidden)
386 {
387     elt.style.visibility = (hidden ? "hidden" : "visible");
388 });
389 
390 /**
391  * Clears a node
392  *
393  * @param {Node} node The node to clear
394  *
395  * @deprecated use the following instead: <code>node.textContent = "";</code>
396  */
397 Dom.clearNode = Deprecated.deprecated("use the following instead: `node.textContent = \"\";`",
398 function(node)
399 {
400     node.textContent = "";
401 });
402 
403 /**
404  * Erases a node
405  *
406  * @param {Node} the Node to erase
407  */
408 Dom.eraseNode = function(node)
409 {
410     while (node.lastChild)
411         node.removeChild(node.lastChild);
412 };
413 
414 // ********************************************************************************************* //
415 
416 /**
417  * Returns true if the passed object is a node
418  *
419  * @param {Object} obj The object to test
420  *
421  * @return {Boolean} true if the passed object is a node, false otherwise
422  */
423 Dom.isNode = function(obj)
424 {
425     try
426     {
427         return obj && obj instanceof window.Node;
428     }
429     catch (ex)
430     {
431         // xxxFlorent: useful?
432         return false;
433     }
434 };
435 // xxxFlorent: I'm too lazy... I guess we should deprecate them
436 Dom.isElement = function(o)
437 {
438     try {
439         return o && o instanceof window.Element;
440     }
441     catch (ex) {
442         return false;
443     }
444 };
445 
446 Dom.isRange = function(o)
447 {
448     try {
449         return o && o instanceof window.Range;
450     }
451     catch (ex) {
452         return false;
453     }
454 };
455 
456 Dom.hasChildElements = function(node)
457 {
458     if (node.contentDocument) // iframes
459         return true;
460 
461     for (var child = node.firstChild; child; child = child.nextSibling)
462     {
463         if (child.nodeType == Node.ELEMENT_NODE)
464             return true;
465     }
466 
467     return false;
468 };
469 
470 // ********************************************************************************************* //
471 // xxxFlorent: [SELECTOR_API2-FIND]
472 Dom.getNextByClass = function(root, state)
473 {
474     function iter(node) { return node.nodeType == Node.ELEMENT_NODE && Css.hasClass(node, state); }
475     return Dom.findNext(root, iter);
476 };
477 
478 // xxxFlorent: [SELECTOR_API2-FIND]
479 Dom.getPreviousByClass = function(root, state)
480 {
481     function iter(node) { return node.nodeType == Node.ELEMENT_NODE && Css.hasClass(node, state); }
482     return Dom.findPrevious(root, iter);
483 };
484 
485 Dom.findNextDown = function(node, criteria)
486 {
487     if (!node)
488         return null;
489 
490     for (var child = node.firstChild; child; child = child.nextSibling)
491     {
492         if (criteria(child))
493             return child;
494 
495         var next = Dom.findNextDown(child, criteria);
496         if (next)
497             return next;
498     }
499 };
500 
501 Dom.findPreviousUp = function(node, criteria)
502 {
503     if (!node)
504         return null;
505 
506     for (var child = node.lastChild; child; child = child.previousSibling)
507     {
508         var next = Dom.findPreviousUp(child, criteria);
509         if (next)
510             return next;
511 
512         if (criteria(child))
513             return child;
514     }
515 };
516 
517 Dom.findNext = function(node, criteria, upOnly, maxRoot)
518 {
519     if (!node)
520         return null;
521 
522     if (!upOnly)
523     {
524         var next = Dom.findNextDown(node, criteria);
525         if (next)
526             return next;
527     }
528 
529     for (var sib = node.nextSibling; sib; sib = sib.nextSibling)
530     {
531         if (criteria(sib))
532             return sib;
533 
534         var next = Dom.findNextDown(sib, criteria);
535         if (next)
536             return next;
537     }
538 
539     if (node.parentNode && node.parentNode != maxRoot)
540     {
541         return Dom.findNext(node.parentNode, criteria, true, maxRoot);
542     }
543     return null;
544 };
545 
546 Dom.findPrevious = function(node, criteria, downOnly, maxRoot)
547 {
548     if (!node)
549         return null;
550 
551     for (var sib = node.previousSibling; sib; sib = sib.previousSibling)
552     {
553         var prev = Dom.findPreviousUp(sib, criteria);
554         if (prev)
555             return prev;
556 
557         if (criteria(sib))
558             return sib;
559     }
560 
561     if (!downOnly)
562     {
563         var next = Dom.findPreviousUp(node, criteria);
564         if (next)
565             return next;
566     }
567 
568     if (node.parentNode && node.parentNode != maxRoot)
569     {
570         if (criteria(node.parentNode))
571             return node.parentNode;
572 
573         return Dom.findPrevious(node.parentNode, criteria, true, maxRoot);
574     }
575     return null;
576 };
577 
578 // ********************************************************************************************* //
579 // Graphics
580 
581 Dom.getClientOffset = function(elt)
582 {
583     function addOffset(elt, coords, view)
584     {
585         var p = elt.offsetParent;
586 
587         var style = view.getComputedStyle(elt, "");
588 
589         if (elt.offsetLeft)
590             coords.x += elt.offsetLeft + parseInt(style.borderLeftWidth);
591         if (elt.offsetTop)
592             coords.y += elt.offsetTop + parseInt(style.borderTopWidth);
593 
594         if (p)
595         {
596             if (p.nodeType == Node.ELEMENT_NODE)
597                 addOffset(p, coords, view);
598         }
599         else if (elt.ownerDocument.defaultView.frameElement)
600         {
601             addOffset(elt.ownerDocument.defaultView.frameElement, coords,
602                 elt.ownerDocument.defaultView);
603         }
604     }
605 
606     var coords = {x: 0, y: 0};
607     if (elt)
608     {
609         var view = elt.ownerDocument.defaultView;
610         addOffset(elt, coords, view);
611     }
612 
613     return coords;
614 };
615 
616 /**
617  * Gets layout info about an element
618  * @param {Object} elt Element to get the info for
619  * @returns {Object} Layout information including "left", "top", "right", "bottom",
620  *     "width" and "height"
621  */
622 Dom.getLTRBWH = function(elt)
623 {
624     var bcrect;
625     var dims = {"left": 0, "top": 0, "right": 0, "bottom": 0, "width": 0, "height": 0};
626 
627     if (elt)
628     {
629         bcrect = elt.getBoundingClientRect();
630         dims.left = bcrect.left;
631         dims.top = bcrect.top;
632         dims.right = bcrect.right;
633         dims.bottom = bcrect.bottom;
634 
635         if (bcrect.width)
636         {
637             dims.width = bcrect.width;
638             dims.height = bcrect.height;
639         }
640         else
641         {
642             dims.width = dims.right - dims.left;
643             dims.height = dims.bottom - dims.top;
644         }
645     }
646     return dims;
647 };
648 
649 /**
650  * Gets the offset size of an element
651  * @param {Object} elt Element to move
652  * @returns {Object} Offset width and height of the element
653  */
654 Dom.getOffsetSize = function(elt)
655 {
656     return {width: elt.offsetWidth, height: elt.offsetHeight};
657 };
658 
659 /**
660  * Gets the next scrollable ancestor
661  * @param {Object} element Element to search the ancestor for
662  * @returns {Object} Scrollable ancestor
663  */
664 Dom.getOverflowParent = function(element)
665 {
666     for (var scrollParent = element.parentNode; scrollParent;
667         scrollParent = scrollParent.offsetParent)
668     {
669         if (scrollParent.scrollHeight > scrollParent.offsetHeight)
670             return scrollParent;
671     }
672 };
673 
674 /**
675  * Checks whether an element is scrolled to the bottom
676  * @param {Object} element Element to check
677  * @returns {Boolean} True, if element is scrolled to the bottom, otherwise false
678  */
679 Dom.isScrolledToBottom = function(element)
680 {
681     var onBottom = (element.scrollTop + element.offsetHeight) == element.scrollHeight;
682 
683     if (FBTrace.DBG_CONSOLE)
684     {
685         FBTrace.sysout("Dom.isScrolledToBottom offsetHeight: " + element.offsetHeight +
686             ", scrollTop: " + element.scrollTop + ", scrollHeight: " + element.scrollHeight +
687             ", onBottom: " + onBottom);
688     }
689 
690     return onBottom;
691 };
692 
693 /**
694  * Scrolls a scrollable element to the bottom
695  * @param {Object} element Element to scroll
696  * @returns {Boolean} True, if the element could be scrolled to the bottom, otherwise false
697  */
698 Dom.scrollToBottom = function(element)
699 {
700     element.scrollTop = element.scrollHeight;
701 
702     if (FBTrace.DBG_CONSOLE)
703     {
704         FBTrace.sysout("scrollToBottom reset scrollTop " + element.scrollTop + " = " +
705             element.scrollHeight);
706 
707         if (element.scrollHeight == element.offsetHeight)
708         {
709             FBTrace.sysout("scrollToBottom attempt to scroll non-scrollable element " +
710                 element, element);
711         }
712     }
713 
714     return (element.scrollTop == element.scrollHeight);
715 };
716 
717 /**
718  * Moves an element
719  * @param {Object} element Element to move
720  * @param {Number} x New horizontal position
721  * @param {Number} y New vertical position
722  */
723 Dom.move = function(element, x, y)
724 {
725     element.style.left = x + "px";
726     element.style.top = y + "px";
727 };
728 
729 /**
730  * Resizes an element
731  * @param {Object} element Element to resize
732  * @param {Number} w New width
733  * @param {Number} h New height
734  */
735 Dom.resize = function(element, w, h)
736 {
737     element.style.width = w + "px";
738     element.style.height = h + "px";
739 };
740 
741 Dom.linesIntoCenterView = function(element, scrollBox)  // {before: int, after: int}
742 {
743     if (!scrollBox)
744         scrollBox = Dom.getOverflowParent(element);
745 
746     if (!scrollBox)
747         return;
748 
749     var offset = Dom.getClientOffset(element);
750 
751     var topSpace = offset.y - scrollBox.scrollTop;
752     var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight) -
753         (offset.y + element.offsetHeight);
754 
755     if (topSpace < 0 || bottomSpace < 0)
756     {
757         var split = (scrollBox.clientHeight/2);
758         var centerY = offset.y - split;
759         scrollBox.scrollTop = centerY;
760         topSpace = split;
761         bottomSpace = split - element.offsetHeight;
762     }
763 
764     return {
765         before: Math.round((topSpace/element.offsetHeight) + 0.5),
766         after: Math.round((bottomSpace/element.offsetHeight) + 0.5)
767     }
768 };
769 
770 // xxxFlorent: read the code and see if that could not be replaced with scrollIntoView
771 
772 /**
773  * Scrolls an element into view
774  * @param {Element} element Element to scroll to
775  * @param {Object} scrollBox Scrolled element (Must be an ancestor of "element" or
776  *     null for automatically determining the ancestor) 
777  * @param {String} alignmentX Horizontal alignment for the element
778  *     (valid values: "centerOrLeft", "left", "middle", "right", "none")
779  * @param {String} alignmentY Vertical alignment for the element
780  *     (valid values: "centerOrTop", "top", "middle", "bottom", "none")
781  * @param {Boolean} scrollWhenVisible Specifies whether "scrollBox" should be scrolled even when
782  *     "element" is completely visible
783  */
784 Dom.scrollTo = function(element, scrollBox, alignmentX, alignmentY, scrollWhenVisible)
785 {
786     if (!element)
787         return;
788 
789     if (!scrollBox)
790         scrollBox = Dom.getOverflowParent(element);
791 
792     if (!scrollBox)
793         return;
794 
795     var offset = Dom.getClientOffset(element);
796 
797     if (!alignmentX)
798         alignmentX = "centerOrLeft";
799 
800     if (!alignmentY)
801         alignmentY = "centerOrTop";
802 
803     if (alignmentY)
804     {
805         var topSpace = offset.y - scrollBox.scrollTop;
806         var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight) -
807             (offset.y + element.offsetHeight);
808 
809         // Element is vertically not completely visible or scrolling is enforced
810         if (topSpace < 0 || bottomSpace < 0 || scrollWhenVisible)
811         {
812             switch (alignmentY)
813             {
814                 case "top":
815                     scrollBox.scrollTop = offset.y;
816                     break;
817 
818                 case "center":
819                 case "centerOrTop":
820                     var elementFitsIntoScrollBox = element.offsetHeight <= scrollBox.clientHeight;
821                     var y = elementFitsIntoScrollBox || alignmentY != "centerOrTop" ?
822                         offset.y - (scrollBox.clientHeight - element.offsetHeight) / 2 :
823                         offset.y;
824                     scrollBox.scrollTop = y;
825                     break;
826 
827                 case "bottom":
828                     var y = offset.y + element.offsetHeight - scrollBox.clientHeight;
829                     scrollBox.scrollTop = y;
830                     break;
831             }
832         }
833     }
834 
835     if (alignmentX)
836     {
837         var leftSpace = offset.x - scrollBox.scrollLeft;
838         var rightSpace = (scrollBox.scrollLeft + scrollBox.clientWidth) -
839             (offset.x + element.clientWidth);
840 
841         // Element is horizontally not completely visible or scrolling is enforced
842         if (leftSpace < 0 || rightSpace < 0 || scrollWhenVisible)
843         {
844             switch (alignmentX)
845             {
846                 case "left":
847                     scrollBox.scrollLeft = offset.x;
848                     break;
849 
850                 case "center":
851                 case "centerOrLeft":
852                     var elementFitsIntoScrollBox = element.offsetWidth <= scrollBox.clientWidth;
853                     var x = elementFitsIntoScrollBox || alignmentX != "centerOrLeft" ?
854                         offset.x - (scrollBox.clientWidth - element.offsetWidth) / 2 :
855                         offset.x;
856                     scrollBox.scrollLeft = x;
857                     break;
858 
859                 case "right":
860                     var x = offset.x + element.offsetWidth - scrollBox.clientWidth;
861                     scrollBox.scrollLeft = x;
862                     break;
863             }
864         }
865     }
866 
867     if (FBTrace.DBG_PANELS)
868         FBTrace.sysout("dom.scrollTo", element.innerHTML);
869 };
870 
871 // xxxFlorent: read it (same as Dom.scrollTo)
872 
873 /**
874  * Centers an element inside a scrollable area
875  * @param {Object} element Element to scroll to
876  * @param {Object} scrollBox Scrolled element (Must be an ancestor of "element" or
877  *     null for automatically determining the ancestor) 
878  * @param {Boolean} notX Specifies whether the element should be centered horizontally
879  * @param {Boolean} notY Specifies whether the element should be centered vertically
880  */
881 Dom.scrollIntoCenterView = function(element, scrollBox, notX, notY)
882 {
883     Dom.scrollTo(element, scrollBox, notX ? "none" : "centerOrLeft",
884         notY ? "none" : "centerOrTop");
885 };
886 
887 /**
888  * Scrolls an element of a menu popup into view.
889  *
890  * @popup {XULElement} the menu popup
891  * @item {XULElement} the item of the popup
892  */
893 Dom.scrollMenupopup = function(popup, item)
894 {
895     var doc = popup.ownerDocument;
896     var box = doc.getAnonymousNodes(popup)[0];
897     var scrollBox = doc.getAnonymousNodes(box)[1];
898 
899     if (item == undefined)
900     {
901         scrollBox.scrollTop = scrollBox.scrollHeight + 100;
902     }
903     else if (item == 0)
904     {
905         scrollBox.scrollTop = 0;
906     }
907     else
908     {
909         var popupRect = popup.getBoundingClientRect();
910         var itemRect = item.getBoundingClientRect();
911 
912         if (itemRect.top < popupRect.top + itemRect.height)
913         {
914             scrollBox.scrollTop += itemRect.top - popupRect.top - itemRect.height;
915         }
916         else if (itemRect.bottom + itemRect.height > popupRect.bottom)
917         {
918             scrollBox.scrollTop -= popupRect.bottom - itemRect.bottom - itemRect.height;
919         }
920     }
921 }
922 
923 // ********************************************************************************************* //
924 // MappedData
925 
926 function getNodeData(element)
927 {
928     var elementData;
929 
930     // force element to be wrapped:
931     element = new XPCNativeWrapper(element);
932 
933     if (!domMappedData.has(element))
934     {
935         elementData = {};
936         domMappedData.set(element, elementData);
937     }
938     else
939         elementData = domMappedData.get(element);
940 
941     return elementData;
942 }
943 
944 /**
945  * Returns stored data about a node.
946  *
947  * @param {Node} node The node
948  * @param {*} key The key
949  *
950  * @return {*} the data
951  */
952 Dom.getMappedData = function(node, key)
953 {
954     var nodeData = getNodeData(node);
955     return nodeData[key];
956 }
957 
958 /**
959  * Stores a data about the given node.
960  *
961  * @param {Node} node The node
962  * @param {*} key The key
963  * @param {*} value The data to store
964  *
965  */
966 Dom.setMappedData = function(node, key, value)
967 {
968     if (!Dom.isNode(node))
969         throw new TypeError("expected an node as the first argument");
970 
971     if (typeof key !== "string")
972         throw new TypeError("the key argument must be a string");
973 
974     var nodeData = getNodeData(node);
975     nodeData[key] = value;
976 }
977 
978 /**
979  * Deletes the data about the given node.
980  *
981  * @param {Node} node The node
982  * @param {*} key The key
983  *
984  */
985 Dom.deleteMappedData = function(node, key)
986 {
987     var nodeData = getNodeData(node);
988     delete nodeData[key];
989 }
990 
991 // ********************************************************************************************* //
992 // DOM Members
993 
994 Dom.getDOMMembers = function(object)
995 {
996     if (!domMemberCache)
997     {
998         domMemberCache = {};
999 
1000         for (var name in domMemberMap)
1001         {
1002             var builtins = domMemberMap[name];
1003             var cache = domMemberCache[name] = {};
1004 
1005             for (var i = 0; i < builtins.length; ++i)
1006                 cache[builtins[i]] = i;
1007         }
1008     }
1009 
1010     if (object instanceof Window)
1011         { return domMemberCache.Window; }
1012     else if (object instanceof Document || object instanceof XMLDocument)
1013         { return domMemberCache.Document; }
1014     else if (object instanceof Location)
1015         { return domMemberCache.Location; }
1016     else if (object instanceof HTMLImageElement)
1017         { return domMemberCache.HTMLImageElement; }
1018     else if (object instanceof HTMLAnchorElement)
1019         { return domMemberCache.HTMLAnchorElement; }
1020     else if (object instanceof HTMLInputElement)
1021         { return domMemberCache.HTMLInputElement; }
1022     else if (object instanceof HTMLButtonElement)
1023         { return domMemberCache.HTMLButtonElement; }
1024     else if (object instanceof HTMLFormElement)
1025         { return domMemberCache.HTMLFormElement; }
1026     else if (object instanceof HTMLBodyElement)
1027         { return domMemberCache.HTMLBodyElement; }
1028     else if (object instanceof HTMLHtmlElement)
1029         { return domMemberCache.HTMLHtmlElement; }
1030     else if (object instanceof HTMLScriptElement)
1031         { return domMemberCache.HTMLScriptElement; }
1032     else if (object instanceof HTMLTableElement)
1033         { return domMemberCache.HTMLTableElement; }
1034     else if (object instanceof HTMLTableRowElement)
1035         { return domMemberCache.HTMLTableRowElement; }
1036     else if (object instanceof HTMLTableCellElement)
1037         { return domMemberCache.HTMLTableCellElement; }
1038     else if (object instanceof HTMLIFrameElement)
1039         { return domMemberCache.HTMLIFrameElement; }
1040     else if (object instanceof SVGSVGElement)
1041         { return domMemberCache.SVGSVGElement; }
1042     else if (object instanceof SVGElement)
1043         { return domMemberCache.SVGElement; }
1044     else if (object instanceof Element)
1045         { return domMemberCache.Element; }
1046     else if (object instanceof Text || object instanceof CDATASection)
1047         { return domMemberCache.Text; }
1048     else if (object instanceof Attr)
1049         { return domMemberCache.Attr; }
1050     else if (object instanceof Node)
1051         { return domMemberCache.Node; }
1052     else if (object instanceof Event || object instanceof Dom.EventCopy)
1053         { return domMemberCache.Event; }
1054     else if (object instanceof Object)
1055         { return domMemberCache.Object; }
1056 
1057     return null;
1058 };
1059 
1060 Dom.isDOMMember = function(object, propName)
1061 {
1062     var members = Dom.getDOMMembers(object);
1063     return members && propName in members;
1064 };
1065 
1066 Dom.isDOMConstant = function(object, name)
1067 {
1068     if (name == undefined)
1069         return Dom.isDOMConstantDep({},object);
1070 
1071     // The constant map has also its own prototype, but it isn't considered to be a constant.
1072     if (name == "__proto__")
1073         return false;
1074 
1075     // object isn't recognized as such when using ===,
1076     // so use this as workaround
1077     var str = Object.prototype.toString.call(object);
1078     var isDOMProperty = ["[object Window]", "[object Node]", "[object Location]",
1079         "[object Event]"].indexOf(str) !== -1;
1080 
1081     if (!(object === window.Window ||
1082         object === window.Object ||
1083         object === window.Node ||
1084         object === window.Location ||
1085         object === window.Event ||
1086         object === Dom.EventCopy ||
1087         object instanceof window.Window ||
1088         object instanceof window.Node ||
1089         object instanceof window.Location ||
1090         object instanceof window.Event ||
1091         object instanceof Dom.EventCopy ||
1092         isDOMProperty))
1093     {
1094         return false;
1095     }
1096 
1097     return Dom.domConstantMap.hasOwnProperty(name);
1098 }
1099 
1100 Dom.isInlineEventHandler = function(name)
1101 {
1102     return !!Dom.domInlineEventHandlersMap[name];
1103 }
1104 
1105 Dom.EventCopy = function(event)
1106 {
1107     // ensure Dom.EventCopy is called as a constructor
1108     if (! (this instanceof Dom.EventCopy))
1109         throw new Error("Dom.EventCopy is a constructor");
1110 
1111     // Because event objects are destroyed arbitrarily by Gecko, we must make a copy of them to
1112     // represent them long term in the inspector.
1113     for (var name in event)
1114     {
1115         try {
1116             this[name] = event[name];
1117         } catch (exc) { }
1118     }
1119 }
1120 
1121 var isDOMConstantDep = Deprecated.deprecated(
1122     "isDOMConstant(name) signature changed (object,name)",
1123     Dom.isDOMConstant);
1124 
1125 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1126 
1127 domMemberMap.Window =
1128 [
1129     "document",
1130     "frameElement",
1131 
1132     "innerWidth",
1133     "innerHeight",
1134     "outerWidth",
1135     "outerHeight",
1136     "screenX",
1137     "screenY",
1138     "mozInnerScreenX",
1139     "mozInnerScreenY",
1140     "pageXOffset",
1141     "pageYOffset",
1142     "scrollX",
1143     "scrollY",
1144     "scrollMaxX",
1145     "scrollMaxY",
1146 
1147     "URL", //FF4.0
1148     "mozAnimationStartTime", //FF4.0
1149     "mozPaintCount", //FF4.0
1150     "mozRequestAnimationFrame", //FF4.0
1151     "mozCancelAnimationFrame",
1152     "mozCancelRequestAnimationFrame",
1153 
1154     "mozCancelAnimationFrame",
1155     "mozCancelRequestAnimationFrame",
1156     "indexedDB",
1157 
1158     "status",
1159     "defaultStatus",
1160 
1161     "parent",
1162     "opener",
1163     "top",
1164     "window",
1165     "content",
1166     "self",
1167 
1168     "location",
1169     "history",
1170     "frames",
1171     "navigator",
1172     "screen",
1173     "menubar",
1174     "toolbar",
1175     "locationbar",
1176     "personalbar",
1177     "statusbar",
1178     "directories",
1179     "scrollbars",
1180     "fullScreen",
1181     "netscape",
1182     "console",
1183     "Components",
1184     "controllers",
1185     "closed",
1186     "crypto",
1187     "pkcs11",
1188 
1189     "name",
1190     "property",
1191     "length",
1192 
1193     "sessionStorage",
1194 
1195     "setTimeout",
1196     "setInterval",
1197     "clearTimeout",
1198     "clearInterval",
1199     "addEventListener",
1200     "removeEventListener",
1201     "dispatchEvent",
1202     "getComputedStyle",
1203     "captureEvents",
1204     "releaseEvents",
1205     "routeEvent",
1206     "enableExternalCapture",
1207     "disableExternalCapture",
1208     "moveTo",
1209     "moveBy",
1210     "resizeTo",
1211     "resizeBy",
1212     "scroll",
1213     "scrollTo",
1214     "scrollBy",
1215     "scrollByLines",
1216     "scrollByPages",
1217     "sizeToContent",
1218     "setResizable",
1219     "getSelection",
1220     "open",
1221     "openDialog",
1222     "close",
1223     "alert",
1224     "confirm",
1225     "prompt",
1226     "dump",
1227     "focus",
1228     "blur",
1229     "find",
1230     "back",
1231     "forward",
1232     "home",
1233     "stop",
1234     "print",
1235     "atob",
1236     "btoa",
1237     "updateCommands",
1238     "XPCNativeWrapper",
1239     "GeckoActiveXObject",
1240     "applicationCache",      // FF3
1241     "GetWeakReference", // Gecko
1242     "XPCSafeJSObjectWrapper", // Gecko
1243     "postMessage",
1244     "localStorage",  // FF3.5
1245     "showModalDialog", // FF 3.0, MS IE4
1246 
1247     "InstallTrigger",
1248 
1249     "performance", // https://developer.mozilla.org/en/Navigation_timing
1250     "matchMedia", // https://developer.mozilla.org/en/DOM/window.matchMedia
1251 
1252     "getInterface",
1253 
1254     "BarProp",
1255     "Controllers",
1256     "Crypto",
1257     "DOMException",
1258     "DOMStringList",
1259     "EventTarget",
1260     "History",
1261     "MimeTypeArray",
1262     "MozURLProperty",
1263     "Navigator",
1264     "NodeList",
1265     "OfflineResourceList",
1266     "Screen",
1267     "Storage",
1268     "XULControllers",
1269     "Document",
1270     "Element",
1271     "Attr",
1272     "CharacterData",
1273     "DOMTokenList",
1274     "Text",
1275 
1276     "HTMLAnchorElement",
1277     "HTMLAudioElement",
1278     "HTMLBaseElement",
1279     "HTMLButtonElement",
1280     "HTMLCollection",
1281     "HTMLCanvasElement",
1282     "HTMLDataListElement",
1283     "HTMLDListElement",
1284     "HTMLDocument",
1285     "HTMLElement",
1286     "HTMLEmbedElement",
1287     "HTMLHtmlElement",
1288     "HTMLBRElement",
1289     "HTMLBodyElement",
1290     "HTMLCollection",
1291     "HTMLDivElement",
1292     "HTMLDocument",
1293     "HTMLElement",
1294     "HTMLFormElement",
1295     "HTMLHRElement",
1296     "HTMLHeadElement",
1297     "HTMLHeadingElement",
1298     "HTMLHtmlElement",
1299     "HTMLIFrameElement",
1300     "HTMLImageElement",
1301     "HTMLInputElement",
1302     "HTMLLabelElement",
1303     "HTMLLegendElement",
1304     "HTMLLinkElement",
1305     "HTMLMapElement",
1306     "HTMLMediaElement",
1307     "HTMLMenuElement",
1308     "HTMLMetaElement",
1309     "HTMLMeterElement",
1310     "HTMLModElement",
1311     "HTMLObjectElement",
1312     "HTMLOListElement",
1313     "HTMLOptionElement",
1314     "HTMLOptionsCollection",
1315     "HTMLOutputElement",
1316     "HTMLPreElement",
1317     "HTMLProgressElement",
1318     "HTMLQuoteElement",
1319     "HTMLScriptElement",
1320     "HTMLSelectElement",
1321     "HTMLSourceElement",
1322     "HTMLSpanElement",
1323     "HTMLStyleElement",
1324     "HTMLTableCellElement",
1325     "HTMLTableElement",
1326     "HTMLTableRowElement",
1327     "HTMLTableSectionElement",
1328     "HTMLTextAreaElement",
1329     "HTMLTitleElement",
1330     "HTMLUListElement",
1331     "HTMLUnknownElement",
1332     "HTMLVideoElement",
1333 
1334     "Infinity",
1335     "JSON",
1336     "Location",
1337     "Math",
1338     "NaN",
1339     "Node",
1340     "StopIteration",
1341     "Window",
1342     "XULElement",
1343     "undefined",
1344     "CSS2Properties",
1345     "CSSStyleDeclaration",
1346     "Error",
1347     "EvalError",
1348     "InternalError",
1349     "Namespace",
1350     "QName",
1351     "RangeError",
1352     "ReferenceError",
1353     "SyntaxError",
1354     "TypeError",
1355     "URIError",
1356     "Array",
1357     "ArrayBuffer",
1358     "Boolean",
1359     "DataView",
1360     "Date",
1361     "Float32Array",
1362     "Float64Array",
1363     "Function",
1364     "Int16Array",
1365     "Int32Array",
1366     "Int8Array",
1367     "Iterator",
1368     "Map",
1369     "Number",
1370     "Object",
1371     "ParallelArray",
1372     "QueryInterface",
1373     "RegExp",
1374     "Set",
1375     "String",
1376     "Uint16Array",
1377     "Uint32Array",
1378     "Uint8Array",
1379     "Uint8ClampedArray",
1380     "WeakMap",
1381     "XML",
1382     "XMLList",
1383     "decodeURI",
1384     "decodeURIComponent",
1385     "dumpProfile",
1386     "encodeURI",
1387     "encodeURIComponent",
1388     "escape",
1389     "isFinite",
1390     "isNaN",
1391     "isXMLName",
1392     "parseFloat",
1393     "parseInt",
1394     "pauseProfilers",
1395     "resumeProfilers",
1396     "startProfiling",
1397     "stopProfiling",
1398     "unescape",
1399     "uneval",
1400     "Performance",
1401     "PerformanceNavigation",
1402     "PerformanceTiming"
1403 ];
1404 
1405 domMemberMap.Object =
1406 [
1407     "arguments",
1408     "caller",
1409     "length",
1410     "name",
1411     "__defineGetter__",
1412     "__defineSetter__",
1413     "__lookupGetter__",
1414     "__lookupSetter__",
1415     "apply",
1416     "bind",
1417     "call",
1418     "constructor",
1419     "create",
1420     "defineProperties",
1421     "defineProperty",
1422     "freeze",
1423     "getOwnPropertyDescriptor",
1424     "getOwnPropertyNames",
1425     "getPrototypeOf",
1426     "hasOwnProperty",
1427     "isExtensible",
1428     "isFrozen",
1429     "isGenerator",
1430     "isPrototypeOf",
1431     "isSealed",
1432     "keys",
1433     "preventExtensions",
1434     "propertyIsEnumerable",
1435     "seal",
1436     "toLocaleString",
1437     "toSource",
1438     "toString",
1439     "unwatch",
1440     "valueOf",
1441     "watch"
1442 ];
1443 
1444 domMemberMap.Location =
1445 [
1446     "href",
1447     "protocol",
1448     "host",
1449     "hostname",
1450     "port",
1451     "pathname",
1452     "search",
1453     "hash",
1454 
1455     "assign",
1456     "reload",
1457     "replace",
1458 
1459     "QueryInterface"
1460 ];
1461 
1462 domMemberMap.Node =
1463 [
1464     "id",
1465     "className",
1466 
1467     "nodeType",
1468     "tagName",
1469     "nodeName",
1470     "localName",
1471     "prefix",
1472     "namespaceURI",
1473     "nodeValue",
1474 
1475     "ownerDocument",
1476     "parentNode",
1477     "offsetParent",
1478     "nextSibling",
1479     "previousSibling",
1480     "firstChild",
1481     "lastChild",
1482     "childNodes",
1483     "attributes",
1484 
1485     "dir",
1486     "baseURI",
1487     "textContent",
1488     "innerHTML",
1489 
1490     "addEventListener",
1491     "removeEventListener",
1492     "dispatchEvent",
1493     "cloneNode",
1494     "appendChild",
1495     "insertBefore",
1496     "replaceChild",
1497     "removeChild",
1498     "compareDocumentPosition",
1499     "hasAttributes",
1500     "hasChildNodes",
1501     "lookupNamespaceURI",
1502     "lookupPrefix",
1503     "normalize",
1504     "isDefaultNamespace",
1505     "isEqualNode",
1506     "isSameNode",
1507     "isSupported",
1508     "getFeature",
1509     "getUserData",
1510     "setUserData",
1511 
1512     "QueryInterface"
1513 ];
1514 
1515 domMemberMap.Document = Arr.extendArray(domMemberMap.Node,
1516 [
1517     "documentElement",
1518     "body",
1519     "title",
1520     "location",
1521     "referrer",
1522     "cookie",
1523     "contentType",
1524     "lastModified",
1525     "characterSet",
1526     "inputEncoding",
1527     "xmlEncoding",
1528     "xmlStandalone",
1529     "xmlVersion",
1530     "strictErrorChecking",
1531     "documentURI",
1532     "URL",
1533 
1534     "defaultView",
1535     "doctype",
1536     "implementation",
1537     "styleSheets",
1538     "images",
1539     "links",
1540     "forms",
1541     "anchors",
1542     "embeds",
1543     "plugins",
1544     "applets",
1545 
1546     "width",
1547     "height",
1548 
1549     "designMode",
1550     "compatMode",
1551     "async",
1552     "readyState",
1553 
1554     "preferredStyleSheetSet",
1555     "lastStyleSheetSet",
1556     "styleSheetSets",
1557     "selectedStyleSheetSet",
1558     "enableStyleSheetsForSet",
1559 
1560     "elementFromPoint",
1561     "hasFocus",
1562     "activeElement",
1563 
1564     /* These are also in domMemberMap.Element, but it reflects the real interface definition */
1565     "getElementsByClassName",
1566     "querySelector",
1567     "querySelectorAll",
1568 
1569     "alinkColor",
1570     "linkColor",
1571     "vlinkColor",
1572     "bgColor",
1573     "fgColor",
1574     "domain",
1575 
1576     "addEventListener",
1577     "removeEventListener",
1578     "dispatchEvent",
1579     "captureEvents",
1580     "releaseEvents",
1581     "routeEvent",
1582     "clear",
1583     "open",
1584     "close",
1585     "execCommand",
1586     "execCommandShowHelp",
1587     "getElementsByName",
1588     "getSelection",
1589     "queryCommandEnabled",
1590     "queryCommandIndeterm",
1591     "queryCommandState",
1592     "queryCommandSupported",
1593     "queryCommandText",
1594     "queryCommandValue",
1595     "write",
1596     "writeln",
1597     "adoptNode",
1598     "appendChild",
1599     "removeChild",
1600     "renameNode",
1601     "cloneNode",
1602     "compareDocumentPosition",
1603     "createAttribute",
1604     "createAttributeNS",
1605     "createCDATASection",
1606     "createComment",
1607     "createDocumentFragment",
1608     "createElement",
1609     "createElementNS",
1610     "createEntityReference",
1611     "createEvent",
1612     "createExpression",
1613     "createNSResolver",
1614     "createNodeIterator",
1615     "createProcessingInstruction",
1616     "createRange",
1617     "createTextNode",
1618     "createTreeWalker",
1619     "domConfig",
1620     "evaluate",
1621     "evaluateFIXptr",
1622     "evaluateXPointer",
1623     "getAnonymousElementByAttribute",
1624     "getAnonymousNodes",
1625     "addBinding",
1626     "removeBinding",
1627     "getBindingParent",
1628     "getBoxObjectFor",
1629     "setBoxObjectFor",
1630     "getElementById",
1631     "getElementsByTagName",
1632     "getElementsByTagNameNS",
1633     "hasAttributes",
1634     "hasChildNodes",
1635     "importNode",
1636     "insertBefore",
1637     "isDefaultNamespace",
1638     "isEqualNode",
1639     "isSameNode",
1640     "isSupported",
1641     "load",
1642     "loadBindingDocument",
1643     "lookupNamespaceURI",
1644     "lookupPrefix",
1645     "normalize",
1646     "normalizeDocument",
1647     "getFeature",
1648     "getUserData",
1649     "setUserData"
1650 ]);
1651 
1652 domMemberMap.Element = Arr.extendArray(domMemberMap.Node,
1653 [
1654     "clientWidth",
1655     "clientHeight",
1656     "offsetLeft",
1657     "offsetTop",
1658     "offsetWidth",
1659     "offsetHeight",
1660     "scrollLeft",
1661     "scrollTop",
1662     "scrollWidth",
1663     "scrollHeight",
1664 
1665     "style",
1666 
1667     "tabIndex",
1668     "title",
1669     "lang",
1670     "align",
1671     "spellcheck",
1672 
1673     "addEventListener",
1674     "removeEventListener",
1675     "dispatchEvent",
1676     "focus",
1677     "blur",
1678     "cloneNode",
1679     "appendChild",
1680     "insertBefore",
1681     "replaceChild",
1682     "removeChild",
1683     "compareDocumentPosition",
1684     "getElementsByTagName",
1685     "getElementsByTagNameNS",
1686     "getAttribute",
1687     "getAttributeNS",
1688     "getAttributeNode",
1689     "getAttributeNodeNS",
1690     "setAttribute",
1691     "setAttributeNS",
1692     "setAttributeNode",
1693     "setAttributeNodeNS",
1694     "removeAttribute",
1695     "removeAttributeNS",
1696     "removeAttributeNode",
1697     "hasAttribute",
1698     "hasAttributeNS",
1699     "hasAttributes",
1700     "hasChildNodes",
1701     "lookupNamespaceURI",
1702     "lookupPrefix",
1703     "normalize",
1704     "isDefaultNamespace",
1705     "isEqualNode",
1706     "isSameNode",
1707     "isSupported",
1708     "getFeature",
1709     "getUserData",
1710     "setUserData",
1711 
1712     "childElementCount",
1713     "children",
1714     "classList",
1715     "clientLeft",
1716     "clientTop",
1717     "contentEditable",
1718     "draggable",
1719     "firstElementChild",
1720     "lastElementChild",
1721     "nextElementSibling",
1722     "previousElementSibling",
1723 
1724     "getBoundingClientRect",
1725     "getClientRects",
1726     "getElementsByClassName",
1727     "mozMatchesSelector",
1728     "querySelector",
1729     "querySelectorAll",
1730     "scrollIntoView",
1731 
1732     "onLoad",//FF4.0
1733     "hidden",//FF4.0
1734     "setCapture",//FF4.0
1735     "releaseCapture"//FF4.0
1736 ]);
1737 
1738 domMemberMap.SVGElement = Arr.extendArray(domMemberMap.Element,
1739 [
1740     "x",
1741     "y",
1742     "width",
1743     "height",
1744     "rx",
1745     "ry",
1746     "transform",
1747     "href",
1748 
1749     "ownerSVGElement",
1750     "viewportElement",
1751     "farthestViewportElement",
1752     "nearestViewportElement",
1753 
1754     "getBBox",
1755     "getCTM",
1756     "getScreenCTM",
1757     "getTransformToElement",
1758     "getPresentationAttribute",
1759     "preserveAspectRatio"
1760 ]);
1761 
1762 domMemberMap.SVGSVGElement = Arr.extendArray(domMemberMap.Element,
1763 [
1764     "x",
1765     "y",
1766     "width",
1767     "height",
1768     "rx",
1769     "ry",
1770     "transform",
1771 
1772     "viewBox",
1773     "viewport",
1774     "currentView",
1775     "useCurrentView",
1776     "pixelUnitToMillimeterX",
1777     "pixelUnitToMillimeterY",
1778     "screenPixelToMillimeterX",
1779     "screenPixelToMillimeterY",
1780     "currentScale",
1781     "currentTranslate",
1782     "zoomAndPan",
1783 
1784     "ownerSVGElement",
1785     "viewportElement",
1786     "farthestViewportElement",
1787     "nearestViewportElement",
1788     "contentScriptType",
1789     "contentStyleType",
1790 
1791     "getBBox",
1792     "getCTM",
1793     "getScreenCTM",
1794     "getTransformToElement",
1795     "getEnclosureList",
1796     "getIntersectionList",
1797     "getViewboxToViewportTransform",
1798     "getPresentationAttribute",
1799     "getElementById",
1800     "checkEnclosure",
1801     "checkIntersection",
1802     "createSVGAngle",
1803     "createSVGLength",
1804     "createSVGMatrix",
1805     "createSVGNumber",
1806     "createSVGPoint",
1807     "createSVGRect",
1808     "createSVGString",
1809     "createSVGTransform",
1810     "createSVGTransformFromMatrix",
1811     "deSelectAll",
1812     "preserveAspectRatio",
1813     "forceRedraw",
1814     "suspendRedraw",
1815     "unsuspendRedraw",
1816     "unsuspendRedrawAll",
1817     "getCurrentTime",
1818     "setCurrentTime",
1819     "animationsPaused",
1820     "pauseAnimations",
1821     "unpauseAnimations"
1822 ]);
1823 
1824 domMemberMap.HTMLImageElement = Arr.extendArray(domMemberMap.Element,
1825 [
1826     "src",
1827     "naturalWidth",
1828     "naturalHeight",
1829     "width",
1830     "height",
1831     "x",
1832     "y",
1833     "name",
1834     "alt",
1835     "longDesc",
1836     "lowsrc",
1837     "border",
1838     "complete",
1839     "hspace",
1840     "vspace",
1841     "isMap",
1842     "useMap",
1843 ]);
1844 
1845 domMemberMap.HTMLAnchorElement = Arr.extendArray(domMemberMap.Element,
1846 [
1847     "name",
1848     "target",
1849     "accessKey",
1850     "href",
1851     "protocol",
1852     "host",
1853     "hostname",
1854     "port",
1855     "pathname",
1856     "search",
1857     "hash",
1858     "hreflang",
1859     "coords",
1860     "shape",
1861     "text",
1862     "type",
1863     "rel",
1864     "rev",
1865     "charset"
1866 ]);
1867 
1868 domMemberMap.HTMLIFrameElement = Arr.extendArray(domMemberMap.Element,
1869 [
1870     "contentDocument",
1871     "contentWindow",
1872     "frameBorder",
1873     "height",
1874     "longDesc",
1875     "marginHeight",
1876     "marginWidth",
1877     "name",
1878     "scrolling",
1879     "src",
1880     "width"
1881 ]);
1882 
1883 domMemberMap.HTMLTableElement = Arr.extendArray(domMemberMap.Element,
1884 [
1885     "bgColor",
1886     "border",
1887     "caption",
1888     "cellPadding",
1889     "cellSpacing",
1890     "frame",
1891     "rows",
1892     "rules",
1893     "summary",
1894     "tBodies",
1895     "tFoot",
1896     "tHead",
1897     "width",
1898 
1899     "createCaption",
1900     "createTFoot",
1901     "createTHead",
1902     "deleteCaption",
1903     "deleteRow",
1904     "deleteTFoot",
1905     "deleteTHead",
1906     "insertRow"
1907 ]);
1908 
1909 domMemberMap.HTMLTableRowElement = Arr.extendArray(domMemberMap.Element,
1910 [
1911     "bgColor",
1912     "cells",
1913     "ch",
1914     "chOff",
1915     "rowIndex",
1916     "sectionRowIndex",
1917     "vAlign",
1918 
1919     "deleteCell",
1920     "insertCell"
1921 ]);
1922 
1923 domMemberMap.HTMLTableCellElement = Arr.extendArray(domMemberMap.Element,
1924 [
1925     "abbr",
1926     "axis",
1927     "bgColor",
1928     "cellIndex",
1929     "ch",
1930     "chOff",
1931     "colSpan",
1932     "headers",
1933     "height",
1934     "noWrap",
1935     "rowSpan",
1936     "scope",
1937     "vAlign",
1938     "width"
1939 
1940 ]);
1941 
1942 domMemberMap.HTMLScriptElement = Arr.extendArray(domMemberMap.Element,
1943 [
1944     "src"
1945 ]);
1946 
1947 domMemberMap.HTMLButtonElement = Arr.extendArray(domMemberMap.Element,
1948 [
1949     "accessKey",
1950     "disabled",
1951     "form",
1952     "name",
1953     "type",
1954     "value",
1955 
1956     "click"
1957 ]);
1958 
1959 domMemberMap.HTMLInputElement = Arr.extendArray(domMemberMap.Element,
1960 [
1961     "type",
1962     "value",
1963     "checked",
1964     "accept",
1965     "accessKey",
1966     "alt",
1967     "autocomplete",
1968     "autofocus",
1969     "controllers",
1970     "defaultChecked",
1971     "defaultValue",
1972     "disabled",
1973     "form",
1974     "formAction",
1975     "formEnctype",
1976     "formMethod",
1977     "formNoValidate",
1978     "formTarget",
1979     "maxLength",
1980     "name",
1981     "readOnly",
1982     "selectionEnd",
1983     "selectionStart",
1984     "size",
1985     "src",
1986     "textLength",
1987     "useMap",
1988 
1989     "files",
1990     "indeterminate",
1991     "multiple",
1992     "list",
1993     "mozGetFileNameArray",
1994     "mozSetFileNameArray",
1995 
1996     "pattern",
1997     "placeholder",
1998     "required",
1999 
2000     "click",
2001     "select",
2002     "setSelectionRange"
2003 ]);
2004 
2005 domMemberMap.HTMLFormElement = Arr.extendArray(domMemberMap.Element,
2006 [
2007     "acceptCharset",
2008     "action",
2009     "author",
2010     "elements",
2011     "encoding",
2012     "enctype",
2013     "entry_id",
2014     "length",
2015     "method",
2016     "name",
2017     "post",
2018     "target",
2019     "text",
2020     "url",
2021 
2022     "reset",
2023     "submit"
2024 ]);
2025 
2026 domMemberMap.HTMLBodyElement = Arr.extendArray(domMemberMap.Element,
2027 [
2028     "aLink",
2029     "background",
2030     "bgColor",
2031     "link",
2032     "text",
2033     "vLink"
2034 ]);
2035 
2036 domMemberMap.HTMLHtmlElement = Arr.extendArray(domMemberMap.Element,
2037 [
2038     "version"
2039 ]);
2040 
2041 domMemberMap.Text = Arr.extendArray(domMemberMap.Node,
2042 [
2043     "data",
2044     "length",
2045 
2046     "appendData",
2047     "deleteData",
2048     "insertData",
2049     "replaceData",
2050     "splitText",
2051     "substringData"
2052 ]);
2053 
2054 domMemberMap.Attr = Arr.extendArray(domMemberMap.Node,
2055 [
2056     "name",
2057     "value",
2058     "specified",
2059     "ownerElement"
2060 ]);
2061 
2062 domMemberMap.Event =
2063 [
2064     "type",
2065     "target",
2066     "currentTarget",
2067     "originalTarget",
2068     "explicitOriginalTarget",
2069     "relatedTarget",
2070     "rangeParent",
2071     "rangeOffset",
2072     "view",
2073 
2074     "keyCode",
2075     "charCode",
2076     "screenX",
2077     "screenY",
2078     "clientX",
2079     "clientY",
2080     "layerX",
2081     "layerY",
2082     "pageX",
2083     "pageY",
2084 
2085     "detail",
2086     "button",
2087     "which",
2088     "ctrlKey",
2089     "shiftKey",
2090     "altKey",
2091     "metaKey",
2092 
2093     "eventPhase",
2094     "timeStamp",
2095     "bubbles",
2096     "cancelable",
2097     "cancelBubble",
2098 
2099     "isTrusted",
2100     "isChar",
2101 
2102     "getPreventDefault",
2103     "initEvent",
2104     "initMouseEvent",
2105     "initKeyEvent",
2106     "initUIEvent",
2107     "preventBubble",
2108     "preventCapture",
2109     "preventDefault",
2110     "stopPropagation"
2111 ];
2112 
2113 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
2114 
2115 var domConstantMap = Dom.domConstantMap =
2116 {
2117     "ELEMENT_NODE": 1,
2118     "ATTRIBUTE_NODE": 1,
2119     "TEXT_NODE": 1,
2120     "CDATA_SECTION_NODE": 1,
2121     "ENTITY_REFERENCE_NODE": 1,
2122     "ENTITY_NODE": 1,
2123     "PROCESSING_INSTRUCTION_NODE": 1,
2124     "COMMENT_NODE": 1,
2125     "DOCUMENT_NODE": 1,
2126     "DOCUMENT_TYPE_NODE": 1,
2127     "DOCUMENT_FRAGMENT_NODE": 1,
2128     "NOTATION_NODE": 1,
2129 
2130     "DOCUMENT_POSITION_DISCONNECTED": 1,
2131     "DOCUMENT_POSITION_PRECEDING": 1,
2132     "DOCUMENT_POSITION_FOLLOWING": 1,
2133     "DOCUMENT_POSITION_CONTAINS": 1,
2134     "DOCUMENT_POSITION_CONTAINED_BY": 1,
2135     "DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC": 1,
2136 
2137     "UNKNOWN_RULE": 1,
2138     "STYLE_RULE": 1,
2139     "CHARSET_RULE": 1,
2140     "IMPORT_RULE": 1,
2141     "MEDIA_RULE": 1,
2142     "FONT_FACE_RULE": 1,
2143     "PAGE_RULE": 1,
2144 
2145     "CAPTURING_PHASE": 1,
2146     "AT_TARGET": 1,
2147     "BUBBLING_PHASE": 1,
2148 
2149     "SCROLL_PAGE_UP": 1,
2150     "SCROLL_PAGE_DOWN": 1,
2151 
2152     "MOUSEUP": 1,
2153     "MOUSEDOWN": 1,
2154     "MOUSEOVER": 1,
2155     "MOUSEOUT": 1,
2156     "MOUSEMOVE": 1,
2157     "MOUSEDRAG": 1,
2158     "CLICK": 1,
2159     "DBLCLICK": 1,
2160     "KEYDOWN": 1,
2161     "KEYUP": 1,
2162     "KEYPRESS": 1,
2163     "DRAGDROP": 1,
2164     "FOCUS": 1,
2165     "BLUR": 1,
2166     "SELECT": 1,
2167     "CHANGE": 1,
2168     "RESET": 1,
2169     "SUBMIT": 1,
2170     "SCROLL": 1,
2171     "LOAD": 1,
2172     "UNLOAD": 1,
2173     "XFER_DONE": 1,
2174     "ABORT": 1,
2175     "ERROR": 1,
2176     "LOCATE": 1,
2177     "MOVE": 1,
2178     "RESIZE": 1,
2179     "FORWARD": 1,
2180     "HELP": 1,
2181     "BACK": 1,
2182     "TEXT": 1,
2183 
2184     "ALT_MASK": 1,
2185     "CONTROL_MASK": 1,
2186     "SHIFT_MASK": 1,
2187     "META_MASK": 1,
2188 
2189     "DOM_VK_TAB": 1,
2190     "DOM_VK_PAGE_UP": 1,
2191     "DOM_VK_PAGE_DOWN": 1,
2192     "DOM_VK_UP": 1,
2193     "DOM_VK_DOWN": 1,
2194     "DOM_VK_LEFT": 1,
2195     "DOM_VK_RIGHT": 1,
2196     "DOM_VK_CANCEL": 1,
2197     "DOM_VK_HELP": 1,
2198     "DOM_VK_BACK_SPACE": 1,
2199     "DOM_VK_CLEAR": 1,
2200     "DOM_VK_RETURN": 1,
2201     "DOM_VK_ENTER": 1,
2202     "DOM_VK_SHIFT": 1,
2203     "DOM_VK_CONTROL": 1,
2204     "DOM_VK_ALT": 1,
2205     "DOM_VK_PAUSE": 1,
2206     "DOM_VK_CAPS_LOCK": 1,
2207     "DOM_VK_ESCAPE": 1,
2208     "DOM_VK_SPACE": 1,
2209     "DOM_VK_END": 1,
2210     "DOM_VK_HOME": 1,
2211     "DOM_VK_PRINTSCREEN": 1,
2212     "DOM_VK_INSERT": 1,
2213     "DOM_VK_DELETE": 1,
2214     "DOM_VK_0": 1,
2215     "DOM_VK_1": 1,
2216     "DOM_VK_2": 1,
2217     "DOM_VK_3": 1,
2218     "DOM_VK_4": 1,
2219     "DOM_VK_5": 1,
2220     "DOM_VK_6": 1,
2221     "DOM_VK_7": 1,
2222     "DOM_VK_8": 1,
2223     "DOM_VK_9": 1,
2224     "DOM_VK_SEMICOLON": 1,
2225     "DOM_VK_EQUALS": 1,
2226     "DOM_VK_A": 1,
2227     "DOM_VK_B": 1,
2228     "DOM_VK_C": 1,
2229     "DOM_VK_D": 1,
2230     "DOM_VK_E": 1,
2231     "DOM_VK_F": 1,
2232     "DOM_VK_G": 1,
2233     "DOM_VK_H": 1,
2234     "DOM_VK_I": 1,
2235     "DOM_VK_J": 1,
2236     "DOM_VK_K": 1,
2237     "DOM_VK_L": 1,
2238     "DOM_VK_M": 1,
2239     "DOM_VK_N": 1,
2240     "DOM_VK_O": 1,
2241     "DOM_VK_P": 1,
2242     "DOM_VK_Q": 1,
2243     "DOM_VK_R": 1,
2244     "DOM_VK_S": 1,
2245     "DOM_VK_T": 1,
2246     "DOM_VK_U": 1,
2247     "DOM_VK_V": 1,
2248     "DOM_VK_W": 1,
2249     "DOM_VK_X": 1,
2250     "DOM_VK_Y": 1,
2251     "DOM_VK_Z": 1,
2252     "DOM_VK_CONTEXT_MENU": 1,
2253     "DOM_VK_NUMPAD0": 1,
2254     "DOM_VK_NUMPAD1": 1,
2255     "DOM_VK_NUMPAD2": 1,
2256     "DOM_VK_NUMPAD3": 1,
2257     "DOM_VK_NUMPAD4": 1,
2258     "DOM_VK_NUMPAD5": 1,
2259     "DOM_VK_NUMPAD6": 1,
2260     "DOM_VK_NUMPAD7": 1,
2261     "DOM_VK_NUMPAD8": 1,
2262     "DOM_VK_NUMPAD9": 1,
2263     "DOM_VK_MULTIPLY": 1,
2264     "DOM_VK_ADD": 1,
2265     "DOM_VK_SEPARATOR": 1,
2266     "DOM_VK_SUBTRACT": 1,
2267     "DOM_VK_DECIMAL": 1,
2268     "DOM_VK_DIVIDE": 1,
2269     "DOM_VK_F1": 1,
2270     "DOM_VK_F2": 1,
2271     "DOM_VK_F3": 1,
2272     "DOM_VK_F4": 1,
2273     "DOM_VK_F5": 1,
2274     "DOM_VK_F6": 1,
2275     "DOM_VK_F7": 1,
2276     "DOM_VK_F8": 1,
2277     "DOM_VK_F9": 1,
2278     "DOM_VK_F10": 1,
2279     "DOM_VK_F11": 1,
2280     "DOM_VK_F12": 1,
2281     "DOM_VK_F13": 1,
2282     "DOM_VK_F14": 1,
2283     "DOM_VK_F15": 1,
2284     "DOM_VK_F16": 1,
2285     "DOM_VK_F17": 1,
2286     "DOM_VK_F18": 1,
2287     "DOM_VK_F19": 1,
2288     "DOM_VK_F20": 1,
2289     "DOM_VK_F21": 1,
2290     "DOM_VK_F22": 1,
2291     "DOM_VK_F23": 1,
2292     "DOM_VK_F24": 1,
2293     "DOM_VK_NUM_LOCK": 1,
2294     "DOM_VK_SCROLL_LOCK": 1,
2295     "DOM_VK_COMMA": 1,
2296     "DOM_VK_PERIOD": 1,
2297     "DOM_VK_SLASH": 1,
2298     "DOM_VK_BACK_QUOTE": 1,
2299     "DOM_VK_OPEN_BRACKET": 1,
2300     "DOM_VK_BACK_SLASH": 1,
2301     "DOM_VK_CLOSE_BRACKET": 1,
2302     "DOM_VK_QUOTE": 1,
2303     "DOM_VK_META": 1,
2304 
2305     "SVG_ZOOMANDPAN_DISABLE": 1,
2306     "SVG_ZOOMANDPAN_MAGNIFY": 1,
2307     "SVG_ZOOMANDPAN_UNKNOWN": 1
2308 };
2309 
2310 // ********************************************************************************************* //
2311 // Inline Event Handlers (introduced in Firefox 9)
2312 
2313 /**
2314  * List of event handlers that are settable via on* DOM properties.
2315  */
2316 Dom.domInlineEventHandlersMap =
2317 {
2318     "onabort": 1,
2319     "onafterprint": 1,
2320     "onafterscriptexecute": 1,
2321     "onbeforeprint": 1,
2322     "onbeforescriptexecute": 1,
2323     "onbeforeunload": 1,
2324     "onblur": 1,
2325     "oncanplay": 1,
2326     "oncanplaythrough": 1,
2327     "onchange": 1,
2328     "onclick": 1,
2329     "oncontextmenu": 1,
2330     "oncopy": 1,
2331     "oncut": 1,
2332     "ondblclick": 1,
2333     "ondevicemotion": 1,
2334     "ondeviceorientation": 1,
2335     "ondrag": 1,
2336     "ondragend": 1,
2337     "ondragenter": 1,
2338     "ondragleave": 1,
2339     "ondragover": 1,
2340     "ondragstart": 1,
2341     "ondrop": 1,
2342     "ondurationchange": 1,
2343     "onemptied": 1,
2344     "onended": 1,
2345     "onerror": 1,
2346     "onfocus": 1,
2347     "onhashchange": 1,
2348     "oninput": 1,
2349     "oninvalid": 1,
2350     "onkeydown": 1,
2351     "onkeypress": 1,
2352     "onkeyup": 1,
2353     "onload": 1,
2354     "onloadeddata": 1,
2355     "onloadedmetadata": 1,
2356     "onloadstart": 1,
2357     "onmessage": 1,
2358     "onmousedown": 1,
2359     "onmousemove": 1,
2360     "onmouseout": 1,
2361     "onmouseover": 1,
2362     "onmouseup": 1,
2363     "onoffline": 1,
2364     "ononline": 1,
2365     "onpagehide": 1,
2366     "onpageshow": 1,
2367     "onpaste": 1,
2368     "onpause": 1,
2369     "onplay": 1,
2370     "onplaying": 1,
2371     "onpopstate": 1,
2372     "onprogress": 1,
2373     "onratechange": 1,
2374     "onreadystatechange": 1,
2375     "onreset": 1,
2376     "onresize": 1,
2377     "onscroll": 1,
2378     "onseeked": 1,
2379     "onseeking": 1,
2380     "onselect": 1,
2381     "onshow": 1,
2382     "onstalled": 1,
2383     "onsubmit": 1,
2384     "onsuspend": 1,
2385     "ontimeupdate": 1,
2386     "onunload": 1,
2387     "onvolumechange": 1,
2388     "onwaiting": 1,
2389     "onmozfullscreenchange": 1,
2390     "ondevicelight": 1,
2391     "ondeviceproximity": 1,
2392     "onmouseenter": 1,
2393     "onmouseleave": 1,
2394     "onmozfullscreenerror": 1,
2395     "onmozpointerlockchange": 1,
2396     "onmozpointerlockerror": 1,
2397     "onuserproximity": 1,
2398     "onwheel": 1
2399 }
2400 
2401 // ********************************************************************************************* //
2402 // Registration
2403 
2404 return Dom;
2405 
2406 // ********************************************************************************************* //
2407 });
2408