Roo/Element.js
[roojs1] / Roo / Element.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11
12  
13 // was in Composite Element!??!?!
14  
15 (function(){
16     var D = Roo.lib.Dom;
17     var E = Roo.lib.Event;
18     var A = Roo.lib.Anim;
19
20     // local style camelizing for speed
21     var propCache = {};
22     var camelRe = /(-[a-z])/gi;
23     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
24     var view = document.defaultView;
25
26 /**
27  * @class Roo.Element
28  * Represents an Element in the DOM.<br><br>
29  * Usage:<br>
30 <pre><code>
31 var el = Roo.get("my-div");
32
33 // or with getEl
34 var el = getEl("my-div");
35
36 // or with a DOM element
37 var el = Roo.get(myDivElement);
38 </code></pre>
39  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
40  * each call instead of constructing a new one.<br><br>
41  * <b>Animations</b><br />
42  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
43  * should either be a boolean (true) or an object literal with animation options. The animation options are:
44 <pre>
45 Option    Default   Description
46 --------- --------  ---------------------------------------------
47 duration  .35       The duration of the animation in seconds
48 easing    easeOut   The YUI easing method
49 callback  none      A function to execute when the anim completes
50 scope     this      The scope (this) of the callback function
51 </pre>
52 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
53 * manipulate the animation. Here's an example:
54 <pre><code>
55 var el = Roo.get("my-div");
56
57 // no animation
58 el.setWidth(100);
59
60 // default animation
61 el.setWidth(100, true);
62
63 // animation with some options set
64 el.setWidth(100, {
65     duration: 1,
66     callback: this.foo,
67     scope: this
68 });
69
70 // using the "anim" property to get the Anim object
71 var opt = {
72     duration: 1,
73     callback: this.foo,
74     scope: this
75 };
76 el.setWidth(100, opt);
77 ...
78 if(opt.anim.isAnimated()){
79     opt.anim.stop();
80 }
81 </code></pre>
82 * <b> Composite (Collections of) Elements</b><br />
83  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
84  * @constructor Create a new Element directly.
85  * @param {String/HTMLElement} element
86  * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
87  */
88     Roo.Element = function(element, forceNew){
89         var dom = typeof element == "string" ?
90                 document.getElementById(element) : element;
91         if(!dom){ // invalid id/element
92             return null;
93         }
94         var id = dom.id;
95         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
96             return Roo.Element.cache[id];
97         }
98
99         /**
100          * The DOM element
101          * @type HTMLElement
102          */
103         this.dom = dom;
104
105         /**
106          * The DOM element ID
107          * @type String
108          */
109         this.id = id || Roo.id(dom);
110     };
111
112     var El = Roo.Element;
113
114     El.prototype = {
115         /**
116          * The element's default display mode  (defaults to "")
117          * @type String
118          */
119         originalDisplay : "",
120
121         visibilityMode : 1,
122         /**
123          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
124          * @type String
125          */
126         defaultUnit : "px",
127         
128         /**
129          * Sets the element's visibility mode. When setVisible() is called it
130          * will use this to determine whether to set the visibility or the display property.
131          * @param visMode Element.VISIBILITY or Element.DISPLAY
132          * @return {Roo.Element} this
133          */
134         setVisibilityMode : function(visMode){
135             this.visibilityMode = visMode;
136             return this;
137         },
138         /**
139          * Convenience method for setVisibilityMode(Element.DISPLAY)
140          * @param {String} display (optional) What to set display to when visible
141          * @return {Roo.Element} this
142          */
143         enableDisplayMode : function(display){
144             this.setVisibilityMode(El.DISPLAY);
145             if(typeof display != "undefined") { this.originalDisplay = display; }
146             return this;
147         },
148
149         /**
150          * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
151          * @param {String} selector The simple selector to test
152          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
153                 search as a number or element (defaults to 10 || document.body)
154          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
155          * @return {HTMLElement} The matching DOM node (or null if no match was found)
156          */
157         findParent : function(simpleSelector, maxDepth, returnEl){
158             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
159             maxDepth = maxDepth || 50;
160             if(typeof maxDepth != "number"){
161                 stopEl = Roo.getDom(maxDepth);
162                 maxDepth = 10;
163             }
164             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
165                 if(dq.is(p, simpleSelector)){
166                     return returnEl ? Roo.get(p) : p;
167                 }
168                 depth++;
169                 p = p.parentNode;
170             }
171             return null;
172         },
173
174
175         /**
176          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
177          * @param {String} selector The simple selector to test
178          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
179                 search as a number or element (defaults to 10 || document.body)
180          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
181          * @return {HTMLElement} The matching DOM node (or null if no match was found)
182          */
183         findParentNode : function(simpleSelector, maxDepth, returnEl){
184             var p = Roo.fly(this.dom.parentNode, '_internal');
185             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
186         },
187         
188         /**
189          * Looks at  the scrollable parent element
190          */
191         findScrollableParent : function(){
192             
193             var el = Roo.get(this.dom.parentNode);
194             
195             while (
196                     el && 
197                     !el.isScrollable() && 
198                     D.getViewHeight() - el.dom.clientHeight <= 15 &&
199                     D.getViewWidth() - el.dom.clientWidth <= 15 &&
200                     el.dom.nodeName.toLowerCase() != 'body'
201             ){
202                 el = Roo.get(el.dom.parentNode);
203             }
204             
205             if(!el.isScrollable()){
206                 return null;
207             }
208             
209             return el;
210         },
211
212         /**
213          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
214          * This is a shortcut for findParentNode() that always returns an Roo.Element.
215          * @param {String} selector The simple selector to test
216          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
217                 search as a number or element (defaults to 10 || document.body)
218          * @return {Roo.Element} The matching DOM node (or null if no match was found)
219          */
220         up : function(simpleSelector, maxDepth){
221             return this.findParentNode(simpleSelector, maxDepth, true);
222         },
223
224
225
226         /**
227          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
228          * @param {String} selector The simple selector to test
229          * @return {Boolean} True if this element matches the selector, else false
230          */
231         is : function(simpleSelector){
232             return Roo.DomQuery.is(this.dom, simpleSelector);
233         },
234
235         /**
236          * Perform animation on this element.
237          * @param {Object} args The YUI animation control args
238          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
239          * @param {Function} onComplete (optional) Function to call when animation completes
240          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
241          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
242          * @return {Roo.Element} this
243          */
244         animate : function(args, duration, onComplete, easing, animType){
245             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
246             return this;
247         },
248
249         /*
250          * @private Internal animation call
251          */
252         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
253             animType = animType || 'run';
254             opt = opt || {};
255             var anim = Roo.lib.Anim[animType](
256                 this.dom, args,
257                 (opt.duration || defaultDur) || .35,
258                 (opt.easing || defaultEase) || 'easeOut',
259                 function(){
260                     Roo.callback(cb, this);
261                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
262                 },
263                 this
264             );
265             opt.anim = anim;
266             return anim;
267         },
268
269         // private legacy anim prep
270         preanim : function(a, i){
271             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
272         },
273
274         /**
275          * Removes worthless text nodes
276          * @param {Boolean} forceReclean (optional) By default the element
277          * keeps track if it has been cleaned already so
278          * you can call this over and over. However, if you update the element and
279          * need to force a reclean, you can pass true.
280          */
281         clean : function(forceReclean){
282             if(this.isCleaned && forceReclean !== true){
283                 return this;
284             }
285             var ns = /\S/;
286             var d = this.dom, n = d.firstChild, ni = -1;
287             while(n){
288                 var nx = n.nextSibling;
289                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
290                     d.removeChild(n);
291                 }else{
292                     n.nodeIndex = ++ni;
293                 }
294                 n = nx;
295             }
296             this.isCleaned = true;
297             return this;
298         },
299
300         // private
301         calcOffsetsTo : function(el){
302             el = Roo.get(el);
303             var d = el.dom;
304             var restorePos = false;
305             if(el.getStyle('position') == 'static'){
306                 el.position('relative');
307                 restorePos = true;
308             }
309             var x = 0, y =0;
310             var op = this.dom;
311             while(op && op != d && op.tagName != 'HTML'){
312                 x+= op.offsetLeft;
313                 y+= op.offsetTop;
314                 op = op.offsetParent;
315             }
316             if(restorePos){
317                 el.position('static');
318             }
319             return [x, y];
320         },
321
322         /**
323          * Scrolls this element into view within the passed container.
324          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
325          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
326          * @return {Roo.Element} this
327          */
328         scrollIntoView : function(container, hscroll){
329             var c = Roo.getDom(container) || document.body;
330             var el = this.dom;
331
332             var o = this.calcOffsetsTo(c),
333                 l = o[0],
334                 t = o[1],
335                 b = t+el.offsetHeight,
336                 r = l+el.offsetWidth;
337
338             var ch = c.clientHeight;
339             var ct = parseInt(c.scrollTop, 10);
340             var cl = parseInt(c.scrollLeft, 10);
341             var cb = ct + ch;
342             var cr = cl + c.clientWidth;
343
344             if(t < ct){
345                 c.scrollTop = t;
346             }else if(b > cb){
347                 c.scrollTop = b-ch;
348             }
349
350             if(hscroll !== false){
351                 if(l < cl){
352                     c.scrollLeft = l;
353                 }else if(r > cr){
354                     c.scrollLeft = r-c.clientWidth;
355                 }
356             }
357             return this;
358         },
359
360         // private
361         scrollChildIntoView : function(child, hscroll){
362             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
363         },
364
365         /**
366          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
367          * the new height may not be available immediately.
368          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
369          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
370          * @param {Function} onComplete (optional) Function to call when animation completes
371          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
372          * @return {Roo.Element} this
373          */
374         autoHeight : function(animate, duration, onComplete, easing){
375             var oldHeight = this.getHeight();
376             this.clip();
377             this.setHeight(1); // force clipping
378             setTimeout(function(){
379                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
380                 if(!animate){
381                     this.setHeight(height);
382                     this.unclip();
383                     if(typeof onComplete == "function"){
384                         onComplete();
385                     }
386                 }else{
387                     this.setHeight(oldHeight); // restore original height
388                     this.setHeight(height, animate, duration, function(){
389                         this.unclip();
390                         if(typeof onComplete == "function") { onComplete(); }
391                     }.createDelegate(this), easing);
392                 }
393             }.createDelegate(this), 0);
394             return this;
395         },
396
397         /**
398          * Returns true if this element is an ancestor of the passed element
399          * @param {HTMLElement/String} el The element to check
400          * @return {Boolean} True if this element is an ancestor of el, else false
401          */
402         contains : function(el){
403             if(!el){return false;}
404             return D.isAncestor(this.dom, el.dom ? el.dom : el);
405         },
406
407         /**
408          * Checks whether the element is currently visible using both visibility and display properties.
409          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
410          * @return {Boolean} True if the element is currently visible, else false
411          */
412         isVisible : function(deep) {
413             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
414             if(deep !== true || !vis){
415                 return vis;
416             }
417             var p = this.dom.parentNode;
418             while(p && p.tagName.toLowerCase() != "body"){
419                 if(!Roo.fly(p, '_isVisible').isVisible()){
420                     return false;
421                 }
422                 p = p.parentNode;
423             }
424             return true;
425         },
426
427         /**
428          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
429          * @param {String} selector The CSS selector
430          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
431          * @return {CompositeElement/CompositeElementLite} The composite element
432          */
433         select : function(selector, unique){
434             return El.select(selector, unique, this.dom);
435         },
436
437         /**
438          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
439          * @param {String} selector The CSS selector
440          * @return {Array} An array of the matched nodes
441          */
442         query : function(selector, unique){
443             return Roo.DomQuery.select(selector, this.dom);
444         },
445
446         /**
447          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
448          * @param {String} selector The CSS selector
449          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
450          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
451          */
452         child : function(selector, returnDom){
453             var n = Roo.DomQuery.selectNode(selector, this.dom);
454             return returnDom ? n : Roo.get(n);
455         },
456
457         /**
458          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
459          * @param {String} selector The CSS selector
460          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
461          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
462          */
463         down : function(selector, returnDom){
464             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
465             return returnDom ? n : Roo.get(n);
466         },
467
468         /**
469          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
470          * @param {String} group The group the DD object is member of
471          * @param {Object} config The DD config object
472          * @param {Object} overrides An object containing methods to override/implement on the DD object
473          * @return {Roo.dd.DD} The DD object
474          */
475         initDD : function(group, config, overrides){
476             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
477             return Roo.apply(dd, overrides);
478         },
479
480         /**
481          * Initializes a {@link Roo.dd.DDProxy} object for this element.
482          * @param {String} group The group the DDProxy object is member of
483          * @param {Object} config The DDProxy config object
484          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
485          * @return {Roo.dd.DDProxy} The DDProxy object
486          */
487         initDDProxy : function(group, config, overrides){
488             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
489             return Roo.apply(dd, overrides);
490         },
491
492         /**
493          * Initializes a {@link Roo.dd.DDTarget} object for this element.
494          * @param {String} group The group the DDTarget object is member of
495          * @param {Object} config The DDTarget config object
496          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
497          * @return {Roo.dd.DDTarget} The DDTarget object
498          */
499         initDDTarget : function(group, config, overrides){
500             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
501             return Roo.apply(dd, overrides);
502         },
503
504         /**
505          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
506          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
507          * @param {Boolean} visible Whether the element is visible
508          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
509          * @return {Roo.Element} this
510          */
511          setVisible : function(visible, animate){
512             if(!animate || !A){
513                 if(this.visibilityMode == El.DISPLAY){
514                     this.setDisplayed(visible);
515                 }else{
516                     this.fixDisplay();
517                     this.dom.style.visibility = visible ? "visible" : "hidden";
518                 }
519             }else{
520                 // closure for composites
521                 var dom = this.dom;
522                 var visMode = this.visibilityMode;
523                 if(visible){
524                     this.setOpacity(.01);
525                     this.setVisible(true);
526                 }
527                 this.anim({opacity: { to: (visible?1:0) }},
528                       this.preanim(arguments, 1),
529                       null, .35, 'easeIn', function(){
530                          if(!visible){
531                              if(visMode == El.DISPLAY){
532                                  dom.style.display = "none";
533                              }else{
534                                  dom.style.visibility = "hidden";
535                              }
536                              Roo.get(dom).setOpacity(1);
537                          }
538                      });
539             }
540             return this;
541         },
542
543         /**
544          * Returns true if display is not "none"
545          * @return {Boolean}
546          */
547         isDisplayed : function() {
548             return this.getStyle("display") != "none";
549         },
550
551         /**
552          * Toggles the element's visibility or display, depending on visibility mode.
553          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
554          * @return {Roo.Element} this
555          */
556         toggle : function(animate){
557             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
558             return this;
559         },
560
561         /**
562          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
563          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
564          * @return {Roo.Element} this
565          */
566         setDisplayed : function(value) {
567             if(typeof value == "boolean"){
568                value = value ? this.originalDisplay : "none";
569             }
570             this.setStyle("display", value);
571             return this;
572         },
573
574         /**
575          * Tries to focus the element. Any exceptions are caught and ignored.
576          * @return {Roo.Element} this
577          */
578         focus : function() {
579             try{
580                 this.dom.focus();
581             }catch(e){}
582             return this;
583         },
584
585         /**
586          * Tries to blur the element. Any exceptions are caught and ignored.
587          * @return {Roo.Element} this
588          */
589         blur : function() {
590             try{
591                 this.dom.blur();
592             }catch(e){}
593             return this;
594         },
595
596         /**
597          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
598          * @param {String/Array} className The CSS class to add, or an array of classes
599          * @return {Roo.Element} this
600          */
601         addClass : function(className){
602             if(className instanceof Array){
603                 for(var i = 0, len = className.length; i < len; i++) {
604                     this.addClass(className[i]);
605                 }
606             }else{
607                 if(className && !this.hasClass(className)){
608                     this.dom.className = this.dom.className + " " + className;
609                 }
610             }
611             return this;
612         },
613
614         /**
615          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
616          * @param {String/Array} className The CSS class to add, or an array of classes
617          * @return {Roo.Element} this
618          */
619         radioClass : function(className){
620             var siblings = this.dom.parentNode.childNodes;
621             for(var i = 0; i < siblings.length; i++) {
622                 var s = siblings[i];
623                 if(s.nodeType == 1){
624                     Roo.get(s).removeClass(className);
625                 }
626             }
627             this.addClass(className);
628             return this;
629         },
630
631         /**
632          * Removes one or more CSS classes from the element.
633          * @param {String/Array} className The CSS class to remove, or an array of classes
634          * @return {Roo.Element} this
635          */
636         removeClass : function(className){
637             if(!className || !this.dom.className){
638                 return this;
639             }
640             if(className instanceof Array){
641                 for(var i = 0, len = className.length; i < len; i++) {
642                     this.removeClass(className[i]);
643                 }
644             }else{
645                 if(this.hasClass(className)){
646                     var re = this.classReCache[className];
647                     if (!re) {
648                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
649                        this.classReCache[className] = re;
650                     }
651                     this.dom.className =
652                         this.dom.className.replace(re, " ");
653                 }
654             }
655             return this;
656         },
657
658         // private
659         classReCache: {},
660
661         /**
662          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
663          * @param {String} className The CSS class to toggle
664          * @return {Roo.Element} this
665          */
666         toggleClass : function(className){
667             if(this.hasClass(className)){
668                 this.removeClass(className);
669             }else{
670                 this.addClass(className);
671             }
672             return this;
673         },
674
675         /**
676          * Checks if the specified CSS class exists on this element's DOM node.
677          * @param {String} className The CSS class to check for
678          * @return {Boolean} True if the class exists, else false
679          */
680         hasClass : function(className){
681             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
682         },
683
684         /**
685          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
686          * @param {String} oldClassName The CSS class to replace
687          * @param {String} newClassName The replacement CSS class
688          * @return {Roo.Element} this
689          */
690         replaceClass : function(oldClassName, newClassName){
691             this.removeClass(oldClassName);
692             this.addClass(newClassName);
693             return this;
694         },
695
696         /**
697          * Returns an object with properties matching the styles requested.
698          * For example, el.getStyles('color', 'font-size', 'width') might return
699          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
700          * @param {String} style1 A style name
701          * @param {String} style2 A style name
702          * @param {String} etc.
703          * @return {Object} The style object
704          */
705         getStyles : function(){
706             var a = arguments, len = a.length, r = {};
707             for(var i = 0; i < len; i++){
708                 r[a[i]] = this.getStyle(a[i]);
709             }
710             return r;
711         },
712
713         /**
714          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
715          * @param {String} property The style property whose value is returned.
716          * @return {String} The current value of the style property for this element.
717          */
718         getStyle : function(){
719             return view && view.getComputedStyle ?
720                 function(prop){
721                     var el = this.dom, v, cs, camel;
722                     if(prop == 'float'){
723                         prop = "cssFloat";
724                     }
725                     if(el.style && (v = el.style[prop])){
726                         return v;
727                     }
728                     if(cs = view.getComputedStyle(el, "")){
729                         if(!(camel = propCache[prop])){
730                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
731                         }
732                         return cs[camel];
733                     }
734                     return null;
735                 } :
736                 function(prop){
737                     var el = this.dom, v, cs, camel;
738                     if(prop == 'opacity'){
739                         if(typeof el.style.filter == 'string'){
740                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
741                             if(m){
742                                 var fv = parseFloat(m[1]);
743                                 if(!isNaN(fv)){
744                                     return fv ? fv / 100 : 0;
745                                 }
746                             }
747                         }
748                         return 1;
749                     }else if(prop == 'float'){
750                         prop = "styleFloat";
751                     }
752                     if(!(camel = propCache[prop])){
753                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
754                     }
755                     if(v = el.style[camel]){
756                         return v;
757                     }
758                     if(cs = el.currentStyle){
759                         return cs[camel];
760                     }
761                     return null;
762                 };
763         }(),
764
765         /**
766          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
767          * @param {String/Object} property The style property to be set, or an object of multiple styles.
768          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
769          * @return {Roo.Element} this
770          */
771         setStyle : function(prop, value){
772             if(typeof prop == "string"){
773                 
774                 if (prop == 'float') {
775                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
776                     return this;
777                 }
778                 
779                 var camel;
780                 if(!(camel = propCache[prop])){
781                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
782                 }
783                 
784                 if(camel == 'opacity') {
785                     this.setOpacity(value);
786                 }else{
787                     this.dom.style[camel] = value;
788                 }
789             }else{
790                 for(var style in prop){
791                     if(typeof prop[style] != "function"){
792                        this.setStyle(style, prop[style]);
793                     }
794                 }
795             }
796             return this;
797         },
798
799         /**
800          * More flexible version of {@link #setStyle} for setting style properties.
801          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
802          * a function which returns such a specification.
803          * @return {Roo.Element} this
804          */
805         applyStyles : function(style){
806             Roo.DomHelper.applyStyles(this.dom, style);
807             return this;
808         },
809
810         /**
811           * Gets the current X position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
812           * @return {Number} The X position of the element
813           */
814         getX : function(){
815             return D.getX(this.dom);
816         },
817
818         /**
819           * Gets the current Y position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
820           * @return {Number} The Y position of the element
821           */
822         getY : function(){
823             return D.getY(this.dom);
824         },
825
826         /**
827           * Gets the current position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
828           * @return {Array} The XY position of the element
829           */
830         getXY : function(){
831             return D.getXY(this.dom);
832         },
833
834         /**
835          * Sets the X position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
836          * @param {Number} The X position of the element
837          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
838          * @return {Roo.Element} this
839          */
840         setX : function(x, animate){
841             if(!animate || !A){
842                 D.setX(this.dom, x);
843             }else{
844                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
845             }
846             return this;
847         },
848
849         /**
850          * Sets the Y position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
851          * @param {Number} The Y position of the element
852          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
853          * @return {Roo.Element} this
854          */
855         setY : function(y, animate){
856             if(!animate || !A){
857                 D.setY(this.dom, y);
858             }else{
859                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
860             }
861             return this;
862         },
863
864         /**
865          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
866          * @param {String} left The left CSS property value
867          * @return {Roo.Element} this
868          */
869         setLeft : function(left){
870             this.setStyle("left", this.addUnits(left));
871             return this;
872         },
873
874         /**
875          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
876          * @param {String} top The top CSS property value
877          * @return {Roo.Element} this
878          */
879         setTop : function(top){
880             this.setStyle("top", this.addUnits(top));
881             return this;
882         },
883
884         /**
885          * Sets the element's CSS right style.
886          * @param {String} right The right CSS property value
887          * @return {Roo.Element} this
888          */
889         setRight : function(right){
890             this.setStyle("right", this.addUnits(right));
891             return this;
892         },
893
894         /**
895          * Sets the element's CSS bottom style.
896          * @param {String} bottom The bottom CSS property value
897          * @return {Roo.Element} this
898          */
899         setBottom : function(bottom){
900             this.setStyle("bottom", this.addUnits(bottom));
901             return this;
902         },
903
904         /**
905          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
906          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
907          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
908          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
909          * @return {Roo.Element} this
910          */
911         setXY : function(pos, animate){
912             if(!animate || !A){
913                 D.setXY(this.dom, pos);
914             }else{
915                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
916             }
917             return this;
918         },
919
920         /**
921          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
922          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
923          * @param {Number} x X value for new position (coordinates are page-based)
924          * @param {Number} y Y value for new position (coordinates are page-based)
925          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
926          * @return {Roo.Element} this
927          */
928         setLocation : function(x, y, animate){
929             this.setXY([x, y], this.preanim(arguments, 2));
930             return this;
931         },
932
933         /**
934          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
935          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
936          * @param {Number} x X value for new position (coordinates are page-based)
937          * @param {Number} y Y value for new position (coordinates are page-based)
938          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
939          * @return {Roo.Element} this
940          */
941         moveTo : function(x, y, animate){
942             this.setXY([x, y], this.preanim(arguments, 2));
943             return this;
944         },
945
946         /**
947          * Returns the region of the given element.
948          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
949          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
950          */
951         getRegion : function(){
952             return D.getRegion(this.dom);
953         },
954
955         /**
956          * Returns the offset height of the element
957          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
958          * @return {Number} The element's height
959          */
960         getHeight : function(contentHeight){
961             var h = this.dom.offsetHeight || 0;
962             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
963         },
964
965         /**
966          * Returns the offset width of the element
967          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
968          * @return {Number} The element's width
969          */
970         getWidth : function(contentWidth){
971             var w = this.dom.offsetWidth || 0;
972             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
973         },
974
975         /**
976          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
977          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
978          * if a height has not been set using CSS.
979          * @return {Number}
980          */
981         getComputedHeight : function(){
982             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
983             if(!h){
984                 h = parseInt(this.getStyle('height'), 10) || 0;
985                 if(!this.isBorderBox()){
986                     h += this.getFrameWidth('tb');
987                 }
988             }
989             return h;
990         },
991
992         /**
993          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
994          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
995          * if a width has not been set using CSS.
996          * @return {Number}
997          */
998         getComputedWidth : function(){
999             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
1000             if(!w){
1001                 w = parseInt(this.getStyle('width'), 10) || 0;
1002                 if(!this.isBorderBox()){
1003                     w += this.getFrameWidth('lr');
1004                 }
1005             }
1006             return w;
1007         },
1008
1009         /**
1010          * Returns the size of the element.
1011          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
1012          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
1013          */
1014         getSize : function(contentSize){
1015             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
1016         },
1017
1018         /**
1019          * Returns the width and height of the viewport.
1020          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
1021          */
1022         getViewSize : function(){
1023             var d = this.dom, doc = document, aw = 0, ah = 0;
1024             if(d == doc || d == doc.body){
1025                 return {width : D.getViewWidth(), height: D.getViewHeight()};
1026             }else{
1027                 return {
1028                     width : d.clientWidth,
1029                     height: d.clientHeight
1030                 };
1031             }
1032         },
1033
1034         /**
1035          * Returns the value of the "value" attribute
1036          * @param {Boolean} asNumber true to parse the value as a number
1037          * @return {String/Number}
1038          */
1039         getValue : function(asNumber){
1040             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
1041         },
1042
1043         // private
1044         adjustWidth : function(width){
1045             if(typeof width == "number"){
1046                 if(this.autoBoxAdjust && !this.isBorderBox()){
1047                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
1048                 }
1049                 if(width < 0){
1050                     width = 0;
1051                 }
1052             }
1053             return width;
1054         },
1055
1056         // private
1057         adjustHeight : function(height){
1058             if(typeof height == "number"){
1059                if(this.autoBoxAdjust && !this.isBorderBox()){
1060                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
1061                }
1062                if(height < 0){
1063                    height = 0;
1064                }
1065             }
1066             return height;
1067         },
1068
1069         /**
1070          * Set the width of the element
1071          * @param {Number} width The new width
1072          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1073          * @return {Roo.Element} this
1074          */
1075         setWidth : function(width, animate){
1076             width = this.adjustWidth(width);
1077             if(!animate || !A){
1078                 this.dom.style.width = this.addUnits(width);
1079             }else{
1080                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
1081             }
1082             return this;
1083         },
1084
1085         /**
1086          * Set the height of the element
1087          * @param {Number} height The new height
1088          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1089          * @return {Roo.Element} this
1090          */
1091          setHeight : function(height, animate){
1092             height = this.adjustHeight(height);
1093             if(!animate || !A){
1094                 this.dom.style.height = this.addUnits(height);
1095             }else{
1096                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
1097             }
1098             return this;
1099         },
1100
1101         /**
1102          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
1103          * @param {Number} width The new width
1104          * @param {Number} height The new height
1105          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1106          * @return {Roo.Element} this
1107          */
1108          setSize : function(width, height, animate){
1109             if(typeof width == "object"){ // in case of object from getSize()
1110                 height = width.height; width = width.width;
1111             }
1112             width = this.adjustWidth(width); height = this.adjustHeight(height);
1113             if(!animate || !A){
1114                 this.dom.style.width = this.addUnits(width);
1115                 this.dom.style.height = this.addUnits(height);
1116             }else{
1117                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
1118             }
1119             return this;
1120         },
1121
1122         /**
1123          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
1124          * @param {Number} x X value for new position (coordinates are page-based)
1125          * @param {Number} y Y value for new position (coordinates are page-based)
1126          * @param {Number} width The new width
1127          * @param {Number} height The new height
1128          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1129          * @return {Roo.Element} this
1130          */
1131         setBounds : function(x, y, width, height, animate){
1132             if(!animate || !A){
1133                 this.setSize(width, height);
1134                 this.setLocation(x, y);
1135             }else{
1136                 width = this.adjustWidth(width); height = this.adjustHeight(height);
1137                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
1138                               this.preanim(arguments, 4), 'motion');
1139             }
1140             return this;
1141         },
1142
1143         /**
1144          * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
1145          * @param {Roo.lib.Region} region The region to fill
1146          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1147          * @return {Roo.Element} this
1148          */
1149         setRegion : function(region, animate){
1150             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
1151             return this;
1152         },
1153
1154         /**
1155          * Appends an event handler
1156          *
1157          * @param {String}   eventName     The type of event to append
1158          * @param {Function} fn        The method the event invokes
1159          * @param {Object} scope       (optional) The scope (this object) of the fn
1160          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
1161          */
1162         addListener : function(eventName, fn, scope, options){
1163             if (this.dom) {
1164                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
1165             }
1166         },
1167
1168         /**
1169          * Removes an event handler from this element
1170          * @param {String} eventName the type of event to remove
1171          * @param {Function} fn the method the event invokes
1172          * @return {Roo.Element} this
1173          */
1174         removeListener : function(eventName, fn){
1175             Roo.EventManager.removeListener(this.dom,  eventName, fn);
1176             return this;
1177         },
1178
1179         /**
1180          * Removes all previous added listeners from this element
1181          * @return {Roo.Element} this
1182          */
1183         removeAllListeners : function(){
1184             E.purgeElement(this.dom);
1185             return this;
1186         },
1187
1188         relayEvent : function(eventName, observable){
1189             this.on(eventName, function(e){
1190                 observable.fireEvent(eventName, e);
1191             });
1192         },
1193
1194         /**
1195          * Set the opacity of the element
1196          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
1197          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1198          * @return {Roo.Element} this
1199          */
1200          setOpacity : function(opacity, animate){
1201             if(!animate || !A){
1202                 var s = this.dom.style;
1203                 if(Roo.isIE){
1204                     s.zoom = 1;
1205                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
1206                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
1207                 }else{
1208                     s.opacity = opacity;
1209                 }
1210             }else{
1211                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
1212             }
1213             return this;
1214         },
1215
1216         /**
1217          * Gets the left X coordinate
1218          * @param {Boolean} local True to get the local css position instead of page coordinate
1219          * @return {Number}
1220          */
1221         getLeft : function(local){
1222             if(!local){
1223                 return this.getX();
1224             }else{
1225                 return parseInt(this.getStyle("left"), 10) || 0;
1226             }
1227         },
1228
1229         /**
1230          * Gets the right X coordinate of the element (element X position + element width)
1231          * @param {Boolean} local True to get the local css position instead of page coordinate
1232          * @return {Number}
1233          */
1234         getRight : function(local){
1235             if(!local){
1236                 return this.getX() + this.getWidth();
1237             }else{
1238                 return (this.getLeft(true) + this.getWidth()) || 0;
1239             }
1240         },
1241
1242         /**
1243          * Gets the top Y coordinate
1244          * @param {Boolean} local True to get the local css position instead of page coordinate
1245          * @return {Number}
1246          */
1247         getTop : function(local) {
1248             if(!local){
1249                 return this.getY();
1250             }else{
1251                 return parseInt(this.getStyle("top"), 10) || 0;
1252             }
1253         },
1254
1255         /**
1256          * Gets the bottom Y coordinate of the element (element Y position + element height)
1257          * @param {Boolean} local True to get the local css position instead of page coordinate
1258          * @return {Number}
1259          */
1260         getBottom : function(local){
1261             if(!local){
1262                 return this.getY() + this.getHeight();
1263             }else{
1264                 return (this.getTop(true) + this.getHeight()) || 0;
1265             }
1266         },
1267
1268         /**
1269         * Initializes positioning on this element. If a desired position is not passed, it will make the
1270         * the element positioned relative IF it is not already positioned.
1271         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
1272         * @param {Number} zIndex (optional) The zIndex to apply
1273         * @param {Number} x (optional) Set the page X position
1274         * @param {Number} y (optional) Set the page Y position
1275         */
1276         position : function(pos, zIndex, x, y){
1277             if(!pos){
1278                if(this.getStyle('position') == 'static'){
1279                    this.setStyle('position', 'relative');
1280                }
1281             }else{
1282                 this.setStyle("position", pos);
1283             }
1284             if(zIndex){
1285                 this.setStyle("z-index", zIndex);
1286             }
1287             if(x !== undefined && y !== undefined){
1288                 this.setXY([x, y]);
1289             }else if(x !== undefined){
1290                 this.setX(x);
1291             }else if(y !== undefined){
1292                 this.setY(y);
1293             }
1294         },
1295
1296         /**
1297         * Clear positioning back to the default when the document was loaded
1298         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
1299         * @return {Roo.Element} this
1300          */
1301         clearPositioning : function(value){
1302             value = value ||'';
1303             this.setStyle({
1304                 "left": value,
1305                 "right": value,
1306                 "top": value,
1307                 "bottom": value,
1308                 "z-index": "",
1309                 "position" : "static"
1310             });
1311             return this;
1312         },
1313
1314         /**
1315         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
1316         * snapshot before performing an update and then restoring the element.
1317         * @return {Object}
1318         */
1319         getPositioning : function(){
1320             var l = this.getStyle("left");
1321             var t = this.getStyle("top");
1322             return {
1323                 "position" : this.getStyle("position"),
1324                 "left" : l,
1325                 "right" : l ? "" : this.getStyle("right"),
1326                 "top" : t,
1327                 "bottom" : t ? "" : this.getStyle("bottom"),
1328                 "z-index" : this.getStyle("z-index")
1329             };
1330         },
1331
1332         /**
1333          * Gets the width of the border(s) for the specified side(s)
1334          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1335          * passing lr would get the border (l)eft width + the border (r)ight width.
1336          * @return {Number} The width of the sides passed added together
1337          */
1338         getBorderWidth : function(side){
1339             return this.addStyles(side, El.borders);
1340         },
1341
1342         /**
1343          * Gets the width of the padding(s) for the specified side(s)
1344          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1345          * passing lr would get the padding (l)eft + the padding (r)ight.
1346          * @return {Number} The padding of the sides passed added together
1347          */
1348         getPadding : function(side){
1349             return this.addStyles(side, El.paddings);
1350         },
1351
1352         /**
1353         * Set positioning with an object returned by getPositioning().
1354         * @param {Object} posCfg
1355         * @return {Roo.Element} this
1356          */
1357         setPositioning : function(pc){
1358             this.applyStyles(pc);
1359             if(pc.right == "auto"){
1360                 this.dom.style.right = "";
1361             }
1362             if(pc.bottom == "auto"){
1363                 this.dom.style.bottom = "";
1364             }
1365             return this;
1366         },
1367
1368         // private
1369         fixDisplay : function(){
1370             if(this.getStyle("display") == "none"){
1371                 this.setStyle("visibility", "hidden");
1372                 this.setStyle("display", this.originalDisplay); // first try reverting to default
1373                 if(this.getStyle("display") == "none"){ // if that fails, default to block
1374                     this.setStyle("display", "block");
1375                 }
1376             }
1377         },
1378
1379         /**
1380          * Quick set left and top adding default units
1381          * @param {String} left The left CSS property value
1382          * @param {String} top The top CSS property value
1383          * @return {Roo.Element} this
1384          */
1385          setLeftTop : function(left, top){
1386             this.dom.style.left = this.addUnits(left);
1387             this.dom.style.top = this.addUnits(top);
1388             return this;
1389         },
1390
1391         /**
1392          * Move this element relative to its current position.
1393          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
1394          * @param {Number} distance How far to move the element in pixels
1395          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1396          * @return {Roo.Element} this
1397          */
1398          move : function(direction, distance, animate){
1399             var xy = this.getXY();
1400             direction = direction.toLowerCase();
1401             switch(direction){
1402                 case "l":
1403                 case "left":
1404                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
1405                     break;
1406                case "r":
1407                case "right":
1408                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
1409                     break;
1410                case "t":
1411                case "top":
1412                case "up":
1413                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
1414                     break;
1415                case "b":
1416                case "bottom":
1417                case "down":
1418                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
1419                     break;
1420             }
1421             return this;
1422         },
1423
1424         /**
1425          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
1426          * @return {Roo.Element} this
1427          */
1428         clip : function(){
1429             if(!this.isClipped){
1430                this.isClipped = true;
1431                this.originalClip = {
1432                    "o": this.getStyle("overflow"),
1433                    "x": this.getStyle("overflow-x"),
1434                    "y": this.getStyle("overflow-y")
1435                };
1436                this.setStyle("overflow", "hidden");
1437                this.setStyle("overflow-x", "hidden");
1438                this.setStyle("overflow-y", "hidden");
1439             }
1440             return this;
1441         },
1442
1443         /**
1444          *  Return clipping (overflow) to original clipping before clip() was called
1445          * @return {Roo.Element} this
1446          */
1447         unclip : function(){
1448             if(this.isClipped){
1449                 this.isClipped = false;
1450                 var o = this.originalClip;
1451                 if(o.o){this.setStyle("overflow", o.o);}
1452                 if(o.x){this.setStyle("overflow-x", o.x);}
1453                 if(o.y){this.setStyle("overflow-y", o.y);}
1454             }
1455             return this;
1456         },
1457
1458
1459         /**
1460          * Gets the x,y coordinates specified by the anchor position on the element.
1461          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
1462          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
1463          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
1464          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
1465          * @return {Array} [x, y] An array containing the element's x and y coordinates
1466          */
1467         getAnchorXY : function(anchor, local, s){
1468             //Passing a different size is useful for pre-calculating anchors,
1469             //especially for anchored animations that change the el size.
1470
1471             var w, h, vp = false;
1472             if(!s){
1473                 var d = this.dom;
1474                 if(d == document.body || d == document){
1475                     vp = true;
1476                     w = D.getViewWidth(); h = D.getViewHeight();
1477                 }else{
1478                     w = this.getWidth(); h = this.getHeight();
1479                 }
1480             }else{
1481                 w = s.width;  h = s.height;
1482             }
1483             var x = 0, y = 0, r = Math.round;
1484             switch((anchor || "tl").toLowerCase()){
1485                 case "c":
1486                     x = r(w*.5);
1487                     y = r(h*.5);
1488                 break;
1489                 case "t":
1490                     x = r(w*.5);
1491                     y = 0;
1492                 break;
1493                 case "l":
1494                     x = 0;
1495                     y = r(h*.5);
1496                 break;
1497                 case "r":
1498                     x = w;
1499                     y = r(h*.5);
1500                 break;
1501                 case "b":
1502                     x = r(w*.5);
1503                     y = h;
1504                 break;
1505                 case "tl":
1506                     x = 0;
1507                     y = 0;
1508                 break;
1509                 case "bl":
1510                     x = 0;
1511                     y = h;
1512                 break;
1513                 case "br":
1514                     x = w;
1515                     y = h;
1516                 break;
1517                 case "tr":
1518                     x = w;
1519                     y = 0;
1520                 break;
1521             }
1522             if(local === true){
1523                 return [x, y];
1524             }
1525             if(vp){
1526                 var sc = this.getScroll();
1527                 return [x + sc.left, y + sc.top];
1528             }
1529             //Add the element's offset xy
1530             var o = this.getXY();
1531             return [x+o[0], y+o[1]];
1532         },
1533
1534         /**
1535          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
1536          * supported position values.
1537          * @param {String/HTMLElement/Roo.Element} element The element to align to.
1538          * @param {String} position The position to align to.
1539          * @param {Array} offsets (optional) Offset the positioning by [x, y]
1540          * @return {Array} [x, y]
1541          */
1542         getAlignToXY : function(el, p, o){
1543             el = Roo.get(el);
1544             var d = this.dom;
1545             if(!el.dom){
1546                 throw "Element.alignTo with an element that doesn't exist";
1547             }
1548             var c = false; //constrain to viewport
1549             var p1 = "", p2 = "";
1550             o = o || [0,0];
1551
1552             if(!p){
1553                 p = "tl-bl";
1554             }else if(p == "?"){
1555                 p = "tl-bl?";
1556             }else if(p.indexOf("-") == -1){
1557                 p = "tl-" + p;
1558             }
1559             p = p.toLowerCase();
1560             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
1561             if(!m){
1562                throw "Element.alignTo with an invalid alignment " + p;
1563             }
1564             p1 = m[1]; p2 = m[2]; c = !!m[3];
1565
1566             //Subtract the aligned el's internal xy from the target's offset xy
1567             //plus custom offset to get the aligned el's new offset xy
1568             var a1 = this.getAnchorXY(p1, true);
1569             var a2 = el.getAnchorXY(p2, false);
1570             var x = a2[0] - a1[0] + o[0];
1571             var y = a2[1] - a1[1] + o[1];
1572             if(c){
1573                 //constrain the aligned el to viewport if necessary
1574                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
1575                 // 5px of margin for ie
1576                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
1577
1578                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
1579                 //perpendicular to the vp border, allow the aligned el to slide on that border,
1580                 //otherwise swap the aligned el to the opposite border of the target.
1581                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
1582                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
1583                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
1584                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
1585
1586                var doc = document;
1587                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
1588                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
1589
1590                if((x+w) > dw + scrollX){
1591                     x = swapX ? r.left-w : dw+scrollX-w;
1592                 }
1593                if(x < scrollX){
1594                    x = swapX ? r.right : scrollX;
1595                }
1596                if((y+h) > dh + scrollY){
1597                     y = swapY ? r.top-h : dh+scrollY-h;
1598                 }
1599                if (y < scrollY){
1600                    y = swapY ? r.bottom : scrollY;
1601                }
1602             }
1603             return [x,y];
1604         },
1605
1606         // private
1607         getConstrainToXY : function(){
1608             var os = {top:0, left:0, bottom:0, right: 0};
1609
1610             return function(el, local, offsets, proposedXY){
1611                 el = Roo.get(el);
1612                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
1613
1614                 var vw, vh, vx = 0, vy = 0;
1615                 if(el.dom == document.body || el.dom == document){
1616                     vw = Roo.lib.Dom.getViewWidth();
1617                     vh = Roo.lib.Dom.getViewHeight();
1618                 }else{
1619                     vw = el.dom.clientWidth;
1620                     vh = el.dom.clientHeight;
1621                     if(!local){
1622                         var vxy = el.getXY();
1623                         vx = vxy[0];
1624                         vy = vxy[1];
1625                     }
1626                 }
1627
1628                 var s = el.getScroll();
1629
1630                 vx += offsets.left + s.left;
1631                 vy += offsets.top + s.top;
1632
1633                 vw -= offsets.right;
1634                 vh -= offsets.bottom;
1635
1636                 var vr = vx+vw;
1637                 var vb = vy+vh;
1638
1639                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
1640                 var x = xy[0], y = xy[1];
1641                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
1642
1643                 // only move it if it needs it
1644                 var moved = false;
1645
1646                 // first validate right/bottom
1647                 if((x + w) > vr){
1648                     x = vr - w;
1649                     moved = true;
1650                 }
1651                 if((y + h) > vb){
1652                     y = vb - h;
1653                     moved = true;
1654                 }
1655                 // then make sure top/left isn't negative
1656                 if(x < vx){
1657                     x = vx;
1658                     moved = true;
1659                 }
1660                 if(y < vy){
1661                     y = vy;
1662                     moved = true;
1663                 }
1664                 return moved ? [x, y] : false;
1665             };
1666         }(),
1667
1668         // private
1669         adjustForConstraints : function(xy, parent, offsets){
1670             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
1671         },
1672
1673         /**
1674          * Aligns this element with another element relative to the specified anchor points. If the other element is the
1675          * document it aligns it to the viewport.
1676          * The position parameter is optional, and can be specified in any one of the following formats:
1677          * <ul>
1678          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
1679          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
1680          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
1681          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
1682          *   <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
1683          *       element's anchor point, and the second value is used as the target's anchor point.</li>
1684          * </ul>
1685          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
1686          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
1687          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
1688          * that specified in order to enforce the viewport constraints.
1689          * Following are all of the supported anchor positions:
1690     <pre>
1691     Value  Description
1692     -----  -----------------------------
1693     tl     The top left corner (default)
1694     t      The center of the top edge
1695     tr     The top right corner
1696     l      The center of the left edge
1697     c      In the center of the element
1698     r      The center of the right edge
1699     bl     The bottom left corner
1700     b      The center of the bottom edge
1701     br     The bottom right corner
1702     </pre>
1703     Example Usage:
1704     <pre><code>
1705     // align el to other-el using the default positioning ("tl-bl", non-constrained)
1706     el.alignTo("other-el");
1707
1708     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
1709     el.alignTo("other-el", "tr?");
1710
1711     // align the bottom right corner of el with the center left edge of other-el
1712     el.alignTo("other-el", "br-l?");
1713
1714     // align the center of el with the bottom left corner of other-el and
1715     // adjust the x position by -6 pixels (and the y position by 0)
1716     el.alignTo("other-el", "c-bl", [-6, 0]);
1717     </code></pre>
1718          * @param {String/HTMLElement/Roo.Element} element The element to align to.
1719          * @param {String} position The position to align to.
1720          * @param {Array} offsets (optional) Offset the positioning by [x, y]
1721          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1722          * @return {Roo.Element} this
1723          */
1724         alignTo : function(element, position, offsets, animate){
1725             var xy = this.getAlignToXY(element, position, offsets);
1726             this.setXY(xy, this.preanim(arguments, 3));
1727             return this;
1728         },
1729
1730         /**
1731          * Anchors an element to another element and realigns it when the window is resized.
1732          * @param {String/HTMLElement/Roo.Element} element The element to align to.
1733          * @param {String} position The position to align to.
1734          * @param {Array} offsets (optional) Offset the positioning by [x, y]
1735          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
1736          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
1737          * is a number, it is used as the buffer delay (defaults to 50ms).
1738          * @param {Function} callback The function to call after the animation finishes
1739          * @return {Roo.Element} this
1740          */
1741         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
1742             var action = function(){
1743                 this.alignTo(el, alignment, offsets, animate);
1744                 Roo.callback(callback, this);
1745             };
1746             Roo.EventManager.onWindowResize(action, this);
1747             var tm = typeof monitorScroll;
1748             if(tm != 'undefined'){
1749                 Roo.EventManager.on(window, 'scroll', action, this,
1750                     {buffer: tm == 'number' ? monitorScroll : 50});
1751             }
1752             action.call(this); // align immediately
1753             return this;
1754         },
1755         /**
1756          * Clears any opacity settings from this element. Required in some cases for IE.
1757          * @return {Roo.Element} this
1758          */
1759         clearOpacity : function(){
1760             if (window.ActiveXObject) {
1761                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
1762                     this.dom.style.filter = "";
1763                 }
1764             } else {
1765                 this.dom.style.opacity = "";
1766                 this.dom.style["-moz-opacity"] = "";
1767                 this.dom.style["-khtml-opacity"] = "";
1768             }
1769             return this;
1770         },
1771
1772         /**
1773          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1774          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1775          * @return {Roo.Element} this
1776          */
1777         hide : function(animate){
1778             this.setVisible(false, this.preanim(arguments, 0));
1779             return this;
1780         },
1781
1782         /**
1783         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1784         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1785          * @return {Roo.Element} this
1786          */
1787         show : function(animate){
1788             this.setVisible(true, this.preanim(arguments, 0));
1789             return this;
1790         },
1791
1792         /**
1793          * @private Test if size has a unit, otherwise appends the default
1794          */
1795         addUnits : function(size){
1796             return Roo.Element.addUnits(size, this.defaultUnit);
1797         },
1798
1799         /**
1800          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
1801          * @return {Roo.Element} this
1802          */
1803         beginMeasure : function(){
1804             var el = this.dom;
1805             if(el.offsetWidth || el.offsetHeight){
1806                 return this; // offsets work already
1807             }
1808             var changed = [];
1809             var p = this.dom, b = document.body; // start with this element
1810             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
1811                 var pe = Roo.get(p);
1812                 if(pe.getStyle('display') == 'none'){
1813                     changed.push({el: p, visibility: pe.getStyle("visibility")});
1814                     p.style.visibility = "hidden";
1815                     p.style.display = "block";
1816                 }
1817                 p = p.parentNode;
1818             }
1819             this._measureChanged = changed;
1820             return this;
1821
1822         },
1823
1824         /**
1825          * Restores displays to before beginMeasure was called
1826          * @return {Roo.Element} this
1827          */
1828         endMeasure : function(){
1829             var changed = this._measureChanged;
1830             if(changed){
1831                 for(var i = 0, len = changed.length; i < len; i++) {
1832                     var r = changed[i];
1833                     r.el.style.visibility = r.visibility;
1834                     r.el.style.display = "none";
1835                 }
1836                 this._measureChanged = null;
1837             }
1838             return this;
1839         },
1840
1841         /**
1842         * Update the innerHTML of this element, optionally searching for and processing scripts
1843         * @param {String} html The new HTML
1844         * @param {Boolean} loadScripts (optional) true to look for and process scripts
1845         * @param {Function} callback For async script loading you can be noticed when the update completes
1846         * @return {Roo.Element} this
1847          */
1848         update : function(html, loadScripts, callback){
1849             if(typeof html == "undefined"){
1850                 html = "";
1851             }
1852             if(loadScripts !== true){
1853                 this.dom.innerHTML = html;
1854                 if(typeof callback == "function"){
1855                     callback();
1856                 }
1857                 return this;
1858             }
1859             var id = Roo.id();
1860             var dom = this.dom;
1861
1862             html += '<span id="' + id + '"></span>';
1863
1864             E.onAvailable(id, function(){
1865                 var hd = document.getElementsByTagName("head")[0];
1866                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
1867                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
1868                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
1869
1870                 var match;
1871                 while(match = re.exec(html)){
1872                     var attrs = match[1];
1873                     var srcMatch = attrs ? attrs.match(srcRe) : false;
1874                     if(srcMatch && srcMatch[2]){
1875                        var s = document.createElement("script");
1876                        s.src = srcMatch[2];
1877                        var typeMatch = attrs.match(typeRe);
1878                        if(typeMatch && typeMatch[2]){
1879                            s.type = typeMatch[2];
1880                        }
1881                        hd.appendChild(s);
1882                     }else if(match[2] && match[2].length > 0){
1883                         if(window.execScript) {
1884                            window.execScript(match[2]);
1885                         } else {
1886                             /**
1887                              * eval:var:id
1888                              * eval:var:dom
1889                              * eval:var:html
1890                              * 
1891                              */
1892                            window.eval(match[2]);
1893                         }
1894                     }
1895                 }
1896                 var el = document.getElementById(id);
1897                 if(el){el.parentNode.removeChild(el);}
1898                 if(typeof callback == "function"){
1899                     callback();
1900                 }
1901             });
1902             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
1903             return this;
1904         },
1905
1906         /**
1907          * Direct access to the UpdateManager update() method (takes the same parameters).
1908          * @param {String/Function} url The url for this request or a function to call to get the url
1909          * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
1910          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
1911          * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
1912          * @return {Roo.Element} this
1913          */
1914         load : function(){
1915             var um = this.getUpdateManager();
1916             um.update.apply(um, arguments);
1917             return this;
1918         },
1919
1920         /**
1921         * Gets this element's UpdateManager
1922         * @return {Roo.UpdateManager} The UpdateManager
1923         */
1924         getUpdateManager : function(){
1925             if(!this.updateManager){
1926                 this.updateManager = new Roo.UpdateManager(this);
1927             }
1928             return this.updateManager;
1929         },
1930
1931         /**
1932          * Disables text selection for this element (normalized across browsers)
1933          * @return {Roo.Element} this
1934          */
1935         unselectable : function(){
1936             this.dom.unselectable = "on";
1937             this.swallowEvent("selectstart", true);
1938             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
1939             this.addClass("x-unselectable");
1940             return this;
1941         },
1942
1943         /**
1944         * Calculates the x, y to center this element on the screen
1945         * @return {Array} The x, y values [x, y]
1946         */
1947         getCenterXY : function(){
1948             return this.getAlignToXY(document, 'c-c');
1949         },
1950
1951         /**
1952         * Centers the Element in either the viewport, or another Element.
1953         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
1954         */
1955         center : function(centerIn){
1956             this.alignTo(centerIn || document, 'c-c');
1957             return this;
1958         },
1959
1960         /**
1961          * Tests various css rules/browsers to determine if this element uses a border box
1962          * @return {Boolean}
1963          */
1964         isBorderBox : function(){
1965             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
1966         },
1967
1968         /**
1969          * Return a box {x, y, width, height} that can be used to set another elements
1970          * size/location to match this element.
1971          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
1972          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
1973          * @return {Object} box An object in the format {x, y, width, height}
1974          */
1975         getBox : function(contentBox, local){
1976             var xy;
1977             if(!local){
1978                 xy = this.getXY();
1979             }else{
1980                 var left = parseInt(this.getStyle("left"), 10) || 0;
1981                 var top = parseInt(this.getStyle("top"), 10) || 0;
1982                 xy = [left, top];
1983             }
1984             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
1985             if(!contentBox){
1986                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
1987             }else{
1988                 var l = this.getBorderWidth("l")+this.getPadding("l");
1989                 var r = this.getBorderWidth("r")+this.getPadding("r");
1990                 var t = this.getBorderWidth("t")+this.getPadding("t");
1991                 var b = this.getBorderWidth("b")+this.getPadding("b");
1992                 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
1993             }
1994             bx.right = bx.x + bx.width;
1995             bx.bottom = bx.y + bx.height;
1996             return bx;
1997         },
1998
1999         /**
2000          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
2001          for more information about the sides.
2002          * @param {String} sides
2003          * @return {Number}
2004          */
2005         getFrameWidth : function(sides, onlyContentBox){
2006             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
2007         },
2008
2009         /**
2010          * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
2011          * @param {Object} box The box to fill {x, y, width, height}
2012          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
2013          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2014          * @return {Roo.Element} this
2015          */
2016         setBox : function(box, adjust, animate){
2017             var w = box.width, h = box.height;
2018             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
2019                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
2020                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
2021             }
2022             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
2023             return this;
2024         },
2025
2026         /**
2027          * Forces the browser to repaint this element
2028          * @return {Roo.Element} this
2029          */
2030          repaint : function(){
2031             var dom = this.dom;
2032             this.addClass("x-repaint");
2033             setTimeout(function(){
2034                 Roo.get(dom).removeClass("x-repaint");
2035             }, 1);
2036             return this;
2037         },
2038
2039         /**
2040          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
2041          * then it returns the calculated width of the sides (see getPadding)
2042          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
2043          * @return {Object/Number}
2044          */
2045         getMargins : function(side){
2046             if(!side){
2047                 return {
2048                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
2049                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
2050                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
2051                     right: parseInt(this.getStyle("margin-right"), 10) || 0
2052                 };
2053             }else{
2054                 return this.addStyles(side, El.margins);
2055              }
2056         },
2057
2058         // private
2059         addStyles : function(sides, styles){
2060             var val = 0, v, w;
2061             for(var i = 0, len = sides.length; i < len; i++){
2062                 v = this.getStyle(styles[sides.charAt(i)]);
2063                 if(v){
2064                      w = parseInt(v, 10);
2065                      if(w){ val += w; }
2066                 }
2067             }
2068             return val;
2069         },
2070
2071         /**
2072          * Creates a proxy element of this element
2073          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
2074          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
2075          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
2076          * @return {Roo.Element} The new proxy element
2077          */
2078         createProxy : function(config, renderTo, matchBox){
2079             if(renderTo){
2080                 renderTo = Roo.getDom(renderTo);
2081             }else{
2082                 renderTo = document.body;
2083             }
2084             config = typeof config == "object" ?
2085                 config : {tag : "div", cls: config};
2086             var proxy = Roo.DomHelper.append(renderTo, config, true);
2087             if(matchBox){
2088                proxy.setBox(this.getBox());
2089             }
2090             return proxy;
2091         },
2092
2093         /**
2094          * Puts a mask over this element to disable user interaction. Requires core.css.
2095          * This method can only be applied to elements which accept child nodes.
2096          * @param {String} msg (optional) A message to display in the mask
2097          * @param {String} msgCls (optional) A css class to apply to the msg element
2098          * @return {Element} The mask  element
2099          */
2100         mask : function(msg, msgCls)
2101         {
2102             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
2103                 this.setStyle("position", "relative");
2104             }
2105             if(!this._mask){
2106                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
2107             }
2108             this.addClass("x-masked");
2109             this._mask.setDisplayed(true);
2110             
2111             // we wander
2112             var z = 0;
2113             var dom = this.dom;
2114             while (dom && dom.style) {
2115                 if (!isNaN(parseInt(dom.style.zIndex))) {
2116                     z = Math.max(z, parseInt(dom.style.zIndex));
2117                 }
2118                 dom = dom.parentNode;
2119             }
2120             // if we are masking the body - then it hides everything..
2121             if (this.dom == document.body) {
2122                 z = 1000000;
2123                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
2124                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
2125             }
2126            
2127             if(typeof msg == 'string'){
2128                 if(!this._maskMsg){
2129                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
2130                 }
2131                 var mm = this._maskMsg;
2132                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
2133                 if (mm.dom.firstChild) { // weird IE issue?
2134                     mm.dom.firstChild.innerHTML = msg;
2135                 }
2136                 mm.setDisplayed(true);
2137                 mm.center(this);
2138                 mm.setStyle('z-index', z + 102);
2139             }
2140             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
2141                 this._mask.setHeight(this.getHeight());
2142             }
2143             this._mask.setStyle('z-index', z + 100);
2144             
2145             return this._mask;
2146         },
2147
2148         /**
2149          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
2150          * it is cached for reuse.
2151          */
2152         unmask : function(removeEl){
2153             if(this._mask){
2154                 if(removeEl === true){
2155                     this._mask.remove();
2156                     delete this._mask;
2157                     if(this._maskMsg){
2158                         this._maskMsg.remove();
2159                         delete this._maskMsg;
2160                     }
2161                 }else{
2162                     this._mask.setDisplayed(false);
2163                     if(this._maskMsg){
2164                         this._maskMsg.setDisplayed(false);
2165                     }
2166                 }
2167             }
2168             this.removeClass("x-masked");
2169         },
2170
2171         /**
2172          * Returns true if this element is masked
2173          * @return {Boolean}
2174          */
2175         isMasked : function(){
2176             return this._mask && this._mask.isVisible();
2177         },
2178
2179         /**
2180          * Creates an iframe shim for this element to keep selects and other windowed objects from
2181          * showing through.
2182          * @return {Roo.Element} The new shim element
2183          */
2184         createShim : function(){
2185             var el = document.createElement('iframe');
2186             el.frameBorder = 'no';
2187             el.className = 'roo-shim';
2188             if(Roo.isIE && Roo.isSecure){
2189                 el.src = Roo.SSL_SECURE_URL;
2190             }
2191             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
2192             shim.autoBoxAdjust = false;
2193             return shim;
2194         },
2195
2196         /**
2197          * Removes this element from the DOM and deletes it from the cache
2198          */
2199         remove : function(){
2200             if(this.dom.parentNode){
2201                 this.dom.parentNode.removeChild(this.dom);
2202             }
2203             delete El.cache[this.dom.id];
2204         },
2205
2206         /**
2207          * Sets up event handlers to add and remove a css class when the mouse is over this element
2208          * @param {String} className
2209          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
2210          * mouseout events for children elements
2211          * @return {Roo.Element} this
2212          */
2213         addClassOnOver : function(className, preventFlicker){
2214             this.on("mouseover", function(){
2215                 Roo.fly(this, '_internal').addClass(className);
2216             }, this.dom);
2217             var removeFn = function(e){
2218                 if(preventFlicker !== true || !e.within(this, true)){
2219                     Roo.fly(this, '_internal').removeClass(className);
2220                 }
2221             };
2222             this.on("mouseout", removeFn, this.dom);
2223             return this;
2224         },
2225
2226         /**
2227          * Sets up event handlers to add and remove a css class when this element has the focus
2228          * @param {String} className
2229          * @return {Roo.Element} this
2230          */
2231         addClassOnFocus : function(className){
2232             this.on("focus", function(){
2233                 Roo.fly(this, '_internal').addClass(className);
2234             }, this.dom);
2235             this.on("blur", function(){
2236                 Roo.fly(this, '_internal').removeClass(className);
2237             }, this.dom);
2238             return this;
2239         },
2240         /**
2241          * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
2242          * @param {String} className
2243          * @return {Roo.Element} this
2244          */
2245         addClassOnClick : function(className){
2246             var dom = this.dom;
2247             this.on("mousedown", function(){
2248                 Roo.fly(dom, '_internal').addClass(className);
2249                 var d = Roo.get(document);
2250                 var fn = function(){
2251                     Roo.fly(dom, '_internal').removeClass(className);
2252                     d.removeListener("mouseup", fn);
2253                 };
2254                 d.on("mouseup", fn);
2255             });
2256             return this;
2257         },
2258
2259         /**
2260          * Stops the specified event from bubbling and optionally prevents the default action
2261          * @param {String} eventName
2262          * @param {Boolean} preventDefault (optional) true to prevent the default action too
2263          * @return {Roo.Element} this
2264          */
2265         swallowEvent : function(eventName, preventDefault){
2266             var fn = function(e){
2267                 e.stopPropagation();
2268                 if(preventDefault){
2269                     e.preventDefault();
2270                 }
2271             };
2272             if(eventName instanceof Array){
2273                 for(var i = 0, len = eventName.length; i < len; i++){
2274                      this.on(eventName[i], fn);
2275                 }
2276                 return this;
2277             }
2278             this.on(eventName, fn);
2279             return this;
2280         },
2281
2282         /**
2283          * @private
2284          */
2285       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
2286
2287         /**
2288          * Sizes this element to its parent element's dimensions performing
2289          * neccessary box adjustments.
2290          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
2291          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
2292          * @return {Roo.Element} this
2293          */
2294         fitToParent : function(monitorResize, targetParent) {
2295           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
2296           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
2297           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
2298             return;
2299           }
2300           var p = Roo.get(targetParent || this.dom.parentNode);
2301           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
2302           if (monitorResize === true) {
2303             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
2304             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
2305           }
2306           return this;
2307         },
2308
2309         /**
2310          * Gets the next sibling, skipping text nodes
2311          * @return {HTMLElement} The next sibling or null
2312          */
2313         getNextSibling : function(){
2314             var n = this.dom.nextSibling;
2315             while(n && n.nodeType != 1){
2316                 n = n.nextSibling;
2317             }
2318             return n;
2319         },
2320
2321         /**
2322          * Gets the previous sibling, skipping text nodes
2323          * @return {HTMLElement} The previous sibling or null
2324          */
2325         getPrevSibling : function(){
2326             var n = this.dom.previousSibling;
2327             while(n && n.nodeType != 1){
2328                 n = n.previousSibling;
2329             }
2330             return n;
2331         },
2332
2333
2334         /**
2335          * Appends the passed element(s) to this element
2336          * @param {String/HTMLElement/Array/Element/CompositeElement} el
2337          * @return {Roo.Element} this
2338          */
2339         appendChild: function(el){
2340             el = Roo.get(el);
2341             el.appendTo(this);
2342             return this;
2343         },
2344
2345         /**
2346          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
2347          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
2348          * automatically generated with the specified attributes.
2349          * @param {HTMLElement} insertBefore (optional) a child element of this element
2350          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
2351          * @return {Roo.Element} The new child element
2352          */
2353         createChild: function(config, insertBefore, returnDom){
2354             config = config || {tag:'div'};
2355             if(insertBefore){
2356                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
2357             }
2358             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
2359         },
2360
2361         /**
2362          * Appends this element to the passed element
2363          * @param {String/HTMLElement/Element} el The new parent element
2364          * @return {Roo.Element} this
2365          */
2366         appendTo: function(el){
2367             el = Roo.getDom(el);
2368             el.appendChild(this.dom);
2369             return this;
2370         },
2371
2372         /**
2373          * Inserts this element before the passed element in the DOM
2374          * @param {String/HTMLElement/Element} el The element to insert before
2375          * @return {Roo.Element} this
2376          */
2377         insertBefore: function(el){
2378             el = Roo.getDom(el);
2379             el.parentNode.insertBefore(this.dom, el);
2380             return this;
2381         },
2382
2383         /**
2384          * Inserts this element after the passed element in the DOM
2385          * @param {String/HTMLElement/Element} el The element to insert after
2386          * @return {Roo.Element} this
2387          */
2388         insertAfter: function(el){
2389             el = Roo.getDom(el);
2390             el.parentNode.insertBefore(this.dom, el.nextSibling);
2391             return this;
2392         },
2393
2394         /**
2395          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
2396          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2397          * @return {Roo.Element} The new child
2398          */
2399         insertFirst: function(el, returnDom){
2400             el = el || {};
2401             if(typeof el == 'object' && !el.nodeType){ // dh config
2402                 return this.createChild(el, this.dom.firstChild, returnDom);
2403             }else{
2404                 el = Roo.getDom(el);
2405                 this.dom.insertBefore(el, this.dom.firstChild);
2406                 return !returnDom ? Roo.get(el) : el;
2407             }
2408         },
2409
2410         /**
2411          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
2412          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
2413          * @param {String} where (optional) 'before' or 'after' defaults to before
2414          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2415          * @return {Roo.Element} the inserted Element
2416          */
2417         insertSibling: function(el, where, returnDom){
2418             where = where ? where.toLowerCase() : 'before';
2419             el = el || {};
2420             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
2421
2422             if(typeof el == 'object' && !el.nodeType){ // dh config
2423                 if(where == 'after' && !this.dom.nextSibling){
2424                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
2425                 }else{
2426                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
2427                 }
2428
2429             }else{
2430                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
2431                             where == 'before' ? this.dom : this.dom.nextSibling);
2432                 if(!returnDom){
2433                     rt = Roo.get(rt);
2434                 }
2435             }
2436             return rt;
2437         },
2438
2439         /**
2440          * Creates and wraps this element with another element
2441          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
2442          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
2443          * @return {HTMLElement/Element} The newly created wrapper element
2444          */
2445         wrap: function(config, returnDom){
2446             if(!config){
2447                 config = {tag: "div"};
2448             }
2449             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
2450             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
2451             return newEl;
2452         },
2453
2454         /**
2455          * Replaces the passed element with this element
2456          * @param {String/HTMLElement/Element} el The element to replace
2457          * @return {Roo.Element} this
2458          */
2459         replace: function(el){
2460             el = Roo.get(el);
2461             this.insertBefore(el);
2462             el.remove();
2463             return this;
2464         },
2465
2466         /**
2467          * Inserts an html fragment into this element
2468          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
2469          * @param {String} html The HTML fragment
2470          * @param {Boolean} returnEl True to return an Roo.Element
2471          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
2472          */
2473         insertHtml : function(where, html, returnEl){
2474             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
2475             return returnEl ? Roo.get(el) : el;
2476         },
2477
2478         /**
2479          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
2480          * @param {Object} o The object with the attributes
2481          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
2482          * @return {Roo.Element} this
2483          */
2484         set : function(o, useSet){
2485             var el = this.dom;
2486             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
2487             for(var attr in o){
2488                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
2489                 if(attr=="cls"){
2490                     el.className = o["cls"];
2491                 }else{
2492                     if(useSet) {
2493                         el.setAttribute(attr, o[attr]);
2494                     } else {
2495                         el[attr] = o[attr];
2496                     }
2497                 }
2498             }
2499             if(o.style){
2500                 Roo.DomHelper.applyStyles(el, o.style);
2501             }
2502             return this;
2503         },
2504
2505         /**
2506          * Convenience method for constructing a KeyMap
2507          * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
2508          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
2509          * @param {Function} fn The function to call
2510          * @param {Object} scope (optional) The scope of the function
2511          * @return {Roo.KeyMap} The KeyMap created
2512          */
2513         addKeyListener : function(key, fn, scope){
2514             var config;
2515             if(typeof key != "object" || key instanceof Array){
2516                 config = {
2517                     key: key,
2518                     fn: fn,
2519                     scope: scope
2520                 };
2521             }else{
2522                 config = {
2523                     key : key.key,
2524                     shift : key.shift,
2525                     ctrl : key.ctrl,
2526                     alt : key.alt,
2527                     fn: fn,
2528                     scope: scope
2529                 };
2530             }
2531             return new Roo.KeyMap(this, config);
2532         },
2533
2534         /**
2535          * Creates a KeyMap for this element
2536          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
2537          * @return {Roo.KeyMap} The KeyMap created
2538          */
2539         addKeyMap : function(config){
2540             return new Roo.KeyMap(this, config);
2541         },
2542
2543         /**
2544          * Returns true if this element is scrollable.
2545          * @return {Boolean}
2546          */
2547          isScrollable : function(){
2548             var dom = this.dom;
2549             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
2550         },
2551
2552         /**
2553          * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
2554          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
2555          * @param {Number} value The new scroll value
2556          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2557          * @return {Element} this
2558          */
2559
2560         scrollTo : function(side, value, animate){
2561             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
2562             if(!animate || !A){
2563                 this.dom[prop] = value;
2564             }else{
2565                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
2566                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
2567             }
2568             return this;
2569         },
2570
2571         /**
2572          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
2573          * within this element's scrollable range.
2574          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
2575          * @param {Number} distance How far to scroll the element in pixels
2576          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2577          * @return {Boolean} Returns true if a scroll was triggered or false if the element
2578          * was scrolled as far as it could go.
2579          */
2580          scroll : function(direction, distance, animate){
2581              if(!this.isScrollable()){
2582                  return;
2583              }
2584              var el = this.dom;
2585              var l = el.scrollLeft, t = el.scrollTop;
2586              var w = el.scrollWidth, h = el.scrollHeight;
2587              var cw = el.clientWidth, ch = el.clientHeight;
2588              direction = direction.toLowerCase();
2589              var scrolled = false;
2590              var a = this.preanim(arguments, 2);
2591              switch(direction){
2592                  case "l":
2593                  case "left":
2594                      if(w - l > cw){
2595                          var v = Math.min(l + distance, w-cw);
2596                          this.scrollTo("left", v, a);
2597                          scrolled = true;
2598                      }
2599                      break;
2600                 case "r":
2601                 case "right":
2602                      if(l > 0){
2603                          var v = Math.max(l - distance, 0);
2604                          this.scrollTo("left", v, a);
2605                          scrolled = true;
2606                      }
2607                      break;
2608                 case "t":
2609                 case "top":
2610                 case "up":
2611                      if(t > 0){
2612                          var v = Math.max(t - distance, 0);
2613                          this.scrollTo("top", v, a);
2614                          scrolled = true;
2615                      }
2616                      break;
2617                 case "b":
2618                 case "bottom":
2619                 case "down":
2620                      if(h - t > ch){
2621                          var v = Math.min(t + distance, h-ch);
2622                          this.scrollTo("top", v, a);
2623                          scrolled = true;
2624                      }
2625                      break;
2626              }
2627              return scrolled;
2628         },
2629
2630         /**
2631          * Translates the passed page coordinates into left/top css values for this element
2632          * @param {Number/Array} x The page x or an array containing [x, y]
2633          * @param {Number} y The page y
2634          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
2635          */
2636         translatePoints : function(x, y){
2637             if(typeof x == 'object' || x instanceof Array){
2638                 y = x[1]; x = x[0];
2639             }
2640             var p = this.getStyle('position');
2641             var o = this.getXY();
2642
2643             var l = parseInt(this.getStyle('left'), 10);
2644             var t = parseInt(this.getStyle('top'), 10);
2645
2646             if(isNaN(l)){
2647                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
2648             }
2649             if(isNaN(t)){
2650                 t = (p == "relative") ? 0 : this.dom.offsetTop;
2651             }
2652
2653             return {left: (x - o[0] + l), top: (y - o[1] + t)};
2654         },
2655
2656         /**
2657          * Returns the current scroll position of the element.
2658          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
2659          */
2660         getScroll : function(){
2661             var d = this.dom, doc = document;
2662             if(d == doc || d == doc.body){
2663                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
2664                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
2665                 return {left: l, top: t};
2666             }else{
2667                 return {left: d.scrollLeft, top: d.scrollTop};
2668             }
2669         },
2670
2671         /**
2672          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
2673          * are convert to standard 6 digit hex color.
2674          * @param {String} attr The css attribute
2675          * @param {String} defaultValue The default value to use when a valid color isn't found
2676          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
2677          * YUI color anims.
2678          */
2679         getColor : function(attr, defaultValue, prefix){
2680             var v = this.getStyle(attr);
2681             if(!v || v == "transparent" || v == "inherit") {
2682                 return defaultValue;
2683             }
2684             var color = typeof prefix == "undefined" ? "#" : prefix;
2685             if(v.substr(0, 4) == "rgb("){
2686                 var rvs = v.slice(4, v.length -1).split(",");
2687                 for(var i = 0; i < 3; i++){
2688                     var h = parseInt(rvs[i]).toString(16);
2689                     if(h < 16){
2690                         h = "0" + h;
2691                     }
2692                     color += h;
2693                 }
2694             } else {
2695                 if(v.substr(0, 1) == "#"){
2696                     if(v.length == 4) {
2697                         for(var i = 1; i < 4; i++){
2698                             var c = v.charAt(i);
2699                             color +=  c + c;
2700                         }
2701                     }else if(v.length == 7){
2702                         color += v.substr(1);
2703                     }
2704                 }
2705             }
2706             return(color.length > 5 ? color.toLowerCase() : defaultValue);
2707         },
2708
2709         /**
2710          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
2711          * gradient background, rounded corners and a 4-way shadow.
2712          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
2713          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
2714          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
2715          * @return {Roo.Element} this
2716          */
2717         boxWrap : function(cls){
2718             cls = cls || 'x-box';
2719             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
2720             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
2721             return el;
2722         },
2723
2724         /**
2725          * Returns the value of a namespaced attribute from the element's underlying DOM node.
2726          * @param {String} namespace The namespace in which to look for the attribute
2727          * @param {String} name The attribute name
2728          * @return {String} The attribute value
2729          */
2730         getAttributeNS : Roo.isIE ? function(ns, name){
2731             var d = this.dom;
2732             var type = typeof d[ns+":"+name];
2733             if(type != 'undefined' && type != 'unknown'){
2734                 return d[ns+":"+name];
2735             }
2736             return d[name];
2737         } : function(ns, name){
2738             var d = this.dom;
2739             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
2740         },
2741         
2742         
2743         /**
2744          * Sets or Returns the value the dom attribute value
2745          * @param {String|Object} name The attribute name (or object to set multiple attributes)
2746          * @param {String} value (optional) The value to set the attribute to
2747          * @return {String} The attribute value
2748          */
2749         attr : function(name){
2750             if (arguments.length > 1) {
2751                 this.dom.setAttribute(name, arguments[1]);
2752                 return arguments[1];
2753             }
2754             if (typeof(name) == 'object') {
2755                 for(var i in name) {
2756                     this.attr(i, name[i]);
2757                 }
2758                 return name;
2759             }
2760             
2761             
2762             if (!this.dom.hasAttribute(name)) {
2763                 return undefined;
2764             }
2765             return this.dom.getAttribute(name);
2766         }
2767         
2768         
2769         
2770     };
2771
2772     var ep = El.prototype;
2773
2774     /**
2775      * Appends an event handler (Shorthand for addListener)
2776      * @param {String}   eventName     The type of event to append
2777      * @param {Function} fn        The method the event invokes
2778      * @param {Object} scope       (optional) The scope (this object) of the fn
2779      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
2780      * @method
2781      */
2782     ep.on = ep.addListener;
2783         // backwards compat
2784     ep.mon = ep.addListener;
2785
2786     /**
2787      * Removes an event handler from this element (shorthand for removeListener)
2788      * @param {String} eventName the type of event to remove
2789      * @param {Function} fn the method the event invokes
2790      * @return {Roo.Element} this
2791      * @method
2792      */
2793     ep.un = ep.removeListener;
2794
2795     /**
2796      * true to automatically adjust width and height settings for box-model issues (default to true)
2797      */
2798     ep.autoBoxAdjust = true;
2799
2800     // private
2801     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
2802
2803     // private
2804     El.addUnits = function(v, defaultUnit){
2805         if(v === "" || v == "auto"){
2806             return v;
2807         }
2808         if(v === undefined){
2809             return '';
2810         }
2811         if(typeof v == "number" || !El.unitPattern.test(v)){
2812             return v + (defaultUnit || 'px');
2813         }
2814         return v;
2815     };
2816
2817     // special markup used throughout Roo when box wrapping elements
2818     El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
2819     /**
2820      * Visibility mode constant - Use visibility to hide element
2821      * @static
2822      * @type Number
2823      */
2824     El.VISIBILITY = 1;
2825     /**
2826      * Visibility mode constant - Use display to hide element
2827      * @static
2828      * @type Number
2829      */
2830     El.DISPLAY = 2;
2831
2832     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
2833     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
2834     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
2835
2836
2837
2838     /**
2839      * @private
2840      */
2841     El.cache = {};
2842
2843     var docEl;
2844
2845     /**
2846      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
2847      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2848      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
2849      * @return {Element} The Element object
2850      * @static
2851      */
2852     El.get = function(el){
2853         var ex, elm, id;
2854         if(!el){ return null; }
2855         if(typeof el == "string"){ // element id
2856             if(!(elm = document.getElementById(el))){
2857                 return null;
2858             }
2859             if(ex = El.cache[el]){
2860                 ex.dom = elm;
2861             }else{
2862                 ex = El.cache[el] = new El(elm);
2863             }
2864             return ex;
2865         }else if(el.tagName){ // dom element
2866             if(!(id = el.id)){
2867                 id = Roo.id(el);
2868             }
2869             if(ex = El.cache[id]){
2870                 ex.dom = el;
2871             }else{
2872                 ex = El.cache[id] = new El(el);
2873             }
2874             return ex;
2875         }else if(el instanceof El){
2876             if(el != docEl){
2877                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
2878                                                               // catch case where it hasn't been appended
2879                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
2880             }
2881             return el;
2882         }else if(el.isComposite){
2883             return el;
2884         }else if(el instanceof Array){
2885             return El.select(el);
2886         }else if(el == document){
2887             // create a bogus element object representing the document object
2888             if(!docEl){
2889                 var f = function(){};
2890                 f.prototype = El.prototype;
2891                 docEl = new f();
2892                 docEl.dom = document;
2893             }
2894             return docEl;
2895         }
2896         return null;
2897     };
2898
2899     // private
2900     El.uncache = function(el){
2901         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
2902             if(a[i]){
2903                 delete El.cache[a[i].id || a[i]];
2904             }
2905         }
2906     };
2907
2908     // private
2909     // Garbage collection - uncache elements/purge listeners on orphaned elements
2910     // so we don't hold a reference and cause the browser to retain them
2911     El.garbageCollect = function(){
2912         if(!Roo.enableGarbageCollector){
2913             clearInterval(El.collectorThread);
2914             return;
2915         }
2916         for(var eid in El.cache){
2917             var el = El.cache[eid], d = el.dom;
2918             // -------------------------------------------------------
2919             // Determining what is garbage:
2920             // -------------------------------------------------------
2921             // !d
2922             // dom node is null, definitely garbage
2923             // -------------------------------------------------------
2924             // !d.parentNode
2925             // no parentNode == direct orphan, definitely garbage
2926             // -------------------------------------------------------
2927             // !d.offsetParent && !document.getElementById(eid)
2928             // display none elements have no offsetParent so we will
2929             // also try to look it up by it's id. However, check
2930             // offsetParent first so we don't do unneeded lookups.
2931             // This enables collection of elements that are not orphans
2932             // directly, but somewhere up the line they have an orphan
2933             // parent.
2934             // -------------------------------------------------------
2935             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
2936                 delete El.cache[eid];
2937                 if(d && Roo.enableListenerCollection){
2938                     E.purgeElement(d);
2939                 }
2940             }
2941         }
2942     }
2943     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
2944
2945
2946     // dom is optional
2947     El.Flyweight = function(dom){
2948         this.dom = dom;
2949     };
2950     El.Flyweight.prototype = El.prototype;
2951
2952     El._flyweights = {};
2953     /**
2954      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
2955      * the dom node can be overwritten by other code.
2956      * @param {String/HTMLElement} el The dom node or id
2957      * @param {String} named (optional) Allows for creation of named reusable flyweights to
2958      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
2959      * @static
2960      * @return {Element} The shared Element object
2961      */
2962     El.fly = function(el, named){
2963         named = named || '_global';
2964         el = Roo.getDom(el);
2965         if(!el){
2966             return null;
2967         }
2968         if(!El._flyweights[named]){
2969             El._flyweights[named] = new El.Flyweight();
2970         }
2971         El._flyweights[named].dom = el;
2972         return El._flyweights[named];
2973     };
2974
2975     /**
2976      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
2977      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2978      * Shorthand of {@link Roo.Element#get}
2979      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
2980      * @return {Element} The Element object
2981      * @member Roo
2982      * @method get
2983      */
2984     Roo.get = El.get;
2985     /**
2986      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
2987      * the dom node can be overwritten by other code.
2988      * Shorthand of {@link Roo.Element#fly}
2989      * @param {String/HTMLElement} el The dom node or id
2990      * @param {String} named (optional) Allows for creation of named reusable flyweights to
2991      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
2992      * @static
2993      * @return {Element} The shared Element object
2994      * @member Roo
2995      * @method fly
2996      */
2997     Roo.fly = El.fly;
2998
2999     // speedy lookup for elements never to box adjust
3000     var noBoxAdjust = Roo.isStrict ? {
3001         select:1
3002     } : {
3003         input:1, select:1, textarea:1
3004     };
3005     if(Roo.isIE || Roo.isGecko){
3006         noBoxAdjust['button'] = 1;
3007     }
3008
3009
3010     Roo.EventManager.on(window, 'unload', function(){
3011         delete El.cache;
3012         delete El._flyweights;
3013     });
3014 })();
3015
3016
3017
3018
3019 if(Roo.DomQuery){
3020     Roo.Element.selectorFunction = Roo.DomQuery.select;
3021 }
3022
3023 Roo.Element.select = function(selector, unique, root){
3024     var els;
3025     if(typeof selector == "string"){
3026         els = Roo.Element.selectorFunction(selector, root);
3027     }else if(selector.length !== undefined){
3028         els = selector;
3029     }else{
3030         throw "Invalid selector";
3031     }
3032     if(unique === true){
3033         return new Roo.CompositeElement(els);
3034     }else{
3035         return new Roo.CompositeElementLite(els);
3036     }
3037 };
3038 /**
3039  * Selects elements based on the passed CSS selector to enable working on them as 1.
3040  * @param {String/Array} selector The CSS selector or an array of elements
3041  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
3042  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
3043  * @return {CompositeElementLite/CompositeElement}
3044  * @member Roo
3045  * @method select
3046  */
3047 Roo.select = Roo.Element.select;
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061