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