Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / src / core / src / dom / Element.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext.Element
17  * @alternateClassName Ext.core.Element
18  *
19  * Encapsulates a DOM element, adding simple DOM manipulation facilities, normalizing for browser differences.
20  *
21  * All instances of this class inherit the methods of {@link Ext.fx.Anim} making visual effects easily available to all
22  * DOM elements.
23  *
24  * Note that the events documented in this class are not Ext events, they encapsulate browser events. Some older browsers
25  * may not support the full range of events. Which events are supported is beyond the control of Ext JS.
26  *
27  * Usage:
28  *
29  *     // by id
30  *     var el = Ext.get("my-div");
31  *
32  *     // by DOM element reference
33  *     var el = Ext.get(myDivElement);
34  *
35  * # Animations
36  *
37  * When an element is manipulated, by default there is no animation.
38  *
39  *     var el = Ext.get("my-div");
40  *
41  *     // no animation
42  *     el.setWidth(100);
43  *
44  * Many of the functions for manipulating an element have an optional "animate" parameter. This parameter can be
45  * specified as boolean (true) for default animation effects.
46  *
47  *     // default animation
48  *     el.setWidth(100, true);
49  *
50  * To configure the effects, an object literal with animation options to use as the Element animation configuration
51  * object can also be specified. Note that the supported Element animation configuration options are a subset of the
52  * {@link Ext.fx.Anim} animation options specific to Fx effects. The supported Element animation configuration options
53  * are:
54  *
55  *     Option    Default   Description
56  *     --------- --------  ---------------------------------------------
57  *     {@link Ext.fx.Anim#duration duration}  .35       The duration of the animation in seconds
58  *     {@link Ext.fx.Anim#easing easing}    easeOut   The easing method
59  *     {@link Ext.fx.Anim#callback callback}  none      A function to execute when the anim completes
60  *     {@link Ext.fx.Anim#scope scope}     this      The scope (this) of the callback function
61  *
62  * Usage:
63  *
64  *     // Element animation options object
65  *     var opt = {
66  *         {@link Ext.fx.Anim#duration duration}: 1,
67  *         {@link Ext.fx.Anim#easing easing}: 'elasticIn',
68  *         {@link Ext.fx.Anim#callback callback}: this.foo,
69  *         {@link Ext.fx.Anim#scope scope}: this
70  *     };
71  *     // animation with some options set
72  *     el.setWidth(100, opt);
73  *
74  * The Element animation object being used for the animation will be set on the options object as "anim", which allows
75  * you to stop or manipulate the animation. Here is an example:
76  *
77  *     // using the "anim" property to get the Anim object
78  *     if(opt.anim.isAnimated()){
79  *         opt.anim.stop();
80  *     }
81  *
82  * # Composite (Collections of) Elements
83  *
84  * For working with collections of Elements, see {@link Ext.CompositeElement}
85  *
86  * @constructor
87  * Creates new Element directly.
88  * @param {String/HTMLElement} element
89  * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this
90  * element in the cache and if there is it returns the same instance. This will skip that check (useful for extending
91  * this class).
92  * @return {Object}
93  */
94  (function() {
95     var DOC = document,
96         EC = Ext.cache;
97
98     Ext.Element = Ext.core.Element = function(element, forceNew) {
99         var dom = typeof element == "string" ? DOC.getElementById(element) : element,
100         id;
101
102         if (!dom) {
103             return null;
104         }
105
106         id = dom.id;
107
108         if (!forceNew && id && EC[id]) {
109             // element object already exists
110             return EC[id].el;
111         }
112
113         /**
114          * @property {HTMLElement} dom
115          * The DOM element
116          */
117         this.dom = dom;
118
119         /**
120          * @property {String} id
121          * The DOM element ID
122          */
123         this.id = id || Ext.id(dom);
124     };
125
126     var DH = Ext.DomHelper,
127     El = Ext.Element;
128
129
130     El.prototype = {
131         /**
132          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
133          * @param {Object} o The object with the attributes
134          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
135          * @return {Ext.Element} this
136          */
137         set: function(o, useSet) {
138             var el = this.dom,
139                 attr,
140                 val;
141             useSet = (useSet !== false) && !!el.setAttribute;
142
143             for (attr in o) {
144                 if (o.hasOwnProperty(attr)) {
145                     val = o[attr];
146                     if (attr == 'style') {
147                         DH.applyStyles(el, val);
148                     } else if (attr == 'cls') {
149                         el.className = val;
150                     } else if (useSet) {
151                         el.setAttribute(attr, val);
152                     } else {
153                         el[attr] = val;
154                     }
155                 }
156             }
157             return this;
158         },
159
160         //  Mouse events
161         /**
162          * @event click
163          * Fires when a mouse click is detected within the element.
164          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
165          * @param {HTMLElement} t The target of the event.
166          */
167         /**
168          * @event contextmenu
169          * Fires when a right click is detected within the element.
170          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
171          * @param {HTMLElement} t The target of the event.
172          */
173         /**
174          * @event dblclick
175          * Fires when a mouse double click is detected within the element.
176          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
177          * @param {HTMLElement} t The target of the event.
178          */
179         /**
180          * @event mousedown
181          * Fires when a mousedown is detected within the element.
182          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
183          * @param {HTMLElement} t The target of the event.
184          */
185         /**
186          * @event mouseup
187          * Fires when a mouseup is detected within the element.
188          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
189          * @param {HTMLElement} t The target of the event.
190          */
191         /**
192          * @event mouseover
193          * Fires when a mouseover is detected within the element.
194          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
195          * @param {HTMLElement} t The target of the event.
196          */
197         /**
198          * @event mousemove
199          * Fires when a mousemove is detected with the element.
200          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
201          * @param {HTMLElement} t The target of the event.
202          */
203         /**
204          * @event mouseout
205          * Fires when a mouseout is detected with the element.
206          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
207          * @param {HTMLElement} t The target of the event.
208          */
209         /**
210          * @event mouseenter
211          * Fires when the mouse enters the element.
212          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
213          * @param {HTMLElement} t The target of the event.
214          */
215         /**
216          * @event mouseleave
217          * Fires when the mouse leaves the element.
218          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
219          * @param {HTMLElement} t The target of the event.
220          */
221
222         //  Keyboard events
223         /**
224          * @event keypress
225          * Fires when a keypress is detected within the element.
226          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
227          * @param {HTMLElement} t The target of the event.
228          */
229         /**
230          * @event keydown
231          * Fires when a keydown is detected within the element.
232          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
233          * @param {HTMLElement} t The target of the event.
234          */
235         /**
236          * @event keyup
237          * Fires when a keyup is detected within the element.
238          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
239          * @param {HTMLElement} t The target of the event.
240          */
241
242
243         //  HTML frame/object events
244         /**
245          * @event load
246          * Fires when the user agent finishes loading all content within the element. Only supported by window, frames,
247          * objects and images.
248          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
249          * @param {HTMLElement} t The target of the event.
250          */
251         /**
252          * @event unload
253          * Fires when the user agent removes all content from a window or frame. For elements, it fires when the target
254          * element or any of its content has been removed.
255          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
256          * @param {HTMLElement} t The target of the event.
257          */
258         /**
259          * @event abort
260          * Fires when an object/image is stopped from loading before completely loaded.
261          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
262          * @param {HTMLElement} t The target of the event.
263          */
264         /**
265          * @event error
266          * Fires when an object/image/frame cannot be loaded properly.
267          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
268          * @param {HTMLElement} t The target of the event.
269          */
270         /**
271          * @event resize
272          * Fires when a document view is resized.
273          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
274          * @param {HTMLElement} t The target of the event.
275          */
276         /**
277          * @event scroll
278          * Fires when a document view is scrolled.
279          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
280          * @param {HTMLElement} t The target of the event.
281          */
282
283         //  Form events
284         /**
285          * @event select
286          * Fires when a user selects some text in a text field, including input and textarea.
287          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
288          * @param {HTMLElement} t The target of the event.
289          */
290         /**
291          * @event change
292          * Fires when a control loses the input focus and its value has been modified since gaining focus.
293          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
294          * @param {HTMLElement} t The target of the event.
295          */
296         /**
297          * @event submit
298          * Fires when a form is submitted.
299          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
300          * @param {HTMLElement} t The target of the event.
301          */
302         /**
303          * @event reset
304          * Fires when a form is reset.
305          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
306          * @param {HTMLElement} t The target of the event.
307          */
308         /**
309          * @event focus
310          * Fires when an element receives focus either via the pointing device or by tab navigation.
311          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
312          * @param {HTMLElement} t The target of the event.
313          */
314         /**
315          * @event blur
316          * Fires when an element loses focus either via the pointing device or by tabbing navigation.
317          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
318          * @param {HTMLElement} t The target of the event.
319          */
320
321         //  User Interface events
322         /**
323          * @event DOMFocusIn
324          * Where supported. Similar to HTML focus event, but can be applied to any focusable element.
325          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
326          * @param {HTMLElement} t The target of the event.
327          */
328         /**
329          * @event DOMFocusOut
330          * Where supported. Similar to HTML blur event, but can be applied to any focusable element.
331          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
332          * @param {HTMLElement} t The target of the event.
333          */
334         /**
335          * @event DOMActivate
336          * Where supported. Fires when an element is activated, for instance, through a mouse click or a keypress.
337          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
338          * @param {HTMLElement} t The target of the event.
339          */
340
341         //  DOM Mutation events
342         /**
343          * @event DOMSubtreeModified
344          * Where supported. Fires when the subtree is modified.
345          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
346          * @param {HTMLElement} t The target of the event.
347          */
348         /**
349          * @event DOMNodeInserted
350          * Where supported. Fires when a node has been added as a child of another node.
351          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
352          * @param {HTMLElement} t The target of the event.
353          */
354         /**
355          * @event DOMNodeRemoved
356          * Where supported. Fires when a descendant node of the element is removed.
357          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
358          * @param {HTMLElement} t The target of the event.
359          */
360         /**
361          * @event DOMNodeRemovedFromDocument
362          * Where supported. Fires when a node is being removed from a document.
363          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
364          * @param {HTMLElement} t The target of the event.
365          */
366         /**
367          * @event DOMNodeInsertedIntoDocument
368          * Where supported. Fires when a node is being inserted into a document.
369          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
370          * @param {HTMLElement} t The target of the event.
371          */
372         /**
373          * @event DOMAttrModified
374          * Where supported. Fires when an attribute has been modified.
375          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
376          * @param {HTMLElement} t The target of the event.
377          */
378         /**
379          * @event DOMCharacterDataModified
380          * Where supported. Fires when the character data has been modified.
381          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
382          * @param {HTMLElement} t The target of the event.
383          */
384
385         /**
386          * @property {String} defaultUnit
387          * The default unit to append to CSS values where a unit isn't provided.
388          */
389         defaultUnit: "px",
390
391         /**
392          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
393          * @param {String} selector The simple selector to test
394          * @return {Boolean} True if this element matches the selector, else false
395          */
396         is: function(simpleSelector) {
397             return Ext.DomQuery.is(this.dom, simpleSelector);
398         },
399
400         /**
401          * Tries to focus the element. Any exceptions are caught and ignored.
402          * @param {Number} defer (optional) Milliseconds to defer the focus
403          * @return {Ext.Element} this
404          */
405         focus: function(defer,
406                         /* private */
407                         dom) {
408             var me = this;
409             dom = dom || me.dom;
410             try {
411                 if (Number(defer)) {
412                     Ext.defer(me.focus, defer, null, [null, dom]);
413                 } else {
414                     dom.focus();
415                 }
416             } catch(e) {}
417             return me;
418         },
419
420         /**
421          * Tries to blur the element. Any exceptions are caught and ignored.
422          * @return {Ext.Element} this
423          */
424         blur: function() {
425             try {
426                 this.dom.blur();
427             } catch(e) {}
428             return this;
429         },
430
431         /**
432          * Returns the value of the "value" attribute
433          * @param {Boolean} asNumber true to parse the value as a number
434          * @return {String/Number}
435          */
436         getValue: function(asNumber) {
437             var val = this.dom.value;
438             return asNumber ? parseInt(val, 10) : val;
439         },
440
441         /**
442          * Appends an event handler to this element.
443          *
444          * @param {String} eventName The name of event to handle.
445          *
446          * @param {Function} fn The handler function the event invokes. This function is passed the following parameters:
447          *
448          * - **evt** : EventObject
449          *
450          *   The {@link Ext.EventObject EventObject} describing the event.
451          *
452          * - **el** : HtmlElement
453          *
454          *   The DOM element which was the target of the event. Note that this may be filtered by using the delegate option.
455          *
456          * - **o** : Object
457          *
458          *   The options object from the addListener call.
459          *
460          * @param {Object} scope (optional) The scope (**this** reference) in which the handler function is executed. **If
461          * omitted, defaults to this Element.**
462          *
463          * @param {Object} options (optional) An object containing handler configuration properties. This may contain any of
464          * the following properties:
465          *
466          * - **scope** Object :
467          *
468          *   The scope (**this** reference) in which the handler function is executed. **If omitted, defaults to this
469          *   Element.**
470          *
471          * - **delegate** String:
472          *
473          *   A simple selector to filter the target or look for a descendant of the target. See below for additional details.
474          *
475          * - **stopEvent** Boolean:
476          *
477          *   True to stop the event. That is stop propagation, and prevent the default action.
478          *
479          * - **preventDefault** Boolean:
480          *
481          *   True to prevent the default action
482          *
483          * - **stopPropagation** Boolean:
484          *
485          *   True to prevent event propagation
486          *
487          * - **normalized** Boolean:
488          *
489          *   False to pass a browser event to the handler function instead of an Ext.EventObject
490          *
491          * - **target** Ext.Element:
492          *
493          *   Only call the handler if the event was fired on the target Element, _not_ if the event was bubbled up from a
494          *   child node.
495          *
496          * - **delay** Number:
497          *
498          *   The number of milliseconds to delay the invocation of the handler after the event fires.
499          *
500          * - **single** Boolean:
501          *
502          *   True to add a handler to handle just the next firing of the event, and then remove itself.
503          *
504          * - **buffer** Number:
505          *
506          *   Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed by the specified number of
507          *   milliseconds. If the event fires again within that time, the original handler is _not_ invoked, but the new
508          *   handler is scheduled in its place.
509          *
510          * **Combining Options**
511          *
512          * In the following examples, the shorthand form {@link #on} is used rather than the more verbose addListener. The
513          * two are equivalent. Using the options argument, it is possible to combine different types of listeners:
514          *
515          * A delayed, one-time listener that auto stops the event and adds a custom argument (forumId) to the options
516          * object. The options object is available as the third parameter in the handler function.
517          *
518          * Code:
519          *
520          *     el.on('click', this.onClick, this, {
521          *         single: true,
522          *         delay: 100,
523          *         stopEvent : true,
524          *         forumId: 4
525          *     });
526          *
527          * **Attaching multiple handlers in 1 call**
528          *
529          * The method also allows for a single argument to be passed which is a config object containing properties which
530          * specify multiple handlers.
531          *
532          * Code:
533          *
534          *     el.on({
535          *         'click' : {
536          *             fn: this.onClick,
537          *             scope: this,
538          *             delay: 100
539          *         },
540          *         'mouseover' : {
541          *             fn: this.onMouseOver,
542          *             scope: this
543          *         },
544          *         'mouseout' : {
545          *             fn: this.onMouseOut,
546          *             scope: this
547          *         }
548          *     });
549          *
550          * Or a shorthand syntax:
551          *
552          * Code:
553          *
554          *     el.on({
555          *         'click' : this.onClick,
556          *         'mouseover' : this.onMouseOver,
557          *         'mouseout' : this.onMouseOut,
558          *         scope: this
559          *     });
560          *
561          * **delegate**
562          *
563          * This is a configuration option that you can pass along when registering a handler for an event to assist with
564          * event delegation. Event delegation is a technique that is used to reduce memory consumption and prevent exposure
565          * to memory-leaks. By registering an event for a container element as opposed to each element within a container.
566          * By setting this configuration option to a simple selector, the target element will be filtered to look for a
567          * descendant of the target. For example:
568          *
569          *     // using this markup:
570          *     <div id='elId'>
571          *         <p id='p1'>paragraph one</p>
572          *         <p id='p2' class='clickable'>paragraph two</p>
573          *         <p id='p3'>paragraph three</p>
574          *     </div>
575          *
576          *     // utilize event delegation to registering just one handler on the container element:
577          *     el = Ext.get('elId');
578          *     el.on(
579          *         'click',
580          *         function(e,t) {
581          *             // handle click
582          *             console.info(t.id); // 'p2'
583          *         },
584          *         this,
585          *         {
586          *             // filter the target element to be a descendant with the class 'clickable'
587          *             delegate: '.clickable'
588          *         }
589          *     );
590          *
591          * @return {Ext.Element} this
592          */
593         addListener: function(eventName, fn, scope, options) {
594             Ext.EventManager.on(this.dom, eventName, fn, scope || this, options);
595             return this;
596         },
597
598         /**
599          * Removes an event handler from this element.
600          *
601          * **Note**: if a *scope* was explicitly specified when {@link #addListener adding} the listener,
602          * the same scope must be specified here.
603          *
604          * Example:
605          *
606          *     el.removeListener('click', this.handlerFn);
607          *     // or
608          *     el.un('click', this.handlerFn);
609          *
610          * @param {String} eventName The name of the event from which to remove the handler.
611          * @param {Function} fn The handler function to remove. **This must be a reference to the function passed into the
612          * {@link #addListener} call.**
613          * @param {Object} scope If a scope (**this** reference) was specified when the listener was added, then this must
614          * refer to the same object.
615          * @return {Ext.Element} this
616          */
617         removeListener: function(eventName, fn, scope) {
618             Ext.EventManager.un(this.dom, eventName, fn, scope || this);
619             return this;
620         },
621
622         /**
623          * Removes all previous added listeners from this element
624          * @return {Ext.Element} this
625          */
626         removeAllListeners: function() {
627             Ext.EventManager.removeAll(this.dom);
628             return this;
629         },
630
631         /**
632          * Recursively removes all previous added listeners from this element and its children
633          * @return {Ext.Element} this
634          */
635         purgeAllListeners: function() {
636             Ext.EventManager.purgeElement(this);
637             return this;
638         },
639
640         /**
641          * Test if size has a unit, otherwise appends the passed unit string, or the default for this Element.
642          * @param size {Mixed} The size to set
643          * @param units {String} The units to append to a numeric size value
644          * @private
645          */
646         addUnits: function(size, units) {
647
648             // Most common case first: Size is set to a number
649             if (Ext.isNumber(size)) {
650                 return size + (units || this.defaultUnit || 'px');
651             }
652
653             // Size set to a value which means "auto"
654             if (size === "" || size == "auto" || size == null) {
655                 return size || '';
656             }
657
658             // Otherwise, warn if it's not a valid CSS measurement
659             if (!unitPattern.test(size)) {
660                 //<debug>
661                 if (Ext.isDefined(Ext.global.console)) {
662                     Ext.global.console.warn("Warning, size detected as NaN on Element.addUnits.");
663                 }
664                 //</debug>
665                 return size || '';
666             }
667             return size;
668         },
669
670         /**
671          * Tests various css rules/browsers to determine if this element uses a border box
672          * @return {Boolean}
673          */
674         isBorderBox: function() {
675             return Ext.isBorderBox || noBoxAdjust[(this.dom.tagName || "").toLowerCase()];
676         },
677
678         /**
679          * Removes this element's dom reference. Note that event and cache removal is handled at {@link Ext#removeNode
680          * Ext.removeNode}
681          */
682         remove: function() {
683             var me = this,
684             dom = me.dom;
685
686             if (dom) {
687                 delete me.dom;
688                 Ext.removeNode(dom);
689             }
690         },
691
692         /**
693          * Sets up event handlers to call the passed functions when the mouse is moved into and out of the Element.
694          * @param {Function} overFn The function to call when the mouse enters the Element.
695          * @param {Function} outFn The function to call when the mouse leaves the Element.
696          * @param {Object} scope (optional) The scope (`this` reference) in which the functions are executed. Defaults
697          * to the Element's DOM element.
698          * @param {Object} options (optional) Options for the listener. See {@link Ext.util.Observable#addListener the
699          * options parameter}.
700          * @return {Ext.Element} this
701          */
702         hover: function(overFn, outFn, scope, options) {
703             var me = this;
704             me.on('mouseenter', overFn, scope || me.dom, options);
705             me.on('mouseleave', outFn, scope || me.dom, options);
706             return me;
707         },
708
709         /**
710          * Returns true if this element is an ancestor of the passed element
711          * @param {HTMLElement/String} el The element to check
712          * @return {Boolean} True if this element is an ancestor of el, else false
713          */
714         contains: function(el) {
715             return ! el ? false: Ext.Element.isAncestor(this.dom, el.dom ? el.dom: el);
716         },
717
718         /**
719          * Returns the value of a namespaced attribute from the element's underlying DOM node.
720          * @param {String} namespace The namespace in which to look for the attribute
721          * @param {String} name The attribute name
722          * @return {String} The attribute value
723          */
724         getAttributeNS: function(ns, name) {
725             return this.getAttribute(name, ns);
726         },
727
728         /**
729          * Returns the value of an attribute from the element's underlying DOM node.
730          * @param {String} name The attribute name
731          * @param {String} namespace (optional) The namespace in which to look for the attribute
732          * @return {String} The attribute value
733          * @method
734          */
735         getAttribute: (Ext.isIE && !(Ext.isIE9 && document.documentMode === 9)) ?
736         function(name, ns) {
737             var d = this.dom,
738             type;
739             if(ns) {
740                 type = typeof d[ns + ":" + name];
741                 if (type != 'undefined' && type != 'unknown') {
742                     return d[ns + ":" + name] || null;
743                 }
744                 return null;
745             }
746             if (name === "for") {
747                 name = "htmlFor";
748             }
749             return d[name] || null;
750         }: function(name, ns) {
751             var d = this.dom;
752             if (ns) {
753                return d.getAttributeNS(ns, name) || d.getAttribute(ns + ":" + name);
754             }
755             return  d.getAttribute(name) || d[name] || null;
756         },
757
758         /**
759          * Update the innerHTML of this element
760          * @param {String} html The new HTML
761          * @return {Ext.Element} this
762          */
763         update: function(html) {
764             if (this.dom) {
765                 this.dom.innerHTML = html;
766             }
767             return this;
768         }
769     };
770
771     var ep = El.prototype;
772
773     El.addMethods = function(o) {
774         Ext.apply(ep, o);
775     };
776
777     /**
778      * @method
779      * @alias Ext.Element#addListener
780      * Shorthand for {@link #addListener}.
781      */
782     ep.on = ep.addListener;
783
784     /**
785      * @method
786      * @alias Ext.Element#removeListener
787      * Shorthand for {@link #removeListener}.
788      */
789     ep.un = ep.removeListener;
790
791     /**
792      * @method
793      * @alias Ext.Element#removeAllListeners
794      * Alias for {@link #removeAllListeners}.
795      */
796     ep.clearListeners = ep.removeAllListeners;
797
798     /**
799      * @method destroy
800      * @member Ext.Element
801      * Removes this element's dom reference. Note that event and cache removal is handled at {@link Ext#removeNode
802      * Ext.removeNode}. Alias to {@link #remove}.
803      */
804     ep.destroy = ep.remove;
805
806     /**
807      * @property {Boolean} autoBoxAdjust
808      * true to automatically adjust width and height settings for box-model issues (default to true)
809      */
810     ep.autoBoxAdjust = true;
811
812     // private
813     var unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i,
814     docEl;
815
816     /**
817      * Retrieves Ext.Element objects. {@link Ext#get} is an alias for {@link Ext.Element#get}.
818      *
819      * **This method does not retrieve {@link Ext.Component Component}s.** This method retrieves Ext.Element
820      * objects which encapsulate DOM elements. To retrieve a Component by its ID, use {@link Ext.ComponentManager#get}.
821      *
822      * Uses simple caching to consistently return the same object. Automatically fixes if an object was recreated with
823      * the same id via AJAX or DOM.
824      *
825      * @param {String/HTMLElement/Ext.Element} el The id of the node, a DOM Node or an existing Element.
826      * @return {Ext.Element} The Element object (or null if no matching element was found)
827      * @static
828      */
829     El.get = function(el) {
830         var ex,
831         elm,
832         id;
833         if (!el) {
834             return null;
835         }
836         if (typeof el == "string") {
837             // element id
838             if (! (elm = DOC.getElementById(el))) {
839                 return null;
840             }
841             if (EC[el] && EC[el].el) {
842                 ex = EC[el].el;
843                 ex.dom = elm;
844             } else {
845                 ex = El.addToCache(new El(elm));
846             }
847             return ex;
848         } else if (el.tagName) {
849             // dom element
850             if (! (id = el.id)) {
851                 id = Ext.id(el);
852             }
853             if (EC[id] && EC[id].el) {
854                 ex = EC[id].el;
855                 ex.dom = el;
856             } else {
857                 ex = El.addToCache(new El(el));
858             }
859             return ex;
860         } else if (el instanceof El) {
861             if (el != docEl) {
862                 // refresh dom element in case no longer valid,
863                 // catch case where it hasn't been appended
864                 // If an el instance is passed, don't pass to getElementById without some kind of id
865                 if (Ext.isIE && (el.id == undefined || el.id == '')) {
866                     el.dom = el.dom;
867                 } else {
868                     el.dom = DOC.getElementById(el.id) || el.dom;
869                 }
870             }
871             return el;
872         } else if (el.isComposite) {
873             return el;
874         } else if (Ext.isArray(el)) {
875             return El.select(el);
876         } else if (el == DOC) {
877             // create a bogus element object representing the document object
878             if (!docEl) {
879                 var f = function() {};
880                 f.prototype = El.prototype;
881                 docEl = new f();
882                 docEl.dom = DOC;
883             }
884             return docEl;
885         }
886         return null;
887     };
888
889     /**
890      * Retrieves Ext.Element objects like {@link Ext#get} but is optimized for sub-elements.
891      * This is helpful for performance, because in IE (prior to IE 9), `getElementById` uses
892      * an non-optimized search. In those browsers, starting the search for an element with a
893      * matching ID at a parent of that element will greatly speed up the process.
894      *
895      * Unlike {@link Ext#get}, this method only accepts ID's. If the ID is not a child of
896      * this element, it will still be found if it exists in the document, but will be slower
897      * than calling {@link Ext#get} directly.
898      *
899      * @param {String} id The id of the element to get.
900      * @return {Ext.Element} The Element object (or null if no matching element was found)
901      * @member Ext.Element
902      * @method getById
903      * @markdown
904      */
905     ep.getById = (!Ext.isIE6 && !Ext.isIE7 && !Ext.isIE8) ? El.get :
906         function (id) {
907             var dom = this.dom,
908                 cached, el, ret;
909
910             if (dom) {
911                 el = dom.all[id];
912                 if (el) {
913                     // calling El.get here is a real hit (2x slower) because it has to
914                     // redetermine that we are giving it a dom el.
915                     cached = EC[id];
916                     if (cached && cached.el) {
917                         ret = cached.el;
918                         ret.dom = el;
919                     } else {
920                         ret = El.addToCache(new El(el));
921                     }
922                     return ret;
923                 }
924             }
925
926             return El.get(id);
927         };
928
929     El.addToCache = function(el, id) {
930         if (el) {
931             id = id || el.id;
932             EC[id] = {
933                 el: el,
934                 data: {},
935                 events: {}
936             };
937         }
938         return el;
939     };
940
941     // private method for getting and setting element data
942     El.data = function(el, key, value) {
943         el = El.get(el);
944         if (!el) {
945             return null;
946         }
947         var c = EC[el.id].data;
948         if (arguments.length == 2) {
949             return c[key];
950         } else {
951             return (c[key] = value);
952         }
953     };
954
955     // private
956     // Garbage collection - uncache elements/purge listeners on orphaned elements
957     // so we don't hold a reference and cause the browser to retain them
958     function garbageCollect() {
959         if (!Ext.enableGarbageCollector) {
960             clearInterval(El.collectorThreadId);
961         } else {
962             var eid,
963             el,
964             d,
965             o;
966
967             for (eid in EC) {
968                 if (!EC.hasOwnProperty(eid)) {
969                     continue;
970                 }
971                 o = EC[eid];
972                 if (o.skipGarbageCollection) {
973                     continue;
974                 }
975                 el = o.el;
976                 d = el.dom;
977                 // -------------------------------------------------------
978                 // Determining what is garbage:
979                 // -------------------------------------------------------
980                 // !d
981                 // dom node is null, definitely garbage
982                 // -------------------------------------------------------
983                 // !d.parentNode
984                 // no parentNode == direct orphan, definitely garbage
985                 // -------------------------------------------------------
986                 // !d.offsetParent && !document.getElementById(eid)
987                 // display none elements have no offsetParent so we will
988                 // also try to look it up by it's id. However, check
989                 // offsetParent first so we don't do unneeded lookups.
990                 // This enables collection of elements that are not orphans
991                 // directly, but somewhere up the line they have an orphan
992                 // parent.
993                 // -------------------------------------------------------
994                 if (!d || !d.parentNode || (!d.offsetParent && !DOC.getElementById(eid))) {
995                     if (d && Ext.enableListenerCollection) {
996                         Ext.EventManager.removeAll(d);
997                     }
998                     delete EC[eid];
999                 }
1000             }
1001             // Cleanup IE Object leaks
1002             if (Ext.isIE) {
1003                 var t = {};
1004                 for (eid in EC) {
1005                     if (!EC.hasOwnProperty(eid)) {
1006                         continue;
1007                     }
1008                     t[eid] = EC[eid];
1009                 }
1010                 EC = Ext.cache = t;
1011             }
1012         }
1013     }
1014     El.collectorThreadId = setInterval(garbageCollect, 30000);
1015
1016     var flyFn = function() {};
1017     flyFn.prototype = El.prototype;
1018
1019     // dom is optional
1020     El.Flyweight = function(dom) {
1021         this.dom = dom;
1022     };
1023
1024     El.Flyweight.prototype = new flyFn();
1025     El.Flyweight.prototype.isFlyweight = true;
1026     El._flyweights = {};
1027
1028     /**
1029      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference
1030      * to this element - the dom node can be overwritten by other code. {@link Ext#fly} is alias for
1031      * {@link Ext.Element#fly}.
1032      *
1033      * Use this to make one-time references to DOM elements which are not going to be accessed again either by
1034      * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link
1035      * Ext#get Ext.get} will be more appropriate to take advantage of the caching provided by the Ext.Element
1036      * class.
1037      *
1038      * @param {String/HTMLElement} el The dom node or id
1039      * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts (e.g.
1040      * internally Ext uses "_global")
1041      * @return {Ext.Element} The shared Element object (or null if no matching element was found)
1042      * @static
1043      */
1044     El.fly = function(el, named) {
1045         var ret = null;
1046         named = named || '_global';
1047         el = Ext.getDom(el);
1048         if (el) {
1049             (El._flyweights[named] = El._flyweights[named] || new El.Flyweight()).dom = el;
1050             ret = El._flyweights[named];
1051         }
1052         return ret;
1053     };
1054
1055     /**
1056      * @member Ext
1057      * @method get
1058      * @alias Ext.Element#get
1059      */
1060     Ext.get = El.get;
1061
1062     /**
1063      * @member Ext
1064      * @method fly
1065      * @alias Ext.Element#fly
1066      */
1067     Ext.fly = El.fly;
1068
1069     // speedy lookup for elements never to box adjust
1070     var noBoxAdjust = Ext.isStrict ? {
1071         select: 1
1072     }: {
1073         input: 1,
1074         select: 1,
1075         textarea: 1
1076     };
1077     if (Ext.isIE || Ext.isGecko) {
1078         noBoxAdjust['button'] = 1;
1079     }
1080 })();
1081